使用Spring Boot自带的Validator对入参dto进行校验

当前端传参到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的自定义方法,可以根据自己的实际业务场景选择不同的实现方案。

发布了38 篇原创文章 · 获赞 6 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/coderlady/article/details/98492192