Spring boot 异常处理机制

 

 

 

 

 

 

 

 

 

 

 

 1.定义枚举

 

 2.自定义异常类

package com.cn86trading.trading.exception;

/**
 * Created with IntelliJ IDEA.
 *
 * @author : 小黑
 * @version : 1.0
 * @Project : CN86
 * @Package : com.cn86trading.trading.exception
 * @ClassName : CustomException .java
 * @createTime : 2022/11/2 17:13
 * @公众号 : 小黑侠
 * @Description :
 */
public class CustomException extends RuntimeException {
    //异常错误编码
    private int code ;
    //异常信息
    private String message;

    public CustomException() {
    }

    public CustomException(CustomExceptionType customExceptionType) {
        this.code = customExceptionType.getCode();
        this.message = customExceptionType.getDesc();
    }

    public CustomException(CustomExceptionType customExceptionType, String message) {
        this.code = customExceptionType.getCode();
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

 3.返回类json  统一封装AjaxResponse

package com.cn86trading.trading.model;

import com.cn86trading.trading.exception.CustomException;
import com.cn86trading.trading.exception.CustomExceptionType;
import lombok.Data;

/**
 * Created with IntelliJ IDEA.
 *
 * @author : 小黑
 * @version : 1.0
 * @Project : CN86
 * @Package : com.cn86trading.trading.model
 * @ClassName : AjaxResponse.java
 * @createTime : 2022/10/31 17:58
 * @公众号 : 小黑侠
 * @Description :
 */
/**
 * 接口数据请求统一响应数据结构
 */
@Data
public class AjaxResponse {
    private boolean isok;  //请求是否处理成功
    private int code; //请求响应状态码
    private String message;  //请求结果描述信息
    private Object data; //请求结果数据(通常用于查询操作)

    private AjaxResponse(){}

    //请求出现异常时的响应数据封装
    public static AjaxResponse error(CustomException e) {
        AjaxResponse resultBean = new AjaxResponse();
        resultBean.setIsok(false);
        resultBean.setCode(e.getCode());
        resultBean.setMessage(e.getMessage());
        return resultBean;
    }

    //请求出现异常时的响应数据封装
    public static AjaxResponse error(CustomExceptionType customExceptionType,
                                     String errorMessage) {
        AjaxResponse resultBean = new AjaxResponse();
        resultBean.setIsok(false);
        resultBean.setCode(customExceptionType.getCode());
        resultBean.setMessage(errorMessage);
        return resultBean;
    }

    //请求成功的响应,不带查询数据(用于删除、修改、新增接口)
    public static AjaxResponse success(){
        AjaxResponse ajaxResponse = new AjaxResponse();
        ajaxResponse.setIsok(true);
        ajaxResponse.setCode(200);
        ajaxResponse.setMessage("请求响应成功!");
        return ajaxResponse;
    }

    //请求成功的响应,带有查询数据(用于数据查询接口)
    public static AjaxResponse success(Object obj){
        AjaxResponse ajaxResponse = new AjaxResponse();
        ajaxResponse.setIsok(true);
        ajaxResponse.setCode(200);
        ajaxResponse.setMessage("请求响应成功!");
        ajaxResponse.setData(obj);
        return ajaxResponse;
    }

    //请求成功的响应,带有查询数据(用于数据查询接口)
    public static AjaxResponse success(Object obj,String message){
        AjaxResponse ajaxResponse = new AjaxResponse();
        ajaxResponse.setIsok(true);
        ajaxResponse.setCode(200);
        ajaxResponse.setMessage(message);
        ajaxResponse.setData(obj);
        return ajaxResponse;
    }

}

 

 

 

 

  测试 :

  总异常异常类统一拦截器

package com.cn86trading.trading.exception;

import com.cn86trading.trading.model.AjaxResponse;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * Created with IntelliJ IDEA.
 *
 * @author : 小黑
 * @version : 1.0
 * @Project : CN86
 * @Package : com.cn86trading.trading.exception
 * @ClassName : WebExceptionHandler .java
 * @createTime : 2022/11/2 20:23
 * @公众号 : 小黑侠
 * @Description :
 */
//所有Controller异常处理
@ControllerAdvice
public class WebExceptionHandler {

    //处理程序员主动转换的自定义异常
    @ExceptionHandler(CustomException.class)
    @ResponseBody
    public AjaxResponse customerException(CustomException e) {
        if(e.getCode() == CustomExceptionType.SYSTEM_ERROR.getCode()){
            //400异常不需要持久化,将异常信息以友好的方式告知用户就可以
            //TODO 将500异常信息持久化处理,方便运维人员处理
        }
        return AjaxResponse.error(e);
    }

    //处理程序员在程序中未能捕获(遗漏的)异常
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public AjaxResponse exception(Exception e) {
        //TODO 将异常信息持久化处理,方便运维人员处理

        return AjaxResponse.error(new CustomException(
                CustomExceptionType.OTHER_ERROR));
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public AjaxResponse handleBindException(MethodArgumentNotValidException ex) {
        FieldError fieldError = ex.getBindingResult().getFieldError();
        return AjaxResponse.error(new CustomException(CustomExceptionType.USER_INPUT_ERROR,
                fieldError.getDefaultMessage()));
    }

    @ExceptionHandler(BindException.class)
    @ResponseBody
    public AjaxResponse handleBindException(BindException ex) {
        FieldError fieldError = ex.getBindingResult().getFieldError();
        return AjaxResponse.error(new CustomException(CustomExceptionType.USER_INPUT_ERROR,
                fieldError.getDefaultMessage()));
    }

    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseBody
    public AjaxResponse handleIllegalArgumentException(IllegalArgumentException e) {
        return AjaxResponse.error(
                new CustomException(CustomExceptionType.USER_INPUT_ERROR,
                        e.getMessage())
        );
    }
}

 

 

 

 

 

 support表示支持哪些响应类,true代表所有。只 响应APPLICATION_JSON。如果是其它类型,需要再做判断

使用@Component 和 @ControllerAdvice使类生效 

package com.cn86trading.trading.exception;

import com.cn86trading.trading.model.AjaxResponse;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * Created with IntelliJ IDEA.
 *
 * @author : 小黑
 * @version : 1.0
 * @Project : CN86
 * @Package : com.cn86trading.trading.exception
 * @ClassName : GlobalResponseAdvice .java
 * @createTime : 2022/11/2 18:00
 * @公众号 : 小黑侠
 * @Description :
 */
@Component
//监听所有Controller异常
@ControllerAdvice
//实现ResponseBodyAdvice 接口的作用是:在将数据返回给用户之前,做最后一步的处理。
// 也就是说,ResponseBodyAdvice 的处理过程在全局异常处理的后面。
public class GlobalResponseAdvice implements ResponseBodyAdvice {

    //support表示支持哪些响应类,true代表所有。
    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body,
                                  MethodParameter methodParameter,
                                  MediaType mediaType,
                                  Class aClass,
                                  ServerHttpRequest serverHttpRequest,
                                  ServerHttpResponse serverHttpResponse) {
        //如果响应结果是JSON数据类型
        if(mediaType.equalsTypeAndSubtype(
                MediaType.APPLICATION_JSON)){
            if(body instanceof AjaxResponse){
                AjaxResponse ajaxResponse = (AjaxResponse)body;
                if(ajaxResponse.getCode() != 888){ //888 不是标准的HTTP状态码,特殊处理
                    serverHttpResponse.setStatusCode(HttpStatus.valueOf(
                            ajaxResponse.getCode()
                    ));
                }

                return body;
            }else{
                serverHttpResponse.setStatusCode(HttpStatus.OK);
                return AjaxResponse.success(body);
            }

        }


        return body;
    }
}

 

服务端参数校验及异常处理

第1种,使用注解进行参数校验

在实体类中使用@NotEmpty(message="文章内容不能为空")设置属性字段

@Valid 需要校验的参数前面加上该注解

  异常此类抛出,然后在自定义异常中添加此异常的拦截捕获并返回。

 

 @Valid会抛出2个异常,都需要捕获。MethodArgumentNotValidException和BindException

 

 jsr303

 

 

 

 

 

 

 

第2种参数校验:利用断言的方式进行参数校验

org.springframework.util.Assert

 

 

 

 

 

 

 

 

org.springframework.util.Assert类提供很多数据校验。可以了解下

 

 

 

三、利用AOP完美处理页面跳转异常

 

 如果不是返回json,比如是jsp,freemarker,thymeleaf等页面时如何跳转。

 

 

 

 自定义AOP

 

 最终实例:

 

 第1步:定义注解

 第2步:引入包

 

 

 第3步:定义AOP切面(切入点)

 

 

 第4步:定义异常类,将所有的Exception/Throwable异常类转化为RuntimeException 的ModelViewException

 

 

第5步:拦截并抛出异常之后,进行全局异常类处理。返回的是Spring 的ModelAndView  跳转到error页面setViewName

 

 

 

 第6步:跳转到error文件,从freemarker目录中查找error.ftl文件

 

 

 

 

 

 

 

posted on 2022-10-18 10:18  王飞侠  阅读(231)  评论(0编辑  收藏  举报

导航