背景
日常开发中,往往需要对一些表单提交的数据进行校验,避免发生一些未知错误。对于数据校验,光靠前端是不够的,稍有开发经验的人都很容易绕过前端校验发送请求,因此在这里后端校验也是必不可少的一个环节。
做法
对于简单校验,数量少的情况通常使用if去判断会比较方便,一旦校验数量多或者是多个方法都需要类似的校验,这时候使用if判断就会显得臃肿,而且每增加一个相似的校验字段就需要新增一个if语句,代码不仅冗余,还不美光,接下来介绍一种现成的注解校验,不仅使用简单易上手,更是让代码提升一个逼格,它就是今天的主角----“JSR-303”
开始
JSR303是一套JavaBean参数校验规则,定义了一些常见参数校验注解,
1.使用SpringBoot引入web校验依赖即可
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
2.接收参数类上加上对应校验注解,下面会列举一些常用校验,如需更多可自行百度
package com.example.demo.dto;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.*;
/**
* <h3>demo</h3>
* <p></p>
*
* @author : ZhengYangYi
* @date : 2022-10-29 23:55
**/
@Data
public class ParamDTO {
@NotNull(message = "id不得为空!")
private String id;
@NotBlank(message ="名字不得为空!")
private String name;
@Min(value = 0, message = "年龄不得小于0!")
private Integer age;
@Email(message = "邮箱格式不正确!")
private String email;
@Length(max = 20, message = "输入的地址长度不得大于20!")
private String address;
}
3.controller层中加入@Validated(支持分组校验,即同一字段不同方法可以有不同的校验规则,比如更新需要id必填,而添加不需要,此时就可以使用分组校验,此处不做详讲)或Valid(不支持分组校验)
package com.example.demo.controller;
import com.example.demo.dto.ParamDTO;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* <h3>demo</h3>
* <p></p>
*
* @author : ZhengYangYi
* @date : 2022-10-29 23:51
**/
@RestController
@RequestMapping("/test")
public class TestController {
@PostMapping("/valid")
public Map<String, String> validParam(@Validated @RequestBody ParamDTO dto, BindingResult result) {
//BindingResult:校验结果绑定对象
//是否存在校验不通过字段
boolean flag = result.hasErrors();
Map<String, String> map = new HashMap<>(16);
if (flag) {
//获取所有校验不通过字段
List<FieldError> fieldErrors = result.getFieldErrors();
for (FieldError fieldError : fieldErrors) {
map.put(fieldError.getField(), fieldError.getDefaultMessage());
}
}
return map;
}
}
4.发送请求即可完成对应校验
5.一般项目使用全局统一异常进行统一返回数据,此时Controller层中的 BindingResult result方法参数需要删除,否则不会抛出异常
package com.example.demo.common;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
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.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
/**
* <h3>demo</h3>
* <p></p>
*
* @author : ZhengYangYi
* @date : 2022-10-30 01:11
**/
@RestControllerAdvice(basePackages = "com.example.demo.controller")
@Slf4j
public class ParamExceptionAdvice {
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Map<String, String> validException(MethodArgumentNotValidException e) {
log.error("参数校验异常:", e);
Map<String, String> map = new HashMap<>(16);
BindingResult bindingResult = e.getBindingResult();
bindingResult.getFieldErrors().forEach(item -> {
map.put(item.getField(), item.getDefaultMessage());
});
return map;
}
}
6.至此注解校验大功告成!