Web 開発 - データ検証
アプリケーション システムの場合、クライアントから送信されるデータは完全に安全かつ有効であるわけではないため、サーバーがデータを受信するときにデータの有効性を検証して、受信データが安全で正しいことを確認する必要があります。次に、Spring Boot がデータ検証を実装する方法を紹介します。
1. Hibernate Validator の概要
データ検証は Web 開発の重要な部分であり、現在、JSR-303/JSR-349、Hibernate Validator、Spring Validation など、データ検証用の仕様とコンポーネントが多数存在します。
- JSR (Java Specific Request) 仕様は、Bean Validation とも呼ばれる Java EE 6 のサブ仕様です。これは、Bean ベースの検証 API のセットを指定し、アノテーションを通じてオブジェクトのプロパティに制約を追加します。
- Hibernate Validator は JSR 仕様の実装であり、@Email、@Length、@Range などの他の検証アノテーションを追加します。
- Spring Validation は、開発者に利便性を提供するための Spring の Hibernate Validator の 2 番目のパッケージです。同時に、Spring Validation は自動検証を SpringMVC モジュールに追加し、検証情報を特定のクラスにカプセル化します。
JSR はデータ検証仕様を定義しており、Hibernate Validator は JSR 仕様に基づいており、さまざまなデータ検証アノテーションといくつかの追加の制約アノテーションを実装しています。Spring Validation は Hibernate Validator のカプセル化と統合です。JSR と Hibernate Validator で一般的に使用されるアノテーションを表に示します。
このテーブルには、Hibernate Validator によって実装された JSR-303 によって定義された検証アノテーションと、Hibernate Validator 自体によって定義された検証アノテーションが含まれており、カスタム制約アノテーションもサポートされています。すべてのアノテーションには、コードとメッセージという 2 つの属性が含まれます。
- メッセージは、データ検証が失敗した場合のエラー メッセージを定義します。
- コードが間違った型を定義しています。
Spring Boot は Spring から開発されているため、Hibernate Validator と Spring Validation を当然サポートしており、Hibernate Validator コンポーネントがデフォルトで使用されます。
2. データ検証
Hibernate Validator を使用してデータを検証するには、受信したデータ モデルを定義し、アノテーションを使用してフィールド検証のルールを記述する必要があります。以下では、例として User オブジェクトを使用して、Hibernate Validator を使用してデータを検証する方法を示します。
2.1 JavaBeanパラメータの検証
Postリクエストのパラメータが多い場合、対応するデータモデル(Java Bean)でデータ検証を行うことができ、フィールド検証のルールをアノテーションで指定することができます。以下は、具体的な例を示したデモンストレーションです。まず、Java Bean エンティティ クラスを作成します。
public class User {
@NotBlank(message = "姓名不允许为空!")
@Length(min = 2, max = 1,message = "姓名长度错误,姓名长度2-10!")
private String name;
@NotNull(message ="年龄不能为空!")
@Min(18)
private int age;
@NotBlank(message ="地址不能为空!")
private String address;
@Pattern(regexp = "((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(166)|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9]))\\d{8}$", message = "手机号格式错误")
private String phone;
@Email(message ="邮箱格式错误")
private String email;
//省略get和set方法
}
この例では、各アノテーションの属性 message は、データ検証が失敗した場合に表示されるプロンプト メッセージです。たとえば、@Email(message="メール形式エラー") のように、メール形式検証が失敗した場合に、メール形式の間違いをプロンプトします。次に、データ検証メソッドを追加します。
@PostMapping(path ="/check")
public String check(@RequestBody @Valid User user, BindingResult result) {
String name = user.getName();
if(result.hasErrors()) {
List<ObjectError> list = result.getAllErrors();
for (ObjectError error : list) {
System.out.println(error.getCode() + "_" + error.getDefaultMessage());
}
}
return name;
}
上記の例では、@RequestBody アノテーションの後に @Valid アノテーションを追加し、検証失敗時の結果セットである BindingResult を追加して検証結果を返しています。
BindingResult は検証対象のパラメータの後に続く必要があることに注意してください。検証対象のパラメータの後に BindingResult オブジェクトが存在しない場合は、BindException がスローされます。
最後に、検証を実行します。
プロジェクトを開始し、postman で /user/check インターフェイスをリクエストすると、データ検証結果がバックグラウンドで出力されます。
Length-密码长度错误,密码长度6-20!
Min-最小不能小于18
Length-姓名长度错误,姓名长度2-10!
上記の出力から、アプリケーション システムが受信データを検証し、対応するデータ検証結果を返したことがわかります。
2.2 URLパラメータの検証
通常、GET リクエストは URL 内のパラメータを渡します。この場合、アノテーションを通じてパラメータの検証ルールを直接指定できます。以下に例を挙げて説明します。
@Validated
public class UserController {
@RequestMapping("/query")
public String query(@Length(min = 2, max = 1, message ="姓名长度错误,姓名长度2-10!")
@RequestParam(name = "name", required = true) String name,
@Min(value = 1, message = "年龄最小只能1")
@Max(value = 99, message = "年龄最大只能9")
@RequestParam(name = "age", required = true) int age) {
System.out.println(name + " , " + age);
return name + " , " + age;
}
}
上記の例では、@Range、@Min、@Max およびその他の注釈を使用して、URL に渡されたパラメーターを検証します。@Valid アノテーションの使用は無効であることに注意してください。検証を有効にするには、メソッドが配置されているコントローラーに @Validated アノテーションを追加する必要があります。
2.3 JavaBeanオブジェクトのカスケード検証
JavaBean オブジェクトの通常の属性フィールドの場合、データ検証にアノテーションを直接使用できますが、それが関連付けられたオブジェクトの場合はどうなるでしょうか。実はこれも非常に簡単で、属性に @Valid アノテーションを追加することで、属性オブジェクトの内部属性として検証用に利用することができます(User オブジェクトを検証し、UserDetail フィールドを検証できます)。サンプルコードは次のとおりです。
public class User {
@Size(min = 3, max = 5, message = "list的Size在[3,5]")
private List<String> list;
@NotNull
@Valid
private Demo3 demo3;
}
public class UserDetail {
@Length(min = 5,max = 17,message = "length长度在[5,17]之间")
private String extField;
}
上記の例では、属性に @Valid を追加すると、User の関連付けられたオブジェクト UserDetail のフィールドに対してデータ検証を実行できます。
2.4 グループ検証
状況によっては、JavaBean オブジェクトのデータ検証ルールが異なる場合があり、JavaBean の一部の属性フィールドをデータのステータスに応じて個別に検証する必要がある場合があります。このとき、グループ検証機能を使用することができます。つまり、状態に応じて制約のグループが有効になります。Hibernate Validator のアノテーションには、グループを指定するために使用される groups パラメータが用意されており、groups パラメータが指定されていない場合、デフォルトで javax.validation.groups.Default グループに属します。
次の例は、グループの検証を示しています。まず、グループ GroupA と GroupB を作成します。サンプルコードは次のとおりです。
public interface GroupA {
}
public interface GroupB {
}
上の例では、2 つのインターフェイス GroupA と GroupB を 2 つの検証ルールのグループとして定義します。次に、エンティティ クラス Person を作成し、関連フィールドに検証グループ化ルールを定義します。サンプル コードは次のとおりです。
public class User {
@NotBlank(message ="userId不能为空",groups = {
GroupA.class})
/**用户id*/
private Integer userId;
@NotBlank(message ="用户名不能为空",groups = {
GroupA.class})
/**用户id*/
private String name;
@Length(min = 30,max = 40,message = "必须在[30,40]",groups = {
GroupB.class})
@Length(min = 20,max = 30,message = "必须在[20,30]",groups = {
GroupA.class})
/**用户名*/
private int age;
}
上の例では、userName フィールドで 2 つのグループ検証ルール、GroupA と GroupB が定義されています。グループ A の検証ルールは年齢が 20 ~ 30 歳、グループ B の検証ルールは年齢が 30 ~ 40 歳です。最後に、検証グループを使用します。
@RequestMapping("/save")
public String save(@RequestBody @Validated({
GroupA.class, Default.class}) Person person, BindingResult result) {
System.out.println(JSON.toJSONString(result.getAllErrors()));
return "success";
上記の例では、{GroupA.class,Default.class} パラメーターが @Validated アノテーションに追加され、グループ検証を定義するフィールドには GroupA 検証ルールが使用され、他のフィールドにはデフォルト ルールが使用されることを示します。
3. カスタム検証
Hibernate Validator はカスタム検証ルールをサポートしています。検証ルールをカスタマイズすることにより、いくつかの複雑で特殊なデータ検証機能を実現できます。次の例は、カスタム検証ルールを作成して使用する方法を示しています。
3.1 カスタム検証アノテーションを宣言する
まず、新しい検証アノテーション @CustomAgeValidator を定義します。サンプル コードは次のとおりです。
@Min(value = 18, message ="年龄最小不能小于18")
@Max(value = 120, message ="年龄最大不能超过120")
@Constraint(validatedBy = {
}) //不指定校验器
@Documented
@Target({
ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAgeValidator {
String message() default "年龄大小必须大于18并且小于123";
Class<?>[] groups() default {
};
Class<? extends Payload>[] payload() default {
};
}
上の例では、年齢データ検証ルールをカスタマイズするために CustomAgeValidator カスタム アノテーションを作成しました。
3.2 カスタム検証アノテーションの使用
カスタム検証アノテーション CustomAgeValidator を作成した後、User の年齢属性にカスタム結合アノテーションを使用します。サンプル コードは次のとおりです。
@public class User {
@NotBlank(message ="姓名不允许为空!")
@Length(min = 2,max = 10,message ="姓名长度错误,姓名长度2-10!")
private String name;
@CustomAgeValidator
private int age;
@NotBlank(message ="地址不能为空!")
private String address;
@Pattern(regexp = "((13[-9])|(14[5,7,9])|(15([-3]][5-9]))|(166)(17[.1,3,5,6,7,8])l(18[0-9])I(19[8|9]))\\d{8}$", message ="手机号格式错误")
private String phone;
@Email(message ="邮箱格式错误")
private String email;
//省略get和set
}
上の例では、特別な検証が必要な年齢フィールドに @CustomAgeValidator カスタム アノテーションを追加し、年齢フィールドでカスタム検証ルールが使用されるようにします。