重溫java web過濾器filter

1殴瘦、Filter是什么?

Filter 技術(shù)是servlet 2.3 新增加的功能。Filter翻譯過來的意思就是過濾器敛惊,能對客戶端的消息進(jìn)行預(yù)處理,然后將請求轉(zhuǎn)發(fā)給其它的web組件绰更,可以對ServletHttpRequest和ServletHttpResponse進(jìn)行修改和檢查瞧挤。例如:在Filter中可以檢查用戶是否登錄锡宋,對未登錄的用戶跳轉(zhuǎn)到登陸界面。

2特恬、過濾器快速入門

要定義一個(gè)過濾器执俩,則需要實(shí)現(xiàn)javax.servlet.Filter接口,一個(gè)過濾器中包含了三個(gè)與生命周期相關(guān)的方法:

void init(FilterConfig? config)? 過濾器初始化時(shí)執(zhí)行癌刽,F(xiàn)ilterConfig 可以用來獲取過濾器的初始化參數(shù)役首。

void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

過濾器過濾請求時(shí)執(zhí)行,包含了request和response妒穴,chain用來是否執(zhí)行下一步請求宋税。

destroy()?? web容器(tomcat)停止時(shí)執(zhí)行

??? 第一步:創(chuàng)建DemoFilter.java

packagecn.zq.filter;importjava.io.IOException;

importjavax.servlet.Filter;

importjavax.servlet.FilterChain;

importjavax.servlet.FilterConfig;

importjavax.servlet.ServletException;

importjavax.servlet.ServletRequest;

importjavax.servlet.ServletResponse;

publicclassDemoServletimplementsFilter{

publicvoidinit(FilterConfig config)throwsServletException{System.out.println("DemoServlet.init...");}publicvoiddoFilter(ServletRequest req, ServletResponse resp, FilterChain chain)throwsIOException, ServletException{

System.out.println("DemoServlet.doFilter..."); ? ? ? ? ? ? ? ?System.out.println("this = "+this); ? ? ? ?}publicvoiddestroy(){System.out.println("DemoServlet.destroy...");}}

第二步:在web.xml文件中添加如下配置:

democn.zq.filter.DemoServletdemo/*

url-pattern配置為/*,表示過濾所有請求讼油。

啟動(dòng)tomcat杰赛,可以看到如下輸出:

說明Filter的init方法在web容器啟動(dòng)的時(shí)候執(zhí)行,讀者可以自行驗(yàn)證destroy()方法會(huì)在web容器停止時(shí)執(zhí)行矮台,訪問主頁:

在訪問主頁的時(shí)候?yàn)g覽器是一片空白的乏屯,控制臺輸出上面的消息,F(xiàn)ilter只會(huì)實(shí)例化一次瘦赫,為什么我們訪問不到我們要訪問的內(nèi)容呢辰晕?只需要在doFilter方法中加入如下的語句就可以了:

chain.doFilter(req, resp);

FilterChain(過濾器鏈)是用來干什么的呢?這個(gè)對象只包含一個(gè)void doFilter(ServletRequest request, ServletResponse response)方法确虱,F(xiàn)ilter調(diào)用此方法去調(diào)用下一個(gè)web組件(Filter,Servlet等)含友,如果不調(diào)用此方法,那么下一個(gè)web組件不會(huì)被執(zhí)行校辩。

再放行之前窘问,我們可以在Filter中設(shè)置響應(yīng)頭信息,如下:

resp.setContentType("text/html;charset=UTF-8");?? ??? ?chain.doFilter(req, resp);

過濾器的過濾過程如下:

過濾器中的各項(xiàng)配置:

配置初始化參數(shù):

democn.zq.filter.DemoServletencodingUTF-8nameRiccioZhangdemo/*

然后在init方法中獲纫酥洹:

publicvoidinit(FilterConfig config)throwsServletException{System.out.println("DemoServlet.init...");String encoding = config.getInitParameter("encoding");String name = config.getInitParameter("name");System.out.println("encoding="+encoding);System.out.println("name="+name);}

<!-- filter的名字 -->demo<!-- 類名 -->cn.zq.filter.DemoServlet<!-- 可以有多個(gè) --><!-- 對哪個(gè)filter進(jìn)行配置 -->demo<!-- ?? 配置過濾的url惠赫,不能是/ ? 其他與servlet配置類似 ? -->/*<!--

? 根據(jù)名字配置對哪個(gè)servlet進(jìn)行過濾

? -->DemoServlet<!--

? ERROR: <error-page>過來的請求

? FORWARD: 對轉(zhuǎn)發(fā)過來的請求進(jìn)行過濾,也就是對request.getRequestDispatcher(path).forward(request, response)

? INCLUDE:對request.getRequestDispatcher(path).include(request, response)過來的請求進(jìn)行過濾

? REQUEST(默認(rèn)): 對客戶端的請求進(jìn)行攔截

? 可以配置多個(gè)

? -->ERROR

3故黑、Filter的應(yīng)用

為了便于編寫Filter儿咱,本節(jié)的所有應(yīng)用中提供了一個(gè)通過的Filter的實(shí)現(xiàn):

packagecn.zq.filter;

importjava.io.IOException;

importjava.io.Serializable;

importjava.util.Enumeration;

importjavax.servlet.Filter;

importjavax.servlet.FilterChain;

importjavax.servlet.FilterConfig;

importjavax.servlet.ServletContext;

importjavax.servlet.ServletException;

importjavax.servlet.ServletRequest;

importjavax.servlet.ServletResponse;

/** * 通用的Filter的實(shí)現(xiàn) *

@authorzq

*

*/

publicabstractclassGenericFilterimplementsFilter,FilterConfig,Serializable{privatestaticfinallongserialVersionUID =5497978960987185665L;

? ? ? ?privateFilterConfig filterConfig;/**

* 需要初始化,應(yīng)該覆蓋整個(gè)方法

*/publicvoidinit(){}publicvoidinit(FilterConfig filterConfig)throwsServletException{this.filterConfig = filterConfig;init();}

abstractpublicvoiddoFilter(ServletRequest request, ServletResponse response,

FilterChain chain)throwsIOException, ServletException;publicvoiddestroy(){}

publicStringgetFilterName(){returngetFilterConfig().getFilterName();}

publicStringgetInitParameter(String name){

returngetFilterConfig().getInitParameter(name);}

publicEnumerationgetInitParameterNames(){

returngetFilterConfig().getInitParameterNames();}

publicServletContextgetServletContext(){returngetFilterConfig().getServletContext();}publicFilterConfiggetFilterConfig(){returnfilterConfig;}}

packagecn.zq.filter;

importjava.io.IOException;

importjavax.servlet.FilterChain;

importjavax.servlet.ServletException;

importjavax.servlet.ServletRequest;

importjavax.servlet.ServletResponse;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

publicabstractclassHttpFilterextendsGenericFilter{

privatestaticfinallongserialVersionUID =1029993995265394412L;

publicvoiddoFilter(ServletRequest request, ServletResponse response, FilterChain chain)throwsIOException, ServletException{HttpServletRequest req = (HttpServletRequest) request;HttpServletResponse resp = (HttpServletResponse) response;doFilter(req, resp, chain);}protectedabstractvoiddoFilter(HttpServletRequest request, HttpServletResponse response,

FilterChain chain)throwsIOException, ServletException;}

3.1场晶、解決GET和POST獲取參數(shù)的亂碼問題

第一步:創(chuàng)建Filter

packagecn.zq.filter;

importjava.io.IOException;

importjava.io.UnsupportedEncodingException;

importjava.util.Iterator;

importjava.util.Map;

importjavax.servlet.FilterChain;

importjavax.servlet.ServletException;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletRequestWrapper;

importjavax.servlet.http.HttpServletResponse;

/**

* 處理字符編碼的Filter

*@authorzq

*

*/

publicclassCharacterEncodingFilterextendsHttpFilter{

? ? ? ?privatestaticfinallongserialVersionUID = -4329981031091311164L;privateString characterEncoding ="UTF-8";publicvoidinit(){String ce = getInitParameter("characterEncoding");if(ce !=null&& !ce.equals("")){characterEncoding = ce.toUpperCase();}}publicvoiddoFilter(HttpServletRequest request,

HttpServletResponse response, FilterChain chain)throwsIOException, ServletException{request.setCharacterEncoding(characterEncoding);response.setContentType("text/html;charset="+characterEncoding);//優(yōu)化:只對GET請求的request進(jìn)行包裝if(request.getMethod().equals("GET")){request =newParameterHandlerRequest(request);}chain.doFilter(request, response);}privateclassParameterHandlerRequestextendsHttpServletRequestWrapper{publicParameterHandlerRequest(HttpServletRequest request){super(request);}publicStringgetParameter(String name){String value =super.getParameter(name);returngetString(value);}privateStringgetString(String value){if(value !=null){try{value =newString( value.getBytes("ISO-8859-1"), getRequest().getCharacterEncoding() );}catch(UnsupportedEncodingException e) {e.printStackTrace();}}returnvalue;}publicString[] getParameterValues(String name) {String[] values =super.getParameterValues(name);if(null!= values){for(inti =0; i < values.length; i++){values[i] = getString(values[i]);}}returnvalues;}publicMap getParameterMap() {Map paramMap =super.getParameterMap();Iterator it = paramMap.values().iterator();while(it.hasNext()){String[] values = it.next();if(null!= values){for(inti =0; i < values.length; i++){values[i] = getString(values[i]);}}}returnparamMap;}}}

第二步:編寫配置文件

CharacterEncodingFiltercn.zq.filter.CharacterEncodingFilterCharacterEncodingFilter/*

這個(gè)過濾器應(yīng)該配置在所有過濾器的前面

第三步:測試

packagecn.zq.servlet;

importjava.io.IOException;

importjava.util.Iterator;

importjava.util.Map;

importjavax.servlet.ServletException;

importjavax.servlet.http.HttpServlet;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

publicclassDemoServletextendsHttpServlet{privatestaticfinallongserialVersionUID = -4363281555738840730L;publicvoiddoGet(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException{?? ??? ?doPost(request, response);?? ?}publicvoiddoPost(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException{?? ??? ?System.out.println("--------"+request.getMethod()+"--------");?? ??? ?System.out.println("request = "+ request);?? ??? ?System.out.println("name = "+ request.getParameter("name"));?? ??? ??? ??? ?String[] names = request.getParameterValues("name");if(names !=null&& names.length >0){?? ??? ??? ?System.out.println("names[0] = "+ names[0]);?? ??? ?}?? ??? ?Map parameterMap = request.getParameterMap();for(Iterator it = parameterMap.keySet().iterator();?? ??? ??? ??? ?it.hasNext();){?? ??? ??? ?String key = it.next();?? ??? ??? ?String[] values = parameterMap.get(key);?? ??? ??? ?System.out.println(key+"="+values[0] );?? ??? ?}?? ?}}

DemoServletcn.zq.servlet.DemoServletDemoServlet/servlet/DemoServlet

<%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%><%Stringpath=request.getContextPath();StringbasePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">My JSP 'index.jsp' starting page<!--

<link rel="stylesheet" type="text/css" href="styles.css">

-->Click

訪問并測試:

這個(gè)過濾器應(yīng)該被配置在所有過濾器的前面混埠,就能解決全站的亂碼了,這樣就不用重復(fù)的編寫解決亂碼問題的代碼了诗轻。

3.2钳宪、設(shè)置所有的jsp頁面不緩存

因?yàn)閖sp頁面的有些內(nèi)容是動(dòng)態(tài)生成的,所有混成jsp頁面的意義不大,我們通常會(huì)設(shè)置這些jsp頁面不緩存使套。

第一步:開發(fā)Filter

packagecn.zq.filter;

importjava.io.IOException;

importjavax.servlet.FilterChain;

importjavax.servlet.ServletException;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

publicclassDynamicPageCacheFilterextendsHttpFilter{/** * */privatestaticfinallongserialVersionUID = -5449451659530735173L;publicvoiddoFilter(HttpServletRequest request,

HttpServletResponse response, FilterChain chain)throwsIOException, ServletException{//設(shè)置3個(gè)響應(yīng)頭response.setHeader("pragma","no-cache");response.setHeader("cache-control","no-cache");response.setDateHeader("expires",0);chain.doFilter(request, response);}}

第二步:配置web.xml

DynamicPageCacheFiltercn.zq.filter.DynamicPageCacheFilterDynamicPageCacheFilter*.jspREQUESTFORWARDINCLUDE

第三步:打開ie,清空所有的緩存鞠柄,cookie侦高,訪問本項(xiàng)目的jsp文件看是否有緩存文件,將Filter拿到厌杜,再訪問看是否有緩存文件奉呛。

控制是否緩存,也可以在jsp頁面中加入這幾個(gè)頭

3.3夯尽、控制靜態(tài)頁面緩存(如html瞧壮,圖片)

第一步:編寫Filter

packagecn.zq.filter;

importjava.io.IOException;

importjava.util.Calendar;

importjavax.servlet.FilterChain;

importjavax.servlet.ServletException;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

publicclassStaticContentCacheFilterextendsHttpFilter{/** * */privatestaticfinallongserialVersionUID =7660878144738222823L;@OverridepublicvoiddoFilter(HttpServletRequest request,

HttpServletResponse response, FilterChain chain)throwsIOException, ServletException{/*

*讓圖片緩存一個(gè)月,html文件緩存一個(gè)星期 ,

*具體的相關(guān)信息可以通過配置文件來配置匙握。

*/String requestURI = request.getRequestURI();longtime =0;intday =0;if(requestURI.endsWith(".jpg")){day =30;}elseif(requestURI.endsWith(".html")){day =7;}Calendar calendar = Calendar.getInstance();calendar.add(Calendar.DATE, day);time = calendar.getTimeInMillis();response.setDateHeader("expires", time);chain.doFilter(request, response);}}

第二步:配置

StaticContentCacheFiltercn.zq.filter.StaticContentCacheFilterStaticContentCacheFilter*.html*.jpg

第三步:測試

請求資源咆槽,再次請求。查看狀態(tài)碼為304圈纺,及緩存文件的日期為N天以后秦忿。這是返回的狀態(tài)碼:HTTP/1.1 304 Not Modified

3.4 驗(yàn)證用戶是否登錄

第一步:開發(fā)filter

packagecn.zq.filter;

importjava.io.IOException;

importjava.io.PrintWriter;

importjavax.servlet.FilterChain;

importjavax.servlet.ServletException;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

importjavax.servlet.http.HttpSession;

/**

* 驗(yàn)證用戶是否登錄的過濾器

*@authorRiccio Zhang

*

*/

publicclassLoginFilterextendsHttpFilter{

privatestaticfinallongserialVersionUID = -6363929637537263967L;

protectedvoiddoFilter(HttpServletRequest request,

HttpServletResponse response, FilterChain chain)throwsIOException, ServletException{HttpSession session = request.getSession();Object user = session.getAttribute("user");//沒有找到user,則說明用戶沒有登錄蛾娶,轉(zhuǎn)到登錄頁面讓用戶登錄if(user ==null){PrintWriter out = response.getWriter();out.print("<script>"+"alert('您還未登錄!');"+"window.location.href='"+request.getContextPath()+"/login.jsp'"+"</script>");return;}chain.doFilter(request, response);}}

第二步:開發(fā)登錄功能灯谣,配置web.xml

packagecn.zq.servlet;

importjava.io.IOException;

importjavax.servlet.ServletException;

importjavax.servlet.http.HttpServlet;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

publicclassLoginServletextendsHttpServlet{

privatestaticfinallongserialVersionUID =3059445154848670189L;publicvoiddoGet(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException{//讓用戶退出登錄request.getSession().invalidate();response.sendRedirect(request.getContextPath() +"/login.jsp");}

publicvoiddoPost(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException{/*

* 讓用戶登錄成功

*/String username = request.getParameter("username");if(username ==null|| username.length() ==0){request.setAttribute("msg","用戶名不能為空!");request.getRequestDispatcher("/login.jsp").forward(request, response);return;}request.getSession().setAttribute("user", username);//重定向到主頁response.sendRedirect(request.getContextPath() +"/page/index.jsp");}}

登錄頁面:/login.jsp

<%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%><%Stringpath=request.getContextPath();StringbasePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">My JSP 'login.jsp' starting page${requestScope.msg }username :

登錄成功跳轉(zhuǎn)頁面:/page/index.jsp

<%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%><%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%><%Stringpath=request.getContextPath();StringbasePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">My JSP 'index.jsp' starting page<!--

<link rel="stylesheet" type="text/css" href="styles.css">

-->歡迎你,
退出

<!-- 對/page/*進(jìn)行過濾 -->LoginFiltercn.zq.filter.LoginFilterLoginFilter/page/*DemoServlet/servlet/DemoServletLoginServlet/login

第三步:測試蛔琅,

在訪問/page/index.jsp頁面時(shí)胎许,未登錄是否會(huì)跳轉(zhuǎn)到登錄頁面。登錄時(shí)顯示用戶的名字罗售。

3.5辜窑、自動(dòng)登錄

自動(dòng)登錄是為了讓用戶下次訪問時(shí),不用輸入用戶名和密碼莽囤。將用戶的信息保存到cookie中谬擦,下次直接從cookie中取。

第一步:開發(fā)登錄頁面

<%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%><%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%><%Stringpath=request.getContextPath();StringbasePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">My JSP 'login.jsp' starting page${requestScope.msg }username :
自動(dòng)登錄不自動(dòng)登錄
1天
一個(gè)星期
一個(gè)月
歡迎您,
退出

第二步:開發(fā)登錄servlet

packagecn.zq.servlet;

importjava.io.IOException;

importjava.net.URLEncoder;

importjavax.servlet.ServletException;

importjavax.servlet.http.Cookie;

importjavax.servlet.http.HttpServlet;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

publicclassLoginServletextendsHttpServlet{/** * */privatestaticfinallongserialVersionUID =3059445154848670189L;

? ? ? ?publicvoiddoGet(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException{//讓用戶退出登錄request.getSession().invalidate();//刪除cookieCookie cookie =newCookie("autoLogin","");/**

* 0表示刪除文件和緩存

* -1表示刪除文件朽缎,但是還有緩存

*/cookie.setMaxAge(0);cookie.setPath("/");response.addCookie(cookie);response.sendRedirect(request.getContextPath() +"/login.jsp");}

publicvoiddoPost(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException{/*

* 讓用戶登錄成功

*/String username = request.getParameter("username");if(username ==null|| username.length() ==0){request.setAttribute("msg","用戶名不能為空惨远!");request.getRequestDispatcher("/login.jsp").forward(request, response);return;}intday =0;String auto = request.getParameter("day");try{day = Integer.parseInt(auto);}catch(Exception e) {}//對中文要進(jìn)行編碼Cookie cookie =newCookie("autoLogin", URLEncoder.encode(username, request.getCharacterEncoding()));cookie.setMaxAge(day*24*3600);cookie.setPath("/");response.addCookie(cookie);request.getSession().setAttribute("user", username);response.sendRedirect(request.getContextPath() +"/page/index.jsp");}}

DemoServlet/servlet/DemoServletLoginServlet/login

第三步:開發(fā)自動(dòng)登錄過濾器

packagecn.zq.filter;

importjava.io.IOException;

importjava.net.URLDecoder;

importjavax.servlet.FilterChain;

importjavax.servlet.ServletException;

importjavax.servlet.http.Cookie;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

importjavax.servlet.http.HttpSession;

publicclassAutoLoginFilterextendsHttpFilter{

privatestaticfinallongserialVersionUID =5891858915933022714L;

@OverridepublicvoiddoFilter(HttpServletRequest request,

HttpServletResponse response, FilterChain chain)throwsIOException, ServletException{/*

* 優(yōu)化:當(dāng)用戶手動(dòng)登錄或退出時(shí),就不需要自動(dòng)登錄话肖,

* 并且用戶已經(jīng)登錄北秽,也不需要自動(dòng)登錄,自動(dòng)登錄的代碼是

* 多此一舉

*/HttpSession session = request.getSession();String requestURI = request.getRequestURI();Object user = session.getAttribute("user");if(!requestURI.contains("/login") && user ==null){//獲取cookieCookie[] cookies = request.getCookies();if(cookies !=null){for(Cookie c : cookies){if("autoLogin".equals(c.getName())){String username = c.getValue();username = URLDecoder.decode(username, request.getCharacterEncoding());session.setAttribute("user", username);break;}}}}chain.doFilter(request, response);}}

AutoLoginFiltercn.zq.filter.AutoLoginFilterAutoLoginFilter/*

3.6最筒、過濾非法語句(臟話)

在過濾器中贺氓,包裝HttpServletRequest,修改getParameter方法

packagecn.zq.filter;

importjava.io.IOException;

importjava.util.Arrays;

importjava.util.List;

importjavax.servlet.FilterChain;

importjavax.servlet.ServletException;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletRequestWrapper;

importjavax.servlet.http.HttpServletResponse;

publicclassDirtyWordsFilterextendsHttpFilter{

privatestaticfinallongserialVersionUID = -5025789414017693051L;

publicvoiddoFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throwsIOException, ServletException{request =newMyHttpServletRequest(request);chain.doFilter(request, response);}}

class

MyHttpServletRequestextendsHttpServletRequestWrapper{List dirtyWords = Arrays.asList(newString[]{"SB","sb","傻B","2B"});publicMyHttpServletRequest(HttpServletRequest request){

? ? ? ? ? ?super(request);}publicStringgetParameter(String name){String value =super.getParameter(name);if(value !=null&& value.length() >0){for(String dw : dirtyWords){value = value.replaceAll(dw,"***");}}returnvalue;}}

3.7、全站壓縮

實(shí)現(xiàn)對輸出流的壓縮:

在tomcat將數(shù)據(jù)輸出到瀏覽器前床蜘,進(jìn)行壓縮辙培,可以減少傳送過去的數(shù)據(jù)蔑水,節(jié)約成本。如果在流量很少的情況下查看相同的內(nèi)容和樂而不為呢扬蕊?

思路:

在調(diào)用request.getOutputStream()或request.getWriter()時(shí)獲取自己的輸出流搀别,將數(shù)據(jù)寫到事先準(zhǔn)備的緩沖中。

在輸出完成后獲取我們自己的緩沖數(shù)據(jù)

然后在對緩沖的數(shù)據(jù)進(jìn)行壓縮尾抑,在過濾器中將數(shù)據(jù)傳輸給瀏覽器

第一步:編寫壓縮數(shù)據(jù)的過濾器

packagecn.zq.filter;

importjava.io.ByteArrayOutputStream;

importjava.io.IOException;

importjava.io.OutputStreamWriter;

importjava.io.PrintWriter;

importjava.util.zip.GZIPOutputStream;

importjavax.servlet.FilterChain;

importjavax.servlet.ServletException;

importjavax.servlet.ServletOutputStream;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

importjavax.servlet.http.HttpServletResponseWrapper;

publicclassGzipFilterextendsHttpFilter{

privatestaticfinallongserialVersionUID =3410826595861585118L;publicvoiddoFilter(HttpServletRequest request,

HttpServletResponse response, FilterChain chain)throwsIOException, ServletException{String ac = request.getHeader("Accept-Encoding");//支持gzip壓縮if(ac !=null&& ac.toLowerCase().indexOf("gzip") != -1){BufferedHttpServletResponse bRes =newBufferedHttpServletResponse(response);chain.doFilter(request, bRes);byte[] data = bRes.getData();System.out.println("->壓縮前數(shù)據(jù)大行浮:"+ data.length);ByteArrayOutputStream bos =newByteArrayOutputStream();GZIPOutputStream gout =newGZIPOutputStream(bos);gout.write(data);gout.close();byte[] compressedData = bos.toByteArray();System.out.println("->壓縮后的數(shù)據(jù)大小:"+compressedData.length);//設(shè)置頭信息response.setContentLength(compressedData.length);response.setHeader("Content-Encoding","gzip");ServletOutputStream out = response.getOutputStream();out.write(compressedData);}else{chain.doFilter(request, response);}}}

classBufferedHttpServletResponseextendsHttpServletResponseWrapper{privateByteArrayOutputStream buf =newByteArrayOutputStream();

? ? ? ?privatePrintWriter pw;

publicBufferedHttpServletResponse(HttpServletResponse response){

super(response);}publicPrintWritergetWriter()throwsIOException{ ? ?pw =newPrintWriter(newOutputStreamWriter(buf, getResponse().getCharacterEncoding()));returnpw;}

publicServletOutputStreamgetOutputStream()throwsIOException{ServletOutputStream sos =newServletOutputStream() {publicvoidwrite(intb)throwsIOException{buf.write(b);}};returnsos;}

publicbyte[] getData(){if(pw !=null){pw.close();}returnbuf.toByteArray();}}

第二步:配置對所有的jsp進(jìn)行壓縮

GzipFiltercn.zq.filter.GzipFilterGzipFilterDemoServlet*.jsp

第三步:測試壓縮過濾器

使用壓縮過濾器應(yīng)該注意:應(yīng)該只用這個(gè)壓縮過濾器對文本進(jìn)行壓縮再愈,例如jsp,html,css,js等進(jìn)行壓縮榜苫,對視頻和圖片的壓縮率很低,不要用來壓縮視頻和圖片翎冲,如果是下載垂睬,那也不應(yīng)該用來壓縮,這樣不但壓縮率很低府适,而且還有可能讓服務(wù)器奔潰羔飞。

關(guān)于壓縮過濾器的優(yōu)化:

在doFilter方法中先將數(shù)據(jù)拿出來,然后放到GzipOutputStream中進(jìn)行壓縮檐春,然后得到壓縮后的字節(jié)再輸出給客戶端逻淌,這樣2次都得到了字節(jié),假如數(shù)據(jù)量較大疟暖,這2次都會(huì)占用較多的內(nèi)存卡儒,能不能從包裝的response拿出來時(shí)直接就是壓縮過后的數(shù)據(jù)呢?改造后的代碼如下:

packagecn.zq.filter;

importjava.io.ByteArrayOutputStream;

importjava.io.IOException;

importjava.io.OutputStreamWriter;

importjava.io.PrintWriter;

importjava.util.zip.GZIPOutputStream;

importjavax.servlet.FilterChain;

importjavax.servlet.ServletException;

importjavax.servlet.ServletOutputStream;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

importjavax.servlet.http.HttpServletResponseWrapper;

publicclassGzipFilterextendsHttpFilter{

privatestaticfinallongserialVersionUID =3410826595861585118L;publicvoiddoFilter(HttpServletRequest request,

HttpServletResponse response, FilterChain chain)throwsIOException, ServletException{String ac = request.getHeader("Accept-Encoding");//支持gzip壓縮if(ac !=null&& ac.toLowerCase().indexOf("gzip") != -1){BufferedHttpServletResponse bRes =newBufferedHttpServletResponse(response);chain.doFilter(request, bRes);byte[] compressedData = bRes.getData();//設(shè)置頭信息response.setContentLength(compressedData.length);response.setHeader("Content-Encoding","gzip");ServletOutputStream out = response.getOutputStream();out.write(compressedData);}else{chain.doFilter(request, response);}}}

classBufferedHttpServletResponseextendsHttpServletResponseWrapper{privateByteArrayOutputStream buf =newByteArrayOutputStream();

? ? ? ?privateGZIPOutputStream gout;

privatePrintWriter pw;

publicBufferedHttpServletResponse(HttpServletResponse response)throwsIOException{super(response);gout =newGZIPOutputStream(buf);}publicPrintWritergetWriter()throwsIOException{ ? ?pw =newPrintWriter(newOutputStreamWriter(gout, getResponse().getCharacterEncoding()));returnpw;}

publicServletOutputStreamgetOutputStream()throwsIOException{ServletOutputStream sos =newServletOutputStream() {publicvoidwrite(intb)throwsIOException{gout.write(b);}};returnsos;}

publicbyte[] getData()throwsIOException{if(pw !=null){pw.close();}gout.close();returnbuf.toByteArray();}}

4.總結(jié)

利用Filter能對請求和響應(yīng)進(jìn)行預(yù)處理俐巴,在到達(dá)目標(biāo)組件之前骨望,對強(qiáng)求進(jìn)行處理,諸如:對請求頭和響應(yīng)頭進(jìn)行處理欣舵。充分的利用了包裝器設(shè)計(jì)模式擎鸠,對request或response進(jìn)行包裝,對其方法進(jìn)行增強(qiáng)缘圈。假如我們拒絕某個(gè)請求劣光,就可以寫一個(gè)過濾器對不希望的請求不放行,即不執(zhí)行chain.doFilter(request, response)方法糟把,過濾器能幫助我們干很多的事情绢涡。

作者:RiccioZhang

出處:https://blog.csdn.net/ricciozhang/article/details/43833401

源網(wǎng)絡(luò),版權(quán)歸原創(chuàng)者所有遣疯。如有侵權(quán)煩請告知雄可,我們會(huì)立即刪除并表示歉意。


更多技術(shù),歡迎關(guān)注下方公眾號

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末数苫,一起剝皮案震驚了整個(gè)濱河市聪舒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌虐急,老刑警劉巖过椎,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異戏仓,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)亡鼠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門赏殃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人间涵,你說我怎么就攤上這事仁热。” “怎么了勾哩?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵抗蠢,是天一觀的道長。 經(jīng)常有香客問我思劳,道長迅矛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任潜叛,我火速辦了婚禮秽褒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘威兜。我一直安慰自己销斟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布椒舵。 她就那樣靜靜地躺著蚂踊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪笔宿。 梳的紋絲不亂的頭發(fā)上犁钟,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機(jī)與錄音措伐,去河邊找鬼特纤。 笑死,一個(gè)胖子當(dāng)著我的面吹牛侥加,可吹牛的內(nèi)容都是我干的捧存。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼昔穴!你這毒婦竟也來了镰官?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤吗货,失蹤者是張志新(化名)和其女友劉穎泳唠,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宙搬,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡笨腥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了勇垛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脖母。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖闲孤,靈堂內(nèi)的尸體忽然破棺而出谆级,到底是詐尸還是另有隱情,我是刑警寧澤讼积,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布肥照,位于F島的核電站,受9級特大地震影響勤众,放射性物質(zhì)發(fā)生泄漏舆绎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一们颜、第九天 我趴在偏房一處隱蔽的房頂上張望亿蒸。 院中可真熱鬧,春花似錦掌桩、人聲如沸边锁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茅坛。三九已至,卻和暖如春则拷,著一層夾襖步出監(jiān)牢的瞬間贡蓖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工煌茬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留斥铺,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓坛善,卻偏偏與公主長得像晾蜘,于是被迫代替她去往敵國和親邻眷。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容