Spring全局异常

前言

最近做一个spring微服务,当请求进入接口后,一旦发生错误,服务就会抛出异常,但是这个异常不是我们封装的,有时候跑出的信息我们想统一处理。
例:如果是客户请求数据错误应该报出400的HttpStatus.BAD_REQUEST。但是由于这个错误是我们内部抛出的他还是会自动抛500,而且服务有很多接口,我们管理也不方便。所以需要一个全局的异常处理。
 

1. 全局异常设置

我们这里设置两种异常,一种是客户请求的问题我们将他全都归为ClientRequestException 异常,我们服务内部的异常我们全都将它归为服务自身异常MyServiceRuntimeException。 

1.1. 自定义客户请求异常

如请求数据错误。

import lombok.Data;

@Data
public class ClientRequestException extends RuntimeException {
    private ErrorCode errorCode;

    public ClientRequestException(ErrorCode errorCode, String appendMsg){
        super(errorCode.getMsg()+" : "+appendMsg);
        this.errorCode = errorCode;
    }

}
1.2. 定义服务端内部异常

如JDBC链接超时。

import lombok.Data;

@Data
public class MyServiceRuntimeException extends RuntimeException {
    private ErrorCode errorCode;

    public MyServiceRuntimeException(ErrorCode errorCode, String appendMsg){
        super(errorCode.getMsg()+" : "+appendMsg);
        this.errorCode = errorCode;
    }

}
1.3. 定义error code  

定义自定义的统一管理的细致的error code。

public enum ErrorCode {
    SYSTEM_ERROR("500-001","System error"),
    SYSTEM_JDBC_CONNECTION_ERROR("500-002","System JDBC connection error"),
    CLIENT_REQUEST_DATA_ERROR("400-001","request Data error");
    private String code;
    private String msg;

    ErrorCode(String code,String msg){
        this.code = code;
        this.msg = msg;
    }

    public String getCode(){
        return code;
    }

    public String getMsg(){
        return msg;
    }
}
1.5.定义全局异常处理类

如下需要用到 @RestControllerAdvice 和 @ExceptionHandler注解分别标注,和写明不同异常的处理方法和报错的归类,

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(MyServiceRuntimeException.class)
    public ResponseEntity<ResponseException> myServiceRuntimeException(MyServiceRuntimeException ex){
        ErrorCode errorCode = ex.getErrorCode();
        ResponseException responseException = new ResponseException(errorCode.getCode(),ex.getMessage());
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(responseException);
    }

    @ExceptionHandler(ClientRequestException.class)
    public ResponseEntity<ResponseException> myClientRuntimeException(ClientRequestException ex){
        ErrorCode errorCode = ex.getErrorCode();
        ResponseException responseException = new ResponseException(errorCode.getCode(),ex.getMessage());
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(responseException);
    }
}
1.6. 自定义注解和AOP

定义AOP用于注解哪些类需要相同的异常处理。 这里仅定义给可能发生JDBC链接异常的所有API使用。客户端数据异常不使用注解(因为只有一接口会有数据检查,没必要做一个切面给他)

package com.acom.springdemo.exception.aop;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CommonExceptionHandler {
}

//第二个class
import com.acom.springdemo.exception.ErrorCode;
import com.acom.springdemo.exception.MyServiceRuntimeException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.transaction.CannotCreateTransactionException;
@Aspect
@Component
public class CommonExceptionHandlerAspect {
    @Around("@annotation(com.acom.springdemo.exception.aop.CommonExceptionHandler)")
    public Object commonExceptionHandle(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object object;
        try{
           object = proceedingJoinPoint.proceed();
        }catch (CannotCreateTransactionException ex){
            throw new MyServiceRuntimeException(ErrorCode.SYSTEM_JDBC_CONNECTION_ERROR,ex.getCause().getMessage());
        }
        return object;
    }
}

2.使用全局异常

2.1. 服务自身异常使用 

如上由于我们对JDBC异常(commonExceptionHandle)新建了注解,所以我们只需要将这个注解加在我们想监控的类上就可以了。

当服务内部出现JDBC链接异常就会有如下异常流程

  • 发生JDBC链接异常Spring框架内部抛出CannotCreateTransactionException
  • 进入自定义注解@CommonExceptionHandler内部代码
  • 注解内部代码捕获后在抛出自定义MyServiceRuntimeException异常
  • MyServiceRuntimeException异常被全局异常统一处理后抛出

2.2. 客户请求数据异常

 假如id==333L就表示数据不对。

服务抛出400异常

该异常流程:

  • 自我的服务发现数据不符合规定,抛出自定 ClientRequestException异常
  • ClientRequestException异常被全局异常捕获,并相应400和自定义的异常信息
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值