過濾器(Filter)的概念
- 過濾器位於客戶端和web應用程序之間,用於檢查和修改兩者之間流過的請求和響應。
- 在請求到達Servlet/JSP之前,過濾器截獲請求。
- 在響應送給客戶端之前,過濾器截獲響應。
- 多個過濾器形成一個過濾器鏈,過濾器鏈中不同過濾器的先後順序由部署文件web.xml中過濾器映射<filter-mapping>的順序決定。
- 最先截獲客戶端請求的過濾器將最後截獲Servlet/JSP的響應信息。
源碼接口Filter
public interface Filter {
/**
* web容器調用本方法,說明過濾器正被加載到web容器中去。容器只有在實例化過濾器時纔會調用該方法一次。
* 容器爲這個方法傳遞一個FilterConfig對象,其中包含與Filter相關的配置信息。
*
* @param filterConfig
* @throws ServletException
*/
default void init(FilterConfig filterConfig) throws ServletException {
}
/**
* 每當請求和響應經過過濾器鏈時,容器都要調用一次該方法。需要注意的是過濾器的一個實例可以同時服務於多個請求,
* 特別需要注意線程同步問題,儘量不用或少用實例變量。 在過濾器的doFilter()方法實現中,任何出現在FilterChain
* 的doFilter方法之前地方,request是可用的;在doFilter()方法之後response是可用的。
*
* @param var1
* @param var2
* @param var3
* @throws IOException
* @throws ServletException
*/
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
/**
* 容器調用destroy()方法指出將從服務中刪除該過濾器。如果過濾器使用了其他資源,需要在這個方法中釋放這些資源。
*/
default void destroy() {
}
}
自定義實現Filter
public class BTCFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
//過濾器的鏈式結構;可以爲一個Web應用組件部署多個過濾器,這些過濾器組成一個過濾器鏈,
// 每個過濾器只執行某個特定的操作或者檢查。這樣請求在到達被訪問的目標之前,需要經過這個過濾器鏈。
chain.doFilter(request, response);
}
}
自定義一個響應結果包裝器,將在這裏提供一個基於內存的輸出器來存儲所有返回給客戶端的原始HTML代碼。
public class ResponseWrapper extends HttpServletResponseWrapper {
private PrintWriter cachedWriter;
private CharArrayWriter bufferedWriter;
public ResponseWrapper(HttpServletResponse response) {
super(response);
// 這個是我們保存返回結果的地方
bufferedWriter = new CharArrayWriter();
// 這個是包裝PrintWriter的,讓所有結果通過這個PrintWriter寫入到bufferedWriter中
cachedWriter = new PrintWriter(bufferedWriter);
}
@Override
public PrintWriter getWriter(){
return cachedWriter;
}
public String getResult() {
//獲取原始的HTML頁面內容
return bufferedWriter.toString();
}
}
使用自定義的響應包裝器
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
// 使用我們自定義的響應包裝器來包裝原始的ServletResponse
ResponseWrapper wrapper = new ResponseWrapper((HttpServletResponse) response);
// 這句話非常重要,注意看到第二個參數是我們的包裝器而不是response
chain.doFilter(request, wrapper);
// 處理截獲的結果並進行處理,比如替換所有的“名稱”爲“自定義的名字”
String result = wrapper.getResult();
result = result.replace("名稱", "替換後的");
// 輸出最終的結果
PrintWriter out = response.getWriter();
out.write(result);
out.flush();
out.close();
}
設置Filter過濾/user/路徑的請求
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean registrationBean=new FilterRegistrationBean();
registrationBean.setFilter(new BTCFilter());
List<String> urlPatterns=new ArrayList<String>();
urlPatterns.add("/user/*");
registrationBean.setUrlPatterns(urlPatterns);
return registrationBean;
}