全局异常处理,自定义业务异常

为什么需要全局异常处理器?

默认情况下,Spring Boot会显示Whitelabel Error Page,但你可以通过自定义错误页面、使用@ControllerAdvice、实现ErrorController或配置ErrorViewResolver等方式来替换默认的错误处理逻辑,以满足你的需求。

  • 统一处理异常:避免在每个控制器方法中重复编写异常处理逻辑。
  • 标准化响应格式:确保所有异常都返回统一的 JSON 格式,便于客户端处理。
  • 提升用户体验:隐藏具体的异常细节,只返回必要的错误信息,避免泄露敏感信息。

系统的Dao、Service、Controller出现都通过throws Exception向上抛出,最后由SpringMVC前端控制器交由异常处理器进行异常处理。

全局异常效果演示

假设你的应用中有一个控制器方法:

@GetMapping("/test")
public String test() {
    throw new IllegalArgumentException("这是一个非法参数异常");
}

当访问 /test 时,会抛出 IllegalArgumentException。这个异常会被 CommonGlobalExceptionHandler 捕获,并处理如下:

  1. 检查异常类型:
    • 因为 IllegalArgumentException 不是 ConditionException,所以进入 else 分支。
  1. 返回一个 JsonResponse 对象:
    • 错误代码为 "500"
    • 错误信息为 "这是一个非法参数异常"

最终返回的 JSON 数据可能是:

{
  "code": "500",
  "data": null,
  "msg": "这是一个非法参数异常"
}

隐藏具体的异常细节,只返回必要的错误信息,避免泄露敏感信息

自定义业务异常

自定义业务异常可以精准描述问题、控制业务流程、方便维护和提升用户体验。

自定义异常类ConditionException,继承RuntimeException。目的是在程序中抛出自定义的异常,同时携带一个错误代码code,方便后续的错误处理。

RuntimeException是Java中的一种未检查异常(unchecked exception)。未检查异常不需要在方法签名中显式声明(使用throws关键字),这使得使用起来更加灵活。

package org.example.model.exception;

public class ConditionException extends RuntimeException {

    private static final long serialVersionUID = 1L;

    private String code;

    public ConditionException(String code, String name) {
        super(name);
        this.code = code;
    }

    public ConditionException(String name) {
        super(name);
        code = "500";
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }
}

如何实现全局异常处理?

1. 创建类

org.example.service.handler 包中创建一个类,命名为 CommonGlobalExceptionHandler。这个类将用于处理全局异常。

package org.example.service.handler;

public class CommonGlobalExceptionHandler {
}

2. 在类上添加必要的注解

为了让 Spring 框架识别这个类是一个全局异常处理器,我们需要添加一些注解。

步骤 1:添加 @ControllerAdvice 注解

@ControllerAdvice 注解用于标记这个类是一个全局异常处理器。它会告诉 Spring,这个类中的方法可以处理来自所有控制器的异常。

@ControllerAdvice
public class CommonGlobalExceptionHandler {
}
步骤 2:添加 @Order 注解

@Order 注解用于指定这个异常处理器的优先级Ordered.HIGHEST_PRECEDENCE 表示这个处理器的优先级最高,确保它会优先处理异常。

@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CommonGlobalExceptionHandler {
}

3. 定义异常处理方法

接下来,我们需要定义一个方法来处理异常。这个方法会捕获所有异常,并返回一个统一的 JSON 响应。

步骤 1:添加方法

我们定义一个方法 commonExceptionHandler,它会处理所有异常。方法的参数包括:

  • HttpServletRequest request:表示当前的 HTTP 请求。
  • Exception e:表示捕获到的异常。

方法的返回类型是 JsonResponse<String>,这是一个自定义的类,用于封装 JSON 响应。

public JsonResponse<String> commonExceptionHandler(HttpServletRequest request, Exception e) {
}
步骤 2:添加注解

为了让 Spring 框架知道这个方法是用来处理异常的,我们需要添加两个注解:

  • @ExceptionHandler(value = Exception.class)指定这个方法可以处理所有类型的异常。
  • @ResponseBody:表示这个方法的返回值将被直接写入 HTTP 响应体中。
@ExceptionHandler(value = Exception.class)
@ResponseBody
public JsonResponse<String> commonExceptionHandler(HttpServletRequest request, Exception e) {
}

4. 实现异常处理逻辑

在方法中,我们需要根据异常类型来生成不同的响应

步骤 1:获取异常信息

首先,获取异常的错误信息。

String errorMsg = e.getMessage();
步骤 2:判断异常类型

我们自定义了一个异常类 ConditionException,它有一个 code 属性,用于表示错误代码。如果捕获到的异常是自定义业务异常 ConditionException,我们返回自定义的错误代码;否则,返回默认的错误代码 "500"

if (e instanceof ConditionException) {
    String errorCode = ((ConditionException) e).getCode();
    return new JsonResponse<>(errorCode, errorMsg);
} else {
    return new JsonResponse<>("500", errorMsg);
}

5. 完整代码

将上述步骤组合起来,完整的代码如下:

package org.example.service.handler;

import org.example.model.JsonResponse;
import org.example.model.exception.ConditionException;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;

@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CommonGlobalExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public JsonResponse<String> commonExceptionHandler(HttpServletRequest request, Exception e) {
        String errorMsg = e.getMessage();
        if (e instanceof ConditionException) {
            String errorCode = ((ConditionException) e).getCode();
            return new JsonResponse<>(errorCode, errorMsg);
        } else {
            return new JsonResponse<>("500", errorMsg);
        }
    }
}

6. 使用场景

当用户触发异常时,这个全局异常处理器会捕获异常,并返回一个统一的 JSON 响应,例如:

{
    "code": "500",
    "message": "Internal Server Error"
}

或者,如果捕获到的是 自定义业务异常ConditionException

{
    "code": "400",
    "message": "Invalid request"
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小编码上说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值