@Valid與@Validated作用
@Valid與@Validated都是用來校驗接收參數(shù)的。
@Valid是使用Hibernate validation的時候使用
@Validated是只用Spring Validator校驗機制使用
說明:java的JSR303聲明了@Valid這類接口,而Hibernate-validator對其進行了實現(xiàn)。
@Validated與@Valid區(qū)別:
@Validated:可以用在類型、方法和方法參數(shù)上。但是不能用在成員屬性(字段)上,不支持嵌套檢測
@Valid:可以用在方法、構造函數(shù)、方法參數(shù)和成員屬性(字段)上,支持嵌套檢測
注意:SpringBoot使用@Valid注解需要引入如下POM
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
校驗參數(shù)注解含義
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-M6CfNsNC-1687851467867)(images/20200913110853722.png)]
全局異常處理類
說明:若不做異常處理,@Validated注解的默認異常消息如下(示例):
2020-09-05 21:48:38.106 WARN 9796 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public java.lang.String com.example.validateddemo.controller.DemoController.validatedDemo1(com.example.validateddemo.entity.dto.UseDto): [Field error in object 'useDto' on field 'username': rejected value [null]; codes [NotBlank.useDto.username,NotBlank.username,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [useDto.username,username]; arguments []; default message [username]]; default message [用戶名不能為空!]] ]
因此我們在這里做了一個全局的異常處理類,用于處理參數(shù)校驗失敗后拋出的異常,同時進行日志輸出。
package com.example.validateddemo.handler;
import com.example.validateddemo.base.Result;
import com.example.validateddemo.enums.ResultEnum;
import com.example.validateddemo.utils.ResultUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import java.util.List;
/**
* @author He Changjie on 2020/9/5
*/
@Slf4j
@ControllerAdvice
public class ValidatedExceptionHandler {
/**
* 處理@Validated參數(shù)校驗失敗異常
* @param exception 異常類
* @return 響應
*/
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result exceptionHandler(MethodArgumentNotValidException exception){
BindingResult result = exception.getBindingResult();
StringBuilder stringBuilder = new StringBuilder();
if (result.hasErrors()) {
List<ObjectError> errors = result.getAllErrors();
if (errors != null) {
errors.forEach(p -> {
FieldError fieldError = (FieldError) p;
log.warn("Bad Request Parameters: dto entity [{}],field [{}],message [{}]",fieldError.getObjectName(), fieldError.getField(), fieldError.getDefaultMessage());
stringBuilder.append(fieldError.getDefaultMessage());
});
}
}
return ResultUtil.validatedException(stringBuilder.toString());
}
}
基礎參數(shù)校驗
實體類
package com.example.validateddemo.entity.dto;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.*;
/**
* 用戶實體
* 數(shù)據(jù)傳輸對象
* @author He Changjie on 2020/9/5
*/
@Data
public class User1Dto {
/**
* 用戶名
*/
@NotBlank(message = "用戶名不能為空!")
private String username;
/**
* 性別
*/
@NotBlank(message = "性別不能為空!")
private String gender;
/**
* 年齡
*/
@Min(value = 1, message = "年齡有誤!")
@Max(value = 120, message = "年齡有誤!")
private int age;
/**
* 地址
*/
@NotBlank(message = "地址不能為空!")
private String address;
/**
* 郵箱
*/
@Email(message = "郵箱有誤!")
private String email;
/**
* 手機號碼
*/
@Pattern(regexp = "^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$",message = "手機號碼有誤!")
private String mobile;
}
控制類
package com.example.validateddemo.controller;
import com.example.validateddemo.entity.dto.Use1Dto;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author He Changjie on 2020/9/5
*/
@RestController
@RequestMapping("/api/v1")
public class Demo1Controller {
@PostMapping("/insert")
public String validatedDemo1(@Validated @RequestBody Use1Dto use1Dto){
System.out.println(use1Dto);
return "success";
}
}
測試
1、參數(shù)校驗不通過:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qZ6aFCYZ-1687851467868)(images/20200905225032404.png)]
嵌套參數(shù)驗證
驗證實體中的其他需要被驗證的對象集合或其他對象
實體類
package com.example.validateddemo.entity.dto;
import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* 隊伍實體
* 數(shù)據(jù)傳輸對象
* @author He Changjie on 2020/9/5
*/
@Data
public class Team1Dto {
/**
* 隊伍名稱
*/
@NotBlank(message = "隊伍名稱不能為空!")
private String name;
/**
* 隊伍人員
*/
@NotNull(message = "隊伍人員不能為空!")
@Valid
private List<User1Dto> userList;
/**
* 隊伍負責人
*/
@NotNull(message = "隊伍負責人不能為空!")
@Valid
private User1Dto user;
}
控制類
package com.example.validateddemo.controller;
import com.example.validateddemo.base.Result;
import com.example.validateddemo.entity.dto.Team1Dto;
import com.example.validateddemo.entity.dto.Use1Dto;
import com.example.validateddemo.utils.ResultUtil;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author He Changjie on 2020/9/5
*/
@RestController
@RequestMapping("/api/v1")
public class Demo1Controller {
@PostMapping("/insert")
public Result validatedDemo1(@Validated @RequestBody Use1Dto use1Dto){
return ResultUtil.success(use1Dto);
}
@PostMapping("/insert2")
public Result validatedDemo2(@Validated @RequestBody Team1Dto team1Dto){
return ResultUtil.success(team1Dto);
}
}
分組參數(shù)驗證
將不同的校驗規(guī)則分給不同的組,在使用時,指定不同的校驗規(guī)則,可以用于更新和新增接口不同的校驗規(guī)則
接口類
package com.example.validateddemo.interfaces;
/**
* 校驗分組1
* @author He Changjie on 2020/9/5
*/
public interface Group1 {
}
package com.example.validateddemo.interfaces;
/**
* 校驗分組2
* @author He Changjie on 2020/9/5
*/
public interface Group2 {
}
實體類
package com.example.validateddemo.entity.dto;
import com.example.validateddemo.interfaces.Group1;
import com.example.validateddemo.interfaces.Group2;
import lombok.Data;
import javax.validation.constraints.*;
/**
* @author He Changjie on 2020/9/5
*/
@Data
public class User2Dto {
/**
* 用戶名
*/
@NotBlank(message = "用戶名不能為空!", groups = {Group1.class})
private String username;
/**
* 性別
*/
@NotBlank(message = "性別不能為空!")
private String gender;
/**
* 年齡
*/
@Min(value = 1, message = "年齡有誤!", groups = {Group1.class})
@Max(value = 120, message = "年齡有誤!", groups = {Group2.class})
private int age;
/**
* 地址
*/
@NotBlank(message = "地址不能為空!")
private String address;
/**
* 郵箱
*/
@Email(message = "郵箱有誤!", groups = {Group2.class})
private String email;
/**
* 手機號碼
*/
@Pattern(regexp = "^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$",message = "手機號碼有誤!", groups = {Group2.class})
private String mobile;
}
控制類
package com.example.validateddemo.controller;
import com.example.validateddemo.base.Result;
import com.example.validateddemo.entity.dto.Team1Dto;
import com.example.validateddemo.entity.dto.User1Dto;
import com.example.validateddemo.entity.dto.User2Dto;
import com.example.validateddemo.interfaces.Group1;
import com.example.validateddemo.interfaces.Group2;
import com.example.validateddemo.utils.ResultUtil;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author He Changjie on 2020/9/5
*/
@RestController
@RequestMapping("/api/v1")
public class Demo1Controller {
@PostMapping("/insert")
public Result validatedDemo1(@Validated @RequestBody User1Dto user1Dto){
return ResultUtil.success(user1Dto);
}
@PostMapping("/insert2")
public Result validatedDemo2(@Validated @RequestBody Team1Dto team1Dto){
return ResultUtil.success(team1Dto);
}
@PostMapping("/insert3")
public Result validatedDemo3(@Validated @RequestBody User2Dto user2Dto){
return ResultUtil.success(user2Dto);
}
@PostMapping("/insert4")
public Result validatedDemo4(@Validated(Group1.class) @RequestBody User2Dto user2Dto){
return ResultUtil.success(user2Dto);
}
@PostMapping("/insert5")
public Result validatedDemo5(@Validated(Group2.class) @RequestBody User2Dto user2Dto){
return ResultUtil.success(user2Dto);
}
}
@Valid和@Validated 區(qū)別
通過源碼分析:
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Valid {
}
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Validated {
Class<?>[] value() default {};
}
分組驗證
@Valid:沒有分組的功能。
@Validated:提供了一個分組功能,可以在入?yún)Ⅱ炞C時,根據(jù)不同的分組采用不同的驗證機制
嵌套驗證
@Validated:可以用在類型、方法和方法參數(shù)上。但是不能用在成員屬性(字段)上,不支持嵌套檢測,只能通過@Valid配合實現(xiàn)嵌套校驗。文章來源:http://www.zghlxwxcb.cn/news/detail-506814.html
@Valid:可以用在方法、構造函數(shù)、方法參數(shù)和成員屬性(字段)上,支持嵌套檢測,可以用在list,set等集合上實現(xiàn)嵌套校驗文章來源地址http://www.zghlxwxcb.cn/news/detail-506814.html
到了這里,關于@Valid、@Validated參數(shù)校驗詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!