- 自定義狀態碼列舉類
- 封裝回傳結果
- 全域例外捕獲處理,使用@RestControllerAdvice注解
- 攔截Controller方法的回傳值,統一處理回傳值/回應體
- 創建Controller,準備測驗
- 請求介面,查看回應結果
近年來,隨著移動互聯網的發展,各種型別的客戶端層出不窮,如果不統一資料介面,則會造成冗余編碼,增加成本,RESTful風格的API正適合通過一套統一的介面為PC、手機APP等設備提供資料服務,
為了保障前后端資料交換的順暢,建議規范資料的回傳,并采用固定的資料格式封裝,如:
回傳成功資訊的JSON格式如下
{
"code": 200,
"msg": "操作成功",
"data": "hello jenkins"
}
回傳例外資訊的JSON格式如下
{
"code": 500,
"msg": "系統例外,請稍后重試:/ by zero"
}
實作步驟如下
1. 自定義狀態碼列舉類,
@AllArgsConstructor
@Getter
public enum StatusCodeEnum {
SC200(200, "操作成功"),
SC999(999, "操作失敗"),
SC401(401, "匿名用戶訪問權限資源時的例外"),
SC403(403, "無訪問權限,請聯系管理員授予權限"),
SC404(404, "請求的資源不存在"),
SC500(500, "系統例外,請稍后重試"),
// ...略
private final Integer code;
private final String msg;
}
2. 封裝回傳結果
@Data
public class ApiResult<T> implements Serializable {
private Integer code;
private String msg;
private T data;
public static <T> ApiResult<T> success(T data) {
return ApiResult.success(StatusCodeEnum.SC200.getMsg(), data);
}
public static <T> ApiResult<T> success(String msg, T data) {
ApiResult<T> apiResult = new ApiResult<>();
apiResult.setCode(StatusCodeEnum.SC200.getCode());
apiResult.setMsg(msg);
apiResult.setData(data);
return apiResult;
}
public static <T> ApiResult<T> fail(Integer code, String msg) {
ApiResult<T> apiResult = new ApiResult<>();
apiResult.setCode(code);
apiResult.setMsg(msg);
return apiResult;
}
}
3. 全域例外捕獲處理,使用@RestControllerAdvice注解,
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 捕獲其他例外
*/
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public ApiResult<String> handle(Exception e) {
log.error("全域例外資訊:{}", e.getMessage());
return ApiResult.fail(StatusCodeEnum.SC500.getCode(), StatusCodeEnum.SC500.getMsg() + ":" + e.getMessage());
}
}
| 注解 | 功能 |
|---|---|
| @RestControllerAdvice | RestController的增強類,可用于實作全域例外處理器 |
| @ExceptionHandler | 統一處理某一類例外,從而減少代碼重復率和復雜度,比如要獲取自定義例外可以@ExceptionHandler(BusinessException.class) |
| @ResponseStatus | 指定客戶端收到的http狀態碼 |
注:請求進來 會按照 filter -> interceptor -> controllerAdvice -> aspect -> controller的順序呼叫,
404例外(NoHandlerFoundException)是無法通過這種方式捕獲的,因為在Filter層發生的例外都會到Spring默認的例外處理,如果你在組態檔配置了server.error.path的話,就會使用你配置的例外處理地址,如果沒有就會使用你配置的error.path路徑地址,如果還是沒有,默認使用/error來作為發生例外的處理地址,如果想要替換默認的非Controller例外處理直接實作Spring提供的ErrorController介面就行了,
第四步是重點
4. 攔截Controller方法的回傳值,統一處理回傳值/回應體,
因為我們后面每寫一個介面都需要呼叫ApiResult.success()這行代碼對結果進行包裝,重復勞動,浪費體力,我們只需要實作SpringBoot提供的ResponseBodyAdvice介面即可,
@RestControllerAdvice
public class ApiResultWrapper implements ResponseBodyAdvice<Object> {
/**
* 是否支持advice功能
*/
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}
/**
* 對回傳的資料進行處理
*/
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
if (o instanceof String) {
return JSON.toJSONString(ApiResult.success(o));
}
// 這個判斷的作用:防止全域例外處理后回傳的結果(型別為ApiResult)再次被包裝
if (o instanceof ApiResult) {
return o;
}
return ApiResult.success(o);
}
}
5. 創建Controller,定義兩個方法,讓第二個方法拋例外
@RestController
public class TestController {
@GetMapping("/test1")
public String test1() {
return "當前時間:" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
@GetMapping("/test2")
public Integer test2() {
System.out.println(1 / 0);
return Integer.MAX_VALUE;
}
}
6. 測驗
分別請求http://localhost:8080/test1、http://localhost:8080/test2,結果如下


在全域例外處理類中寫了一行代碼
log.error("全域例外資訊:{}", e.getMessage());
所以呼叫test2方法時控制臺列印例外資訊如下
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/293944.html
標籤:java
上一篇:用戶登錄專案第三期——用戶登錄
