springmvc 参数校验/aop失效/@PathVariable 参数为空

添加依赖

1 <!-- 参数校验 -->
2 <dependency>
3     <groupId>org.hibernate.validator</groupId>
4     <artifactId>hibernate-validator</artifactId>
5     <version>6.0.17.Final</version>
6 </dependency>

一.基本类型参数(String)校验

1.注解要写在接口中,实现类会自动继承,如果实现类的某个重写方法没有加上了注解,接口中却没有定义,运行时会产生redefine异常

接口:

User getUserById(@NotNull(message = "uid不能为null") @Min(value = 1,message = "uid不合法") Integer id);
实现类:

@Override
public User getUserById(@NotNull(message = "uid不能为null") @Min(value = 1,message = "uid不合法") Integer id) {
return userMapper.getUserById(id);
}

Controller(restful风格最容易出的问题就是参数为空,只要不传就是404,不要尝试:xxx/getUserById/null,这种写法是400,给url设置null没有意义,解决方式很简单,给Controller增加一个映射路径即可,空参数导致的bind异常可以用在全局异常处理器捕获即可,当然你在web.xml中统一处理404也可以):

1 @RequestMapping(value = {"/getUserById/{uid}","/getUserById"})
2 public @ResponseBody Object getUserById(@PathVariable Integer uid) {
3     return userService.getUserById(uid);
4 }

2.提供校验器,自定义异常(可选),全局异常处理器

校验器:

1 public class ParamsValidator {
2 
3     public static ExecutableValidator getValidator() {
4         ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
5         return validatorFactory.getValidator().forExecutables();
6     }
7 }
View Code

自定义异常(可选):

 1 public class ValidParamException extends RuntimeException {
 2     private static final long serialVersionUID = 1L;
 3 
 4     private Set<ConstraintViolation<Object>> validateResult;
 5 
 6     public ValidParamException() {
 7         super();
 8     }
 9 
10     public ValidParamException(String message) {
11         super(message);
12     }
13 
14     public ValidParamException(Set<ConstraintViolation<Object>> validateResult) {
15         this.validateResult = validateResult;
16     }
17 
18     public Set<ConstraintViolation<Object>> getValidateResult() {
19         return validateResult;
20     }
21 
22     public void setValidateResult(Set<ConstraintViolation<Object>> validateResult) {
23         this.validateResult = validateResult;
24     }
25 
26     @Override
27     public String getMessage() {
28         return validateResult.iterator().next().getMessage();
29     }
30 
31     public Map<Object, String> getErrorMap() {
32         Map<Object, String> map = new HashMap<Object, String>(6);
33         Iterator<ConstraintViolation<Object>> iterator = validateResult.iterator();
34         while (iterator.hasNext()) {
35             ConstraintViolation<Object> cons = iterator.next();
36             Path propertyPath = cons.getPropertyPath();
37             String message = cons.getMessage();
38             map.put(propertyPath, message);
39         }
40         return map;
41     }
42 
43 }
View Code

全局异常处理器:

 1 @ControllerAdvice
 2 @EnableWebMvc
 3 public class GlobalExceptionHandler {
 4     // 单参数校验
 5     @ExceptionHandler(ValidParamException.class)
 6     public @ResponseBody Map<Object, String> validParamException(HttpServletRequest req, ValidParamException vpe) {
 7         return vpe.getErrorMap();
 8     }
 9 
10     // 对象类型参数校验
11     @ExceptionHandler(MethodArgumentNotValidException.class)
12     public @ResponseBody Map<Object, String> methodArgumentNotValidException(MethodArgumentNotValidException ex) {
13         String parameterName = ex.getParameter().getParameterName();
14         Map<Object, String> map = new HashMap<Object, String>(6);
15         map.put(parameterName, ex.getLocalizedMessage());
16         return map;
17     }
18 
19     // pathvariable不传递参数时抛出的异常
20     @ExceptionHandler(ServletRequestBindingException.class)
21     public @ResponseBody Map<Object, String> servletRequestBindingException(ServletRequestBindingException ex) {
22         Map<Object, String> map = new HashMap<Object, String>(6);
23         map.put("error", ex.getLocalizedMessage());
24         return map;
25     }
26 }

3.使用aop进行拦截

关于aop"失效"的问题有几点说明:

1)如果拦截controller,那么aop的配置要写在springmvc的配置文件中,拦截其他层(如service)写在spring的配置文件中

2)被拦截的类必须也被spring管理否则无法拦截成功

3)开启注解扫描时,springmvc只扫描@Controller类型的注解,其他的如@Service,@Repository注解由spring进行扫描

aop:

 1 @Component
 2 @Aspect
 3 public class UserAspect {
 4 
 5     private ExecutableValidator validator = ParamsValidator.getValidator();
 6 
 7     @Pointcut("execution (* cn.tele.service.*.*(..))")
 8     private void pt() {
 9     }
10 
11     @Before("pt()")
12     public void checkParams(JoinPoint jp) {
13 
14         Object target = jp.getTarget();
15         Object[] params = jp.getArgs();
16         MethodSignature methodSignature = (MethodSignature) jp.getSignature();
17 
18         String[] paramNames = methodSignature.getParameterNames();
19         Method method = methodSignature.getMethod();
20 
21         Set<ConstraintViolation<Object>> validateResult = validator.validateParameters(target, method, params);
22         if (!validateResult.isEmpty()) {
23             throw new ValidParamException(validateResult);
24         }
25     }
26 
27 }
View Code

4.测试结果:

1)传入-1

 2)不传

 

可以在aop中打印日志啥的

 

二.对象类型参数校验

1.在javaBean中添加注解,对一些特殊字段进行分组,如id,插入数据时,不需要校验可以为null,而查询,删除,更新等操作必须校验

 1 @NotNull(message = "uid不能为null",groups = {Query.class,Update.class,Delete.class})
 2 @Min(value = 1,message = "uid不合法")
 3 private Integer uid;
 4 
 5 @NotBlank(message = "姓名不能为空")
 6 @Size(max = 20,message = "姓名最大长度为50个字符")
 7 private String userName;
 8 
 9 @NotBlank(message = "性别不能为空")
10 @Size(max = 20,message = "性别最大长度位20个字符")
11 private String sex;
12 
13 @NotNull
14 @Max(value = 70,message = "最大年龄为70岁")
15 private Integer age;
16 
17 @NotNull
18 private Integer departmentId;
19 
20 @Value(value = "1")
21 private Integer state;

分组只是个标记,用接口定义就好

1 public interface Query {
2 
3 }

2.在参数前添加@Valited注解,该注解支持分组,@Valid不支持,如果你选择的校验位置与上面定义的aop拦截的位置相同,那就会出问题了,

你的代码会走aop的逻辑然后去用你校验单个参数的校验器去进行校验,这样无法校验出问题,因此推荐放在controller层

1 @RequestMapping("/insertUser")
2 public @ResponseBody String insertUser(@Validated @RequestBody User user) {
3     Integer count = userService.insertUser(user);
4     return count ==1 ? "成功增加1条记录" : "增加" + user + "失败";
5 }

校验指定分组

 

3.抛出的异常会走上面贴出的全局异常处理器的代码

4.测试

1)正常情况,注意没有id

 2)丢失userName

posted @ 2019-09-16 19:33  tele  阅读(2636)  评论(0编辑  收藏  举报