Java參數(shù)校驗(yàn)@Validated、@Valid介紹及使用詳解
概述
介紹及使用
描述:Javax.validation是 spring 集成自帶的一個(gè)參數(shù)校驗(yàn)接口??赏ㄟ^(guò)添加注解來(lái)設(shè)置校驗(yàn)條件。springboot框架創(chuàng)建web項(xiàng)目后,不需要再添加其他的依賴。
使用:在Controller上使用 @Valid 或 @Validated 注解 開啟校驗(yàn)
public String test(@RequestBody @Valid MyRequest req){};@Validated 和 @Valid 的異同
相同點(diǎn):
- 在檢驗(yàn)參數(shù)符合規(guī)范的功能上基本一致;
不同點(diǎn):
- 提供者不同:
- validated 是Spring Validation驗(yàn)證框架對(duì)參數(shù)的驗(yàn)證機(jī)制;
- valid是 javax 提供的參數(shù)驗(yàn)證機(jī)制
- 作用域不同:
- validated :類,方法,參數(shù)
- valid:方法,字段,構(gòu)造方法,參數(shù),TYPE_US
注:TYPE_USE:在 Java 8 之前的版本中,只能允許在聲明式前使用 Annotation。而在 Java 8 版本中,Annotation 可以被用在任何使用 Type 的地方,例如:初始化對(duì)象時(shí) (new),對(duì)象類型轉(zhuǎn)化時(shí),使用 implements 表達(dá)式時(shí),或者使用 throws 表達(dá)式時(shí)。
//初始化對(duì)象時(shí)
String myString = new @Valid String();
//對(duì)象類型轉(zhuǎn)化時(shí)
myString = (@Valid String) str;
//使用 implements 表達(dá)式時(shí)
class MyList<T> implements List<@Valid T> {...}
//使用 throws 表達(dá)式時(shí)
public void validateValues() throws @Valid ValidationFailedException{...}參數(shù)校驗(yàn)常用注解
除了前四個(gè) @Null,@ NotNull,@ NotBlank,@NotEmpty外,其他所有的注解,傳 null 時(shí)都會(huì)被當(dāng)作有效處理
注解常用參數(shù)值:message(校驗(yàn)不通過(guò)反饋信息)
JSR303定義的基礎(chǔ)校驗(yàn)類型:
| 注解 | 驗(yàn)證的數(shù)據(jù)類型 | 備注 |
|---|---|---|
| Null | 任意類型 | 參數(shù)值必須是 Null |
| NotNull | 任意類型 | 參數(shù)值必須不是 Null |
| NotBlank | 只能作用于字符串 | 字符串不能為 null,而且字符串長(zhǎng)度必須大于0,至少包含一個(gè)非空字符串 |
| NotEmpty | CharSequence Collection Map Array | 參數(shù)值不能為null,且不能為空 (字符串長(zhǎng)度必須大于0,空字符串(“ ”)可以通過(guò)校驗(yàn)) |
| Size(min,max ) | CharSequence Collection Map Array | 字符串:字符串長(zhǎng)度必須在指定的范圍內(nèi) Collection:集合大小必須在指定的范圍內(nèi) Map:map的大小必須在指定的范圍內(nèi) Array:數(shù)組長(zhǎng)度必須在指定的范圍內(nèi) |
| Pattern(regexp) | 字符串類型 | 驗(yàn)證字符串是否符合正則表達(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ù)字,且最大長(zhǎng)度不超過(guò)integer位,整數(shù)部分最高位不超過(guò)fraction位 |
| AssertTrue | 布爾類型 | 參數(shù)值必須為 true |
| AssertFalse | 布爾類型 | 參數(shù)值必須為 false |
| Past | 時(shí)間類型(Date) | 參數(shù)值為時(shí)間,且必須小于 當(dāng)前時(shí)間 |
| PastOrPresent | 時(shí)間類型(Date) | 參數(shù)值為時(shí)間,且必須小于或等于 當(dāng)前時(shí)間 |
| Future | 時(shí)間類型(Date) | 參數(shù)值為時(shí)間,且必須大于 當(dāng)前時(shí)間 |
| FutureOrPresent | 時(shí)間類型(Date) | 參數(shù)值為時(shí)間,且必須大于或等于 當(dāng)前日期 |
| 字符串類型 | 被注釋的元素必須是電子郵箱地址 |
Hibernate Validator 中附加的 constraint :
| 注解 | 驗(yàn)證的數(shù)據(jù)類型 | 備注 |
|---|---|---|
| Length | 字符串類型 | 字符串的長(zhǎng)度在min 和 max 之間 |
| Range | 數(shù)字類型 字符串類型 | 數(shù)值或者字符串的值必須在 min 和 max 指定的范圍內(nèi) |
Pattern注解校驗(yàn) 常用正則表達(dá)式
@Pattern(regexp = "^[1-9]]\\d*$", message = "XX參數(shù)值必須是正整數(shù)")
高階使用
自定義分組校驗(yàn)
有時(shí)多個(gè)場(chǎng)景接口公用一個(gè)請(qǐng)求對(duì)象,不同業(yè)務(wù)場(chǎng)景對(duì)請(qǐng)求對(duì)象的參數(shù)校驗(yàn)需求不同,可以使用分組校驗(yàn)來(lái)解決
注意:
- 沒(méi)有指定顯示分組的被校驗(yàn)字段和校驗(yàn)注解,默認(rèn)都是 Default 組(即 Default.class)
- 若自定義的分組接口未繼承 Default 分組,且 @Validated(或 @Valid)注解未傳參 Default.class,則只會(huì)校驗(yàn)請(qǐng)求對(duì)象中進(jìn)行了顯示分組的字段,不會(huì)校驗(yàn)?zāi)J(rèn)分組(沒(méi)有進(jìn)行顯示分組)的字段
- 自定義的分組接口不繼承 Default 分組 + @Validated(或 @Valid)注解傳參 {自定義分組接口.class, Default.class}
- = 自定義的分組接口繼承 Default 分組 + @Validated(或 @Valid)注解只傳參自定義分組接口
示例:
新建自定義分組校驗(yàn)接口
public interface Student {
}import javax.validation.groups.Default;
public interface Teacher extends Default {
}新建請(qǐng)求對(duì)象
@Data
public class UserDTO {
@NotBlank(message = "不能沒(méi)有名稱")
private String name;
@NotBlank(message = "老師不能沒(méi)有手機(jī)號(hào)", groups = Teacher.class)
private String phone;
@NotEmpty(message = "學(xué)生不能沒(méi)有書", groups = Student.clas)
@Size(min = 2, message = "學(xué)生必須有兩本書", groups = Student.class)
private List<String> bookNames;
}Controller
@RestController
public class ValidatedController {
/**
* 測(cè)試 校驗(yàn)student分組+默認(rèn)分組
*/
@PostMapping("student")
public UserDTO validatedStudent(@Validated(value = {Student.class, Default.class}) @RequestBody UserDTO userDTO) {
return userDTO;
}
/**
* 測(cè)試 校驗(yàn)student分組+默認(rèn)分組
*/
@PostMapping("teacher")
public UserDTO validatedTeacher(@Validated(value = {Teacher.class}) @RequestBody UserDTO userDTO) {
return userDTO;
}
/**
* 測(cè)試 分組校驗(yàn) default
*/
@PostMapping("default")
public UserDTO validatedDefault(@Validated(value = {Default.class}) @RequestBody UserDTO userDTO) {
return userDTO;
}
/**
* 測(cè)試 分組校驗(yàn) onlyStudent
*/
@PostMapping("onlyStudent")
public UserDTO validatedOnlyStudent(@Validated(value = {Student.class}) @RequestBody UserDTO userDTO) {
return userDTO;
}自定義校驗(yàn)注解
定義注解
@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";
}
}嵌套檢驗(yàn)
描述:當(dāng)對(duì)象 Man 的字段 houses 包含 House 對(duì)象類型時(shí),在檢驗(yàn) houses 字段時(shí)可以檢驗(yàn) House 對(duì)象的屬性字段時(shí),就稱為嵌套檢驗(yàn)
方案:在被檢驗(yàn)的字段上添加 @Valid 注解就可以實(shí)現(xiàn)嵌套檢驗(yàn)
示例如下:
- 在檢驗(yàn) Man 對(duì)象的 houses 字段時(shí),在houses 字段上添加 @Valid 注解后,就可以檢驗(yàn) list 中的 House 的屬性是否符合要求;
- 否則只會(huì)檢驗(yàn) houses 的集合大小是否大于1,不會(huì)校驗(yàn)集合中的 House 對(duì)象,比如 House 對(duì)象的 name 長(zhǎng)度是否符合要求。
class Man{
@Valid
@Size(min = 1)
private List<House> houses;
}
class House{
@Length(min = 1,max = 10)
private String name;
}拓展
異常處理
參數(shù)校驗(yàn)異常:MethodArgumentNotValidException
方式一:基于異常監(jiān)聽(tīng)@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ù)驗(yàn)證異常
*/
@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ù)驗(yàn)證異常
*/
@ExceptionHandler(BindException.class)
public DataResult handleBindException(BindException ex) {
FieldError fieldError = ex.getBindingResult().getFieldError();
log.warn("必填校驗(yàn)異常:{}({})", 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ù)校驗(yàn)@Validated、@Valid使用詳解的文章就介紹到這了,更多相關(guān)java參數(shù)校驗(yàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 使用@Validated和@Valid 解決list校驗(yàn)的問(wèn)題
- Java中的三種校驗(yàn)注解的使用(@Valid,@Validated和@PathVariable)
- spring @Validated 注解開發(fā)中使用group分組校驗(yàn)的實(shí)現(xiàn)
- SpringBoot參數(shù)校驗(yàn)之@Validated的使用詳解
- @Valid和@Validated注解校驗(yàn)以及異常處理方式
- 使用@Validated注解進(jìn)行校驗(yàn)卻沒(méi)有效果的解決
- Spring 中@Validated 分組校驗(yàn)的使用解析
- Spring利用@Validated注解實(shí)現(xiàn)參數(shù)校驗(yàn)詳解
- JAVA校驗(yàn)之@Valid和@Validated實(shí)踐指南
相關(guān)文章
SpringBoot整合MyBatis和SpringBoot整合MyBatis-Plus教程
這篇文章主要介紹了SpringBoot整合MyBatis和SpringBoot整合MyBatis-Plus教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-05-05
基于Java Socket實(shí)現(xiàn)一個(gè)簡(jiǎn)易在線聊天功能(一)
這篇文章主要給大家介紹基于Java Socket實(shí)現(xiàn)一個(gè)簡(jiǎn)易在線聊天功能(一),分為客戶端和服務(wù)端兩段代碼,非常具有參考價(jià)值,感興趣的朋友一起學(xué)習(xí)吧2016-05-05
Java網(wǎng)絡(luò)編程基礎(chǔ)篇之單向通信
這篇文章主要介紹了Java網(wǎng)絡(luò)編程里通過(guò)套接字實(shí)現(xiàn)單向通信的方法及相關(guān)實(shí)例,屬于網(wǎng)絡(luò)編程入門程序,雖然簡(jiǎn)單,但具有一定參考價(jià)值,需要的朋友可以參考下。2017-09-09
在webservice里調(diào)用耗時(shí)方法出錯(cuò)的解決方案
這篇文章主要介紹了在webservice里調(diào)用耗時(shí)方法出錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
spring boot整合RabbitMQ實(shí)例詳解(Fanout模式)
這篇文章主要介紹了spring boot整合RabbitMQ的實(shí)例講解(Fanout模式),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-04-04
spring聲明式事務(wù) @Transactional 不回滾的多種情況以及解決方案
本文主要介紹了spring聲明式事務(wù) @Transactional 不回滾的多種情況以及解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11
Java?Stream?的?Collectors.toMap高級(jí)應(yīng)用與最佳實(shí)踐
文章講解Java?Stream?API中Collectors.toMap的使用,涵蓋基礎(chǔ)語(yǔ)法、鍵沖突處理、自定義Map類型、null值安全、復(fù)雜值轉(zhuǎn)換及性能優(yōu)化等場(chǎng)景,本文將從基礎(chǔ)用法入手,逐步深入探討其高級(jí)應(yīng)用與最佳實(shí)踐,感興趣的朋友一起看看吧2025-08-08

