SpringBoot 全局異常處理終極指南
@RestController
@RequestMapping("/user")
publicclassUserController {
@GetMapping("/{id}")
public ApiResponse<String> getUser(@PathVariableint id) {
if (id == 0) {
thrownewBusinessException(404, "用戶不存在");
}
return ApiResponse.success("用戶ID: " + id);
}
}
@GetMapping("/{id}")
public User getUser(@PathVariableint id) {
try {
return userService.findById(id);
} catch (Exception e) {
e.printStackTrace();
returnnull;
}
}
-
? try-catch邏輯冗余,重復代碼太多。 -
? 一旦拋出異常,返回值不明確,前端無法準確感知錯誤信息。
@ControllerAdvice + @ExceptionHandler。ApiResponse,用于統一接口返回格式:publicclassApiResponse<T> {
privateint code;
private String message;
private T data;
publicApiResponse(int code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
publicstatic <T> ApiResponse<T> success(T data) {
returnnewApiResponse<>(200, "success", data);
}
publicstatic <T> ApiResponse<T> error(int code, String message) {
returnnewApiResponse<>(code, message, null);
}
// getter & setter
}
除了系統異常(NullPointerException、SQLException 等),我們還需要定義 業務異常,用于明確業務邏輯錯誤:publicclassBusinessExceptionextendsRuntimeException {
privateint code;
publicBusinessException(int code, String message) {
super(message);
this.code = code;
}
publicintgetCode() {
return code;
}
}
例如:用戶不存在、余額不足、參數非法等,都可以通過 BusinessException 來拋出。接下來,通過 @RestControllerAdvice來統一捕獲異常:@RestControllerAdvice
publicclassGlobalExceptionHandler {
// 處理業務異常
@ExceptionHandler(BusinessException.class)
public ApiResponse<?> handleBusinessException(BusinessException ex) {
return ApiResponse.error(ex.getCode(), ex.getMessage());
}
// 處理參數校驗異常
@ExceptionHandler(MethodArgumentNotValidException.class)
public ApiResponse<?> handleValidException(MethodArgumentNotValidException ex) {
Stringmsg= ex.getBindingResult().getFieldError().getDefaultMessage();
return ApiResponse.error(400, msg);
}
// 兜底異常處理
@ExceptionHandler(Exception.class)
public ApiResponse<?> handleException(Exception ex) {
ex.printStackTrace(); // 可接入日志系統
return ApiResponse.error(500, "服務器內部錯誤");
}
}
{
"code":200,
"message":"success",
"data":"用戶ID: 1"
}
{
"code":404,
"message":"用戶不存在",
"data":null
}
{
"code":500,
"message":"服務器內部錯誤",
"data":null
}
try-catch。Logback、ELK)或異常監控平臺(如 Sentry)。@ExceptionHandler(Exception.class)
public ApiResponse<?> handleException(Exception ex, HttpServletRequest request) {
// 記錄日志信息
ErrorLoglog=newErrorLog();
log.setUri(request.getRequestURI());
log.setMethod(request.getMethod());
log.setMessage(ex.getMessage());
log.setStackTrace(Arrays.toString(ex.getStackTrace()));
log.setCreateTime(LocalDateTime.now());
errorLogRepository.save(log); // JPA 或 MyBatis 保存
return ApiResponse.error(500, "服務器內部錯誤");
}
其中 ErrorLog 可以定義為:@Entity
publicclassErrorLog {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String uri;
private String method;
private String message;
private String stackTrace;
private LocalDateTime createTime;
// getter & setter
}
logback-spring.xml 中使用 logstash-logback-encoder 輸出 JSON:<configuration>
<appendername="LOGSTASH"class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app-log.json</file>
<encoderclass="net.logstash.logback.encoder.LoggingEventEncoder"/>
</appender>
<rootlevel="INFO">
<appender-refref="LOGSTASH"/>
</root>
</configuration>
logstash.conf):input {
file {
path =>"/usr/local/app/logs/app-log.json"
codec => json
}
}
output {
elasticsearch {
hosts => ["http://localhost:9200"]
index => "springboot-error-%{+YYYY.MM.dd}"
}
}
Kibana Dashboard,可以實現:Prometheus Alertmanager)。https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx
使用 RestTemplate 發送 POST 請求:@Component
publicclassFeishuBotNotifier {
privatestaticfinalStringWEBHOOK_URL="https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxx";
privatefinalRestTemplaterestTemplate=newRestTemplate();
publicvoidsendAlert(String title, String content) {
Map<String, Object> body = newHashMap<>();
body.put("msg_type", "text");
Map<String, String> text = newHashMap<>();
text.put("text", String.format("【異常告警】\n標題: %s\n詳情: %s", title, content));
body.put("content", text);
restTemplate.postForEntity(WEBHOOK_URL, body, String.class);
}
}
@RestControllerAdvice
@RequiredArgsConstructor
publicclassGlobalExceptionHandler {
privatefinal FeishuBotNotifier feishuBotNotifier;
@ExceptionHandler(Exception.class)
public ApiResponse<?> handleException(Exception ex, HttpServletRequest request) {
// 構造告警信息
Stringtitle="SpringBoot 服務異常";
Stringcontent= String.format("URI: %s\nMethod: %s\n錯誤: %s",
request.getRequestURI(), request.getMethod(), ex.getMessage());
// 發送飛書告警
feishuBotNotifier.sendAlert(title, content);
ex.printStackTrace();
return ApiResponse.error(500, "服務器內部錯誤");
}
}
【異常告警】
標題: SpringBoot 服務異常
詳情:
URI: /user/0
Method: GET
錯誤: 用戶不存在
-
? 全局異常處理:統一返回格式,簡化開發。 -
? 業務異常區分:明確業務錯誤與系統錯誤。 -
? 日志落庫:異常可持久化追溯。 -
? ELK 接入:日志可視化分析,支持查詢與報表。 -
? 飛書機器人告警:重大異常實時通知,提高運維響應速度。
接口開發 → 異常收斂 → 日志分析 → 實時告警 的完整鏈路,既保證了系統的可維護性,也提升了線上運維的響應效率。
摘抄自網絡,便于檢索查找。

浙公網安備 33010602011771號