当前端传参到controller时,后台经常要对其传来的参数进行校验,例如校验是否为空,金额的大小校验等。此时你很快就想到了用if eles如下:
public Object save(String name){
if(name==null){
throw new Exception("名称不能为空");
}
return studentService.save(name);
}
但是,如果传来的参数是这样:
public Object save(@RequestBody SaveInput input){
if(input.getName()==null){
throw new Exception("名称不能为空");
}
if(input.getAge()==null){
throw new Exception("年龄不能为空");
}
if...
return studentService.save(input);
}
额,我估计这样写在代码评审时你会被打死。下面我们来看下如何用springboot自带的validator来进行优雅的校验。
下面我们直接来撸代码:
//前端传来的dto对象
@Data
public class saveInput{
private String name;
private Integer age;
}
/**
自定义一个类实现Validator接口,重写这个接口的supports方法和validate方法
*/
@Component
public class SaveInputValidator implements Validator {
@Override
public boolean supports(Class<?> aClass) {
return SaveInput.class.isAssignableFrom(aClass);
}
/**
*这里只是举例,你可以完全按照自己的业务去做校验
**/
@Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "field.required");
SaveInput input = (SaveInput) target;
if(input.getAge<0){
errors.reject(400,"年龄不能小于0");
}
}
}
//controller
@RestController
@RequestMapping("/UserCotroller")
public class UserCotrollerextends {
@Autowired private PriceAdjustPurHeadService priceAdjustPurHeadService;
@Autowired private UserService userService;
@Autowired private SaveInputValidator saveInputValidator;
//1、对自定义的SaveInputValidator进行绑定
@InitBinder()
public void setupBinder(WebDataBinder binder) {
if (binder.getTarget() == null) {
return;
}
if (saveInputValidator.supports(binder.getTarget().getClass())) {
binder.addValidators(saveInputValidator);
}
}
//2、添加 @Validated注解
@PostMapping(value = "/save")
public Object save(@RequestBody @Validated SaveInput input){
return userService.save(name);
}
}
以上就是第一种情况,SaveInput里面的属性都是基本数据类型时可用,但是当SaveInput里面还有其他的自定义的dto你可能会遇到下面这种情况
@Data
public class saveInput{
private Head head;//单头
private List<Detatil> detailes;//明细数组
}
@Data
public class Head{
private String no;
private String ClassName;
}
@Data
public class Detail{
private String name;
private String age;
}
这种情况下,SaveInputValidator 定义改变:
@Component
public class HeadValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return Head.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
Head dto = (Head ) target;
// 校验
}
}
@Component
public class DetailValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return PriceAdjustPurDetailInputDTO.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
Detail dto = (Detail ) target;
// 校验
}
}
/**
* 自定义Validator
*/
@Component
public class SaveInputValidator implements Validator {
@Autowired HeadtValidator headValidator;
@Autowired DetailValidator detailValidator;
@Override
public boolean supports(Class<?> aClass) {
return SaveInput.class.isAssignableFrom(aClass);
}
@Override
public void validate(Object target, Errors errors) {
SaveInput input = (SaveInput) target;
Head head = input.getHead();
List<Detail> details = input.getDetails();
//将错误信息进行入栈操作,
errors.pushNestedPath("head");//head与saveInput中的head参数名保持一致
ValidationUtils.invokeValidator(headValidator,head,errors);
//错误信息出栈
errors.popNestedPath();
// 校验明细是否为空
int dx = 0;
for (Detail d : details) {
//错误信息入栈
errors.pushNestedPath("details[" + dx + "]");//details与saveInput中details名称保持一致
ValidationUtils.invokeValidator(detailValidator, d, errors);
//错误信息出栈
errors.popNestedPath();
dx++;
}
}
}
以上就是Validator的自定义方法,可以根据自己的实际业务场景选择不同的实现方案。