首先是異常的分類
1、統一的控制器異常處理器
首先,在web項目中的異常處理的原則是:
@ControllerAdvice
public class ControllerExceptionHandler<T> {
@ExceptionHandler(Exception.class)
@ResponseBody
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Response<? extends Object> handleControllerException(Exception e) {
Response<Object> response = new Response<>();
response.setCode("500");
response.setMessage(e.getMessage());
return response;
}
}
這是統一處理controller拋出的異常的地方,但是,當該類存在的時候,異常是不會傳遞到interceptor中的afterCompletion()方法中的,也就是afterCompletion()方法中的ex會爲空。
因爲異常處理類的執行是在interceptor類中的afterCompletion()方法之前的。
2、統一的響應處理
統一的響應處理是通過filter來實現的,我試過通過interceptor和advice這樣的方式來實現,但是都沒有達成目的。以下是實現,實現是通過spring提供的ContentCachingRequestWrapper和ContentCachingResponseWrapper來完成的。
在次過程中踩過兩個坑:
1、設置處理以後的響應數據不能成功
2、返回的數據沒有content-type設置
第一個問題:
是通過respWrapper.reset()和respWrapper.copyBodyToResponse()來實現將response清空和刷新寫入的數據,在使用ContentCachingXXXXXWrapper的時候,一定要使用copyBodyToResponse()來刷新response,否則返回的body中會是空的。
第二個問題:
需要設置response的content-type爲application/json;charset=UTF-8,但是該設置一定要是在copyBodyToResponse()之前。
所以,總結以上兩個問題,copyBodyToResponse()方法一定是在所有操作的最後。
@Configuration
public class ControllerResponseHandler implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper((HttpServletRequest) request);
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(
(HttpServletResponse) response);
chain.doFilter(requestWrapper, responseWrapper);
// 通過判斷URL中是否有v1來判斷該訪問是否是到達controller的,因爲我在controller的地址上都加了一個v1
if (reqWrapper.getRequestURI().contains("v1/")) {
wrapResponse(respWrapper);
respWrapper.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
}
respWrapper.copyBodyToResponse();
}
private void wrapResponse(ContentCachingResponseWrapper response) throws IOException {
// 判斷響應的類型是否是json或是否是正常的,如果是錯誤響應,那麼不需要通過該類進行響應處理,而是通過統一的異常處理類來處理
if (MediaType.APPLICATION_JSON_UTF8_VALUE.equals(response.getContentType()) && response.getStatus() < 300) {
byte[] b = response.getContentAsByteArray();
// 重置response中的body
response.reset();
Response<Object> result = new Response<>();
if (b.length == 0) {
result.setCode(ResponseStatus.NO_RESOURCE.getCode());
result.setMessage(ResponseStatus.NO_RESOURCE.getMessage());
} else {
result.setCode(ResponseStatus.SUCESS.getCode());
result.setMessage(ResponseStatus.SUCESS.getMessage());
}
result.setData(JSON.parse(b));
// 通過response的outputStream寫入新的數據
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(JSON.toJSONBytes(result));
}
}
}