
定义接口 ,根据接口 将不同的校验规则分给不同的组,在使用时,指定不同的校验规则
Group1.Java
package com.example.validateddemo.interfaces;
/**
* 校验分组1
* @author He Changjie on 2020/9/5
*/
public interface Group1 {
}Group2.Java
package com.example.validateddemo.interfaces;
/**
* 校验分组2
* @author He Changjie on 2020/9/5
*/
public interface Group2 {
}使用注解时,可以给属性设置多个校验进行分组!
User2Dto.Java
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.*;
@Data
public class User2Dto {
/**
* 用户名
*/
@NotBlank(message = "用户名不能为空!", groups = {Group1.class}) //给属性设置组!
private String username;
/**
* 性别
*/
@NotBlank(message = "性别不能为空!")
private String gender;
/**
* 年龄
*/
@Min(value = 1, message = "年龄有误!", groups = {Group1.class}) //设置 Group1
@Max(value = 120, message = "年龄有误!", groups = {Group2.class}) //设置 Group2
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;
}Controller 中指定了,校验的组类型!
Demo1Controller.Java
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 {
//不指定分组,即是默认组 或 Default.Class 即对没有进行分组的JSR303 数据进行校验!
@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);
}
}查看insert4 使用了Group1 的组校验~

查看insert5 使用了Group2 的组校验~
不指定组使用默认组进行校验! 则,没有进行分组的JSR303 注解生效进行校验通过!

@Validated
校验注解进行分组!
groups = {组接口.class}不指定即没有组的校验进行校验核对!
@Validated(组接口.class)在比较两者嵌套验证时,先说明下什么叫做嵌套验证。比如我们现在有个实体叫做Item:
Item带有很多属性,属性里面有属性id,属性值id,属性名和属性值,如下所示:
或其它引用类型!Item.Java
public class Item {
@NotNull(message = "id不能为空")
@Min(value = 1, message = "id必须为正整数")
private Long id;
@NotNull(message = "props不能为空")
@Size(min = 1, message = "至少要有一个属性")
private List<Prop> props;
}Prop.Java
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;
}Prop 属性
属性这个实体也有自己的验证机制,比如属性和属性值id不能为空,属性名和属性值不能为空等ItemController.Java
@RestController
public class ItemController {
@RequestMapping("/item/add")
public void addItem(@Validated Item item, BindingResult bindingResult) {
doSomething();
}
}@NotNull**和**@Size** 无论入参采用 @Validated 还是 @Valid验证
Spring Validation框架只会对Item的id和props做非空和数量验证,
不会对props字段里的Prop实体进行字段验证为了能够进行嵌套验证,必须手动在Item实体的props字段上明确指出这个字段里面的实体也要进行验证。
由此推断:
Item.Java
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<Prop> props;
}然后我们在ItemController的addItem函数上再使用@Validated或者@Valid,就能对Item的入参进行嵌套验证。
嵌套验证:
注解并不会自动的进行,校验内部的元素!@Valid 对实体属性进行嵌套校验!Controller控制层写参数接收的入口
配套使用!随意一个Controller
@RequestMapping(value = "/test", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody ResponseEntity<Pesponsibles> testBindingResult(@Valid @RequestBody Parameter parameter,BindingResult bindingResult)
{
log.info("test start");
Pesponsibles pesponsibles=new Pesponsibles();
//判断是否存在,校验异常数据!打印日志!
if(bindingResult.hasErrors()){
List<FieldError> fieldErrors = bindingResult.getFieldErrors(); //获取校验异常集合!
//遍历 输出日志!
fieldErrors.forEach(fieldError -> {
//日志打印不符合校验的字段名和错误提示
log.error("error field is : {} ,message is : {}", fieldError.getField(), fieldError.getDefaultMessage());
});
//控制台查看!
for(int i=0;i<fieldErrors.size();i++){
//控制台打印不符合校验的字段名和错误提示
System.out.println("error field is :"+fieldErrors.get(i).getField()+",message is :"+fieldErrors.get(i).getDefaultMessage());
}
//返回前台数据异常!这里就根据自己项目情况而定
return new ResponseEntity<>(pesponsibles, HttpStatus.BAD_REQUEST);
}
//没有异常操作...👍
return new ResponseEntity<>(pesponsibles, HttpStatus.OK);
}@Valid / @Validated 要和 BindingResult 搭配使用,用来输出获取校验失败的数据,返回前端。
目前少见了!**提示用户!**可以先了解:此篇文章:异常处理!
因为每个Controller 都会需要进行 BindingResult 可能会比较麻烦,可以使用全局异常进行捕获处理!
全局处理异常类
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;
@Slf4j
@ControllerAdvice
public class ValidatedExceptionHandler {
/**
* 处理@Validated参数校验失败异常
* @param exception 异常类
* @return 响应
*/
@ResponseBody
//@ResponseStatus的作用就是为了改变HTTP响应的状态码
@ResponseStatus(HttpStatus.BAD_REQUEST) //改变响应时候 HttpStatus状态 400 接口异常!
@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());
}
}@ControllerAdvice ,很多初学者可能都没有听说过这个注解
注解声明异常类型, 当类中出现改异常会进入该方法处理
@ControllerAdvice类中 则全局的Controller 都会有这个方法,任何地方出现异常都会走到这方法中!全局异常
当将异常抛到controller时,可以对异常进行统一处理:
@ControllerAdvice
public class MyGlobalExceptionHandler {
//注解捕获, Exception类型异常, 即所有的异常都将捕获!
@ExceptionHandler(Exception.class)
public ModelAndView customException(Exception e) {
ModelAndView mv = new ModelAndView();
mv.addObject("message", e.getMessage());
mv.setViewName("myerror");
return mv;
}
}在该类中,可以定义多个方法,不同的方法处理不同的异常
就相当于一个全局的Controller 累下的方法,可以被所有的Controller类共享…可以做**全局异常**,**初始化数据** 数据绑定!