16、spring-boot-參數(shù)校驗

一、概要

validation主要是校驗用戶提交的數(shù)據(jù)的合法性,比如是否為空,密碼是否符合規(guī)則,郵箱格式是否正確等等,校驗框架比較多,用的比較多的是hibernate-validator, 也支持國際化,也可以自定義校驗類型的注解
官方文檔

二、基礎(chǔ)使用

import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.*;
@Data
public class UserQuery {
    private Long id;
    @NotBlank
    @Length(min = 6, max = 15)
    private String username;
    @NotBlank
    @Email
    private String email;
    @NotBlank
    @Pattern(regexp = "^(1[3-9][0-9])\\d{8}$", message = "手機號格式不正確")
    private String phone;
    @Min(value = 1)
    @Max(value = 100)
    private int age;
    @NotBlank
    @Length(min = 6, max = 12, message = "昵稱長度為6到12位")
    private String nickname;
}
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
@RestController
public class AccountController {
    @PostMapping("/users")
    public String register(@Valid @RequestBody UserQuery user, BindingResult result) {
        if (result.hasErrors()) {
            FieldError fieldError = result.getFieldError();
            String field = fieldError.getField();
            String msg = fieldError.getDefaultMessage();
            return field + ":" + msg;
        }
        return "success";
    }
}

三、常用驗證

1、JSR-330

validator內(nèi)置注解

注解 詳細信息
@Null 被注釋的元素必須為 null
@NotNull 被注釋的元素必須不為 null
@AssertTrue 被注釋的元素必須為 true
@AssertFalse 被注釋的元素必須為 false
@Min(value) 被注釋的元素必須是一個數(shù)字,其值必須大于等于指定的最小值
@Max(value) 被注釋的元素必須是一個數(shù)字,其值必須小于等于指定的最大值
@DecimalMin(value) 被注釋的元素必須是一個數(shù)字,其值必須大于等于指定的最小值
@DecimalMax(value) 被注釋的元素必須是一個數(shù)字,其值必須小于等于指定的最大值
@Size(max, min) 被注釋的元素的大小必須在指定的范圍內(nèi)
@Digits (integer, fraction) 被注釋的元素必須是一個數(shù)字,其值必須在可接受的范圍內(nèi)
@Past 被注釋的元素必須是一個過去的日期
@Future 被注釋的元素必須是一個將來的日期
@Pattern(value) 被注釋的元素必須符合指定的正則表達式

2、Hibernate Validator 附加的 constraint

注解 詳細信息
@Email 被注釋的元素必須是電子郵箱地址
@Length 被注釋的字符串的大小必須在指定的范圍內(nèi)
@NotEmpty 被注釋的字符串的必須非空
@Range 被注釋的元素必須在合適的范圍內(nèi)
@NotBlank 驗證字符串非null,且長度必須大于0

注意

  • @NotNull適用于任何類型被注解的元素必須不能與NULL
  • @NotEmpty適用于String Map或者數(shù)組不能為Null且長度必須大于0
  • @NotBlank 只能用于String上面 不能為null,調(diào)用trim()后,長度必須大于0

四、校驗?zāi)J?/h2>

1、說明

  1. 普通模式(默認是這個模式)
  2. 快速失敗返回模式

2、普通模式

校驗完所有的屬性,然后返回所有的驗證失敗信息。默認就是普通模式無需配置

3、快速返回模式

只要有一個驗證失敗,則返回錯誤信息

@Configuration
public class ValidateConfig {
    @Bean
    public Validator validator() {
        ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
                .configure()
                .failFast(true)
                .buildValidatorFactory();
        return validatorFactory.getValidator();
    }
}

五、校驗方式

1、說明

常見的驗證方式:

  1. 封裝成Bean進行校驗
  2. 單個參數(shù)校驗
  3. 分組校驗
  4. 關(guān)聯(lián)校驗

2、栗子

2.1、請求參數(shù)封裝成實體類

@Data
@Validated
public class ProductQuery {
    @NotNull
    private String keyword;
    @Min(value = 0, message = "參數(shù)不合法")
    private Long categoryId;
    private Integer page = 1;
    private Integer size = 10;
    private Integer sort = 0;
}
@RestController
public class ValidatedController {
    @GetMapping("/validated")
    public String validatedBean(@Valid  ProductQuery userVo, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            // 直接獲取錯誤信息
            List<String> errors = bindingResult.getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.toList());
            //獲取參數(shù)的屬性信息
            // List<String> errors = bindingResult.getFieldErrors().stream().map(FieldError::getDefaultMessage).collect(Collectors.toList());
        }
        return "sucess";
    }
}

2.2、方法參數(shù)校驗

  1. 在類上使用@Validated注解
  2. 在參數(shù)上使用校驗注解即可
@RestController
@Validated
public class ValidatedController {
    @GetMapping("/validated/params")
    public String validatedParams(@RequestParam @NotNull Long id, BindingResult bindingResult) {
        return bindingResult.hasErrors() ? "success" : "error";
    }
}

2.3、關(guān)聯(lián)校驗

校驗對象內(nèi)部包含另一個校驗對象

@Data
@Validated
public class ProductQuery {
    @NotNull
    private String keyword;
    @Min(value = 0, message = "參數(shù)不合法")
    private Long categoryId;
    private Integer page = 1;
    private Integer size = 10;
    private Integer sort = 0;
    @Valid
    BrandQuery brandQuery;
}
@Data
public class BrandQuery {
    @NotBlank
    private String brandName;
}
@GetMapping("/validated/association")
public String validatedAssociation(@Validated ProductQuery userVo, BindingResult bindingResult) {
  return bindingResult.hasErrors() ? "success" : "error";
}

2.4、分組校驗

在實際開發(fā)中經(jīng)常會遇到這種情況:想要用一個實體類去接收多個controller的參數(shù),但是不同controller所需要的參數(shù)又有些許不同。

分組順序校驗時,按指定的分組先后順序進行驗證,前面的驗證不通過,后面的分組就不行驗證。

六、校驗錯誤處理

1、說明

  1. ConstraintViolationException
  2. MethodArgumentNotValidException
  3. BindException

2、栗子

2.1、方法參數(shù)校驗處理

校驗失敗會拋出ConstraintViolationException異常 然后我們在全局異常捕獲類捕獲這個異常,返回統(tǒng)一的結(jié)果集

@GetMapping("/validated/constraint")public ResponseResult<String> validatedError(@RequestParam @NotNull Long id) {  return ResponseResult.success("success");}
@RestControllerAdvice@Slf4jpublic class GlobalExceptionHandler {    /**     * ConstraintViolationException     * 單個參數(shù)違反約束校驗異常     */    @ExceptionHandler(ConstraintViolationException.class)    public ResponseResult<String> handleConstraintViolationException(ConstraintViolationException e) {        log.error(e.getMessage(), e);        return ResponseResult.error();    }}

2.2、請求參數(shù)表單對象

@Data@Validatedpublic class ProductQuery {    @NotNull    private String productId;    @NotNull    private String keyword;    @Min(value = 0, message = "參數(shù)不合法")    private Long categoryId;    private Integer page = 1;    private Integer size = 10;    private Integer sort = 0;    @Valid    BrandQuery brandQuery;}
@PostMapping("/validate/method")public User methodArgs(@Valid @RequestBody ProductQuery productQuery){    return user;}

2.3、普通對象

也是不使用@RequestBody 會拋出BindException異常

@PostMapping("/validate/method")public ResponseResult<String> methodArgs(@Valid ProductQuery productQuery){    return ResponseResult.success("success");}

七、自定義校驗

1、說明

  1. 創(chuàng)建約束注解類
  2. 創(chuàng)建驗證器

2、創(chuàng)建注解類

@Target({ElementType.PARAMETER, ElementType.FIELD})@Documented@Retention(RetentionPolicy.RUNTIME)@Constraint(validatedBy = CustomOrderValidator.class)public @interface CustomOrder {    String values();    String message() default "必須是規(guī)定字段";    Class<?>[] groups() default {};    Class<? extends Payload>[] payload() default {};}

3、創(chuàng)建校驗類

/** * 自定義排序字段校驗規(guī)則 */public class CustomOrderValidator implements ConstraintValidator<CustomOrder, String> {    private String values;    @Override    public void initialize(CustomOrder constraintAnnotation) {        this.values = constraintAnnotation.values();    }    /**     * 否則,校驗不通過。     *     * @param value 用戶輸入的值,如從前端傳入的某個值     */    @Override    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {        String[] args = values.split(", ");        if (args.length > 0) {            for (String val : args) {                if (val.equals(value)) {                    return true;                }            }        }        return false;    }}

4、使用

@GetMapping("/search")public ResponseResult<String> search(@CustomOrder(values = "1,2,3,4") Integer sort) {  return ResponseResult.success("success");}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容