1、导包
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.1.Final</version>
</dependency>
2、注解说明
 
3、需要数据校验的地方
两种请求:
- get、delete等请求,参数形式为RequestParam/PathVariable
- post、put等请求,参数形式为RequestBoty
RequestParam/PathVariable形式的参数校验
Get、Delete请求一般会使用RequestParam/PathVariable形式参数参数,这种形式的参数校验一般需要以下两个步骤,如果校验失败,会抛出ConstraintViolationException异常。
必须在Controller类上标注@Validated注解; 在接口参数前声明约束注解(如@NotBlank等)
@RestController
@Validated
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
@MyLog("获取用户")
public R user(@Max(value = 12,message = "用户id不能为空") @PathVariable("id")Integer id,
@NotBlank(message = "用户名不能为空") @RequestParam("username") String username){
User user = userService.getById(id);
return R.ok().put("data",user);
}
@PostMapping("/add")
public R add( @RequestBody Teacher teacher){
ValidatorUtils.validateObject(teacher, AddGroup.class);
System.out.println(JSONUtil.toJsonStr(teacher));
return R.ok();
}
}
RequestBoty形式的参数校验
POST、PUT请求一般会使用requestBody传递参数,这种情况下,在入参对象上添加@Validated注解就能实现自动参数校验。
比如,有一个保存用户信息的接口,要求username长度是2-20位,password字段长度是8-20位,还要加上邮箱校验。如果校验失败,会抛出MethodArgumentNotValidException异常,Spring默认会将其转为400(Bad Request)请求.
分组校验
背景:在执行保存和更新操作的时候,校验的参数可能存在差异,比如保存的时候不需要校验Id,而更新的时候就需要校验id(主键),写两个实体类复用率会很低。所以这个时候分组校验就很有必要
public interface AddGroup {
}
public interface UpdateGroup {
}
实体类
@Data
public class Teacher {
@NotNull(message = "id不能为空",groups = UpdateGroup.class)
private Integer id;
@NotBlank(message = "教师账号不能为空",groups = {UpdateGroup.class, AddGroup.class})
private String tid;
@NotBlank(message = "密码不能为空",groups = {UpdateGroup.class, AddGroup.class})
private String pwd;
@NotBlank(message = "教师姓名不能为空",groups = {UpdateGroup.class, AddGroup.class})
private String tname;
@Email(message = "教师邮箱不合法",groups = {UpdateGroup.class, AddGroup.class})
private String email;
@NotNull(message = "学生信息不能为空",groups = {UpdateGroup.class, AddGroup.class})
@Valid
private List<Student> students;
}
@Data
public class Student {
@NotNull(message = "id不能为空",groups = UpdateGroup.class)
private Integer id;
@NotBlank(message = "学生账号不能为空",groups = {UpdateGroup.class, AddGroup.class})
private String sid;
@NotBlank(message = "密码不能为空",groups = {UpdateGroup.class, AddGroup.class})
private String pwd;
@NotBlank(message = "学生姓名不能为空",groups = {UpdateGroup.class, AddGroup.class})
private String sname;
@Email(message = "学生邮箱不合法",groups = {UpdateGroup.class, AddGroup.class})
private String email;
}
分组校验工具类
public class ValidatorUtils {
private static final ValidatorFactory VALIDATOR_FACTORY = Validation.buildDefaultValidatorFactory();
public static void validateObject(Object paramObject) {
Validator validator = VALIDATOR_FACTORY.getValidator();
Set<ConstraintViolation<Object>> validateResult = validator.validate(paramObject);
if (CollectionUtils.isEmpty(validateResult)) {
return;
}
StringBuilder errorMessageSb = new StringBuilder();
for (ConstraintViolation<Object> violation : validateResult) {
errorMessageSb.append(violation.getMessage()).append(";");
}
throw new RRException(errorMessageSb.toString());
}
public static void validateObject(Object paramObject, Class<?> classes) {
Validator validator = VALIDATOR_FACTORY.getValidator();
Set<ConstraintViolation<Object>> validateResult = validator.validate(paramObject, classes);
if (CollectionUtils.isEmpty(validateResult)) {
return;
}
Set<String> errorMsgSet = new HashSet<>();
for (ConstraintViolation<Object> violation : validateResult) {
errorMsgSet.add(violation.getMessage());
}
throw new RRException(String.join("<br>", errorMsgSet));
}
private ValidatorUtils() {
}
}
自定义异常处理类
public class RRException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String msg;
private int code = 500;
public RRException(String msg) {
super(msg);
this.msg = msg;
}
public RRException(String msg, Throwable e) {
super(msg, e);
this.msg = msg;
}
public RRException(String msg, int code) {
super(msg);
this.msg = msg;
this.code = code;
}
public RRException(String msg, int code, Throwable e) {
super(msg, e);
this.msg = msg;
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
全局异常处理类
@RestControllerAdvice
@Log4j
public class RRExceptionHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
@ExceptionHandler(RRException.class)
public R handleRRException(RRException e){
R r = new R();
r.put("code", e.getCode());
r.put("msg", e.getMessage());
return r;
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public R handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
logger.error("[全局异常处理] [参数校验不通过]{}", e.getMessage(), e);
return R.error(e.getMessage());
}
@ExceptionHandler(UnexpectedTypeException.class)
public R handleUnexpectedTypeException(UnexpectedTypeException e) {
logger.error("[全局异常处理] [参数校验类型不匹配]{}", e.getMessage(), e);
return R.error(e.getMessage());
}
@ExceptionHandler(ConstraintViolationException.class)
public R handleConstraintViolationException(ConstraintViolationException e) {
Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
List<String> msgList = new ArrayList<>();
for (ConstraintViolation<?> constraintViolation : constraintViolations) {
msgList.add(constraintViolation.getMessageTemplate());
}
return R.error(String.join("<br>",msgList));
}
@ExceptionHandler(Exception.class)
public R handleException(Exception e){
logger.error(e.getMessage(), e);
return R.error();
}
}
返回类
public class R extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
public R() {
put("code", 200);
put("msg", "success");
}
public static R error() {
return error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "未知异常,请联系管理员");
}
public static R error(String msg) {
return error(HttpStatus.INTERNAL_SERVER_ERROR.value(), msg);
}
public static R error(int code, String msg) {
R r = new R();
r.put("code", code);
r.put("msg", msg);
return r;
}
public static R ok(String msg) {
R r = new R();
r.put("msg", msg);
return r;
}
public static R ok(Map<String, Object> map) {
R r = new R();
r.putAll(map);
return r;
}
public static R ok() {
return new R();
}
public R put(String key, Object value) {
super.put(key, value);
return this;
}
public Integer getCode() {
return (Integer) get("code");
}
}
参考 添加链接描述
|