javaweb 中的过滤器 包装器
請求過濾器:完畢安全檢查,又一次格式化請求首部或體。建立請求審計或日志
響應(yīng)過濾器:
?? ?壓縮響應(yīng)流,追加或改動響應(yīng)流創(chuàng)建一個全然不同的響應(yīng).
過濾器和servlet三個相似地方:
1.容器知道過濾器的api,過濾器api的其他成員能夠訪問ServletContext 還能夠與其他過濾器鏈接
2.容器管理過濾器的生命周期,過濾器有init和destroy方法。還有doFilter方法
3.web應(yīng)用能夠有非常多過濾器。須要在配置文件里配置
過濾器的生命周期
init 容器實例化一個過濾器時。在init方法中完畢調(diào)用過濾器之前全部的初始化任務(wù)。
保存filterConfig對象
的一個引用,以備過濾去以后使用.
其次調(diào)用 doFIlter 能夠保存username記錄到一個文件里,壓縮響應(yīng)輸出。
最后destroy刪除一個過濾器實例,
FilterChain的doFIlter 方法要負責明白接下來調(diào)用誰的doFilter放大,假設(shè)到達鏈尾,則要確定調(diào)用哪個servlet的service方法。
在配置文件里確定過濾器的順序
在配置文件里做三件事
1.聲明過濾器
2.將過濾器映射到你想過濾的web資源
3,組織這些映射,創(chuàng)建過濾器調(diào)用序列
聲明過濾器
<filter>
? ?? ?<filter-name>BeerRequest</filter-name>
? ?? ?<filter-class>com.gac.test.BeerRequestFilter</filter-class>
? ?? ?<init-param>
? ?? ??? ?<param-name>LogFileName</param-name>
? ?? ??? ?<param-value>UserLog.txt</param-value>
? ?? ?</init-param>
? </filter>
? 聲明url模式的過濾器映射
? <filter-mapping>
? ?? ?<filter-name>BeerRequest</filter-name>
? ?? ?<url-pattern>*.do</url-pattern>
? </filter-mapping>
聲明相應(yīng)servlet名的過濾器映射
?<filter-mapping>
? ?? ?<filter-name>BeerRequest</filter-name>
? ?? ?<servlet-name>AdviceServlet</servlet-name>
? </filter-mapping>
? 為通過請求分派請求的web資源聲明一個過濾器映射
?<filter-mapping>
? ?? ?<filter-name>MonitorFilter</filter-name>
? ?? ?<url-pattern>*.do</url-pattern>
?? ?<dispatcher>REQUEST</dispatcher>
?? ?和/或
?? ?<dispatcher>INCLUDE</dispatcher>
?? ?和/或
?? ?<dispatcher>FORWARD</dispatcher>
?? ?和/或
?? ?<dispatcher>ERRO</dispatcher>
? </filter-mapping>
聲明規(guī)則:
必需要有filter-name
必需要有url-pattern或servlet-name元素當中之中的一個
能夠有0-4個dispatcher
Request值表示對client請求啟用過濾器,假設(shè)沒有指定<dispatcher>元素。則默覺得
Rquest
INCLUDE值表示對由一個include()調(diào)用分派來的請求啟用過濾器
FORWARD值表示對一個由forward()調(diào)用分派來的請求啟用過濾器
ERROR值表示對錯誤處理調(diào)用資源啟用過濾器
過濾器請求路徑樣例
<filter-mapping>
?? ?<filter-name>Filter1</filter-name>????????????????????????? ?
?? ?<url-pattern>/Recipes/*<url-pattern>?????? /Recipes/HopsReport.do 過濾器序列 1 5
</filter-mapping>?? ??? ??? ??? ?? /Recipes/HopsList.do 過濾器 15 2?? ??? ??? ??? ??? ??? ??? ??? ??? ?
<filter-mapping>?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ?<filter-name>Filter2</filter-name>????????? /Recipes/Modify/ModRecipes.do 過濾器 1 5 4
?? ?<url-pattern>/Recipes/HopsList.do<url-pattern>? /HopsList.do 過濾器 5
</filter-mapping>
<filter-mapping>???????????????????????????????????????? /Recipes/Add/AddRecipes.do 過濾器 1 3 5
?? ?<filter-name>Filter3</filter-name>
?? ?<url-pattern>/Recipes/Add/*<url-pattern>
</filter-mapping>
<filter-mapping>
?? ?<filter-name>Filter4</filter-name>
?? ?<url-pattern>/Recipes/Modify/ModRecipes.do<url-pattern>
</filter-mapping>
<filter-mapping>
?? ?<filter-name>Filter5</filter-name>
?? ?<url-pattern>/*<url-pattern>
</filter-mapping>
/**************************************************************/
//過濾器必須實現(xiàn)Filter接口
public class BeerRequestFilter implements Filter{
?? ?private FilterConfig fc;
?? ?//完畢清理工作
?? ?@Override
?? ?public void destroy() {
?? ??? ?// TODO Auto-generated method stub
?? ??? ?
?? ?}
?? ?//詳細的業(yè)務(wù)邏輯
?? ?@Override
?? ?public void doFilter(ServletRequest req, ServletResponse resp,
?? ??? ??? ?FilterChain chain) throws IOException, ServletException {
?? ??? ?// TODO Auto-generated method stub
?? ??? ?HttpServletRequest httpReq = (HttpServletRequest) req;//能夠?qū)⒄埱蠛晚憫?yīng)對象強制轉(zhuǎn)換為Http類型
?? ??? ?String name = httpReq.getRemoteUser();
?? ??? ?if(name != null){
?? ??? ??? ?fc.getServletContext().log("User"+name +"is updating");
?? ??? ?}
?? ??? ?chain.doFilter(req, resp);//接下來要調(diào)用的過濾器或者servlet
?? ??? ?
?? ?}
?? ?//必須實現(xiàn)init 通常只在當中保存配置config對象
?? ?@Override
?? ?public void init(FilterConfig config) throws ServletException {
?? ??? ?// TODO Auto-generated method stub
?? ??? ?this.fc = config;
?? ?}
}
/***************************************************************/
為過濾器壓縮數(shù)據(jù)響應(yīng)為了不實現(xiàn)太多的函數(shù)降低復雜性能夠利用包裝器。
利用包裝器的演示樣例
public class CompressFilter implements Filter{
?? ?private ServletContext ctx;
?? ?private FilterConfig cfg;
?? ?@Override
?? ?public void destroy() {
?? ??? ?// TODO Auto-generated method stub
?? ??? ?cfg = null;
?? ??? ?ctx = null;
?? ?}
?? ?
?? ?//這個過濾器核心是用裝飾包裝響應(yīng)對象,他用一個壓縮的IO流包裝輸出流.
?? ?//當且僅當客戶包括一個Accept-Encoding首部 才會完畢輸出流壓縮
?? ?@Override
?? ?public void doFilter(ServletRequest request, ServletResponse response,
?? ??? ??? ?FilterChain chain) throws IOException, ServletException {
?? ??? ?// TODO Auto-generated method stub
?? ??? ?HttpServletRequest req = (HttpServletRequest)request;
?? ??? ?HttpServletResponse resp? =(HttpServletResponse) response;
?? ??? ?
?? ??? ?String valid_encodings = req.getHeader("Accept-Encoding");//客戶是否接收gzip壓縮
?? ??? ?if( valid_encodings.indexOf("gzip") > -1 ){
?? ??? ??? ?ComPressResponseWrapper wrappedResp = new ComPressResponseWrapper(resp);
?? ??? ??? ?wrappedResp.setHeader("Content-Encoding","gzip");
?? ??? ??? ?chain.doFilter(req, wrappedResp);
?? ??? ??? ?
?? ??? ??? ?GZIPOutputStream gzos = wrappedResp.getGZIPOutputStream();
?? ??? ??? ?gzos.finish();
?? ??? ??? ?ctx.log(cfg.getFilterName()+": finished the request. ");
?? ??? ??? ?
?? ??? ?}else{
?? ??? ??? ?ctx.log(cfg.getFilterName()+": no encoding performed.");
?? ??? ?}
?? ?}
?? ?//init方法保存配置對象,并保存servlet上下文對象的一個直接引用 以便完畢日志記錄
?? ?@Override
?? ?public void init(FilterConfig filterConfig) throws ServletException {
?? ??? ?// TODO Auto-generated method stub
?? ??? ?this.cfg = filterConfig;
?? ??? ?ctx = cfg.getServletContext();
?? ??? ?ctx.log(cfg.getFilterName()+" initialized.");
?? ?}
}
public class ComPressResponseWrapper extends HttpServletResponseWrapper{
?? ?private GZIPServletOutputStream servletGzipOS = null;//servlet響應(yīng)的壓縮輸出流
?? ?private PrintWriter pw = null;
?? ?
?? ?public ComPressResponseWrapper(HttpServletResponse response) {
?? ??? ?super(response);
?? ??? ?// TODO Auto-generated constructor stub
?? ?}
?? ?
?? ?public void setContentLength(int len){}
?? ?
?? ?/*過濾器使用這個裝飾器的方法壓縮過濾器提供一個GZIP輸出流的句柄,以便過濾器完畢和刷新輸出GZIP流*/
?? ?public GZIPOutputStream getGZIPOutputStream(){
?? ??? ?return this.servletGzipOS.internalGzipOS;
?? ??? ?
?? ?}
?? ?
?? ?private Object streamUsed = null;//同意訪問所裝飾的servlet輸出流
?? ?public ServletOutputStream getOutputStream()throws IOException{
?? ??? ?//僅當servlet還沒有訪問打印書寫器時 同意servlet訪問servlet輸出流
?? ??? ??? ?if((null != streamUsed) && (streamUsed!=pw)){
?? ??? ??? ??? ?throw new IllegalStateException();
?? ??? ??? ?}
?? ??? ??? ?
?? ??? ??? ?//用我們的壓縮輸出流包裝原來的servlet輸出流
?? ??? ??? ?if(servletGzipOS == null){
?? ??? ??? ??? ?servletGzipOS =
?? ??? ??? ??? ??? ??? ?new GZIPServletOutputStream(getResponse().getOutputStream());
?? ??? ??? ??? ?
?? ??? ??? ??? ?streamUsed = servletGzipOS;
?? ??? ??? ?}
?? ??? ??? ?return servletGzipOS;
?? ?}
?? ?
?? ?//執(zhí)行訪問所裝飾的打印書寫器
?? ?public PrintWriter getWriter() throws IOException{
?? ??? ?if((streamUsed != null) && (streamUsed != servletGzipOS)){
?? ??? ??? ?throw new IllegalStateException();
?? ??? ?}
?? ??? ?if(pw == null){
?? ??? ??? ?servletGzipOS =
?? ??? ??? ??? ??? ?new GZIPServletOutputStream(getResponse().getOutputStream());
?? ??? ??? ?OutputStreamWriter osw =
?? ??? ??? ??? ??? ?new OutputStreamWriter(servletGzipOS,getResponse().getCharacterEncoding());
?? ??? ??? ?pw = new PrintWriter(osw);
?? ??? ??? ?streamUsed = pw;
?? ??? ?}
?? ??? ?return pw;
?? ?}
}
class GZIPServletOutputStream extends ServletOutputStream{
?? ?/*internalGzipOs保存對原始Gzip流的一個引用。這個實例變量在包范圍內(nèi)私有,所以響應(yīng)包裝器能夠訪問這個變量*/
?? ?GZIPOutputStream internalGzipOS;
?? ?//裝飾器構(gòu)造函數(shù)
?? ?GZIPServletOutputStream(ServletOutputStream sos) throws IOException{
?? ??? ?this.internalGzipOS = new GZIPOutputStream(sos);
?? ?}
?? ?//這種方法把write調(diào)用托付給GZIP壓縮流 從而實現(xiàn)壓縮裝飾 GZIP壓縮流包裝了原來的ServletOutputStream
?? ?@Override
?? ?public void write(int b) throws IOException {
?? ??? ?// TODO Auto-generated method stub
?? ??? ?internalGzipOS.write(b);
?? ?}
}
轉(zhuǎn)載于:https://www.cnblogs.com/clnchanpin/p/6852725.html
總結(jié)
以上是生活随笔為你收集整理的javaweb 中的过滤器 包装器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2017/5 JavaScript基础4
- 下一篇: 11.python并发入门(part8