当前位置: 代码迷 >> 综合 >> SpringBoot —— 统一异常处理
  详细解决方案

SpringBoot —— 统一异常处理

热度:105   发布时间:2023-09-18 12:46:35

前言

在 Controller 里提供接口,通常需要捕捉异常,进行异常处理。最简单的方法使用try/catch进行异常捕捉。

当方法很多,每个都需要 try catch,代码会显得臃肿,写起来也比较麻烦。
这时就需要进行统一的异常处理。

1.使用方法

通过 Spring 的 AOP 特性就可以很方便的实现异常的统一处理:使用@ControllerAdvice、@RestControllerAdvice捕获运行时异常。

代码结构
SpringBoot —— 统一异常处理
新建异常枚举类

package com.local.dev.root.devroot.common.enums;/*** 异常枚举类*/
public enum ExceptionEnum {
    // 400BAD_REQUEST("400", "请求数据格式不正确!"),UNAUTHORIZED("401", "登录凭证过期!"),FORBIDDEN("403", "没有访问权限!"),NOT_FOUND("404", "请求的资源找不到!"),// 500INTERNAL_SERVER_ERROR("500", "服务器内部错误!"),SERVICE_UNAVAILABLE("503", "服务器正忙,请稍后再试!"),// 未知异常UNKNOWN("10000", "未知异常!"),// 自定义IS_NOT_NULL("10001","%s不能为空");/*** 错误码*/private String code;/*** 错误描述*/private String msg;ExceptionEnum(String code, String msg) {
    this.code = code;this.msg = msg;}public String getCode() {
    return code;}public String getMsg() {
    return msg;}
}

自定义异常类

package com.local.dev.root.devroot.common.exception;import com.local.dev.root.devroot.common.enums.ExceptionEnum;/*** 自定义业务异常类*/
public class BusinessException extends RuntimeException {
    private ExceptionEnum exceptionEnum;private String code;private String errorMsg;public BusinessException() {
    super();}public BusinessException(ExceptionEnum exceptionEnum) {
    super("{code:" + exceptionEnum.getCode() + ",errorMsg:" + exceptionEnum.getMsg() + "}");this.exceptionEnum = exceptionEnum;this.code = exceptionEnum.getCode();this.errorMsg = exceptionEnum.getMsg();}public BusinessException(String code, String errorMsg) {
    super("{code:" + code + ",errorMsg:" + errorMsg + "}");this.code = code;this.errorMsg = errorMsg;}public BusinessException(String code, String errorMsg, Object... args) {
    super("{code:" + code + ",errorMsg:" + String.format(errorMsg, args) + "}");this.code = code;this.errorMsg = String.format(errorMsg, args);}public ExceptionEnum getExceptionEnum() {
    return exceptionEnum;}public String getErrorMsg() {
    return errorMsg;}public void setErrorMsg(String errorMsg) {
    this.errorMsg = errorMsg;}public String getCode() {
    return code;}public void setCode(String code) {
    this.code = code;}
}

ExceptionHandlerConfig.java
@RestControllerAdvice,统一异常处理

package com.local.dev.root.devroot.common.config.exception;import com.local.dev.root.devroot.common.enums.ExceptionEnum;
import com.local.dev.root.devroot.common.exception.BusinessException;
import com.local.dev.root.devroot.common.exception.ErrorPageException;
import com.local.dev.root.devroot.common.pojo.ApiResponse;
import com.local.dev.root.devroot.common.util.ErrorUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;/*** RestControllerAdvice,统一异常处理*/
@Slf4j
@RestControllerAdvice
public class ExceptionHandlerConfig {
    /*** 业务异常处理** @param e 业务异常* @return*/@ExceptionHandler(value = BusinessException.class)@ResponseBodypublic ApiResponse exceptionHandler(BusinessException e) {
    log.error(ErrorUtil.errorInfoToString(e));return ApiResponse.error(e.getCode(), e.getErrorMsg());}/*** 未知异常处理*/@ExceptionHandler(value = Exception.class)@ResponseBodypublic ApiResponse exceptionHandler(Exception e) {
    // 把错误信息输入到日志中log.error(ErrorUtil.errorInfoToString(e));return ApiResponse.error(ExceptionEnum.UNKNOWN.getCode(),ExceptionEnum.UNKNOWN.getMsg());}/*** 错误页面异常*/@ExceptionHandler(value = ErrorPageException.class)@ResponseBodypublic ApiResponse exceptionHandler(ErrorPageException e) {
    log.error(ErrorUtil.errorInfoToString(e));return ApiResponse.error(e.getCode(), e.getErrorMsg());}/*** 空指针异常*/@ExceptionHandler(value = NullPointerException.class)@ResponseBodypublic ApiResponse exceptionHandler(NullPointerException e) {
    log.error(ErrorUtil.errorInfoToString(e));return ApiResponse.error(ExceptionEnum.INTERNAL_SERVER_ERROR.getCode(),ExceptionEnum.INTERNAL_SERVER_ERROR.getMsg());}
}

测试类

package com.local.dev.root.devroot.controller;import com.local.dev.root.devroot.common.pojo.ApiResponse;
import com.local.dev.root.devroot.service.dev.TestServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/hello")
public class HelloWorld {
    @Autowiredprivate TestServiceImpl testServiceImpl;@RequestMapping("world")public String HelloWorld() {
    return "Hello World!";}@RequestMapping("error1")public ApiResponse Error1() {
    return ApiResponse.ok();}@RequestMapping("error2")public ApiResponse Error2() {
    String msg = null;msg.equals("xx");return ApiResponse.ok("访问成功");}@RequestMapping("error3")public ApiResponse Error3() {
    testServiceImpl.getBusinessException();return ApiResponse.ok("访问成功");}
}

testServiceImpl 抛出自定义异常

package com.local.dev.root.devroot.service.dev;import com.local.dev.root.devroot.common.enums.ExceptionEnum;
import com.local.dev.root.devroot.common.exception.BusinessException;
import org.springframework.stereotype.Service;@Service
public class TestServiceImpl {
    public Object getBusinessException() {
    throw new BusinessException(ExceptionEnum.IS_NOT_NULL.getCode(),ExceptionEnum.IS_NOT_NULL.getMsg(), "参数");}
}

2.测试

正常
http://localhost:8080/hello/error1
SpringBoot —— 统一异常处理
空指针异常
http://localhost:8080/hello/error2
SpringBoot —— 统一异常处理
业务异常
http://localhost:8080/hello/error3
SpringBoot —— 统一异常处理

3.查看日志

SpringBoot —— 统一异常处理
打开error日志
SpringBoot —— 统一异常处理

? 上一章:SpringBoot —— 多线程定时任务的实现(注解配置、task:annotation-driven配置)
? 下一章:SpringBoot —— 简单整合Redis实例及StringRedisTemplate与RedisTemplate对比和选择