spring攔截器攔截request與response業務資料
阿新 • • 發佈:2019-01-04
來源:http://blog.csdn.net/u013979547/article/details/53449788
Controller層的作用是處理業務邏輯並返回資料,那怎麼返回資料呢?介面的請求通過HttpServletRequest和HttpServletResponse實現前後端的互動,ServletResponse中有一個getWriter()方法獲取到一個PrintWriter物件,通過PrintWriter的.print()方法即可將資料通過HttpServletResponse傳遞給前端。
首先定義一個返回資料的module,
public class ResponseModel { public static final intSUCCESS = 200; public static final int ERROR = 100; private Integer status; private String message; private Object data; private Locale locale; public ResponseModel(){ this.status = SUCCESS; this.locale = Locale.CHINA; } public ResponseModel put(String key, Object value){ if(this.data == null || !(data instanceof Map)){ this.data = new HashMap<String,Object>(); } Map<String, Object> map = (Map<String,Object>)this.data; map.put(key,value); return this; } public Object getData(){ return data; } publicResponseModel setData(Object data){ this.data = data; return this; } public ResponseModel setErrorMsg(ErrorMsg errorMsg){ this.setStatus(errorMsg.getCode()); this.setMessage(errorMsg.getMessage()); return this; } public ResponseModel setStatus(int status){ this.status = status; if(ERROR == status){ this.setMessage("系統錯誤"); } return this; } public ResponseModel setMessage(String message){ this.message = message; return this; } public int getStatus(){ return status; } public String getMessage(){ return message; } }
再定義一個holder的Bean,返回module作為一個執行緒級變數放到Bean中,
@Component public class ResponseHolder { private static ThreadLocal<Object> model = new ThreadLocal<>(); public void clean(){ model.remove(); } public ResponseModel getModel(){ Object o = model.get(); if(o == null){ this.setModel(new ResponseModel()); o = this.getObject(); } if(o != null && o instanceof ResponseModel){ return (ResponseModel) o; }else { return null; } } public Object getObject(){ return model.get(); } public void setModel(Object o){ model.set(o); } public ResponseModel put(String key, Object value){ ResponseModel responseModel = this.getModel(); Object data = responseModel.getData(); if(data == null || !(data instanceof Map)){ data = new HashMap<String,Object>(); responseModel.setData(data); } Map<String,Object> map = (Map<String,Object>) data; map.put(key,value); return responseModel; } public ResponseModel setData(Object data){ ResponseModel responseModel = this.getModel(); responseModel.setData(data); return responseModel; } public ResponseModel setErrorMsg(ErrorMsg errorMsg){ ResponseModel responseModel = this.getModel(); responseModel.setStatus(errorMsg.getCode()); responseModel.setMessage(errorMsg.getMessage()); return responseModel; } }
其中的ErrorMsg是一個錯誤列舉,
public enum ErrorMsg { TEST(1,"test"), SUCCESS(200,"交易完成"), LOGIN_FAIL(101,"登入失敗"), LOGOUT_SUCCESS(104,"登出成功"), USER_NOT_FOUND(102,"未註冊使用者"), USER_DISABLED(103,"無效使用者"), NO_LOGIN(105,"未登入"), VERIFY_CODE_ERROR(106,"驗證碼錯誤"), SYSTEM_ERROR(100,"系統錯誤"); private int code; private String message; public int getCode(){ return code; } public String getMessage(){ return message; } ErrorMsg(int code, String message){ this.code = code; this.message = message; } }
接下來定義攔截器,在每個controller完成後從holder中取出資料通過HttpServletResponse傳遞給前端,
@Component public class ResponseInterceptor implements HandlerInterceptor { @Autowired private ResponseHolder responseHolder; private Logger logger = LogManager.getLogger(ResponseInterceptor.class); @Override public boolean preHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception{ return true; } @Override public void postHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3, ModelAndView var4) throws Exception{ //do noting } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception exception) throws Exception{ if(responseHolder == null){ logger.error("system error", exception); responseHolder.setErrorMsg(ErrorMsg.SYSTEM_ERROR); } String json = JSON.toJSONString(responseHolder.getModel()); this.returnJson(response,json); responseHolder.clean(); } private void returnJson(HttpServletResponse response, String json) throws Exception{ PrintWriter writer = null; response.setCharacterEncoding("UTF-8"); response.setContentType("text/html; charset=utf-8"); try { writer = response.getWriter(); writer.print(json); } catch (IOException e) { logger.error("response error",e); } finally { if (writer != null) writer.close(); } } }
spring提供了攔截器HandlerInterceptorAdapter對應提供了三個preHandle,postHandle,afterCompletion方法。preHandle在業務處理器處理請求之前被呼叫,
postHandle在業務處理器處理請求執行完成後,生成檢視之前執行,afterCompletion在DispatcherServlet完全處理完請求後被呼叫,可用於清理資源等 。
攔截器定義完成後,不配置是不起作用的,傳統的spring專案通過XML檔案配置,spring—boot是為了實現無XML配置,所以可以通過如下方式新增,
@Configuration public class WebAppConfig extends org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter { @Autowired private ResponseInterceptor responseInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(responseInterceptor).addPathPatterns("/**").excludePathPatterns("/identifyCode/generate"); } }
這裡可是整個攔截器的核心,通過實現addInterceptors介面,我們可以新增自己想加的攔截器,也能配置特殊不需要攔截的介面。程式碼雖簡單,但值得細細揣摩,也有許多可優化的地方!