SpringBoot异常处理(二)

参数校验机制

JSR-303 Hibernate

参数接收方式:

  • URL路径中的参数 {id} (@PathVariable(name="id") int-whatever)
  • URL中的查询参数 ?name=Chanuncy (@RequestPara(name String-whatever)
  • requestbody中的json字符串 {"name":"7yue","age":18} (@RequestBody Map<String,Object> person)
  • 一般会新建一个dto(data transfer object) 来接受和发送参数,一个对象一个dto
@Getter
@Builder
public class PersonDTO {
    private String name;
    private Integer age;
    private String  password1;
    private String  password2;

}

简单参数检验:

@Validated 开启验证

@Range @Max @Min

@RestController
@RequestMapping("/banner")
//开启验证 下文@Max验证
@Validated
public class BannerController {
    @RequestMapping("/test1/{id}")
    public String test1(@PathVariable @Max(5) int id,
                        @RequestBody @Validated PersonDTO person){
                                     //开启PersonDTO  @Length验证
        return "ok";
    }

复杂参数验证:(对象)

@Validated 开启验证

@Valid 级联验证

PersonDTO:

@Getter
@Builder
//自定义注解后面会讲到
@PasswordEqual
public class PersonDTO {
    @Length(min = 2, max=10, message = "大小不匹配")
    private String name;
    private Integer age;

    private String  password1;
    private String  password2;
    //@Valid  开启SchoolDTO schoolName 验证
    private SchoolDTO school;
}
@Getter
@Setter
public class SchoolDTO{
    @Length(min=2)
    priavte String schoolName;
}

自定义参数校验注解:

当逻辑十分复杂时就要自己定义参数校验注解

先导:注解和反射

四个元注解:

  • @Target
  • @Rentention
  • @Documented
  • @Inherited

使用注解的机制:反射

通过反射获取Class实例的方法:

  • 对象.getClass()
  • 类.class
  • Class.forName(全类名)

新建一个验证两次输入相同字符串的注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
//将注解和逻辑处理类关联
@Constraint(validatedBy = PasswordValidator.class)
public @interface PasswordEqual {
    String message() default "passwords are not equal";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

逻辑处理:

//ConstraintValidator<注解的名字,注解修饰的对象>
public class PasswordValidator implements ConstraintValidator<PasswordEqual, PersonDTO> {
    @Override
    public boolean isValid(PersonDTO personDTO, ConstraintValidatorContext constraintValidatorContext) {
        String password1 = personDTO.getPassword1();
        String password2 = personDTO.getPassword2();
        boolean match = password1.equals(password2);
        return match;
    }
}

上述参数校验会抛出一个未处理的异常,所以我们要写对应的异常处理

在Spring-Boot异常处理(一)中的GlobalExceptionAdvice中添加:

//dto参数校验异常 
@ResponseBody
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public UnifyResponse handleBeanValidation(HttpServletRequest req,MethodArgumentNotValidException e){
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
        String errorMessage = this.formatAllErrorMessages(allErrors);
        return new UnifyResponse(10001,errorMessage,req.getMethod() + ' ' + req.getRequestURI());
    }

    //url参数异常
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public UnifyResponse handleConstraintViolationException(HttpServletRequest req, ConstraintViolationException e){
        return new UnifyResponse(10001,e.getMessage(),req.getMethod() + ' ' + req.getRequestURI());
    }


    //格式化dto参数校验异常错误信息
    private String formatAllErrorMessages(List<ObjectError> errors){
        StringBuffer errorMsg = new StringBuffer();
        errors.forEach(error -> errorMsg.append(error.getDefaultMessage()).append(';'));
        return  errorMsg.toString();
    }
posted @ 2020-03-21 01:18  ChauncyL  阅读(209)  评论(0)    收藏  举报