@Valid: 嵌套校验 = 入参@Valid + 属性上@Valid
用在方法入参上无法单独提供嵌套验证功能。
能配合嵌套验证注解@Valid进行嵌套验证。
能够用在成员属性(字段)上,提示验证框架进行嵌套验证。
@Validated: 嵌套校验 = 入参@Validated + 属性上@Valid
用在方法入参上无法单独提供嵌套验证功能。
能配合嵌套验证注解@Valid进行嵌套验证。
不能用在成员属性(字段)上,也无法提示框架进行嵌套验证。
参考:https://blog.csdn.net/qq_27680317/article/details/79970590
pom
结果类 状态码类org.projectlombok lombok 1.18.20 org.springframework.boot spring-boot-starter-web 2.4.5 org.springframework.boot spring-boot-starter-actuator 2.4.5 junit junit 4.12 compile org.springframework.boot spring-boot-starter-validation 2.4.5 org.springframework.boot spring-boot-starter-json 2.4.5 com.alibaba fastjson 1.2.76 io.springfox springfox-swagger-ui 2.9.2 io.springfox springfox-swagger2 2.9.2
public enum ApiCode {
SUCCESS(200, "操作成功"),
FAIL(500, "操作失败"),
SYSTEM_EXCEPTION(5000, "系统异常!"),
PARAMETER_EXCEPTION(5001, "请求参数校验异常"),
;
private final int code;
private final String msg;
ApiCode(final int code, final String msg) {
this.code = code;
this.msg = msg;
}
public static ApiCode getApiCode(int code) {
ApiCode[] ecs = ApiCode.values();
for (ApiCode ec : ecs) {
if (ec.getCode() == code) {
return ec;
}
}
return SUCCESS;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
@Data @Accessors(chain = true) @Builder @AllArgsConstructor public class ApiResult两个实体类implements Serializable { private int code; private String msg; private boolean success; private T data; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date time = new Date(); public ApiResult() { } public static ApiResult result(boolean flag){ if (flag){ return ok(); } return fail(); } public static ApiResult result(ApiCode apiCode){ return result(apiCode,null); } public static ApiResult result(ApiCode apiCode,Object data){ return result(apiCode,null,data); } public static ApiResult result(ApiCode apiCode,String msg,Object data){ boolean success = false; if (apiCode.getCode() == ApiCode.SUCCESS.getCode()){ success = true; } String message = apiCode.getMsg(); if (StringUtils.isNotBlank(msg)){ message = msg; } return ApiResult.builder() .code(apiCode.getCode()) .msg(message) .data(data) .success(success) .time(new Date()) .build(); } public static ApiResult ok(){ return ok(null); } public static ApiResult ok(Object data){ return result(ApiCode.SUCCESS,data); } public static ApiResult ok(Object data,String msg){ return result(ApiCode.SUCCESS,msg,data); } public static ApiResult okMap(String key,Object value){ Map map = new HashMap<>(); map.put(key,value); return ok(map); } public static ApiResult fail(ApiCode apiCode){ return result(apiCode,null); } public static ApiResult fail(String msg){ return result(ApiCode.FAIL,msg,null); } public static ApiResult fail(ApiCode apiCode,Object data){ if (ApiCode.SUCCESS == apiCode){ throw new RuntimeException("失败结果状态码不能为" + ApiCode.SUCCESS.getCode()); } return result(apiCode,data); } public static ApiResult fail(String key,Object value){ Map map = new HashMap<>(); map.put(key,value); return result(ApiCode.FAIL,map); } public static ApiResult fail() { return fail(ApiCode.FAIL); } }
参考:https://blog.csdn.net/qq_27680317/article/details/79970590
public class Item {
@NotNull(message = "id不能为空")
@Min(value = 1, message = "id必须为正整数")
private Long id;
@Valid // 嵌套验证必须用@Valid
@NotNull(message = "props不能为空")
@Size(min = 1, message = "props至少要有一个自定义属性")
private List props;
}
————————————————
public class Prop {
@NotNull(message = "pid不能为空")
@Min(value = 1, message = "pid必须为正整数")
private Long pid;
@NotNull(message = "vid不能为空")
@Min(value = 1, message = "vid必须为正整数")
private Long vid;
@NotBlank(message = "pidName不能为空")
private String pidName;
@NotBlank(message = "vidName不能为空")
private String vidName;
}
全局异常
@ControllerAdvice
@RestController
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(value = HttpStatus.OK)
public ApiResult handleMethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException ex) {
BindingResult bindingResult = ex.getBindingResult();
List list = new ArrayList<>();
List fieldErrors = bindingResult.getFieldErrors();
for (FieldError fieldError : fieldErrors) {
list.add(fieldError.getDefaultMessage());
}
Collections.sort(list);
log.error("fieldErrors" + JSON.toJSONString(list));
return ApiResult.fail(ApiCode.PARAMETER_EXCEPTION, list);
}
}
Swagger
@Configuration
@EnableSwagger2 //开启Swagger2
public class SwaggerConfig
{
//配置
@Bean
public Docket docket(){
return new Docket(documentationType.SWAGGER_2).apiInfo(apiInfo());
}
//作者信息
private ApiInfo apiInfo() {
Contact contact = new Contact("Huishi", "https://blog.csdn.net/qq_36937684?spm=1001.2101.3001.5343", "939276378@qq.com");
return new ApiInfo("文档","测试 Spring-boot-valid","v1.0","https://mvnrepository.com/search?q=springfox++swagger",contact,"Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0", new ArrayList());
}
}
控制层
@RestController
public class ItemController {
@Autowired
ItemService itemService;
@PostMapping("/item/add") // 或者用@Validated也是一样的
public @ResponseBody ApiResult addItem(@Valid @RequestBody Item item) throws Exception {
int add = itemService.add(item);
return ApiResult.ok(add);
}
}
测试
①正常
{
"id": 2,
"props": [
{
"pid": 3,
"pidName": "string",
"vid": 8,
"vidName": "string"
}
]
}
返回
{
"code": 200,
"msg": "操作成功",
"success": true,
"data": 2,
"time": "2021-10-15 06:08:54"
}
②Item类 id属性为空
{
"props": [
{
"pid": 3,
"pidName": "string",
"vid": 8,
"vidName": "string"
}
]
}
返回
{
"code": 5001,
"msg": "请求参数校验异常",
"success": false,
"data": [
"id不能为空"
],
"time": "2021-10-15 06:10:51"
}
③Prop类 不满足条件
{
"id": 3,
"props": [
{
"pid": 0,
"pidName": "string",
"vid": 8,
"vidName": "string"
}
]
}
返回
{
"code": 5001,
"msg": "请求参数校验异常",
"success": false,
"data": [
"pid必须为正整数"
],
"time": "2021-10-15 06:11:58"
}



