自定义注解实现密码的校验以及参数错误的全局异常处理

自定义注解实现密码的校验以及参数错误的全局异常处理

  • 编写自定义注解

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    // 注解的作用目标,ElementType.TYPE表示只能作用在类上
    @Target(ElementType.TYPE)
    // 注解校验的关联类
    @Constraint(validatedBy = PasswordValidator.class)
    public @interface PasswordEqual {
    
        // 注解中不能使用包装类型
        int min() default 4;
    
        int max() default 24;
    
        String message() default "passwords are not equal";
    
        // groups和payload方法是注解中必须要有的两个方法
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    }
    
  • 编写自定义注解的关联类

    /**
     * ConstraintValidator泛型中的第一个参数是关联的注解,第二个参数是注解修饰的目标的类型
     */
    public class PasswordValidator implements ConstraintValidator<PasswordEqual, PersonDTO> {
    
        private int max;
    
        private int min;
    
        /**
         * 初始化方法
         * @param constraintAnnotation
         */
        @Override
        public void initialize(PasswordEqual constraintAnnotation) {
    
            this.min = constraintAnnotation.min();
            this.max = constraintAnnotation.max();
        }
    
        /**
         * 校验的方法
         * @param personDTO
         * @param constraintValidatorContext
         * @return
         */
        @Override
        public boolean isValid(PersonDTO personDTO, ConstraintValidatorContext constraintValidatorContext) {
            if(personDTO == null) {
                return false;
            }
            String password1 = personDTO.getPassword1();
            String password2 = personDTO.getPassword2();
            if(password1==null) {
                this.setErrorMessage(constraintValidatorContext, "密码不能为空");
                return false;
            }
            if(password1.length()<min || password1.length()>max) {
                this.setErrorMessage(constraintValidatorContext, "密码的长度不能少于"+this.min+"个字符, 不能超过"+this.max+"个字符");
                return false;
            }
            boolean match = password1.equals(password2);
            if(!match) {
                this.setErrorMessage(constraintValidatorContext, "两次输入的密码不一致");
            }
    
            return match;
        }
    
        // 设置校验失败的提示消息
        private void setErrorMessage(ConstraintValidatorContext constraintValidatorContext, String errorMessage) {
            constraintValidatorContext.disableDefaultConstraintViolation();
            constraintValidatorContext
                    .buildConstraintViolationWithTemplate(errorMessage)
                    .addConstraintViolation();
        }
    }
    
  • 编写实体类

    @PasswordEqual
    public class PersonDTO {
    
        private String password1;
    
        private String password2;
    
        public String getPassword1() {
            return password1;
        }
    
        public void setPassword1(String password1) {
            this.password1 = password1;
        }
    
        public String getPassword2() {
            return password2;
        }
    
        public void setPassword2(String password2) {
            this.password2 = password2;
        }
    }
    
  • 在控制器中使用

    @RestController
    @RequestMapping(value = "/hello")
    public class HelloWorldController {
    
        @GetMapping(value = "/say")
        public String say(@Validated PersonDTO personDTO) {
    
            return "hello, world";
        }
    }
    
  • 参数错误的全局异常处理

    @ControllerAdvice
    @RestController
    public class GlobalException {
    
        /**
         * 参数校验失败的全局异常处理
         * @param e
         * @return
         */
        // 自定义request状态码
        @ResponseStatus(value = HttpStatus.BAD_REQUEST)
        @ExceptionHandler(value = {BindException.class})
        public Map<String, String> handlerArgsBindException(BindException e) {
            List<ObjectError> errors = e.getAllErrors();
            Map<String, String> map = new HashMap<>();
            errors.forEach(error -> map.put(error.getObjectName(), error.getDefaultMessage()));
            return map;
        }
    }
    
    

    handlerArgsBindException只捕获了通过URL传参而产生的异常,对于RequestBody传参和PathValiable产生的异常没有做处理,可以再定义两个异常捕获的方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章