【SpringBoot】全局异常处理类

全局异常处理是Spring Boot项目中非常重要的一部分,它可以帮助我们统一处理各种异常,返回友好的错误信息,提升系统的健壮性和用户体验。以下是详细的全局异常处理代码实现。

全局异常处理类


创建一个全局异常处理类`GlobalExceptionHandler`,使用`@RestControllerAdvice`注解标记该类,并通过`@ExceptionHandler`注解捕获特定异常。

GlobalExceptionHandler.java

package com.example.morningboxspring.exception;

import com.example.morningboxspring.common.Result;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.http.HttpServletRequest;
/**
 * 功能:GlobalExceptionHandler
 * 作者:爱因斯坦乐
 * 日期:2025/3/1
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

 // 处理请求体缺失或格式错误异常
@ExceptionHandler(HttpMessageNotReadableException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Result<String> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpServletRequest request) {
 return Result.error(HttpStatus.BAD_REQUEST.value(), "请求体缺失或格式错误: " + ex.getMessage());
 }

// 处理参数类型不匹配异常
 @ExceptionHandler(MethodArgumentTypeMismatchException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Result<String> handleMethodArgumentTypeMismatch(MethodArgumentTypeMismatchException ex, HttpServletRequest request) {
 return Result.error(HttpStatus.BAD_REQUEST.value(), "参数类型不匹配: " + ex.getMessage());
}

 // 处理空指针异常
 @ExceptionHandler(NullPointerException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Result<String> handleNullPointerException(NullPointerException ex, HttpServletRequest request) {
 return Result.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "空指针异常: " + ex.getMessage());
 }

// 处理其他未捕获的异常
 @ExceptionHandler(Exception.class)
 @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Result<String> handleException(Exception ex, HttpServletRequest request) {
return Result.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "服务器内部错误: " + ex.getMessage());
}
}

统一返回结果类


为了统一返回格式,我们可以定义一个通用的返回结果类`Result`。

Result.java

package com.example.morningboxspring.common;

/**
 * 功能:Result
 * 作者:爱因斯坦乐
 * 日期:2025/3/1
 */
public class Result<T> {
    private int code; // 状态码
    private String message; // 返回信息
    private T data; // 返回数据

    // 成功返回
    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<>();
        result.setCode(200);
        result.setMessage("成功");
        result.setData(data);
        return result;
    }

    // 错误返回
    public static <T> Result<T> error(int code, String message) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setMessage(message);
        return result;
    }

    // Getter 和 Setter
    public int getCode() {
        return code;
    }

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

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

测试全局异常处理

 测试请求体缺失异常


发送一个`POST`请求,但不提供请求体:


POST http://localhost:8080/user

**响应**:
```json
{
  "code": 400,
  "message": "请求体缺失或格式错误: Required request body is missing",
  "data": null
}
```

 测试参数类型不匹配异常


发送一个`GET`请求,路径变量类型错误:

GET http://localhost:8080/user/{1}

**响应**:
```json
{
  "code": 400,
  "message": "参数类型不匹配: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Long'; nested exception is java.lang.NumberFormatException: For input string: \"{1}\"",
  "data": null
}
```

测试空指针异常


在代码中模拟一个空指针异常:
```java
@GetMapping("/test-npe")
public Result<String> testNullPointerException() {
    String str = null;
    return Result.success(str.toLowerCase()); // 触发空指针异常
}
```

发送请求:

GET http://localhost:8080/user/test-npe

**响应**:
```json
{
  "code": 500,
  "message": "空指针异常: null",
  "data": null
}
```

测试其他未捕获的异常


在代码中模拟一个未捕获的异常:
```java
@GetMapping("/test-exception")
public Result<String> testException() {
    throw new RuntimeException("测试异常");
}
```

发送请求:

GET http://localhost:8080/user/test-exception

**响应**:
```json
{
  "code": 500,
  "message": "服务器内部错误: 测试异常",
  "data": null
}
```

扩展异常处理


您可以根据项目需求扩展更多的异常处理逻辑。例如:
- **自定义业务异常**:定义自己的业务异常类,并在全局异常处理中捕获。
- **验证异常**:捕获`MethodArgumentNotValidException`,处理参数校验失败的情况。

自定义业务异常

package com.morningbox.exception;

public class BusinessException extends RuntimeException {
    private final int code;

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

    public int getCode() {
        return code;
    }
}

捕获自定义业务异常

@ExceptionHandler(BusinessException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Result<String> handleBusinessException(BusinessException ex, HttpServletRequest request) {
    return Result.error(ex.getCode(), ex.getMessage());
}


通过全局异常处理,可以:
1. 统一处理各种异常,返回友好的错误信息。
2. 提升系统的健壮性和用户体验。
3. 根据项目需求扩展更多的异常处理逻辑。