异常捕获的一些细节
# 异常捕获的一些细节
# SpringBoot中的异常捕获
在本地进行开发时,程序运行,它的错误信息默认是打印在控制台的,但实际开发中,我们应该将这些错误信息返回给前端,以便定位问题与修复bug。
因此错误异常的处理十分重要,而错误异常的处理,在编程世界中有一个特殊的名字——异常捕获。
在 Spring Boot 应用中,异常处理是确保系统健壮性和用户体验的重要环节。下面就介绍一些, Spring Boot 中异常捕获和处理的常见方法、注意事项以及关键注解的使用说明。
# @ControllerAdvice
我们可以使用 @ControllerAdvice
搭配@ExceptionHandler
实现全局异常处理,只需要定义类,添加该注解即可定义方式如下(或者使用@RestControllerAdvice
):
@ControllerAdvice
public class MyGlobalExceptionHandler {
@ExceptionHandler(ArithmeticException.class)
public ResultResp customException(ArithmeticException e) {
System.out.println(e.getMessage());
return ResultResp.successOf(e.getMessage());
}
}
2
3
4
5
6
7
8
9
解析:@ExceptionHandler 注解用来指明异常的处理类型,即如果这里指定为 NullpointerException,则数组越界异常就不会进到这个方法中来。在该类中,可以定义多个方法,不同的方法处理不同的异常,例如专门处理空指针的方法、专门处理数组越界的方法…,也可以直接在一个方法中处理所有的异常信息。
# 特点
它有以下两个特点
- 可与
@ExceptionHandler
配合使用,集中处理异常。 - 可以限定作用范围(例如只处理特定包下的 Controller)。
@ControllerAdvice(basePackages = "com.example.controller")
public class GlobalExceptionHandler {
// 异常处理方法
}
2
3
4
# 返回结果
这种异常的返回结果,通常来说是一个固定的结构。
通常我们用一个结果类,或者枚举类(enum)来进行异常信息的管理,常有字段——code、message
@Data
public class ResultResp<T> {
private String message;
private Integer code;
private Boolean status = true;
private T data;
public static ResultResp errorOf(Integer code,String message){
ResultResp resultResp = new ResultResp();
resultResp.setStatus(false);
resultResp.setCode(code);
resultResp.setMessage(message);
return resultResp;
}
public static <T> ResultResp successOf(T t){
ResultResp resultResp = new ResultResp();
resultResp.setCode(200);
resultResp.setData(t);
resultResp.setMessage("请求成功");
return resultResp;
}
public static <T> ResultResp isOk(String message,Integer code){
ResultResp resultResp = new ResultResp();
resultResp.setMessage(message);
resultResp.setCode(code);
return resultResp;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# @RestControllerAdvice
- 作用:是
@ControllerAdvice
和@ResponseBody
的组合注解,专为 RESTful API 设计。 - 特点:返回值会自动序列化为 JSON/XML 响应体,无需手动添加
@ResponseBody
。
@RestControllerAdvice
public class GlobalExceptionHandler {
// 异常处理方法
}
2
3
4
# @ExceptionHandler
- 作用:标记异常处理方法,指定处理的异常类型。
- 特点:
- 可以定义多个方法处理不同类型的异常。
- 支持捕获异常的子类。
@ExceptionHandler(ServiceException.class)
public ResponseEntity<?> handleServiceException(ServiceException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(e.getMessage());
}
2
3
4
5
# ErrorrController接口
异常系统统一映射到 /error , 你可以实现 ErrorController来实现异常的控制
@Controller
@RequestMapping(value = "/error")
public class CustomizeErrorController implements ErrorController {
private HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer) request
.getAttribute("javax.servlet.error.status_code");
if (statusCode == null) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
try {
return HttpStatus.valueOf(statusCode);
} catch (Exception ex) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
}
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView errorHtml(HttpServletRequest request, Model model) {
HttpStatus status = getStatus(request);
if (status.is4xxClientError()) {
model.addAttribute("message", "你这个请求错了吧,要不然换个姿势?");
}
if (status.is5xxServerError()) {
model.addAttribute("message", "服务冒烟了,要不然你稍后再试试!!!");
}
return new ModelAndView("error");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 扩展
当然@ControllerAdvice
还可实现,全局数据绑定以及全局数据预处理,这里就不展开了。
ControllerAdvice扩展-博客 (opens new window)
# 全局异常处理
在编写异常处理代码时,我们通常选择定义一个全局类,这样以便实现:集中处理所有异常,避免在每个 Controller 中重复编写 try-catch
。
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理自定义异常
@ExceptionHandler(ServiceException.class)
public Result<?> handleServiceException(ServiceException e) {
return Result.error(e.getStatus().getCode(), e.getMessage());
}
// 处理运行时异常
@ExceptionHandler(RuntimeException.class)
public Result<?> handleRuntimeException(RuntimeException e) {
return Result.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
}
// 处理其他异常
@ExceptionHandler(Exception.class)
public Result<?> handleException(Exception e) {
return Result.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "系统内部错误");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 注意事项
# 1.避免重复 try-catch
- 全局异常处理器可以替代大部分
try-catch
,减少冗余代码。 - 仅在需要特殊处理的场景(如事务回滚)中使用局部
try-catch
。
# 2. 异常类的继承关系
- 自定义异常应继承
RuntimeException
(运行时异常),而非Exception
(检查型异常)。 - 检查型异常(如
IOException
)需显式处理,而运行时异常可自动抛出。
# 3. 安全性
- 避免暴露敏感信息:返回给前端的异常信息应简洁,不包含堆栈跟踪或数据库密码等敏感数据。
- 日志记录:在异常处理方法中记录详细日志,便于排查问题。
# 4.优先级与覆盖
- 如果多个
@ControllerAdvice
类处理同一异常,优先使用 最近声明的类。 - 可通过
@Order
注解显式指定优先级。