應用中的異常,有兩件事要考慮,怎么處理這個異常,怎么把異常可讀性高地返回給前端用戶
1.怎么把異常可讀性高的返回給前端用戶或API的消費者
自定義錯誤代碼和錯誤內容
2.怎么處理異常
比如遇到某個異常時需要發郵件通知IT團隊
@ControllerAdvice 是 Spring Framework 提供的一個注解,用于定義全局的異常處理、數據綁定和模型屬性的增強。
它的主要作用是集中管理控制器的全局邏輯,例如異常處理,而不需要在每個控制器中重復編寫相同的代碼。 ?
主要功能
全局異常處理:通過 @ExceptionHandler 注解 捕獲并處理控制器中拋出的異常。
全局數據綁定:通過 @InitBinder 注解對請求參數進行預處理。
全局模型屬性:通過 @ModelAttribute 注解為所有控制器提供公共的模型數據
3.自定義錯誤代碼和內容,并且使用@ControllerAdvice統一處理異常
3.1 自定義錯誤碼,可以把Demo換成projectname
public enum ExceptionCode {IN_VALID_REQUEST("Demo0001", ""),BAD_REQUEST("Demo400", "Bad Request"),NOT_FOUND("Demo404", "Resource Not Found"),INTERNAL_SERVER_ERROR("Demo500", "Internal Server Error");private final String code;private final String message;ExceptionCode(String code, String message) {this.code = code;this.message = message;}public String getCode() {return code;}public String getMessage() {return message;}
}
3.2 自定義異常InvalidationException
public class InvalidationRequestException extends RuntimeException {public InvalidationRequestException(String message) {super(message);}public InvalidationRequestException(String message, Throwable cause) {super(message, cause);}
}
3.3 自定義ExceptionAdvice,統一處理exception
當controller中拋出InvalidationRequestException時,就會被@ControllerAdvice 中的 @ExceptionHandler handleInvalidationException()方法捕獲并處理該異常
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;import java.util.HashMap;
import java.util.Map;@ControllerAdvice
public class GlobalExceptionHandler {private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);@ExceptionHandler(InvalidationRequestException.class)@ResponseBodypublic ResponseEntity<Map<String, String>> handleInvalidationException(InvalidationRequestException ex) {logger.warn("InvalidationRequestException: {}", ex.getMessage());//其它異常處理邏輯,比如發郵件,打電話通知IT團隊//返回給UI或API消費者Map<String, String> response = new HashMap<>();response.put("code", ExceptionCode.IN_VALIDATED_REQUEST.getCode());response.put("detail",ex.getMessage());return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);}@ExceptionHandler(Exception.class)public ResponseEntity<String> handleGenericException(Exception ex) {return new ResponseEntity<>("An error occurred: " + ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);}
}
3.4 controller, 拋出InvalidationException異常
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class DemoController {@GetMapping("/validate")public String validateParameter(@RequestParam String input) {if (input == null || input.trim().isEmpty()) {throw new InvalidationRequestException("Input parameter is invalid or empty");}return "Input is valid: " + input;}
}
3.5 測試
啟動應用,訪問?http://localhost:8082/validate?input
校驗失敗時,返回http狀態碼是400,body如下
{"code": "Demo0001","detail": "Input parameter is invalid or empty"}
==========================================
1.異常直接拋出
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class DemoController {@GetMapping("/throwException")public String throwException() {throw new RuntimeException("This is a runtime exception!");}
}
啟動應用,訪問?http://localhost:8082/throwException
會獲得一個狀態碼為500的異常?An error occurred: This is a runtime exception!
思考:這個異常對用戶或者call API的消費者來說,可讀性太低,不能明確的知道是什么錯誤
2.自定義狀態碼和錯誤信息,返回給前端用戶或者API 消費者可讀性高的異常
自定義錯誤碼,可以把Demo換成projectname
public enum ExceptionCode {IN_VALIDATED_REQUEST("Demo0001", ""),BAD_REQUEST("Demo400", "Bad Request"),NOT_FOUND("Demo404", "Resource Not Found"),INTERNAL_SERVER_ERROR("Demo500", "Internal Server Error");private final String code;private final String message;ExceptionCode(String code, String message) {this.code = code;this.message = message;}public String getCode() {return code;}public String getMessage() {return message;}
}
controller拋出異常
import com.example.demo_async.exception.ExceptionCode;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;
import java.util.Map;@RestController
public class DemoController {@GetMapping("/testErrorCode")public ResponseEntity<Map<String, String>> testErrorCode() {Map<String, String> response = new HashMap<>();response.put("code", ExceptionCode.BAD_REQUEST.getCode());response.put("detail", ExceptionCode.BAD_REQUEST.getMessage());return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);}
}
返回http status? 400, body 如下
{"code": "Demo400","detail": "Bad Request"}
思考:如果有很多個controller方法都會拋出這個異常,就需要在每個方法里寫一遍異常處理的邏輯,會產生大量的重復代碼,怎么解決呢?