在开发过程中经常需要对一些参数进行校验比如非空判断,字符长度判断之类的,如果参数很多的话会给自己添加很多工作量,而且代码会很难看 会有很多很多的if-else 例如这样的代码
if(StringUtils.isBlank(user.getId())){
System.out.println("id不能为空");
}
if(StringUtils.isBlank(user.getName())){
System.out.println("name不能为空");
}
用Hibernate Validator可以很好的解决这个问题,简化代码量以及优化代码结构,Hibernate Validator不需要单独引入依赖,springboot的web起步依赖里面包含了,图示如下 这是项目的pom文件
大家可以看到这是起步依赖
点进去之后可以看到
这就是我们所需要的组件,所以大家选择了web起步依赖的话就可以直接使用的
这是我的bean,可以看到我在字段上面加了注解
NotBlank大家肯定很熟悉了,表示非空 空格也会被判定成空,这个意思是这两个字段都不允许为空,可以用来代替if-else的判断
@Validated表示这个对象使用Validator进行校验
大家看我访问这个uri会返回什么
大家可以看到,返回了一大串信息,对两个参数都进行了校验,接下来给大家介绍一下 BindingResult对象,这个对象里面主要是封装了上面的返回信息
大家可以看到信息已经被取出来了,可是有的同学希望在拦截到第一个参数时就返回,而不是同时返回两个被拦截的参数,我们需要加上这样一个配置
@Bean
public javax.validation.Validator validator(){
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure()
.addProperty( "hibernate.validator.fail_fast", "true" )
.buildValidatorFactory();
return validatorFactory.getValidator();
}
true为快速返回即拦截到一个参数时就返回
接下来可以看到,只打印了一个参数被拦截的message
接下来跟大家分享一下用统一异常处理来校验
我使用@RestControllerAdvice来进行异常处理,关于@RestControllerAdvice详解可以自行去百度,很多大神已经分析得很透彻了
当接口方法去掉BindingResult时校验到不合法的参数会抛出异常,如果是用表单形式提交的参数会抛出BindException我们使用@ExceptionHandler处理即可
@RestControllerAdvice
public class ExceptionHadlers {
//表单格式
@ExceptionHandler(value = BindException.class)
public Map errorHandler(BindException ex) {
BindingResult result = ex.getBindingResult();
StringBuilder errorMsg = new StringBuilder();
for (ObjectError error : result.getAllErrors()) {
errorMsg.append(error.getDefaultMessage()).append(",");
}
errorMsg.delete(errorMsg.length() - 1, errorMsg.length());
Map map = new HashMap();
map.put("code", 400);
map.put("msg", errorMsg.toString());
return map;
}
}
这样每次请求的参数校验不通过的情况下都会直接返回这个map
这个参数拦截对json格式的不生效,也就是header里面加了application/json的参数
大家可以看到,没有进入@ExceptionHandler,但是又返回了异常信息,我代码里面并没有任何返回,说明是抛出了其它的异常,后面发现是抛出了MethodArgumentNotValidException,同理 我们再加一个@ExceptionHandler
@RestControllerAdvice
public class ExceptionHadlers {
//json格式
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Map errorHandler(MethodArgumentNotValidException ex) {
StringBuilder errorMsg = new StringBuilder();
BindingResult re = ex.getBindingResult();
for (ObjectError error : re.getAllErrors()) {
errorMsg.append(error.getDefaultMessage()).append(",");
}
errorMsg.delete(errorMsg.length() - 1, errorMsg.length());
Map map = new HashMap();
map.put("code", 400);
map.put("msg", errorMsg.toString());
return map;
}
//表单格式
@ExceptionHandler(value = BindException.class)
public Map errorHandler(BindException ex) {
BindingResult result = ex.getBindingResult();
StringBuilder errorMsg = new StringBuilder();
for (ObjectError error : result.getAllErrors()) {
errorMsg.append(error.getDefaultMessage()).append(",");
}
errorMsg.delete(errorMsg.length() - 1, errorMsg.length());
Map map = new HashMap();
map.put("code", 400);
map.put("msg", errorMsg.toString());
return map;
}
}
这样配置后当有校验到不合法参数时就会自动被拦截,省去许多if-else
注意:使用统一异常处理时必须要把接口方法入参里面的BindingResult去掉,我测试时发现如果加上这个对象了就不会抛出任何异常,如果自己没有对BindingResult做逻辑处理的话,代码会继续往下走,建议如果使用BindingResult的话,可以自行处理一下逻辑。