@ExceptionHandler與@Aspect對異常的全局處理

之前做過的項目都是從service一路拋到controller,然後定義一個controller層的統一異常處理類,最近做的項目卻是使用AOP進行全局的異常攔截處理,很好奇兩種方式有何不同,如果同時定義又會怎樣,經過驗證,
1、如果定義了AOP處理異常,正常請求後在controller層發生異常後@ExceptionHandler就捕獲不到了,因爲他是對於controller層拋出去的異常進行處理,而在切面處異常已經被處理,所以不會執行。
2、如果定義的請求方式是GET,用了POST方式進行請求時報的異常,由於此時未進入AOP,因此@ExceptionHandler會處理該異常而不是由AOP處理了

以下是代碼。
自定義異常

/**
 * 自定義異常
 */
@Getter
@Setter
public class MyException extends RuntimeException {
    private String code ;
    private String msg ;

    public MyException(String code, String msg) {
        super(msg);
        this.code = code;
        this.msg = msg;
    }
}

controller層

/**
 * controller demo
 */
@RestController
@Slf4j
public class DemoController {

    @GetMapping("demo")
    public BaseResponse demo(String str){
        log.info("str:{}",str);
        if (StringUtils.isEmpty(str)){
            throw new NullPointerException();
        }
        if ("123".equals(str)){
            throw new MyException(Constant.ResultCode.MY_EXCEPTION_CODE,Constant.ResultMsg.MY_EXCEPTION_MESSAGE);
        }
        return ResponseUtils.buildSuccess();
    }
}

controller層異常攔截

/**
 * 異常攔截接口
 */
public interface GlobalExceptionHandler<T extends Throwable> {

    @ExceptionHandler/*({MyException.class,NullPointerException.class})*/   //可以直接寫@ExceptionHandler,不指明異常類,會自動映射
    BaseResponse exceptionHandler(T t);   //還可以聲明接收其他任意參數
}
/**
 * 異常攔截實現,可以定義不同異常不同處理邏輯
 */
@ControllerAdvice
@ResponseBody
@Slf4j
public class GlobalExceptionHandlerImpl implements GlobalExceptionHandler {

    @ExceptionHandler
    public BaseResponse myExceptionHandler(MyException e){
        log.error("捕獲到MyException:{}",e.getMsg(),e);
        return ResponseUtils.buildFail(e.getCode(),e.getMsg());
    }

    @Override
    public BaseResponse exceptionHandler(Throwable t) {
        log.error("捕獲到異常:{}",t.getMessage(),t);
        return ResponseUtils.buildFail();
    }
}

返回值基類

/**
 * 返回基類
 */
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BaseResponse<T> {

    private String code;
    private String msg;
    private T data;
    private boolean success;
    private String traceId;

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("{");
        sb.append("\"code\":\"")
                .append(code).append('\"');
        sb.append(",\"msg\":\"")
                .append(msg).append('\"');
        sb.append(",\"data\":")
                .append(data);
        sb.append(",\"success\":")
                .append(success);
        sb.append(",\"traceId\":\"")
                .append(traceId).append('\"');
        sb.append("}");
        return sb.toString();
    }
}

返回值操作工具類

/**
 * 返回值操作工具
 */
public class ResponseUtils<T> {

    public static BaseResponse buildSuccess(){
        return buildSuccess(null);
    }

    public static BaseResponse buildSuccess(Object data){
        return BaseResponse.builder()
                .code(Constant.ResultCode.SUCCESS_CODE)
                .msg(Constant.ResultMsg.SUCCESS_MESSAGE)
                .success(true)
                .data(data)
                .build();
    }

    public static BaseResponse buildFail(){
        return buildFail(Constant.ResultCode.ERROR_CODE,Constant.ResultMsg.ERROR_MESSAGE);
    }

    public static BaseResponse buildFail(String code,String msg){
        return buildResult(code, msg, null);
    }

    public static BaseResponse buildResult(String code,String msg,Object data){
        return BaseResponse.builder()
                .code(StringUtils.isEmpty(code) ? Constant.ResultCode.SUCCESS_CODE : code)
                .msg(StringUtils.isEmpty(msg) ? (Constant.ResultCode.SUCCESS_CODE.equals(code) ? Constant.ResultMsg.SUCCESS_MESSAGE : Constant.ResultMsg.ERROR_MESSAGE) : msg)
                .success(Constant.ResultCode.SUCCESS_CODE.equals(code))
                .data(data)
                .build();
    }
}

常數類

/**
 * 常數類
 */
public class Constant {

    public final class ResultCode{
        public static final String SUCCESS_CODE = "0000";
        public static final String ERROR_CODE = "1001";
        public static final String MY_EXCEPTION_CODE = "1002";

    }
    public final class ResultMsg{
        public static final String SUCCESS_MESSAGE = "請求成功";
        public static final String ERROR_MESSAGE = "未知錯誤";
        public static final String MY_EXCEPTION_MESSAGE = "請求出錯";
    }
}

AOP切面

/**
 * AOP
 */
@Aspect
@Slf4j
@Component
public class AopAspect {

    @Pointcut("execution(* com.star.dream.project.controller..*(..))")
    private void traceLogAspect() {
    }

    @Around("traceLogAspect()")
    public Object around(ProceedingJoinPoint joinPoint) {
        String interfaceName = String.format("%s.%s", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
        Object result;
        try {
            result = joinPoint.proceed();
        } catch (Throwable ex) {
            if (ex instanceof MyException) {
                MyException e = (MyException) ex;
                result = ResponseUtils.buildFail(e.getCode(),e.getMsg());
                log.error(String.format("調用接口%s異常,錯誤信息:%s", interfaceName, e.getMsg()), e);
            } else {
                result = ResponseUtils.buildFail();
                log.error(String.format("調用接口%s異常,錯誤信息:%s", interfaceName, ex.toString()), ex);
            }
        }
        return result;
    }
}

使用到的全部依賴

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>${commons-lang.version}</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${org.aspectj.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>${org.aspectj.version}</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>${cglib.version}</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>
    </dependencies>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章