微服务框架(十四)Spring Boot @ControllerAdvice异常处理

  此系列文章将会描述Java框架Spring Boot、服务治理框架Dubbo、应用容器引擎Docker,及使用Spring Boot集成Dubbo、Mybatis等开源框架,其中穿插着Spring Boot中日志切面等技术的实现,然后通过gitlab-CI以持续集成为Docker镜像。
  本文为Spring Boot使用@ControllerAdvice进行自定义异常捕捉及处理

本系列文章中所使用的框架版本为Spring Boot 2.0.3-RELEASE,Spring 5.0.7-RELEASE,Dubbo 2.6.2。

注解

@ControllerAdvice

控制器增强,所有在Controller中被抛出的异常将会被使用@ControllerAdvice注解的类捕捉。默认情况下, @ControllerAdvice全局应用于所有控制器的方法。

若所有异常处理类返回的数据格式为json,则可以使用 @RestControllerAdvice 代替 @ControllerAdvice
@RestControllerAdvice = @ControllerAdvice + @ResponseBody

@ExceptionHandler

异常处理器,在特定异常处理程序的类或方法中以处理异常的注解。

业务异常

常规的Controller层,会抛出业务异常、校检异常等

@RestController
@RequestMapping(value = "/")
public class TestController {

    @Autowired
    private BussinessService bussinessService ;

    @RequestMapping(value = "/basic", method = RequestMethod.POST)
    public Resp<RespVO> getBasic(@RequestBody @Valid ReqVO reqVO) {

		RespVO respVO = bussinessService.getResult(reqVO);
		if(respVO  == nullthrows BussinessExceptionMapper.build("调用失败");

        return Resp.createSuccess(respVO);
    }

}

业务异常定义

@Setter
@Getter
public class BussinessException extends RuntimeException {

    public static final String UNKNOWN_EXCEPTION = "unknown.exception";
    public static final String SERVICE_FAIL = "service.fail";
    public static final String NETWORK_EXCEPTION = "network.exception";
    public static final String TIMEOUT_EXCEPTION = "timeout.exception";

    private String code;

    public BussinessException() {
        super();
    }

    public BussinessException(String message, Throwable cause) {
        super(message, cause);
    }

    public BussinessException(String message) {
        super(message);
    }

    public BussinessException(Throwable cause) {
        super(cause);
    }

    public BussinessException(String code, String message, Throwable cause) {
        super(message, cause);
        this.code = code;
    }

    public BussinessException(String code, String message) {
        super(message);
        this.code = code;
    }
}

业务异常构造类

public class BussinessExceptionMapper {

    public static BussinessException build(String message) {
        return build(BussinessException.SERVICE_FAIL, message);
    }

    public static BussinessException build(String code, String message) {
        return new BussinessException(code, message);
    }

    public static BussinessException build(String message, Throwable cause) {
        return build(BussinessException.SERVICE_FAIL, message, cause);
    }

    public static BussinessException build(String code, String message, Throwable cause) {
        return new BussinessException(code, message, cause);
    }

}

异常处理

@Controller@RestController中的异常捕捉及处理

参数校检异常

使用hibernate validator校检参数,@Valid注解抛出的校检异常为MethodArgumentNotValidException,在@ExceptionHandler注释的方法中捕捉第一个错误信息

    @ResponseBody
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public Resp validHandler(MethodArgumentNotValidException ex) {

        logger.error("ValidException:", ex);

        List<ObjectError> list = ex
                .getBindingResult().getAllErrors();

        String errorMsg = StringUtils.defaultString(list.get(0).getDefaultMessage(), "参数错误");

        return Resp.createError(RespCode.PARAM_ERR, "input.param.error", errorMsg);
    }

业务异常

    @ResponseBody
    @ExceptionHandler(value = BussinessException.class)
    public Resp bussinessHandler(BussinessException ex) {

        logger.error("BussinessException:", ex);

        return Resp.createError(RespCode.BUSINESS_INVALID, ex.getCode(), ex.getMessage());
    }

Dubbo Rpc异常及运行时异常

@ControllerAdvice
public class GlobalControllerAdvice {

    private Logger logger = LoggerFactory.getLogger(GlobalControllerAdvice.class);

    @ResponseBody
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public Resp validHandler(MethodArgumentNotValidException ex) {

        logger.error("ValidException:", ex);

        List<ObjectError> list = ex
                .getBindingResult().getAllErrors();

        String errorMsg = StringUtils.defaultString(list.get(0).getDefaultMessage(), "参数错误");

        return Resp.createError(RespCode.PARAM_ERR, "input.param.error", errorMsg);
    }

    @ResponseBody
    @ExceptionHandler(value = BussinessException.class)
    public Resp bussinessHandler(BussinessException ex) {

        logger.error("BussinessException:", ex);

        return Resp.createError(RespCode.BUSINESS_INVALID, ex.getCode(), ex.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public Resp errorHandler(Exception e) {

        logger.error("uncaught Exception:", e);

        Resp resp;
        if (e instanceof RpcException) {
            resp = Resp.createError(RespCode.ERROR, "rpc.exception",
                    e.getMessage());
        } else if (e instanceof RuntimeException) {
            resp = Resp.createError(RespCode.ERROR, "runtime.exception",
                    "运行时异常,详见堆栈日志");
        } else {
            resp = Resp.createError(RespCode.BUSINESS_INVALID,
                    "service.fail", "服务失败");
        }

        return resp;
    }


}

参考资料:
1.ControllerAdvice
2.RestControllerAdvice

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值