网站首页 > 技术文章 正文
异常处理是每个 Java程序员需要面对的一个问题,在Spring中,提供了多种机制来处理控制器抛出的异常,确保应用程序在面对各种错误情况时能够优雅地响应。这篇文章,我们来详细分析Spring MVC中,几种优雅处理异常的方式。
1. 使用@ExceptionHandler注解
@ExceptionHandler注解允许在单个Controller中定义处理特定异常的方法。当 Controller的方法抛出指定的异常时,Spring会调用相应的处理方法。
如下示例,展示了如何在 Controller层优雅处理异常:
@Controller
public class MyController {
@RequestMapping("/example")
public String example() {
// 可能抛出异常的业务逻辑
if (1/0) {
throw new CustomException("自定义异常发生");
}
return "success";
}
@ExceptionHandler(CustomException.class)
public ModelAndView handleCustomException(CustomException ex) {
ModelAndView mav = new ModelAndView();
mav.addObject("message", ex.getMessage());
mav.setViewName("errorPage");
return mav;
}
}
优点: 简单直观,适用于单个控制器的异常处理。
缺点: 如果多个控制器需要相同的异常处理逻辑,需要在每个控制器中重复定义。
2. 使用@ControllerAdvice注解
@ControllerAdvice是一种全局的异常处理方式,可以应用于所有 Controller。通过将异常处理逻辑集中在一个地方,可以避免代码重复,提高维护性。
如下示例,展示了如何使用@ControllerAdvice优雅处理全局异常:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(CustomException.class)
public ModelAndView handleCustomException(CustomException ex) {
ModelAndView mav = new ModelAndView();
mav.addObject("message", ex.getMessage());
mav.setViewName("errorPage");
return mav;
}
@ExceptionHandler(Exception.class)
public ModelAndView handleGeneralException(Exception ex) {
ModelAndView mav = new ModelAndView();
mav.addObject("message", "发生了一个错误: " + ex.getMessage());
mav.setViewName("errorPage");
return mav;
}
}
优点:
- 全局统一管理异常处理逻辑。
- 代码更清晰,易于维护。
缺点:
- 全局处理不适用于需要针对某些控制器有特殊处理需求的情况,需结合其他方法使用。
3. 实现HandlerExceptionResolver接口
HandlerExceptionResolver 是一种更底层的异常处理机制,通过实现该接口,开发者可以自定义异常解析逻辑。
如下示例,展示了如何实现HandlerExceptionResolver接口优雅处理异常:
public class MyExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
ModelAndView mav = new ModelAndView();
if (ex instanceof CustomException) {
mav.addObject("message", ex.getMessage());
mav.setViewName("customErrorPage");
} else {
mav.addObject("message", "未知错误");
mav.setViewName("errorPage");
}
return mav;
}
}
配置:
在 Spring 配置文件中注册自定义异常解析器:
<bean class="com.example.MyExceptionResolver"/>
优点:
- 高度灵活,可以处理各种复杂的异常情景。
缺点:
- 需要更多的配置和实现工作。
- 不如注解方式直观,适用性较低。
4. 使用@ResponseStatus注解
@ResponseStatus注解可以用于自定义异常对应的 HTTP 状态码和错误信息,当抛出带有该注解的异常时,Spring会自动设置相应的状态码。
如下示例,展示了如何使用@ResponseStatus注解优雅处理异常:
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "资源未找到")
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
使用:
@Controller
public class MyController {
@RequestMapping("/resource")
public String getResource() {
// 假设资源未找到
throw new ResourceNotFoundException("资源ID不存在");
}
}
优点:
- 简单快捷,适用于直接映射到特定 HTTP 状态码的异常情况。
缺点:
- 无法返回自定义的错误页面或更复杂的错误信息。
5. 使用ResponseEntity和@RestControllerAdvice
在构建 RESTful API时,常用ResponseEntity来返回自定义的错误响应,并结合@RestControllerAdvice可以全局处理异常并返回 JSON 格式的错误信息。
如下示例,展示了如何使用ResponseEntity和@RestControllerAdvice来处理 RESTful API的异常:
@RestControllerAdvice
public class RestExceptionHandler {
@ExceptionHandler(CustomException.class)
public ResponseEntity<ErrorResponse> handleCustomException(CustomException ex) {
ErrorResponse error = new ErrorResponse("CUSTOM_ERROR", ex.getMessage());
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGeneralException(Exception ex) {
ErrorResponse error = new ErrorResponse("GENERAL_ERROR", "内部服务器错误");
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
public class ErrorResponse {
private String errorCode;
private String errorMessage;
// 构造方法、getter 和 setter
}
优点:
- 适用于 RESTful 服务,能够返回结构化的错误信息(如 JSON)。
- 全局统一管理,易于维护。
缺点:
- 需要定义额外的错误响应类。
6. 使用@ControllerAdvice和@ExceptionHandler
如果使用 Spring Boot,可以更便捷地使用 @ControllerAdvice 结合自动配置实现异常处理。
如下示例,展示了如何使用@ControllerAdvice和@ExceptionHandler来处理异常:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ValidationErrorResponse> handleValidationExceptions(
MethodArgumentNotValidException ex) {
ValidationErrorResponse errors = new ValidationErrorResponse();
ex.getBindingResult().getAllErrors().forEach((error) -> {
errors.addError(((FieldError) error).getField(), error.getDefaultMessage());
});
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
// 其它异常处理方法
}
优点:
- 与 Spring Boot 无缝集成,减少配置。
- 提供了诸多便利的功能,如自动处理验证错误等。
7. 总结
本文,我们分析了 Spring MVC优雅处理异常的几种方法以及代码示例,我们可以根据具体需求选择合适的方法:
- 局部控制器处理:使用 @ExceptionHandler 注解,适用于单个控制器的特定异常处理。
- 全局处理:使用 @ControllerAdvice 或 @RestControllerAdvice,适用于跨多个控制器的统一异常处理。
- 自定义解析:实现 HandlerExceptionResolver 接口,适用于需要高度自定义的异常处理逻辑。
- 状态码注解:使用 @ResponseStatus 注解,适用于简单的异常状态码映射。
- RESTful API:结合 ResponseEntity 和全局异常处理,返回结构化的错误响应。
从实际工作来看,@ControllerAdvice 或 @RestControllerAdvice是使用频率最高的一种方式。
猜你喜欢
- 2024-12-25 Spring Boot整合Spring Cloud GateWay代理第三方应用的调用接口?
- 2024-12-25 Java 近期新闻:Hibernate 6.0、JobRunr 5.0、JHipster 7.8.0
- 2024-12-25 Keycloak Servlet Filter Adapter使用
- 2024-12-25 如何在Spring Boot中保证RESTful接口的安全性?
- 2024-12-25 Java项目实战第6天:登录业务的实现
- 2024-12-25 JavaEE概述总结:Servlet生命周期+JSP内置对象
- 2024-12-25 SpringBoot 无感刷新 Token springboot的token
- 2024-12-25 若依开发框架解析笔记(7)-jwt的应用
- 2024-12-25 Spring MVC中提供了哪些扩展机制?如何使用这些扩展机制?
- 2024-12-25 49个Spring经典面试题总结(附带答案)
- 1509℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 527℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 492℃MySQL service启动脚本浅析(r12笔记第59天)
- 472℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 469℃启用MySQL查询缓存(mysql8.0查询缓存)
- 450℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 429℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 426℃MySQL server PID file could not be found!失败
- 最近发表
- 标签列表
-
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- chromepost (65)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- js判断是否是json字符串 (67)
- checkout-b (67)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- linux删除一个文件夹 (65)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)