• 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

  • 相关阅读:
    线程的故事:我的3位母亲成就了优秀的我!
    Semaphore自白:限流器用我就对了!
    CyclicBarrier:人齐了,老司机就可以发车了!
    最新版Swagger 3升级指南和新功能体验!
    阿里巴巴Druid,轻松实现MySQL数据库连接加密!
    try-catch-finally中的4个大坑,不小心就栽进去了!
    Git 常用命令总结,将会持续更新
    oracle in 条件超长问题解决
    关于java中使用split方法末尾空值被丢弃的问题
    Ubuntu 嵌入式开发准备
  • 原文地址:https://www.cnblogs.com/tele-share/p/11528741.html
Copyright © 2020-2023  润新知