【 <二> 丹方改良:Spring 时代的 JavaWeb】之 Spring Boot 中的异常处理:全局异常与自定义异常

发布于:2025-03-23 ⋅ 阅读:(28) ⋅ 点赞:(0)

 <前文回顾>

点击此处查看 合集 https://blog.csdn.net/foyodesigner/category_12907601.html?fromshare=blogcolumn&sharetype=blogcolumn&sharerId=12907601&sharerefer=PC&sharesource=FoyoDesigner&sharefrom=from_link

<今日更新>

一、开篇整活儿

今儿个咱唠唠 Spring Boot 里头的异常处理。这玩意儿吧,说大不大,说小不小,整好了是锦上添花,整不好就是火上浇油。你要是刚入门,那可得悠着点儿,别一上来就整得自己“翻车”了。

二、Java 中的异常是啥构型?

Java 里头的异常,说白了就是程序运行时出的岔子。Java 的异常体系是“树形结构”,最顶上是 Throwable,往下分成 Error 和 Exception。Error 是那种严重的、没法儿处理的错误,比如说内存溢出啥的。Exception 是那种可以处理的异常,比如说空指针、数组越界啥的。

1. Exception 的分类

Exception 又分成两种:受检异常非受检异常

  • 受检异常:这种异常你得在代码里头显式处理,要么 try-catch,要么 throws。比如说 IOException,你要是读写文件,那得处理这个异常。
  • 非受检异常:这种异常不用显式处理,比如说 NullPointerException、ArrayIndexOutOfBoundsException,这些异常通常是代码写得不严谨导致的。

Java Code

// 受检异常示例

try {

    FileInputStream fis = new FileInputStream("file.txt");

} catch (IOException e) {

    e.printStackTrace();

}

// 非受检异常示例

String str = null;

System.out.println(str.length()); // 这里会抛出 NullPointerException

2. 异常之间的关系

Java 里头的异常是“继承关系”,子类异常可以捕获父类异常。比如说,IOException 是 Exception 的子类,你要是 catch 了 Exception,那 IOException 也能被捕获。

Java Code

try {

    // 一些可能抛出异常的代码

} catch (IOException e) {

    // 处理 IOException

} catch (Exception e) {

    // 处理其他 Exception

}

这段代码里头,IOException 会被第一个 catch 捕获,其他的 Exception 会被第二个 catch 捕获。

三、Spring Boot 中的全局异常处理

Spring Boot 里头有个 @ControllerAdvice 注解,专门用来做全局异常处理。你可以把它想象成一个“兜底的”,Controller 里头没处理的异常,它都能接住。

1. 全局异常处理示例

Java Code

@ControllerAdvice

public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)

    public ResponseEntity<String> handleException(Exception e) {

        return new ResponseEntity<>("出错了:" + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);

    }

}

这段代码里头,@ControllerAdvice 是用来定义一个全局的异常处理类,@ExceptionHandler 是用来处理特定类型的异常的。ResponseEntity 是用来返回 HTTP 响应的,里头可以带上状态码和响应体。

2. 处理特定异常

你可以针对不同的异常,写不同的处理方法。比如说,处理 NullPointerException 和 IllegalArgumentException。

Java Code

@ControllerAdvice

public class GlobalExceptionHandler {

    @ExceptionHandler(NullPointerException.class)

    public ResponseEntity<String> handleNullPointerException(NullPointerException e) {

        return new ResponseEntity<>("空指针异常:" + e.getMessage(), HttpStatus.BAD_REQUEST);

    }

    @ExceptionHandler(IllegalArgumentException.class)

    public ResponseEntity<String> handleIllegalArgumentException(IllegalArgumentException e) {

        return new ResponseEntity<>("参数不合法:" + e.getMessage(), HttpStatus.BAD_REQUEST);

    }

}

这段代码里头,NullPointerException 和 IllegalArgumentException 会被分别处理,返回不同的错误信息。

四、自定义异常

有时候,Java 自带的异常不够用,你得自己整一个。自定义异常很简单,继承 Exception 或者 RuntimeException 就行。

1. 自定义异常示例

Java Code

public class MyCustomException extends RuntimeException {

    public MyCustomException(String message) {

        super(message);

    }

}

这段代码里头,MyCustomException 是自定义异常,继承自 RuntimeException,所以它是非受检异常。

2. 使用自定义异常

你可以在代码里头抛出这个自定义异常。

Java Code

@RestController

@RequestMapping("/api")

public class MyController {

    @GetMapping("/test")

    public String test() {

        throw new MyCustomException("这是我的自定义异常");

    }

}

这段代码里头,test 方法会抛出 MyCustomException,然后被全局异常处理器捕获。

3. 处理自定义异常

你可以在全局异常处理器里头,专门处理这个自定义异常。

Java Code

@ControllerAdvice

public class GlobalExceptionHandler {

    @ExceptionHandler(MyCustomException.class)

    public ResponseEntity<String> handleMyCustomException(MyCustomException e) {

        return new ResponseEntity<>("自定义异常:" + e.getMessage(), HttpStatus.BAD_REQUEST);

    }

}

这段代码里头,MyCustomException 会被专门处理,返回自定义的错误信息。

五、异常的 AOP 处理

AOP(面向切面编程)是 Spring 里头的一个高级特性,可以用来在方法执行前后做一些额外的事情。异常处理也可以用 AOP 来做。

1. AOP 处理异常示例

Java Code

@Aspect

@Component

public class ExceptionAspect {

    @AfterThrowing(pointcut = "execution(* com.example.demo.controller.*.*(..))", throwing = "e")

    public void handleException(Exception e) {

        System.out.println("捕获到异常:" + e.getMessage());

    }

}

这段代码里头,@Aspect 是用来定义一个切面,@AfterThrowing 是用来在方法抛出异常后执行的。pointcut 是指定哪些方法需要被切面处理,throwing 是指定异常对象的变量名。

2. AOP 和全局异常处理的区别

AOP 和全局异常处理都可以用来处理异常,但它们的应用场景不一样。全局异常处理是用来处理 Controller 里头的异常,而 AOP 可以用来处理任何地方的异常,比如说 Service 层、DAO 层啥的。

六、Spring Boot 里头的异常处理坑点

1. 异常处理的顺序

Spring Boot 里头,异常处理的顺序很重要。你要是先 catch 了 Exception,那后面的 catch 就不起作用了。

Java Code

@ControllerAdvice

public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)

    public ResponseEntity<String> handleException(Exception e) {

        return new ResponseEntity<>("出错了:" + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);

    }

    @ExceptionHandler(NullPointerException.class)

    public ResponseEntity<String> handleNullPointerException(NullPointerException e) {

        return new ResponseEntity<>("空指针异常:" + e.getMessage(), HttpStatus.BAD_REQUEST);

    }

}

这段代码里头,NullPointerException 会被 handleException 捕获,handleNullPointerException 就不起作用了。

2. 异常信息的暴露

Spring Boot 里头,默认会把异常信息返回给客户端。你要是觉得这样不安全,可以把异常信息隐藏掉。

Java Code

@ControllerAdvice

public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)

    public ResponseEntity<String> handleException(Exception e) {

        return new ResponseEntity<>("出错了", HttpStatus.INTERNAL_SERVER_ERROR);

    }

}

这段代码里头,异常信息被隐藏了,客户端只能看到“出错了”。

3. 日志记录

异常处理里头,日志记录是个大事儿。你要是没记日志,那出了问题就抓瞎了。

Java Code

@ControllerAdvice

public class GlobalExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(Exception.class)

    public ResponseEntity<String> handleException(Exception e) {

        logger.error("捕获到异常:", e);

        return new ResponseEntity<>("出错了", HttpStatus.INTERNAL_SERVER_ERROR);

    }

}

这段代码里头,异常信息被记录到日志里头了,方便以后排查问题。

专有名词解释

  1. Throwable:Java 中所有错误和异常的基类。
  2. Error:Java 中表示严重错误的类,通常无法恢复。
  3. Exception:Java 中表示可恢复异常的类。
  4. 受检异常:必须在代码中显式处理的异常。
  5. 非受检异常:不需要显式处理的异常。
  6. ControllerAdvice:Spring 中用于定义全局异常处理类的注解。
  7. ExceptionHandler:Spring 中用于处理特定类型异常的注解。
  8. ResponseEntity:Spring 中用于封装 HTTP 响应的类。
  9. AOP:面向切面编程,一种编程范式,用于在方法执行前后做一些额外的事情。
  10. Aspect:Spring 中用于定义切面的注解。
  11. AfterThrowing:Spring 中用于在方法抛出异常后执行的注解。
  12. Logger:用于记录日志的工具类。