Java參數(shù)校驗@Validated、@Valid介紹及使用詳解
概述
介紹及使用
描述:Javax.validation是 spring 集成自帶的一個參數(shù)校驗接口??赏ㄟ^添加注解來設(shè)置校驗條件。springboot框架創(chuàng)建web項目后,不需要再添加其他的依賴。
使用:在Controller上使用 @Valid 或 @Validated 注解 開啟校驗
public String test(@RequestBody @Valid MyRequest req){};
@Validated 和 @Valid 的異同
相同點:
- 在檢驗參數(shù)符合規(guī)范的功能上基本一致;
不同點:
- 提供者不同:
- validated 是Spring Validation驗證框架對參數(shù)的驗證機制;
- valid是 javax 提供的參數(shù)驗證機制
- 作用域不同:
- validated :類,方法,參數(shù)
- valid:方法,字段,構(gòu)造方法,參數(shù),TYPE_US
注:TYPE_USE:在 Java 8 之前的版本中,只能允許在聲明式前使用 Annotation。而在 Java 8 版本中,Annotation 可以被用在任何使用 Type 的地方,例如:初始化對象時 (new),對象類型轉(zhuǎn)化時,使用 implements 表達(dá)式時,或者使用 throws 表達(dá)式時。
//初始化對象時 String myString = new @Valid String(); //對象類型轉(zhuǎn)化時 myString = (@Valid String) str; //使用 implements 表達(dá)式時 class MyList<T> implements List<@Valid T> {...} //使用 throws 表達(dá)式時 public void validateValues() throws @Valid ValidationFailedException{...}
參數(shù)校驗常用注解
除了前四個 @Null,@ NotNull,@ NotBlank,@NotEmpty外,其他所有的注解,傳 null 時都會被當(dāng)作有效處理
注解常用參數(shù)值:message(校驗不通過反饋信息)
JSR303定義的基礎(chǔ)校驗類型:
注解 | 驗證的數(shù)據(jù)類型 | 備注 |
---|---|---|
Null | 任意類型 | 參數(shù)值必須是 Null |
NotNull | 任意類型 | 參數(shù)值必須不是 Null |
NotBlank | 只能作用于字符串 | 字符串不能為 null,而且字符串長度必須大于0,至少包含一個非空字符串 |
NotEmpty | CharSequence Collection Map Array | 參數(shù)值不能為null,且不能為空 (字符串長度必須大于0,空字符串(“ ”)可以通過校驗) |
Size(min,max ) | CharSequence Collection Map Array | 字符串:字符串長度必須在指定的范圍內(nèi) Collection:集合大小必須在指定的范圍內(nèi) Map:map的大小必須在指定的范圍內(nèi) Array:數(shù)組長度必須在指定的范圍內(nèi) |
Pattern(regexp) | 字符串類型 | 驗證字符串是否符合正則表達(dá)式 |
Min(value) | 整型類型 | 參數(shù)值必須大于等于 最小值 |
Max(value) | 整型類型 | 參數(shù)值必須小于等于 最大值 |
DecimalMin(value) | 整型類型 | 參數(shù)值必須大于等于 最小值 |
DecimalMax(value) | 整型類型 | 參數(shù)值必須小于等于 最大值 |
Positive | 數(shù)字類型 | 參數(shù)值為正數(shù) |
PositiveOrZero | 數(shù)字類型 | 參數(shù)值為正數(shù)或0 |
Negative | 數(shù)字類型 | 參數(shù)值為負(fù)數(shù) |
NegativeOrZero | 數(shù)字類型 | 參數(shù)值為負(fù)數(shù)或0 |
Digits(integer,fraction) | 數(shù)字類型 | 參數(shù)值為數(shù)字,且最大長度不超過integer位,整數(shù)部分最高位不超過fraction位 |
AssertTrue | 布爾類型 | 參數(shù)值必須為 true |
AssertFalse | 布爾類型 | 參數(shù)值必須為 false |
Past | 時間類型(Date) | 參數(shù)值為時間,且必須小于 當(dāng)前時間 |
PastOrPresent | 時間類型(Date) | 參數(shù)值為時間,且必須小于或等于 當(dāng)前時間 |
Future | 時間類型(Date) | 參數(shù)值為時間,且必須大于 當(dāng)前時間 |
FutureOrPresent | 時間類型(Date) | 參數(shù)值為時間,且必須大于或等于 當(dāng)前日期 |
字符串類型 | 被注釋的元素必須是電子郵箱地址 |
Hibernate Validator 中附加的 constraint :
注解 | 驗證的數(shù)據(jù)類型 | 備注 |
---|---|---|
Length | 字符串類型 | 字符串的長度在min 和 max 之間 |
Range | 數(shù)字類型 字符串類型 | 數(shù)值或者字符串的值必須在 min 和 max 指定的范圍內(nèi) |
Pattern注解校驗 常用正則表達(dá)式
@Pattern(regexp = "^[1-9]]\\d*$", message = "XX參數(shù)值必須是正整數(shù)")
高階使用
自定義分組校驗
有時多個場景接口公用一個請求對象,不同業(yè)務(wù)場景對請求對象的參數(shù)校驗需求不同,可以使用分組校驗來解決
注意:
- 沒有指定顯示分組的被校驗字段和校驗注解,默認(rèn)都是 Default 組(即 Default.class)
- 若自定義的分組接口未繼承 Default 分組,且 @Validated(或 @Valid)注解未傳參 Default.class,則只會校驗請求對象中進(jìn)行了顯示分組的字段,不會校驗?zāi)J(rèn)分組(沒有進(jìn)行顯示分組)的字段
- 自定義的分組接口不繼承 Default 分組 + @Validated(或 @Valid)注解傳參 {自定義分組接口.class, Default.class}
- = 自定義的分組接口繼承 Default 分組 + @Validated(或 @Valid)注解只傳參自定義分組接口
示例:
新建自定義分組校驗接口
public interface Student { }
import javax.validation.groups.Default; public interface Teacher extends Default { }
新建請求對象
@Data public class UserDTO { @NotBlank(message = "不能沒有名稱") private String name; @NotBlank(message = "老師不能沒有手機號", groups = Teacher.class) private String phone; @NotEmpty(message = "學(xué)生不能沒有書", groups = Student.clas) @Size(min = 2, message = "學(xué)生必須有兩本書", groups = Student.class) private List<String> bookNames; }
Controller
@RestController public class ValidatedController { /** * 測試 校驗student分組+默認(rèn)分組 */ @PostMapping("student") public UserDTO validatedStudent(@Validated(value = {Student.class, Default.class}) @RequestBody UserDTO userDTO) { return userDTO; } /** * 測試 校驗student分組+默認(rèn)分組 */ @PostMapping("teacher") public UserDTO validatedTeacher(@Validated(value = {Teacher.class}) @RequestBody UserDTO userDTO) { return userDTO; } /** * 測試 分組校驗 default */ @PostMapping("default") public UserDTO validatedDefault(@Validated(value = {Default.class}) @RequestBody UserDTO userDTO) { return userDTO; } /** * 測試 分組校驗 onlyStudent */ @PostMapping("onlyStudent") public UserDTO validatedOnlyStudent(@Validated(value = {Student.class}) @RequestBody UserDTO userDTO) { return userDTO; }
自定義校驗注解
定義注解
@Documented //指定注解的處理類 @Constraint(validatedBy = {VersionValidatorHandler.class }) @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) @Retention(RUNTIME) public @interface ConstantVersion { String message() default "{constraint.default.const.message}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; String value(); }
注解處理類
public class VersionValidatorHandler implements ConstraintValidator<Constant, String> { private String constant; @Override public void initialize(Constant constraintAnnotation) { //獲取設(shè)置的字段值 this.constant = constraintAnnotation.value(); } @Override public boolean isValid(String value, ConstraintValidatorContext context) { //判斷參數(shù)是否等于設(shè)置的字段值,返回結(jié)果 return constant.equals(value); } }
自定義注解使用
@ConstantVersion (message = "verson只能為1.0.0",value="1.0.0") String version;
Controller
@RestController public class TestController { @RequestMapping("/test") public String createUser(@Valid User user, BindingResult bindingResult){ if (bindingResult.hasErrors()){ return bindingResult.getFieldError().getDefaultMessage(); } return "success"; } }
嵌套檢驗
描述:當(dāng)對象 Man 的字段 houses 包含 House 對象類型時,在檢驗 houses 字段時可以檢驗 House 對象的屬性字段時,就稱為嵌套檢驗
方案:在被檢驗的字段上添加 @Valid 注解就可以實現(xiàn)嵌套檢驗
示例如下:
- 在檢驗 Man 對象的 houses 字段時,在houses 字段上添加 @Valid 注解后,就可以檢驗 list 中的 House 的屬性是否符合要求;
- 否則只會檢驗 houses 的集合大小是否大于1,不會校驗集合中的 House 對象,比如 House 對象的 name 長度是否符合要求。
class Man{ @Valid @Size(min = 1) private List<House> houses; } class House{ @Length(min = 1,max = 10) private String name; }
拓展
異常處理
參數(shù)校驗異常:MethodArgumentNotValidException
方式一:基于異常監(jiān)聽@ControllerAdvice(參考:https://www.cnblogs.com/gezi0815/p/13815397.html)
/** * 全局異常處理器 */ @Slf4j @ControllerAdvice public class GlobalExceptionHandler { /** * 異常處理 */ @ResponseBody @ExceptionHandler(value = Exception.class) public DataResult exceptionHandler(Exception e) { log.error("GlobalExceptionHandler.exceptionHandler , 異常信息",e); return DataResult.fail(e.getMessage()); } /** * 業(yè)務(wù)異常 */ @ResponseBody @ExceptionHandler(value = BplCommonException.class) public DataResult bplCommonExceptionHandler(BplCommonException e) { log.warn("",e); return DataResult.fail(e.getMessage()); } /** * 處理所有RequestBody注解參數(shù)驗證異常 */ @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseBody public DataResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e){ log.warn(e.getMessage()); return DataResult.fail(e.getBindingResult().getAllErrors().get(0).getDefaultMessage()); } /** * 處理所有RequestParam注解數(shù)據(jù)驗證異常 */ @ExceptionHandler(BindException.class) public DataResult handleBindException(BindException ex) { FieldError fieldError = ex.getBindingResult().getFieldError(); log.warn("必填校驗異常:{}({})", fieldError.getDefaultMessage(),fieldError.getField()); return DataResult.fail(ex.getBindingResult().getAllErrors().get(0).getDefaultMessage()); } }
方式二:基于Handle或Filter(參考:https://blog.51cto.com/u_12012821/2511625)
if (e instanceof MethodArgumentNotValidException) { String errorMsg = ((MethodArgumentNotValidException) e) .getBindingResult() .getAllErrors() .stream() .map(DefaultMessageSourceResolvable::getDefaultMessage) .collect(Collectors.joining(",")); resp = R.builder() .code(ResultCodeEnum.BUSINESS_ERROR.getCode()) .message(errorMsg).success(false) .build(); }
到此這篇關(guān)于Java參數(shù)校驗@Validated、@Valid使用詳解的文章就介紹到這了,更多相關(guān)java參數(shù)校驗內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring?Boot整合Log4j2.xml的問題及解決方法
這篇文章主要介紹了Spring?Boot整合Log4j2.xml的問題,本文給大家分享解決方案,需要的朋友可以參考下2023-09-09Spring框架通過工廠創(chuàng)建Bean的三種方式實現(xiàn)
這篇文章主要介紹了Spring框架通過工廠創(chuàng)建Bean的三種方式實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03Eclipse連接Mysql數(shù)據(jù)庫操作總結(jié)
這篇文章主要介紹了Eclipse連接Mysql數(shù)據(jù)庫操作總結(jié)的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-08-08Flink實現(xiàn)特定統(tǒng)計的歸約聚合reduce操作
這篇文章主要介紹了Flink實現(xiàn)特定統(tǒng)計的歸約聚合reduce操作,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-02-02利用synchronized實現(xiàn)線程同步的案例講解
這篇文章主要介紹了利用synchronized實現(xiàn)線程同步的案例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02SpringBoot thymeleaf eclipse熱部署方案操作步驟
今天小編就為大家分享一篇關(guān)于SpringBoot thymeleaf eclipse熱部署方案操作步驟,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-03-03