spring boot @Valid 与 @Validated 使用 及 统一异常处理

该博客详细介绍了Spring Boot中@Valid和@Validated的使用,包括实体类添加验证规则、Controller层的注解应用。同时,讲解了如何实现分组校验,通过定义不同的校验分组并指定校验规则。最后,讨论了@ControllerAdvice进行统一异常处理,强调了异常类的设计以及如何封装错误信息以达到统一响应格式的目的。

spring boot @Valid 与 @Validated 使用 及 统一异常处理

1.@Valid使用
1.实体类添加验证规则

有多种校验规则

@Data
public class PaperDTO {
    /**
     * 试卷id
     */
    @NotNull(message = "必填字段不能为空")
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    private Long id;
    /**
     * 试卷名
     */
    @NotNull(message = "必填字段不能为空")
    private String name;
    /**
     * 试卷类型
     */
    @NotNull(message = "必填字段不能为空")
    private Long paperType;
    /**
     * 试卷难度
     */
    @NotNull(message = "必填字段不能为空")
    private Long difficuty;
    /**
     * 总分
     */
    @NotNull(message = "必填字段不能为空")
    private BigDecimal score;
    //若需要嵌套校验则在需要校验的结构体上添加@Valid
    @Valid
    private List<User> users
}
2.在Controller层方法添加校验注解
@PostMapping("/addPaper")
public PaperDTO doAddPaper(@RequestBody @Valid PaperDTO paperDTO) {
    //处理传入数据
    return paperDTO;
}
2.@Validated 分组校验使用
1.添加分组的接口

IdGroup.class

public interface IdGroup {
}

AddGroup.class

public interface AddGroup {
}

UpdateGroup.class

public interface UpdateGroup {
}
2.需要校验结构体添加校验规则
@Data
public class PaperDTO {
    /**
     * 试卷id
     */
    @NotNull(groups = {IdGroup.class,UpdateGroup.class}, message = "必填字段不能为空")
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    private Long id;
    /**
     * 试卷名
     */
    @NotNull(groups = {AddGroup.class,UpdateGroup.class}, message = "必填字段不能为空")
    private String name;
    /**
     * 试卷类型
     */
    @NotNull(groups = {AddGroup.class,UpdateGroup.class}, message = "必填字段不能为空")
    private Long paperType;
    /**
     * 试卷难度
     */
    @NotNull(groups = {AddGroup.class,UpdateGroup.class}, message = "必填字段不能为空")
    private Long difficuty;
    /**
     * 总分
     */
    @NotNull(groups = {AddGroup.class,UpdateGroup.class}, message = "必填字段不能为空")
    private BigDecimal score;
}
3.Controller层添加校验注解

这时,只会校验对应分组的校验规则

如果需要嵌套校验,同添加@Valid注解即可

//发布指定试卷
@PostMapping("publishPaper")
public Boolean doPublishPaper(@RequestBody @Validated(IdGroup.class) PaperDTO request) {
    //处理传入试卷id
    return response;
}
//添加试卷
@PostMapping("addPaper")
public Boolean doPublishPaper(@RequestBody @Validated(AddGroup.class) PaperDTO request) {
    //处理传入试卷
    return response;
}
//修改试卷
@PostMapping("updatePaper")
public Boolean doPublishPaper(@RequestBody @Validated(UpdateGroup.class) PaperDTO request) {
    //处理传入试卷
    return response;
}
3.@ControllerAdvice统一异常处理

这个统一异常处理定义的响应,需要CommonResponse 结构体,没有也无所谓,将错误信息按自己想要的结构体封装好返回也一样

统一异常类,最好继承RuntimeException,这样不用强制调用产生统一异常的方法每个都处理统一异常

public class PaperServiceException extends RuntimeException {
    /**
     * 异常码
     * */
    private final String code;
    /**
     * 异常发生时请求url
     * */
    private final String url;
    /**
     * 异常信息
     * */
    private final String message;
    public PaperServiceException(){
        this.code = "230000";
        this.message = "无信息异常";
        this.url = "";
    }

    public PaperServiceException(String code,String message){
        this.code = code;
        this.message = message;
        this.url = "";
    }

    public PaperServiceException(String code,String url,String message){
        this.code = code;
        this.message = message;
        this.url = url;
    }
    public String getUrl() {
        return url;
    }

    public String getCode() {
        return code;
    }


    @Override
    public String getMessage() {
        return message;
    }

    @Override
    public String toString() {
        return "PaperServiceException{" +
                "错误码(code)=" + code +
                ", 请求地址(url)='" + url + '\'' +
                ", 详细信息(message)='" + message + '\'' +
                '}';
    }
}

统一异常类型类

public class PaperServiceExceptionType {
    public static final String PUBLISH_ERROR = "230401";
    /**
     * 字段校验错误
     * */
    public static final String VALID_ERROR = "230001";
    /**
     * 数据初始化错误
     * */
    //........自定义各种错误类型码
    private PaperServiceExceptionType(){

    }
}

使用ControllerAdvice统一异常处理

//合并了@ControllerAdvice与@RestController
@Slf4j
@RestControllerAdvice
public class ExceptionController {
    /**
     *  校验错误拦截处理
     *
     * @param exception 错误信息集合
     * @return 错误信息
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public CommonResponse<String> validationBodyException(MethodArgumentNotValidException exception){
    	//对校验错误信息进行封装,并输出到日志
        BindingResult result = exception.getBindingResult();
        StringBuilder errorMessage = new StringBuilder();
        if (result.hasErrors()) {

            List<ObjectError> errors = result.getAllErrors();
            errors.forEach(p ->{

                FieldError fieldError = (FieldError) p;
                log.error(PaperServiceExceptionType.VALID_ERROR+":数据校验错误 : object{"+fieldError.getObjectName()+"},field{"+fieldError.getField()+
                        "},errorMessage{"+fieldError.getDefaultMessage()+"}");
                errorMessage.append(fieldError.getDefaultMessage());
            });

        }
        //封装错误到响应信息
        CommonResponse<String> response = new CommonResponse<>();
        ResHeader header = new ResHeader();
        response.setHeader(header);
        header.setErrorCode(PaperServiceExceptionType.VALID_ERROR);
        header.setMessage(errorMessage.toString());
        response.setBody(PaperServiceExceptionType.VALID_ERROR+":传入数据错误"+errorMessage.toString());
        return response;
    }
    /**
     * 请求方式不支持
     */
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public CommonResponse<String> handleException(HttpRequestMethodNotSupportedException e) {
        log.error(e.getMessage(), e);
        CommonResponse<String> response = new CommonResponse<>();
        ResHeader header = new ResHeader();
        response.setHeader(header);
        header.setErrorCode(PaperServiceExceptionType.VALID_ERROR);
        header.setMessage("不支持' " + e.getMethod() + "'请求");
        response.setBody(PaperServiceExceptionType.VALID_ERROR+":传入请求错误不支持" + e.getMethod() + "'请求");
        return response;
    }
    //请求的数据格式错误的处理
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public CommonResponse<String> handleException(HttpMessageNotReadableException e) {
        log.error(e.getMessage(), e);
        CommonResponse<String> response = new CommonResponse<>();
        ResHeader header = new ResHeader();
        response.setHeader(header);
        header.setErrorCode(PaperServiceExceptionType.VALID_ERROR);
        header.setMessage("传入数据格式错误");
        response.setBody(PaperServiceExceptionType.VALID_ERROR+":传入数据格式错误");
        return response;
    }
    @ExceptionHandler(PaperServiceException.class)
    public CommonResponse<String> handleMyException(HttpServletRequest request, PaperServiceException exception){
        CommonResponse<String> response = new CommonResponse<>();
        ResHeader header = new ResHeader();
        /**
         * 获取异常发生时请求的url
         * */
        PaperServiceException exceptionVO = new PaperServiceException(exception.getCode()
                ,String.valueOf(request.getRequestURL()),exception.getMessage());
        /**
         * 日志保存异常的信息
         * */
        log.error("服务出错:",exception.toString());
        /**
         * 设置返回的响应的头部异常码以及信息
         * */
        header.setErrorCode(String.valueOf(exception.getCode()));
        header.setMessage(exception.getMessage());
        response.setHeader(header);
        response.setBody(exceptionVO.getCode()+":"+exceptionVO.getMessage());
        return response;
    }
    //其他异常处理
    @ExceptionHandler(Exception.class)
    public CommonResponse<String> handleMyException(HttpServletRequest request, Exception exception){
        CommonResponse<String> response = new CommonResponse<>();
        ResHeader header = new ResHeader();
        /**
         * 获取异常发生时请求的url
         * */
       String url = String.valueOf(request.getRequestURL());
        /**
         * 日志保存异常的信息
         * */
        log.error("服务出错:",exception.toString());
        /**
         * 设置返回的响应的头部异常码以及信息
         * */
        header.setErrorCode(PaperServiceExceptionType.SYSTEM_ERROR);
        header.setMessage("服务器处理数据时发生异常"+url+exception.toString());
        exception.printStackTrace();
        response.setHeader(header);
        response.setBody(PaperServiceExceptionType.SYSTEM_ERROR+":"+"服务器处理数据发生异常");
        return response;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值