この記事では、元の著者である、最初の有名なアドレスのテキストで再現場合はオープンの公共の数字が白転載ため、お申し込みください。
ガイド-springboot:春ブートチュートリアル(一緒に暇な時間の保守、メンテナンス歓迎)初心者に適しただけでなく、経験豊富な開発者のアクセス。
データ検証の重要性は、その後、再びそれを確認HTTPツールの数によってブラウザバイパスへの直接ユーザーを避けるためにも、フロントエンドのデータ検証の場合には、我々はまだ、着信バックエンドデータを持って、言ったことはなかっただろうバックエンドのデータにいくつかの違法直接リクエスト。
プロジェクトの彼の実務経験と組み合わせるこの記事では、と言うことができる友人はあなたが学ぶことができます理解していない、あなたはすぐにプロジェクトをバックアップするために練習することができ、記事の内容は非常に実用的な記述します。
今私はどのように、特に春の番組プログラムによって、Javaプログラムのインスタンスのパラメータの優雅検証で実証します。
ビルド・インフラストラクチャ
その依存関係
通常のJavaプログラムの開発する場合は、次のようにこれに依存する必要がする必要があるかもしれません。
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.9.Final</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.6</version>
</dependency>
使用春のブートプログラムは、その後、ちょうどspring-boot-starter-web
十分な、それの依存子は、私たちが必要なものを含めます。この依存性に加えて、以下のデモもそうその依存関係に追加することを忘れないでください、ロンボクを使用しています。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Entityクラス
以下のものを用い、エンティティ・クラスの一例です。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
@NotNull(message = "classId 不能为空")
private String classId;
@Size(max = 33)
@NotNull(message = "name 不能为空")
private String name;
@Pattern(regexp = "((^Man$|^Woman$|^UGM$))", message = "sex 值不在可选范围")
@NotNull(message = "sex 不能为空")
private String sex;
@Email(message = "email 格式不正确")
@NotNull(message = "email 不能为空")
private String email;
}
正規表現の説明:
- ^string : 匹配以 string 开头的字符串 - string$ :匹配以 string 结尾的字符串 - ^string$ :精确匹配 string 字符串 - ((^Man$|^Woman$|^UGM$)) : 值只能在 Man,Woman,UGM 这三个值中选择
ます。https:次のセクションから参照チェックノートの内容を示して//www.cnkirito.moe/spring-validation/、@感謝徐Jingfeng。
JSR申し出は、注意事項をご確認ください:
@Null
注釈付き要素がnullでなければなりません@NotNull
注釈付きの要素はnullであってはなりません@AssertTrue
注釈付きされている要素が真でなければなりません@AssertFalse
注釈付きされている要素はfalseでなければなりません@Min(value)
注釈付き要素は、値が指定された最小値よりも大きくなければならない数でなければなりません@Max(value)
注釈付き要素は、指定されたに等しい最大値未満でなければならない数でなければなりません@DecimalMin(value)
注釈付き要素は、値が指定された最小値よりも大きくなければならない数でなければなりません@DecimalMax(value)
注釈付き要素は、指定されたに等しい最大値未満でなければならない数でなければなりません@Size(max=, min=)
指定された範囲内に注釈されるべき要素のサイズ@Digits (integer, fraction)
注釈付き要素は、その値が許容範囲内でなければならない数でなければなりません@Past
注釈付き要素は、過去の日付でなければなりません@Future
注釈付き要素は、将来の日付でなければなりません
@Pattern(regex=,flag=)
注釈付きされている要素は、指定された正規表現を満たす必要があります。
Hibernateバリは、検証のアノテーションを提供します:
@NotBlank(message =)
認証文字列がnullでなく、長さが0より大きくなければなりません@Email
注釈付き要素は、電子メールアドレスでなければなりません@Length(min=,max=)
文字列のサイズが指定された範囲内でなければなりません@NotEmpty
注釈付きの文字列はnullであってはなりません@Range(min=,max=,message=)
要素は、適切な範囲で注釈を付けなければなりません
入力コントローラの検証
検証要求ボディ(requestBody)
コントローラ:
私たちは、追加のパラメータを確認する必要があり@Valid
、検証が失敗した場合、それは投げ、コメントをMethodArgumentNotValidException
。デフォルトでは、春は非常にHTTPステータス400(不正な要求)には、この変換されます。
@RestController
@RequestMapping("/api")
public class PersonController {
@PostMapping("/person")
public ResponseEntity<Person> getPerson(@RequestBody @Valid Person person) {
return ResponseEntity.ok().body(person);
}
}
exceptionHandlerの:
カスタム例外ハンドラは、私たちは例外、およびいくつかの簡単な処理をキャッチすることができます。場合は、理解していないコードを扱う以下の例外のために、あなたは記事を参照することができ、「いくつかの一般的な異常姿勢のSpringBoot治療を」。
@ControllerAdvice(assignableTypes = {PersonController.class})
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidationExceptions(
MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errors);
}
}
テストを通じて検証:
私は発効は、もちろん、あなたはまた、ポストマンツールでこれを確認できることを確認しMockMvcコントローラーのシミュレーションにより、次のように要求します。
我々は、すべての状況の正確なパラメータを入力してみてください。
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class PersonControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@Test
public void should_get_person_correctly() throws Exception {
Person person = new Person();
person.setName("SnailClimb");
person.setSex("Man");
person.setClassId("82938390");
person.setEmail("[email protected]");
mockMvc.perform(post("/api/person")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(objectMapper.writeValueAsString(person)))
.andExpect(MockMvcResultMatchers.jsonPath("name").value("SnailClimb"))
.andExpect(MockMvcResultMatchers.jsonPath("classId").value("82938390"))
.andExpect(MockMvcResultMatchers.jsonPath("sex").value("Man"))
.andExpect(MockMvcResultMatchers.jsonPath("email").value("[email protected]"));
}
}
認証は、不正な状況が例外をスローし、正確に捉えることができるパラメータ。
@Test
public void should_check_person_value() throws Exception {
Person person = new Person();
person.setSex("Man22");
person.setClassId("82938390");
person.setEmail("SnailClimb");
mockMvc.perform(post("/api/person")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(objectMapper.writeValueAsString(person)))
.andExpect(MockMvcResultMatchers.jsonPath("sex").value("sex 值不在可选范围"))
.andExpect(MockMvcResultMatchers.jsonPath("name").value("name 不能为空"))
.andExpect(MockMvcResultMatchers.jsonPath("email").value("email 格式不正确"));
}
次のように検証結果を使用して郵便配達は以下のとおりです。
パラメータの検証要求(パス変数とリクエストパラメータ)
コントローラ:
必ずクラスに追加することを忘れないようにする必要がありますValidated
ノート、このパラメータは、メソッドのパラメータをチェックするために春を告げることができます。
@RestController
@RequestMapping("/api")
@Validated
public class PersonController {
@GetMapping("/person/{id}")
public ResponseEntity<Integer> getPersonByID(@Valid @PathVariable("id") @Max(value = 5,message = "超过 id 的范围了") Integer id) {
return ResponseEntity.ok().body(id);
}
@PutMapping("/person")
public ResponseEntity<String> getPersonByName(@Valid @RequestParam("name") @Size(max = 6,message = "超过 name 的范围了") String name) {
return ResponseEntity.ok().body(name);
}
}
exceptionHandlerの:
@ExceptionHandler(ConstraintViolationException.class)
ResponseEntity<String> handleConstraintViolationException(ConstraintViolationException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
}
テストを通じて検証:
@Test
public void should_check_param_value() throws Exception {
mockMvc.perform(get("/api/person/6")
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isBadRequest())
.andExpect(content().string("getPersonByID.id: 超过 id 的范围了"));
}
@Test
public void should_check_param_value2() throws Exception {
mockMvc.perform(put("/api/person")
.param("name","snailclimbsnailclimb")
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isBadRequest())
.andExpect(content().string("getPersonByName.name: 超过 name 的范围了"));
}
認証方式のサービス
我々はまた、任意の入力春のコンポーネントは、レベルコントローラの入力を検証するのではなく、我々が使用できることを確認することができます@Validated
し、@Valid
要件コメントのこの組み合わせを達成するために。
必ずクラスに追加することを忘れないようにする必要がありますValidated
ノート、このパラメータは、メソッドのパラメータをチェックするために春を告げることができます。
@Service
@Validated
public class PersonService {
public void validatePerson(@Valid Person person){
// do something
}
}
テストを通じて検証:
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class PersonServiceTest {
@Autowired
private PersonService service;
@Test(expected = ConstraintViolationException.class)
public void should_throw_exception_when_person_is_not_valid() {
Person person = new Person();
person.setSex("Man22");
person.setClassId("82938390");
person.setEmail("SnailClimb");
service.validatePerson(person);
}
}
Validatorは、手動でプログラミングパラメータを検証します
私たちは、手動でいくつかのシーンをチェックし、検証結果を取得する必要があるかもしれません。
@Test
public void check_person_manually() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Person person = new Person();
person.setSex("Man22");
person.setClassId("82938390");
person.setEmail("SnailClimb");
Set<ConstraintViolation<Person>> violations = validator.validate(person);
//output:
//email 格式不正确
//name 不能为空
//sex 值不在可选范围
for (ConstraintViolation<Person> constraintViolation : violations) {
System.out.println(constraintViolation.getMessage());
}
}
私たちの上にValidator
ファクトリクラスを取得するためにValidator
あなたがすることもでき、もちろん、例を@Autowired
直接注入する方法。しかし、非春のコンポーネントのクラスでは、この方法では、それが唯一のファクトリクラスによって得ることができますValidator
。
@Autowired
Validator validate
バリデータとカスタマイズ(実用)
チェックは注釈がニーズを満たすことができない来る場合は、実装上の注意をカスタマイズすることができます。
ケース:チェック特定のフィールド選択可能な範囲かどうか
例えば、我々は今、このような要望を持っている:人クラス1つの以上のフィールド領域のみフィールド領域China
、China-Taiwan
、China-HongKong
1で3。
最初のステップは、あなたはコメントを作成する必要があります。
@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = RegionValidator.class)
@Documented
public @interface Region {
String message() default "Region 值不在可选范围内";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
第二のステップは、あなたが実装する必要があるConstraintValidator
インターフェイスを、そしてオーバーライドするisValid
方法を:
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
public class RegionValidator implements ConstraintValidator<Region, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
HashSet<Object> regions = new HashSet<>();
regions.add("China");
regions.add("China-Taiwan");
regions.add("China-HongKong");
return regions.contains(value);
}
}
今、あなたはこのコメントを使用することができます。
@Region
private String region;
ケースII:チェックの電話番号
私たちの電話番号を確認し、これは正規表現を介して行うことができ、正当なものであるに関連する正規表現がオンラインで見つけることができ、あなたも、特定の事業者の電話番号セクションに正規表現を検索することができます。
PhoneNumber.java
import javax.validation.Constraint;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Documented
@Constraint(validatedBy = PhoneNumberValidator.class)
@Target({FIELD, PARAMETER})
@Retention(RUNTIME)
public @interface PhoneNumber {
String message() default "Invalid phone number";
Class[] groups() default {};
Class[] payload() default {};
}
PhoneNumberValidator.java
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class PhoneNumberValidator implements ConstraintValidator<PhoneNumber,String> {
@Override
public boolean isValid(String phoneField, ConstraintValidatorContext context) {
if (phoneField == null) {
// can be null
return true;
}
return phoneField.matches("^1(3[0-9]|4[57]|5[0-35-9]|8[0-9]|70)\\d{8}$") && phoneField.length() > 8 && phoneField.length() < 14;
}
}
取得し、我々は今、この注釈付きを使用することができます。
@PhoneNumber(message = "phoneNumber 格式不正确")
@NotNull(message = "phoneNumber 不能为空")
private String phoneNumber;
使用検証グループ
単純なポイントは、オブジェクトの検証作業の異なる方法で異なるルールがあるということです、このプロジェクトの私の現在の経験を次の例は、(あまりを使用することであると述べた我々はそれがあるかもしれないと述べたグループを、確認するために使用する必要がありますいくつかのシナリオの下では、明確ではありませんコード自体はこのレベルが)たくさんの悩みを書くために、その後、理解するための多くの問題ですので。
二つのインターフェースを作成します。
public interface AddPersonGroup {
}
public interface DeletePersonGroup {
}
私たちは、グループを確認するためにこれを使用することができます
@NotNull(groups = DeletePersonGroup.class)
@Null(groups = AddPersonGroup.class)
private String group;
@Service
@Validated
public class PersonService {
public void validatePerson(@Valid Person person) {
// do something
}
@Validated(AddPersonGroup.class)
public void validatePersonGroupForAdd(@Valid Person person) {
// do something
}
@Validated(DeletePersonGroup.class)
public void validatePersonGroupForDelete(@Valid Person person) {
// do something
}
}
テストを通じて検証:
@Test(expected = ConstraintViolationException.class)
public void should_check_person_with_groups() {
Person person = new Person();
person.setSex("Man22");
person.setClassId("82938390");
person.setEmail("SnailClimb");
person.setGroup("group1");
service.validatePersonGroupForAdd(person);
}
@Test(expected = ConstraintViolationException.class)
public void should_check_person_with_groups2() {
Person person = new Person();
person.setSex("Man22");
person.setClassId("82938390");
person.setEmail("SnailClimb");
service.validatePersonGroupForDelete(person);
}
注意しなければならない。このように、検証グループを使用し、これはアンチパターンである、それは貧しいコードのロジックになります。
コードのアドレスします。https://github.com/Snailclimb/springboot-guide/tree/master/source-code/advanced/bean-validation-demo
@NotNull
VS @Column(nullable = false)
(重要)
JPA動作するデータを使用しているとき、私たちはしばしば遭遇する@Column(nullable = false)
拘束のこのタイプを、それと@NotNull
はどのような違いを生むのでしょうか?これは非常に重要であることを理解!
@NotNull
JSR 303ビーン検証が承認され、それがデータベースの制約自体とは何の関係もありません。@Column(nullable = false)
:JPAは、空でないアプローチとして宣言されています。
結論は、後者は、データベーステーブルにテーブル制約を作成する場合を示すために使用される前者は、検証するために使用されることです。
ALL
- []原理分析
参照
- https://reflectoring.io/bean-validation-with-spring-boot/
- https://www.cnkirito.moe/spring-validation//
推奨されるオープンソースプロジェクト
他のオープンソースプロジェクトの推薦:
- JavaGuide:Javaの学習[+]面接ガイドは、Javaプログラマの大半はコアな知識を習得する必要がカバーしています。
- ガイド-springboot:春ブートチュートリアル(一緒に暇な時間の保守、メンテナンス歓迎)初心者に適しただけでなく、経験豊富な開発者のアクセス。
- 進歩-プログラマー:私は技術スタッフが、いくつかの良い習慣を持つべきだと思います!
- -security-JWTスプリングガイド:ゼロから始めましょう!(検証機関を含む)春のセキュリティが強化されたJWTコードの後端部。