springboot-パラメータの検証

1はじめに

パラメータ検証とは何ですか?

プロジェクトを書くとき、コントローラーを書くとき、私たちは多かれ少なかれこのようなコードを書きました

@RequestMapping("/{studentId}")
public ResponseEntity<String> queryInfo(@PathVariable("studentId") String sudentId){
    
    

	if(!StringUtils.isEmpty(sudentId)){
    
    
		//....
	}
}

フロントエンドから送信されたデータを検証してから、業務を
遂行する必要があります...検証を検証するだけだと思います。しかし、検証する必要のあるデータが多い場合、1つのメソッドに10のメソッドがあり、このように100のメソッドがあります...データの検証に時間を浪費することになります。明らかにこれは望ましくありません。

コントローラ層では、インターフェイスの入力パラメータを検証する必要がある場合があります。独自の検証ロジックコードを使用して実装すると、いくつかの欠点があります。まず、気が散ってビジネスの記述に集中できなくなります。論理コード; 2つ目は、検証論理コードとビジネス論理コードを結合することであり、コードサイズは比較的肥大化しています。この状況を回避するために、Spring検証のValidatedアノテーションを使用して、インターフェースパラメーターの検証作業を完了することができます。次の例を示します。

2.使用方法

2.1Mavenの依存関係を追加する

 <!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
    <dependency>
      <groupId>javax.validation</groupId>
      <artifactId>validation-api</artifactId>
      <version>1.1.0.Final</version>
    </dependency>

2.2検証フィールドに検証メモを追加する

class Profile{
    
    
        @NotNull(message = "字段值不能为空")
        private String name;
        @NotNull
        private String sex;
        @Max(value = 20,message = "最大长度为20")
        private String address;
        @NotNull
        @Size(max=10,min=5,message = "字段长度要在5-10之间")
        private String fileName;
        @Pattern(regexp = "^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.[a-zA-Z0-9]{2,6}$",message = "不满足邮箱正则表达式")
        private String email;
        @AssertTrue(message = "字段为true才能通过")
        private boolean isSave;
        @Future(message = "时间在当前时间之后才可以通过")
        private Date date;
 
}

2.3コントローラーレイヤーでの検証に@Validatedを使用する

@RequestMapping("file/upload")
 public void upload(@RequestPart("files") MultipartFile files, @Validated Profile profile, Errors error) throws IOException {
    
    
       if(error.hasErrors()){
    
    
           return;
       }
       files.transferTo(new File(files.getOriginalFilename()));保存文件
}

コントローラで直接確認することもできます

  1. コントローラが検証済みの検証をオンにします
@RestController
@RequestMapping("/test")
@Validated
public class TestController{
    
    ...}
  1. メソッドで直接パラメータを検証します
@GetMapping(value = "/method/{type}")
    public ResponseModel test(
    	@Pattern(regexp = "[1,2]",message = "类型只能为1或2")@PathVariable(value = "type")String types,
		@NotBlank(message="内容不能为空")String content,
        @Length(max = 64,message = "长度最大为64")String title,
        @NotEmpty(message = "集合不能为空")List<String> ids,
        @Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$",message = "手机号格式有误") @NotBlank String mobile,
        @Max(value = 100,message = "最大值为100") @Min(value = 1,message = "最小值为1")Integer intValue) {
    
    ...}

2.4注釈とは何ですか

@Null注釈付き要素はnullである必要があります
@NotNull注釈付き要素はnullである必要があります
@AssertTrue注釈付き要素はtrueである必要があります
@AssertFalse注釈付き要素はfalseである必要があります
@Min(value)注釈付き要素は数値である必要があります。指定された最小値
以上@Max(value)注釈付き要素は数値である必要があり、その値は指定された最大値以下である必要があります
@DecimalMin(value)注釈付き要素は数値である必要があります。その値は指定された最小値以上である必要があります
@DecimalMax(value)注釈付き要素は数値である必要があり、その値は指定された最大値以下である必要があります
@Size(max =、min =)サイズ注釈付き要素のは指定された範囲内である必要があります
@Digits(整数、分数)注釈付き要素は数値であり、その値は許容範囲内である必要があります
@Past注釈付き要素は過去の日付である必要があります
@Future注釈付き要素は将来の日付である必要があります
@Pattern(regex =、flag =)コメント化された要素は、指定された正規式に準拠している必要があります

2.5グループチェック

このシナリオを紹介します。ユーザーのアカウントパスワードの編集と保存、およびパスワードの追加には、2つの異なる状況があります。

編集と変更->保存:ユーザー名とパスワードが条件を満たしているかどうかを確認するだけで、IDを確認する必要はありません(IDはデータベースにすでに存在するため)。

新規->保存:ユーザー名とパスワードが条件を満たしているかどうかを確認し、IDを確認する必要性を追加しました。

現時点では、グループを使用してBean属性変数を検証します。これにより、複数の検証も満たすことができます。具体的には、次の2つの手順が必要です

手順1:グループインターフェイスクラスを作成する

パケットインターフェイスクラスは単なる通常のインターフェイスクラスであり、あまり意味がありません。この属性が検証される状況を識別するためにのみ使用されます。これは、java.io.Serializable

public interface addUser{
    
     

}

public interface editUser{
    
    

}

手順2:xxx.classインターフェイスをコントローラーメソッドパラメーターに追加する

新しく追加されたユーザーに対してID検証を実行する@Validated({addUser.class})と、新しく追加されたユーザーUser.getId()を検証する必要があることを示すインターフェイスクラスが追加されます

@Controller  
public class UserController {
    
      

  	@RequestMapping("/saveAdd")  
    public String saveAddUser(@Validated({
    
    addUser.class}) User user, BindingResult result) {
    
      

        if(result.hasErrors()) {
    
      
			return "error";  
        }  
        return "success";  
    }
}

ステップ3:Beanにグループを追加する

Userエンティティクラスにグループ化されたグループを追加する@NotEmpty(groups={addUser.class})ことはUserController@Validated({addUser.class})に対応saveAddUser新しく追加されたユーザーIDは、新しく追加されたユーザーが実行されたときにのみ検証されることを示します。

public class User {
    
       

    //在分组addUser时,验证id不能为空,其他情况下不做验证
	@NotEmpty(groups={
    
    addUser.class})
    private String id;

    @NotEmpty(message = "用户名不能为空")
    private String username;

    @Size(min=6 ,max= 20 ,message = "密码最少6位,最高20位")
    private String password;
    ......
}

上記の3つの手順は、グループ検証を簡単に完了することができますが、グループ検証に3つのポイントを追加します。

  1. グループが割り当てられていない場合、デフォルトでは毎回認証が必要です
  2. 次のコードに示すように、グループのグループ化を通じて、同じ変数に対して複数の検証を実行できます。
//对用户名进行两次不同情况的验证。
@NotEmpty(groups={
    
    First.class})
@Size(min=1,max=10,groups={
    
    Second.class})
public String username; 
  1. デフォルトでは、異なるグループ化制約が順不同で検証されますが、検証の相互制約が非常に重要な場合があります(たとえば、前のグループ検証が失敗した、後続の検証が検証されないなど)。グループのグループ化には、前後の検証順序もあります。@GroupSequenceアノテーションを使用して並べ替えます。
/*
 * 分组顺序接口类
 */
import javax.validation.GroupSequence;

//分组序列先Frist再Second
@GroupSequence({
    
    First.class,Second.class})
public interface Group{
    
    

}

@Controller  
public class UserController {
    
      

    @RequestMapping("/saveAdd")  
    public String saveAddUser(@Validated({
    
    Group.class}) User user, BindingResult result) {
    
      
        if(result.hasErrors()) {
    
      
            return "error";  
        }  
        return "success";  
    }

3.例外キャッチ

上記でデータ検証の実行方法を学びましたが、問題があります。検証に失敗した場合、例外が発生した場合はどうすればよいですか?例外情報を取得してから、発生した例外をフロントエンドに通知します。

それをJSONオブジェクトにカプセル化してフロントエンドに返す方法は?ケースを使用してデモンストレーションする

  1. テストBeanを追加し、テストクラスにいくつかのフィールドを定義します。各フィールドには、特定の制限があります。
public class BeanValidation {
    
    
	@Size(min=6,max=10)
	private String field1;
	@Range(min=0,max=1)
	private Long field2;
	@AssertFalse
	private Boolean field3;
	public String getField1() {
    
    
		return field1;
	}
	public void setField1(String field1) {
    
    
		this.field1 = field1;
	}
	public Long getField2() {
    
    
		return field2;
	}
	public void setField2(Long field2) {
    
    
		this.field2 = field2;
	}
	public Boolean getField3() {
    
    
		return field3;
	}
	public void setField3(Boolean field3) {
    
    
		this.field3 = field3;
	}
	
}
  1. テストインターフェイスを追加します。@ Validatedアノテーションは、パラメータの有効性を確認するためにインターフェイスで使用されます。パラメータが有効な場合は、元のデータを返します。
	@RequestMapping("globalexceptiontest")
	public Object globalExceptionTest(@Validated @RequestBody BeanValidation data)
	{
    
    
		ResultMsg resultMsg = new ResultMsg(ResultStatusCode.OK.getErrcode(), ResultStatusCode.OK.getErrmsg(), data);
		return resultMsg;
	}
  1. グローバル例外処理が追加されていない場合、以下に示すように、デフォルトの例外処理が使用され、結果が返されます。

ここに画像の説明を挿入します返される結果は、それ自体のデータ構造とは大きく異なり、フロントエンド処理が結果を返すのも非常に面倒です。

  1. カスタムパラメータ例外によって返されるデータクラスArgumentInvalidResult
public class ArgumentInvalidResult {
    
    
	private String field;
	private Object rejectedValue;
	private String defaultMessage;
 
	public String getField() {
    
    
		return field;
	}
	public void setField(String field) {
    
    
		this.field = field;
	}
	public Object getRejectedValue() {
    
    
		return rejectedValue;
	}
	public void setRejectedValue(Object rejectedValue) {
    
    
		this.rejectedValue = rejectedValue;
	}
	public String getDefaultMessage() {
    
    
		return defaultMessage;
	}
	public void setDefaultMessage(String defaultMessage) {
    
    
		this.defaultMessage = defaultMessage;
	}
}
  1. グローバル例外処理クラスGlobalExceptionHandlerを追加します
@ControllerAdvice
//如果返回的为json数据或其它对象,添加该注解
@ResponseBody
public class GlobalExceptionHandler {
    
    
	//添加全局异常处理流程,根据需要设置需要处理的异常,本文以MethodArgumentNotValidException为例
	@ExceptionHandler(value=MethodArgumentNotValidException.class)
	public Object MethodArgumentNotValidHandler(HttpServletRequest request,
			MethodArgumentNotValidException exception) throws Exception
	{
    
    
		//按需重新封装需要返回的错误信息
		List<ArgumentInvalidResult> invalidArguments = new ArrayList<>();
		//解析原错误信息,封装后返回,此处返回非法的字段名称,原始值,错误信息
		for (FieldError error : exception.getBindingResult().getFieldErrors()) {
    
    
			ArgumentInvalidResult invalidArgument = new ArgumentInvalidResult();
			invalidArgument.setDefaultMessage(error.getDefaultMessage());
			invalidArgument.setField(error.getField());
			invalidArgument.setRejectedValue(error.getRejectedValue());
			invalidArguments.add(invalidArgument);
		}
		
		ResultMsg resultMsg = new ResultMsg(ResultStatusCode.PARAMETER_ERROR.getErrcode(), ResultStatusCode.PARAMETER_ERROR.getErrmsg(), invalidArguments);
		return resultMsg;
	}
}
  1. テストを実行する
  • パラメータが有効な場合

ここに画像の説明を挿入します

  • パラメータが不正な場合は、パラメータが有効な場合と同じスタイルのエラーメッセージを返します

ここに画像の説明を挿入します

注意:

  1. ここで、@ ControllerAdviceに注釈が付けられ、@ ControllerAdviceは@Controllerの拡張バージョンであり、通常は@ExceptionHandlerと組み合わせて使用​​されます。

@Controllerにアノテーションが付けられている場合、例外処理は現在のコントローラークラスのメソッドでのみ機能しますが、@ ControllerAdviceを使用すると、グローバルに機能します。

  1. キャプチャする例外クラスのクラスオブジェクトを@ExceptionHandlerアノテーションに入力します

おすすめ

転載: blog.csdn.net/saienenen/article/details/112756539