Spring Boot中不使用ControllerAdvice如何捕获并抛出精确异常?
Spring Boot REST接口异常处理(仅try-catch实现)
核心结论:优先捕获精确异常
直接捕获业务/系统中明确可能抛出的精确异常类型,比捕获通用Exception更严谨,能避免误抓无关异常、提升代码可读性,减少后续维护混乱。
具体实现步骤
1. 定义自定义业务异常(按需)
针对业务场景定义专属异常,继承RuntimeException(Spring会自动将未捕获的RuntimeException映射为对应HTTP状态码):
// 用户未找到异常(对应HTTP 404) public class UserNotFoundException extends RuntimeException { public UserNotFoundException(String message) { super(message); } } // 数据库访问异常(对应HTTP 500) public class DatabaseAccessException extends RuntimeException { public DatabaseAccessException(String message, Throwable cause) { super(message, cause); } }
2. Controller中按精确异常分catch块处理
在try块执行业务逻辑,每个catch块对应一种异常类型,完成邮件通知后抛出异常给客户端:
@GetMapping(value = "/users") public Users getUsers() { try { return service.getUsers(); } catch (UserNotFoundException ex) { // 发送管理员邮件:用户查询未找到 sendAdminEmail("业务异常提醒", "请求/users时未找到匹配用户,异常信息:" + ex.getMessage()); // 抛出异常,Spring自动返回404响应 throw ex; } catch (DatabaseAccessException ex) { // 发送管理员邮件:数据库访问失败 sendAdminEmail("系统异常警告", "请求/users数据库访问失败,异常栈:\n" + getStackTraceAsString(ex)); // 抛出异常,Spring自动返回500响应 throw ex; } catch (Exception ex) { // 兜底处理未知异常(谨慎使用) sendAdminEmail("未知异常告警", "请求/users发生未知异常,异常栈:\n" + getStackTraceAsString(ex)); // 转为通用友好异常抛出,避免暴露敏感信息 throw new RuntimeException("系统繁忙,请稍后再试", ex); } } // 邮件发送工具方法(示例,需结合实际邮件客户端实现) private void sendAdminEmail(String subject, String content) { // 示例逻辑:使用Spring JavaMailSender // SimpleMailMessage message = new SimpleMailMessage(); // message.setTo("admin@yourdomain.com"); // message.setSubject(subject); // message.setText(content); // mailSender.send(message); } // 异常栈转为字符串工具方法 private String getStackTraceAsString(Throwable ex) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); ex.printStackTrace(pw); return sw.toString(); }
两种捕获方式对比
- 直接捕获精确异常:推荐,逻辑清晰、针对性强,不会误处理空指针、参数错误这类代码bug级异常,维护成本低。
- 捕获通用Exception再识别:不推荐,会捕获所有异常,容易掩盖潜在代码问题,且需用
instanceof判断异常类型,代码可读性差,示例写法如下(仅作对比,不建议使用):
// 不推荐的写法 try { return service.getUsers(); } catch (Exception ex) { if (ex instanceof UserNotFoundException) { sendAdminEmail("业务异常", ex.getMessage()); throw (UserNotFoundException) ex; } else if (ex instanceof DatabaseAccessException) { sendAdminEmail("系统异常", getStackTraceAsString(ex)); throw (DatabaseAccessException) ex; } else { sendAdminEmail("未知异常", getStackTraceAsString(ex)); throw new RuntimeException("系统繁忙", ex); } }
内容的提问来源于stack exchange,提问作者elvis
相关产品推荐
相关产品推荐

