前書き
通常のビジネス開発プロセスでのコントローラーレイヤーのパラメーター検証の記述方法がわかりません。次のような直接的な判断はありますか?
public String add(UserVO userVO) {
if(userVO.getAge() == null){
return "年龄不能为空";
}
if(userVO.getAge() > 120){
return "年龄不能超过120";
}
if(userVO.getName().isEmpty()){
return "用户名不能为空";
}
// 省略一堆参数校验...
return "OK";
}
ビジネスコードはまだ書かれておらず、光学パラメータの検証のために多くの判断が書かれています。このように書くことには何の問題もありませんが、エレガントでプロフェッショナルではないという印象を人々に与えます。
実際、Spring
フレームワークはすでに一連の検証コンポーネントである検証をカプセル化しています。その特徴は使いやすく、自由度が高いことです。次のレッスンでは、springboot-2.3.1.RELEASE
単純なWebプロジェクトを構築する方法を説明します。開発プロセス中にパラメーターをエレガントにチェックする方法について、順を追って説明します。
1.環境設定
springboot-2.3
始まり、検証パッケージは、独立したとしてされているstarter
次の依存関係を導入する必要があるので、コンポーネント:
<!--校验组件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!--web组件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
springboot-2.3
以前のバージョンでは、Webの依存関係を導入する必要があります。
2.小さなテスト
パラメータの検証は非常に簡単です。まず、検証するフィールドに検証ルールの注釈を追加します
public class UserVO {
@NotNull(message = "age 不能为空")
private Integer age;
}
次に、controller
メソッド@Validated
を追加し、エラーメッセージの受信に使用するためBindingResult
、最初のバージョンがあります。
public String add1(@Validated UserVO userVO, BindingResult result) {
List<FieldError> fieldErrors = result.getFieldErrors();
if(!fieldErrors.isEmpty()){
return fieldErrors.get(0).getDefaultMessage();
}
return "OK";
}
ツール(postman)を使用してインターフェースをリクエストします。パラメーターがルールを満たしていない場合、対応するmessage
情報が返されます:
age 不能为空
多くの組み込み検証アノテーションがあり、次のようにリストされています。
注釈 | チェック機能 |
---|---|
@AssertFalse | 偽でなければならない |
@AssertTrue | 本当でなければならない |
@DecimalMax | 与えられた値以下 |
@ DecimalMin#@ DecimalMin# | 与えられた値以上 |
@Digits | 整数の最大数と小数の最大数を設定できます |
@Eメール | メール形式に準拠しているか確認してください |
@未来 | 未来でなければなりません |
@FutureOrPresent | 現在または未来の時間 |
@Max | マックス |
@Min | 最小 |
@負 | 負の数(0を含まない) |
あずきっく | 負または0 |
@NotBlank | nullではなく、空白以外の文字が少なくとも1つ含まれている |
@空ではない | nullでも空でもない |
@NotNull | nullではない |
@ヌル | 無効です |
@過去 | 過去でなければなりません |
@PastOrPresent | 現在を含む過去でなければなりません |
@PositiveOrZero | 正または0 |
@サイズ | コンテナ内の要素の数を確認してください |
3.標準の戻り値
検証するパラメーターがさらに増えたら、すべての検証失敗情報を一度に返して、インターフェイスの呼び出し側が調整しやすくします。これには、統一された戻り形式が必要です。一般的なものは、結果クラスをカプセル化することです。
public class ResultInfo<T>{
private Integer status;
private String message;
private T response;
// 省略其他代码...
}
controller
メソッド、第2版を変更します。
public ResultInfo add2(@Validated UserVO userVO, BindingResult result) {
List<FieldError> fieldErrors = result.getFieldErrors();
List<String> collect = fieldErrors.stream()
.map(o -> o.getDefaultMessage())
.collect(Collectors.toList());
return new ResultInfo<>().success(400,"请求参数错误",collect);
}
このメソッドが要求されると、すべてのエラーパラメータが返されます。
{
"status": 400,
"message": "请求参数错误",
"response": [
"年龄必须在[1,120]之间",
"bg 字段的整数位最多为3位,小数位最多为1位",
"name 不能为空",
"email 格式错误"
]
}
4.グローバル例外処理
それぞれのController
方法でBindingResult
情報処理を書くと、やはり使いづらい。チェック例外は、グローバル例外処理を通じて均一に処理できます。
@validated
コメントを書いて書いBindingResult
ていない場合、Springは例外をスローします。その結果、この検証例外を均一に処理するグローバル例外処理クラスを作成できるため、例外情報を整理するためにコードを繰り返す必要がなくなります。
グローバル例外処理クラスはクラス@RestControllerAdvice
でマークする必要があるだけであり、対応する例外処理メソッドで@ExceptionHandler
注釈を使用して、処理する例外を指定します。
@RestControllerAdvice
public class GlobalControllerAdvice {
private static final String BAD_REQUEST_MSG = "客户端请求参数错误";
// <1> 处理 form data方式调用接口校验失败抛出的异常
@ExceptionHandler(BindException.class)
public ResultInfo bindExceptionHandler(BindException e) {
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
List<String> collect = fieldErrors.stream()
.map(o -> o.getDefaultMessage())
.collect(Collectors.toList());
return new ResultInfo().success(HttpStatus.BAD_REQUEST.value(), BAD_REQUEST_MSG, collect);
}
// <2> 处理 json 请求体调用接口校验失败抛出的异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResultInfo methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
List<String> collect = fieldErrors.stream()
.map(o -> o.getDefaultMessage())
.collect(Collectors.toList());
return new ResultInfo().success(HttpStatus.BAD_REQUEST.value(), BAD_REQUEST_MSG, collect);
}
// <3> 处理单个参数校验失败抛出的异常
@ExceptionHandler(ConstraintViolationException.class)
public ResultInfo constraintViolationExceptionHandler(ConstraintViolationException e) {
Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
List<String> collect = constraintViolations.stream()
.map(o -> o.getMessage())
.collect(Collectors.toList());
return new ResultInfo().success(HttpStatus.BAD_REQUEST.value(), BAD_REQUEST_MSG, collect);
}
}
実際、グローバルな例外処理クラスでは、複数の例外処理メソッドを記述できます。クラスの代表者は、3つのパラメータ検証中にスローされる可能性のある例外をまとめました。
フォームデータメソッドを使用してインターフェイスを呼び出すと、検証例外によってBindExceptionがスローされます
jsonリクエストボディを使用してインターフェースを呼び出し、検証例外がMethodArgumentNotValidExceptionをスローします
単一パラメーター検証例外がConstraintViolationExceptionをスローする
注:単一パラメーター検証では、パラメーターに検証メモを追加し、クラスにマークを付ける必要があります
@Validated
。
グローバル例外処理クラスは、一対Exception.class
の例外処理の追加など、処理する必要のあるさまざまな例外を追加できます。すべてをExceptionHandler
処理できない場合は、例外情報を記録し、わかりやすいプロンプトを返します。
5.グループチェック
同じパラメーターに対して異なるシナリオで異なる検証ルールを適用する必要がある場合は、パケット検証を使用する必要があります。例:新しく登録されたユーザーが名前を指定していない場合、name
フィールドを空にすることができますが、名前を空の文字に更新することはできません。
グループ検証には3つのステップがあります。
グループ化クラス(またはインターフェース)を定義する
検証アノテーションに
groups
属性指定のグループを追加しますController
メソッド@Validated
アノテーションにグループ化クラスを追加する
public interface Update extends Default{
}
public class UserVO {
@NotBlank(message = "name 不能为空",groups = Update.class)
private String name;
// 省略其他代码...
}
@PostMapping("update")
public ResultInfo update(@Validated({Update.class}) UserVO userVO) {
return new ResultInfo().success(userVO);
}
注意深い学生は、カスタムUpdate
グループインターフェイスがインターフェイスを継承していることに気づいたかもしれませんDefault
。検証アノテーション(例:) @NotBlank
と@validated
デフォルトDefault.class
は、javax.validation.groups.Default
アノテーションで説明されているグループに属しています。
/**
* Default Jakarta Bean Validation group.
* <p>
* Unless a list of groups is explicitly defined:
* <ul>
* <li>constraints belong to the {@code Default} group</li>
* <li>validation applies to the {@code Default} group</li>
* </ul>
* Most structural constraints should belong to the default group.
*
* @author Emmanuel Bernard
*/
public interface Default {
}
Update
パケットインターフェイスを作成する場合、継承されたDefault
場合、次の2つの書き込みは同等です。
@Validated({Update.class})
@Validated({Update.class,Default.class})
フィールドが検証される/update
だけでなく、name
デフォルトでDefault.class
グループに属する他のフィールドも検証されることを確認するようインターフェースに要求します
{
"status": 400,
"message": "客户端请求参数错误",
"response": [
"name 不能为空",
"age 不能为空",
"email 不能为空"
]
}
それがされている場合はUpdate
継承されていないDefault
、@Validated({Update.class})
唯一のUpdate.class
パラメータフィールドに属するグループがチェックされます。。変更後、インターフェースは次のような結果を得るために再び要求されたあなたは、他のフィールドがチェックに関与していないことがわかります。
{
"status": 400,
"message": "客户端请求参数错误",
"response": [
"name 不能为空"
]
}
6.再帰的な検証
OrderVOクラスの属性がUserVOクラスに追加され、OrderVOの属性も検証する必要がある場合、再帰的な検証が使用されます。これ@Valid
は、対応するプロパティに注釈を追加することで実現できます(コレクションにも同じことが当てはまります)。
OrderVOクラスは次のとおりです
public class OrderVO {
@NotNull
private Long id;
@NotBlank(message = "itemName 不能为空")
private String itemName;
// 省略其他代码...
}
タイプOrderVOの属性をUserVOクラスに追加します。
public class UserVO {
@NotBlank(message = "name 不能为空",groups = Update.class)
private String name;
//需要递归校验的OrderVO
@Valid
private OrderVO orderVO;
// 省略其他代码...
}
呼び出し要求の検証は次のとおりです。
7.カスタムチェック
Springの検証は非常に多くの機能を提供し、日々の開発におけるほとんどのパラメーター検証シナリオに対応できます。ただし、優れたフレームワークは簡単に拡張できる必要があります。スケーラビリティを使用すると、より複雑なビジネスシナリオに対処できます。結局のところ、開発プロセスでは、唯一の不変は変更自体です。
Spring Validationを使用すると、ユーザーは検証をカスタマイズできます。実装は2つのステップで非常に簡単です。
カスタムチェックアノテーション
検証クラスを書く
コードも非常にシンプルで、コメントを一目で理解できます
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {HaveNoBlankValidator.class})// 标明由哪个类执行校验逻辑
public @interface HaveNoBlank {
// 校验出错时默认返回的消息
String message() default "字符串中不能含有空格";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
/**
* 同一个元素上指定多个该注解时使用
*/
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
public @interface List {
NotBlank[] value();
}
}
public class HaveNoBlankValidator implements ConstraintValidator<HaveNoBlank, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// null 不做检验
if (value == null) {
return true;
}
if (value.contains(" ")) {
// 校验失败
return false;
}
// 校验成功
return true;
}
}
カスタム検証アノテーションは組み込みのアノテーションと同じです。必要なフィールドに対応するアノテーションを追加するだけで、学生は自分で検証できます
レビュー
上記は、Spring Validationを使用してパラメーターをエレガントに検証する方法の全体的な内容です。以下は、記事で言及されている検証機能に焦点を当てています
組み込みのさまざまな一般的な検証ノート
単一パラメーター検証をサポート
例外を自動的にアセンブルおよび検証するグローバル例外処理と組み合わせる
パケットチェック
再帰的チェックをサポート
カスタムチェック
方法はありませんが、テクニックは達成できます。方法がない場合は、テクニックで終わります
みんながJava Wayパブリックアカウントをフォローすることを歓迎します
良い記事、私は読んでいます❤️