1. 程式人生 > >spring攔截器攔截request與response業務資料

spring攔截器攔截request與response業務資料

來源:http://blog.csdn.net/u013979547/article/details/53449788

Controller層的作用是處理業務邏輯並返回資料,那怎麼返回資料呢?介面的請求通過HttpServletRequest和HttpServletResponse實現前後端的互動,ServletResponse中有一個getWriter()方法獲取到一個PrintWriter物件,通過PrintWriter的.print()方法即可將資料通過HttpServletResponse傳遞給前端。

      首先定義一個返回資料的module,

public class ResponseModel {
    public static final int 
SUCCESS
= 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;     }     public
ResponseModel 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介面,我們可以新增自己想加的攔截器,也能配置特殊不需要攔截的介面。程式碼雖簡單,但值得細細揣摩,也有許多可優化的地方!