您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# Spring Boot项目怎么处理全局异常
## 目录
1. [引言](#引言)
2. [为什么需要全局异常处理](#为什么需要全局异常处理)
3. [Spring Boot异常处理机制](#spring-boot异常处理机制)
4. [实现全局异常处理的5种方式](#实现全局异常处理的5种方式)
- [4.1 @ControllerAdvice + @ExceptionHandler](#41-controlleradvice--exceptionhandler)
- [4.2 实现ErrorController接口](#42-实现errorcontroller接口)
- [4.3 @ResponseStatus自定义异常](#43-responsestatus自定义异常)
- [4.4 HandlerExceptionResolver](#44-handlerexceptionresolver)
- [4.5 Filter异常处理](#45-filter异常处理)
5. [最佳实践与进阶技巧](#最佳实践与进阶技巧)
6. [常见问题解决方案](#常见问题解决方案)
7. [总结](#总结)
## 引言
在Web应用开发中,异常处理是保证系统健壮性和用户体验的关键环节。Spring Boot作为流行的Java框架,提供了多种灵活的全局异常处理机制。本文将深入探讨5种核心实现方案,并通过完整代码示例展示如何构建企业级异常处理体系。
## 为什么需要全局异常处理
传统的try-catch方式存在以下问题:
- **代码重复**:每个Controller都需要重复异常处理逻辑
- **维护困难**:异常逻辑分散难以统一管理
- **响应不规范**:错误响应格式不一致
- **安全隐患**:可能暴露堆栈信息
全局异常处理的优势:
```java
// 传统方式 vs 全局处理
@GetMapping("/old")
public String oldMethod() {
try {
// 业务逻辑
} catch (Exception e) {
// 每个方法都要重复处理
return "error";
}
}
// 全局处理方式
@GetMapping("/new")
public String newMethod() {
// 只需关注业务逻辑
throw new BusinessException("操作失败");
}
Spring Boot异常处理流程: 1. 请求进入Controller 2. 发生异常时查找@ExceptionHandler 3. 未处理则交给HandlerExceptionResolver 4. 最后进入BasicErrorController
sequenceDiagram
participant Client
participant Controller
participant ExceptionHandler
participant ErrorController
Client->>Controller: HTTP Request
Controller->>ExceptionHandler: 抛出异常
alt 有匹配的@ExceptionHandler
ExceptionHandler-->>Client: 自定义响应
else 无匹配处理器
Controller->>ErrorController: 转交处理
ErrorController-->>Client: 默认错误页
end
最推荐的解决方案:
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理业务异常
@ExceptionHandler(BusinessException.class)
public Result<Void> handleBusinessException(BusinessException e) {
log.error("业务异常: {}", e.getMessage());
return Result.fail(e.getCode(), e.getMessage());
}
// 处理系统异常
@ExceptionHandler(Exception.class)
public Result<Void> handleException(Exception e) {
log.error("系统异常: ", e);
return Result.fail(500, "系统繁忙");
}
// 处理验证异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<Void> handleValidException(MethodArgumentNotValidException e) {
String message = e.getBindingResult()
.getFieldError()
.getDefaultMessage();
return Result.fail(400, message);
}
}
进阶配置:
// 自定义注解实现异常分类处理
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExceptionAdvice {}
// 按包路径指定处理范围
@ControllerAdvice(annotations = ExceptionAdvice.class)
public class AnnotationExceptionHandler {...}
// 响应状态码自动设置
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(IllegalArgumentException.class)
public ErrorResponse handleIllegalArgument(...) {...}
适用于处理未被捕获的异常:
@RestController
public class CustomErrorController implements ErrorController {
private final ErrorAttributes errorAttributes;
public CustomErrorController(ErrorAttributes errorAttributes) {
this.errorAttributes = errorAttributes;
}
@RequestMapping("/error")
public Result<?> handleError(HttpServletRequest request) {
Map<String, Object> attributes = errorAttributes
.getErrorAttributes(new ServletWebRequest(request),
ErrorAttributeOptions.defaults());
return Result.fail(
(int)attributes.get("status"),
(String)attributes.get("message")
);
}
}
定义层次化异常体系:
// 基础异常类
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public class BaseException extends RuntimeException {
private final int code;
public BaseException(int code, String message) {
super(message);
this.code = code;
}
}
// 具体业务异常
public class OrderNotFoundException extends BaseException {
public OrderNotFoundException() {
super(404001, "订单不存在");
}
}
// 使用示例
@GetMapping("/order/{id}")
public Order getOrder(@PathVariable Long id) {
return orderRepo.findById(id)
.orElseThrow(OrderNotFoundException::new);
}
底层处理方案:
@Component
public class CustomExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
if (ex instanceof AuthenticationException) {
return handleAuthException((AuthenticationException)ex, response);
}
return null; // 返回null继续后续处理
}
private ModelAndView handleAuthException(...) {
response.setStatus(401);
response.setContentType("application/json");
// 写入JSON响应
return new ModelAndView(); // 空视图表示已处理
}
}
处理过滤器链中的异常:
@Component
public class ExceptionHandlingFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
try {
filterChain.doFilter(request, response);
} catch (BusinessException e) {
ErrorResponse error = new ErrorResponse(e.getCode(), e.getMessage());
response.setStatus(400);
response.getWriter().write(JsonUtils.toJson(error));
} catch (Exception e) {
// 处理其他异常
}
}
}
@ExceptionHandler(Exception.class)
public Result<?> handleException(Exception e, HttpServletRequest request) {
log.error("""
[全局异常] 请求路径: {} | 方法: {} | 参数: {} | 异常类型: {}
异常信息: {} | 堆栈: {}
""",
request.getRequestURI(),
request.getMethod(),
request.getQueryString(),
e.getClass().getName(),
e.getMessage(),
ExceptionUtils.getStackTrace(e));
// ...
}
# messages.properties
error.order.notFound=订单不存在,ID: {0}
error.auth.denied=无访问权限
@RestControllerAdvice
public class GlobalExceptionHandler {
@Autowired
private MessageSource messageSource;
@ExceptionHandler(OrderNotFoundException.class)
public Result<?> handleOrderNotFound(
OrderNotFoundException e,
HttpServletRequest request) {
String message = messageSource.getMessage(
"error.order.notFound",
new Object[]{e.getOrderId()},
request.getLocale());
return Result.fail(404, message);
}
}
@ExceptionHandler(Exception.class)
public Result<?> handleException(Exception e, MeterRegistry registry) {
registry.counter("system.exception",
"type", e.getClass().getSimpleName())
.increment();
// ...
}
解决方案:通过@Order注解指定优先级
@Order(Ordered.HIGHEST_PRECEDENCE)
@RestControllerAdvice
public class HighPriorityExceptionHandler {...}
解决方案:配置ErrorController或添加兜底路由
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/notFound")
.setViewName("forward:/error/404");
}
}
解决方案:配置AsyncUncaughtExceptionHandler
@Configuration
public class AsyncConfig implements AsyncConfigurer {
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new CustomAsyncExceptionHandler();
}
}
本文详细介绍了Spring Boot中5种全局异常处理方案,实际项目中推荐组合使用:
完整示例项目结构:
src/
├── main/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ ├── exception/ # 异常定义
│ │ ├── config/ # 异常配置
│ │ ├── handler/ # 处理器实现
│ │ └── Application.java
│ └── resources/
│ ├── messages/ # 国际化资源
│ └── application.yml
通过合理的异常处理设计,可以显著提升系统的: - 可维护性(集中管理) - 健壮性(兜底处理) - 用户体验(友好提示) - 可观测性(完善日志)
最佳实践建议:建立完整的异常分类体系,结合监控告警系统,实现从异常发生到修复的完整闭环。 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。