自定义注解实现密码的校验以及参数错误的全局异常处理
-
编写自定义注解
@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产生的异常没有做处理,可以再定义两个异常捕获的方法