在filter中可以得到代表用户请求和响应的request、response对象,因此在编程中可以使用Decorator(装饰器)模式对request、response对象进行包装,再把包装对象传给目标资源,从而实现一些特殊需求。
一、Decorator设计模式
1.1、Decorator设计模式介绍
当某个对象的方法不适应业务需求时,通常有2种方式可以对方法进行增强:
- 编写子类,覆盖需增强的方法。
- 使用Decorator设计模式对方法进行增强。
-
使用代理
在阎宏博士的《JAVA与模式》一书中开头是这样描述装饰(Decorator)模式的:装饰模式又名包装(Wrapper)模式。装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
那么在实际应用中遇到需增强对象的方法时,到底选用哪种方式比较好呢?这个没有具体的定式,只能是根据具体的需求来采用具体的方式,不过有一种情况下,必须使用Decorator设计模式:即被增强的对象,开发人员只能得到它的对象,无法得到它的class文件。比如request、response对象,开发人员之所以在servlet中能通过sun公司定义的HttpServletRequest\response接口去操作这些对象,是因为Tomcat服务器厂商编写了request、response接口的实现类。web服务器在调用servlet时,会用这些接口的实现类创建出对象,然后传递给servlet程序。此种情况下,由于开发人员根本不知道服务器厂商编写的request、response接口的实现类是哪个?在程序中只能拿到服务器厂商提供的对象,因此就只能采用Decorator设计模式对这些对象进行增强。
1.2、Decorator设计模式的实现
1.首先看需要被增强对象继承了什么接口或父类,编写一个类也去继承这些接口或父类。
2.在类中定义一个变量,变量类型即需增强对象的类型。
3.在类中定义一个构造函数,接收需增强的对象。
4.覆盖需增强的方法,编写增强的代码。
二、使用Decorator设计模式增强request对象
Servlet API 中提供了一个request对象的Decorator设计模式的默认实现类HttpServletRequestWrapper,HttpServletRequestWrapper 类实现了request 接口中的所有方法,但这些方法的内部实现都是仅仅调用了一下所包装的的 request 对象的对应方法,以避免用户在对request对象进行增强时需要实现request接口中的所有方法。
2.1、使用Decorator模式包装request对象解决get和post请求方式下的中文乱码问题
编写一个用于处理中文乱码的过滤器CharacterEncodingFilter,代码如下:
<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> me.gacl.web.filter; <span class="hljs-keyword">import</span> java.io.IOException; <span class="hljs-keyword">import</span> javax.servlet.Filter; <span class="hljs-keyword">import</span> javax.servlet.FilterChain; <span class="hljs-keyword">import</span> javax.servlet.FilterConfig; <span class="hljs-keyword">import</span> javax.servlet.ServletException; <span class="hljs-keyword">import</span> javax.servlet.ServletRequest; <span class="hljs-keyword">import</span> javax.servlet.ServletResponse; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletRequest; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletRequestWrapper; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletResponse; <span class="hljs-javadoc">/** *<span class="hljs-javadoctag"> @ClassName</span>: CharacterEncodingFilter *<span class="hljs-javadoctag"> @Description</span>: 此过滤器用来解决解决get、post请求方式下的中文乱码问题 *<span class="hljs-javadoctag"> @author</span>: 孤傲苍狼 *<span class="hljs-javadoctag"> @date</span>: 2014-8-31 下午11:09:37 * */</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CharacterEncodingFilter</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Filter</span> {</span> <span class="hljs-keyword">private</span> FilterConfig filterConfig = <span class="hljs-keyword">null</span>; <span class="hljs-comment">//设置默认的字符编码</span> <span class="hljs-keyword">private</span> String defaultCharset = <span class="hljs-string">"UTF-8"</span>; <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doFilter</span>(ServletRequest req, ServletResponse resp, FilterChain chain) <span class="hljs-keyword">throws</span> IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; <span class="hljs-comment">//得到在web.xml中配置的字符编码</span> String charset = filterConfig.getInitParameter(<span class="hljs-string">"charset"</span>); <span class="hljs-keyword">if</span>(charset==<span class="hljs-keyword">null</span>){ charset = defaultCharset; } request.setCharacterEncoding(charset); response.setCharacterEncoding(charset); response.setContentType(<span class="hljs-string">"text/html;charset="</span>+charset); MyCharacterEncodingRequest requestWrapper = <span class="hljs-keyword">new</span> MyCharacterEncodingRequest(request); chain.doFilter(requestWrapper, response); } <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">init</span>(FilterConfig filterConfig) <span class="hljs-keyword">throws</span> ServletException { <span class="hljs-comment">//得到过滤器的初始化配置信息</span> <span class="hljs-keyword">this</span>.filterConfig = filterConfig; } <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">destroy</span>() { } } <span class="hljs-javadoc">/** *<span class="hljs-javadoctag"> @ClassName</span>: MyCharacterEncodingRequest *<span class="hljs-javadoctag"> @Description</span>: Servlet API中提供了一个request对象的Decorator设计模式的默认实现类HttpServletRequestWrapper, * (HttpServletRequestWrapper类实现了request接口中的所有方法,但这些方法的内部实现都是仅仅调用了一下所包装的的 request对象的对应方法) * 以避免用户在对request对象进行增强时需要实现request接口中的所有方法。 * 所以当需要增强request对象时,只需要写一个类继承HttpServletRequestWrapper类,然后在重写需要增强的方法即可 *<span class="hljs-javadoctag"> @author</span>: 孤傲苍狼 *<span class="hljs-javadoctag"> @date</span>: 2014-9-2 下午10:42:57 * 1.实现与被增强对象相同的接口 2、定义一个变量记住被增强对象 3、定义一个构造函数,接收被增强对象 4、覆盖需要增强的方法 5、对于不想增强的方法,直接调用被增强对象(目标对象)的方法 */</span> class MyCharacterEncodingRequest extends HttpServletRequestWrapper{ <span class="hljs-comment">//定义一个变量记住被增强对象(request对象是需要被增强的对象)</span> <span class="hljs-keyword">private</span> HttpServletRequest request; <span class="hljs-comment">//定义一个构造函数,接收被增强对象</span> <span class="hljs-keyword">public</span> <span class="hljs-title">MyCharacterEncodingRequest</span>(HttpServletRequest request) { <span class="hljs-keyword">super</span>(request); <span class="hljs-keyword">this</span>.request = request; } <span class="hljs-comment">/* 覆盖需要增强的getParameter方法 * @see javax.servlet.ServletRequestWrapper#getParameter(java.lang.String) */</span> <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> String <span class="hljs-title">getParameter</span>(String name) { <span class="hljs-keyword">try</span>{ <span class="hljs-comment">//获取参数的值</span> String value= <span class="hljs-keyword">this</span>.request.getParameter(name); <span class="hljs-keyword">if</span>(value==<span class="hljs-keyword">null</span>){ <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>; } <span class="hljs-comment">//如果不是以get方式提交数据的,就直接返回获取到的值</span> <span class="hljs-keyword">if</span>(!<span class="hljs-keyword">this</span>.request.getMethod().equalsIgnoreCase(<span class="hljs-string">"get"</span>)) { <span class="hljs-keyword">return</span> value; }<span class="hljs-keyword">else</span>{ <span class="hljs-comment">//如果是以get方式提交数据的,就对获取到的值进行转码处理</span> value = <span class="hljs-keyword">new</span> String(value.getBytes(<span class="hljs-string">"ISO8859-1"</span>),<span class="hljs-keyword">this</span>.request.getCharacterEncoding()); <span class="hljs-keyword">return</span> value; } }<span class="hljs-keyword">catch</span> (Exception e) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(e); } } }</code>
在web.xml文件中配置CharacterEncodingFilter
<code class="hljs xml has-numbering"><span class="hljs-comment"><!--配置字符过滤器,解决get、post请求方式下的中文乱码问题--></span> <span class="hljs-tag"><<span class="hljs-title">filter</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-name</span>></span>CharacterEncodingFilter<span class="hljs-tag"></<span class="hljs-title">filter-name</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-class</span>></span>me.gacl.web.filter.CharacterEncodingFilter<span class="hljs-tag"></<span class="hljs-title">filter-class</span>></span> <span class="hljs-tag"></<span class="hljs-title">filter</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-mapping</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-name</span>></span>CharacterEncodingFilter<span class="hljs-tag"></<span class="hljs-title">filter-name</span>></span> <span class="hljs-tag"><<span class="hljs-title">url-pattern</span>></span>/*<span class="hljs-tag"></<span class="hljs-title">url-pattern</span>></span> <span class="hljs-tag"></<span class="hljs-title">filter-mapping</span>></span></code>
编写jsp测试页面,如下:
<code class="hljs xml has-numbering"><span class="vbscript"><%@ page language=<span class="hljs-string">"java"</span> pageEncoding=<span class="hljs-string">"UTF-8"</span>%></span> <span class="vbscript"><%--引入jstl标签库 --%></span> <span class="vbscript"><%@taglib uri=<span class="hljs-string">"http://java.sun.com/jsp/jstl/core"</span> prefix=<span class="hljs-string">"c"</span>%></span> <span class="hljs-doctype"><!DOCTYPE HTML></span> <span class="hljs-tag"><<span class="hljs-title">html</span>></span> <span class="hljs-tag"><<span class="hljs-title">head</span>></span> <span class="hljs-tag"><<span class="hljs-title">title</span>></span>使用字符过滤器解决解决get、post请求方式下的中文乱码问题<span class="hljs-tag"></<span class="hljs-title">title</span>></span> <span class="hljs-tag"></<span class="hljs-title">head</span>></span> <span class="hljs-tag"><<span class="hljs-title">body</span>></span> <span class="vbscript"><%--使用c:url标签构建url,构建好的url存储在servletDemo1变量中--%></span> <span class="hljs-tag"><<span class="hljs-title">c:url</span> <span class="hljs-attribute">value</span>=<span class="hljs-value">"/servlet/ServletDemo1"</span> <span class="hljs-attribute">scope</span>=<span class="hljs-value">"page"</span> <span class="hljs-attribute">var</span>=<span class="hljs-value">"servletDemo1"</span>></span> <span class="vbscript"><%--构建的url的附带的中文参数 ,参数名是:username,值是:孤傲苍狼--%></span> <span class="hljs-tag"><<span class="hljs-title">c:param</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"username"</span> <span class="hljs-attribute">value</span>=<span class="hljs-value">"孤傲苍狼"</span>></span><span class="hljs-tag"></<span class="hljs-title">c:param</span>></span> <span class="hljs-tag"></<span class="hljs-title">c:url</span>></span> <span class="vbscript"><%--使用<span class="hljs-keyword">get</span>的方式访问 --%></span> <span class="hljs-tag"><<span class="hljs-title">a</span> <span class="hljs-attribute">href</span>=<span class="hljs-value">"${servletDemo1}"</span>></span>超链接(get方式请求)<span class="hljs-tag"></<span class="hljs-title">a</span>></span> <span class="hljs-tag"><<span class="hljs-title">hr</span>/></span> <span class="vbscript"><%--使用post方式提交表单 --%></span> <span class="hljs-tag"><<span class="hljs-title">form</span> <span class="hljs-attribute">action</span>=<span class="hljs-value">"${pageContext.request.contextPath}/servlet/ServletDemo1"</span> <span class="hljs-attribute">method</span>=<span class="hljs-value">"post"</span>></span> 用户名:<span class="hljs-tag"><<span class="hljs-title">input</span> <span class="hljs-attribute">type</span>=<span class="hljs-value">"text"</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"username"</span> <span class="hljs-attribute">value</span>=<span class="hljs-value">"孤傲苍狼"</span> /></span> <span class="hljs-tag"><<span class="hljs-title">input</span> <span class="hljs-attribute">type</span>=<span class="hljs-value">"submit"</span> <span class="hljs-attribute">value</span>=<span class="hljs-value">"post方式提交"</span>></span> <span class="hljs-tag"></<span class="hljs-title">form</span>></span> <span class="hljs-tag"></<span class="hljs-title">body</span>></span> <span class="hljs-tag"></<span class="hljs-title">html</span>></span></code>
编写处理用户请求的ServletDemo1
<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> me.gacl.web.controller; <span class="hljs-keyword">import</span> java.io.IOException; <span class="hljs-keyword">import</span> java.io.PrintWriter; <span class="hljs-keyword">import</span> javax.servlet.ServletException; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServlet; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletRequest; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletResponse; <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ServletDemo1</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">HttpServlet</span> {</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doGet</span>(HttpServletRequest request, HttpServletResponse response) <span class="hljs-keyword">throws</span> ServletException, IOException { <span class="hljs-comment">//接收参数</span> String username = request.getParameter(<span class="hljs-string">"username"</span>); <span class="hljs-comment">//获取请求方式</span> String method = request.getMethod(); <span class="hljs-comment">//获取输出流</span> PrintWriter out = response.getWriter(); out.write(<span class="hljs-string">"请求的方式:"</span>+method); out.write(<span class="hljs-string">"<br/>"</span>); out.write(<span class="hljs-string">"接收到的参数:"</span>+username); } <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doPost</span>(HttpServletRequest request, HttpServletResponse response) <span class="hljs-keyword">throws</span> ServletException, IOException { doGet(request, response); } }</code>
测试结果如下:
从运行结果中可以看到,无论是get请求方式还是post请求方式,中文乱码问题都可以完美解决了。
2.2、使用Decorator模式包装request对象实现html标签转义功能
编写一个html转义过滤器,代码如下:
<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> me.gacl.web.filter; <span class="hljs-keyword">import</span> java.io.IOException; <span class="hljs-keyword">import</span> javax.servlet.Filter; <span class="hljs-keyword">import</span> javax.servlet.FilterChain; <span class="hljs-keyword">import</span> javax.servlet.FilterConfig; <span class="hljs-keyword">import</span> javax.servlet.ServletException; <span class="hljs-keyword">import</span> javax.servlet.ServletRequest; <span class="hljs-keyword">import</span> javax.servlet.ServletResponse; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletRequest; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletRequestWrapper; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletResponse; <span class="hljs-javadoc">/** *<span class="hljs-javadoctag"> @ClassName</span>: HtmlFilter *<span class="hljs-javadoctag"> @Description</span>: html转义过滤器 *<span class="hljs-javadoctag"> @author</span>: 孤傲苍狼 *<span class="hljs-javadoctag"> @date</span>: 2014-9-2 下午11:28:41 * */</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HtmlFilter</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Filter</span> {</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doFilter</span>(ServletRequest req, ServletResponse resp, FilterChain chain) <span class="hljs-keyword">throws</span> IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; MyHtmlRequest myrequest = <span class="hljs-keyword">new</span> MyHtmlRequest(request); chain.doFilter(myrequest, response); } <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">destroy</span>() { } <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">init</span>(FilterConfig filterConfig) <span class="hljs-keyword">throws</span> ServletException { } } <span class="hljs-javadoc">/** *<span class="hljs-javadoctag"> @ClassName</span>: MyHtmlRequest *<span class="hljs-javadoctag"> @Description</span>: 使用Decorator模式包装request对象,实现html标签转义功能 *<span class="hljs-javadoctag"> @author</span>: 孤傲苍狼 *<span class="hljs-javadoctag"> @date</span>: 2014-9-2 下午11:29:09 * */</span> class MyHtmlRequest extends HttpServletRequestWrapper { <span class="hljs-keyword">private</span> HttpServletRequest request; <span class="hljs-keyword">public</span> <span class="hljs-title">MyHtmlRequest</span>(HttpServletRequest request) { <span class="hljs-keyword">super</span>(request); <span class="hljs-keyword">this</span>.request = request; } <span class="hljs-comment">/* 覆盖需要增强的getParameter方法 * @see javax.servlet.ServletRequestWrapper#getParameter(java.lang.String) */</span> <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> String <span class="hljs-title">getParameter</span>(String name) { String value = <span class="hljs-keyword">this</span>.request.getParameter(name); <span class="hljs-keyword">if</span> (value == <span class="hljs-keyword">null</span>) { <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>; } <span class="hljs-comment">//调用filter转义value中的html标签</span> <span class="hljs-keyword">return</span> filter(value); } <span class="hljs-javadoc">/** *<span class="hljs-javadoctag"> @Method</span>: filter *<span class="hljs-javadoctag"> @Description</span>: 过滤内容中的html标签 *<span class="hljs-javadoctag"> @Anthor</span>:孤傲苍狼 *<span class="hljs-javadoctag"> @param</span> message *<span class="hljs-javadoctag"> @return</span> */</span> <span class="hljs-keyword">public</span> String <span class="hljs-title">filter</span>(String message) { <span class="hljs-keyword">if</span> (message == <span class="hljs-keyword">null</span>){ <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>; } <span class="hljs-keyword">char</span> content[] = <span class="hljs-keyword">new</span> <span class="hljs-keyword">char</span>[message.length()]; message.getChars(<span class="hljs-number">0</span>, message.length(), content, <span class="hljs-number">0</span>); StringBuffer result = <span class="hljs-keyword">new</span> StringBuffer(content.length + <span class="hljs-number">50</span>); <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < content.length; i++) { <span class="hljs-keyword">switch</span> (content[i]) { <span class="hljs-keyword">case</span> <span class="hljs-string">'<'</span>: result.append(<span class="hljs-string">"<"</span>); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> <span class="hljs-string">'>'</span>: result.append(<span class="hljs-string">">"</span>); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> <span class="hljs-string">'&'</span>: result.append(<span class="hljs-string">"&"</span>); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> <span class="hljs-string">'"'</span>: result.append(<span class="hljs-string">"""</span>); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">default</span>: result.append(content[i]); } } <span class="hljs-keyword">return</span> result.toString(); } }</code>
在web.xml文件中配置HtmlFilter
<code class="hljs xml has-numbering"><span class="hljs-comment"><!--配置Html过滤器,转义内容中的html标签--></span> <span class="hljs-tag"><<span class="hljs-title">filter</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-name</span>></span>HtmlFilter<span class="hljs-tag"></<span class="hljs-title">filter-name</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-class</span>></span>me.gacl.web.filter.HtmlFilter<span class="hljs-tag"></<span class="hljs-title">filter-class</span>></span> <span class="hljs-tag"></<span class="hljs-title">filter</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-mapping</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-name</span>></span>HtmlFilter<span class="hljs-tag"></<span class="hljs-title">filter-name</span>></span> <span class="hljs-tag"><<span class="hljs-title">url-pattern</span>></span>/*<span class="hljs-tag"></<span class="hljs-title">url-pattern</span>></span> <span class="hljs-tag"></<span class="hljs-title">filter-mapping</span>></span></code>
编写jsp测试页面,如下:
<code class="hljs xml has-numbering"><span class="vbscript"><%@ page language=<span class="hljs-string">"java"</span> import=<span class="hljs-string">"java.util.*"</span> pageEncoding=<span class="hljs-string">"UTF-8"</span>%></span> <span class="hljs-doctype"><!DOCTYPE HTML></span> <span class="hljs-tag"><<span class="hljs-title">html</span>></span> <span class="hljs-tag"><<span class="hljs-title">head</span>></span> <span class="hljs-tag"><<span class="hljs-title">title</span>></span>html过滤器测试<span class="hljs-tag"></<span class="hljs-title">title</span>></span> <span class="hljs-tag"></<span class="hljs-title">head</span>></span> <span class="hljs-tag"><<span class="hljs-title">body</span>></span> <span class="hljs-tag"><<span class="hljs-title">form</span> <span class="hljs-attribute">action</span>=<span class="hljs-value">"${pageContext.request.contextPath}/servlet/ServletDemo2"</span> <span class="hljs-attribute">method</span>=<span class="hljs-value">"post"</span>></span> 留言: <span class="hljs-tag"><<span class="hljs-title">textarea</span> <span class="hljs-attribute">rows</span>=<span class="hljs-value">"8"</span> <span class="hljs-attribute">cols</span>=<span class="hljs-value">"70"</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"message"</span>></span> <span class="hljs-tag"><<span class="hljs-title">script</span> <span class="hljs-attribute">type</span>=<span class="hljs-value">"text/javascript"</span>></span><span class="javascript"> <span class="hljs-keyword">while</span>(<span class="hljs-literal">true</span>){ alert(<span class="hljs-string">"死循环了,我会不停地弹出了"</span>); } </span><span class="hljs-tag"></<span class="hljs-title">script</span>></span> <span class="hljs-tag"><<span class="hljs-title">a</span> <span class="hljs-attribute">href</span>=<span class="hljs-value">"http://www.cnblogs.com"</span>></span>访问博客园<span class="hljs-tag"></<span class="hljs-title">a</span>></span> <span class="hljs-tag"></<span class="hljs-title">textarea</span>></span> <span class="hljs-tag"><<span class="hljs-title">input</span> <span class="hljs-attribute">type</span>=<span class="hljs-value">"submit"</span> <span class="hljs-attribute">value</span>=<span class="hljs-value">"发表"</span>></span> <span class="hljs-tag"></<span class="hljs-title">form</span>></span> <span class="hljs-tag"></<span class="hljs-title">body</span>></span> <span class="hljs-tag"></<span class="hljs-title">html</span>></span></code>
编写处理用户请求的ServletDemo2
<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> me.gacl.web.controller; <span class="hljs-keyword">import</span> java.io.IOException; <span class="hljs-keyword">import</span> javax.servlet.ServletException; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServlet; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletRequest; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletResponse; <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ServletDemo2</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">HttpServlet</span> {</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doGet</span>(HttpServletRequest request, HttpServletResponse response) <span class="hljs-keyword">throws</span> ServletException, IOException { <span class="hljs-comment">//获取用户输入的内容</span> String message = request.getParameter(<span class="hljs-string">"message"</span>); response.getWriter().write(<span class="hljs-string">"您上次的留言是:<br/>"</span> + message); } <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doPost</span>(HttpServletRequest request, HttpServletResponse response) <span class="hljs-keyword">throws</span> ServletException, IOException { doGet(request, response); } }</code>
测试结果如下:
从运行结果中可以看到,所有的html标签都被转义输出了。
2.3、使用Decorator模式包装request对象实现敏感字符过滤功能
编写一个敏感字符过滤器,代码如下:
<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> me.gacl.web.filter; <span class="hljs-keyword">import</span> java.io.BufferedReader; <span class="hljs-keyword">import</span> java.io.IOException; <span class="hljs-keyword">import</span> java.io.InputStream; <span class="hljs-keyword">import</span> java.io.InputStreamReader; <span class="hljs-keyword">import</span> java.io.UnsupportedEncodingException; <span class="hljs-keyword">import</span> java.util.ArrayList; <span class="hljs-keyword">import</span> java.util.List; <span class="hljs-keyword">import</span> javax.servlet.Filter; <span class="hljs-keyword">import</span> javax.servlet.FilterChain; <span class="hljs-keyword">import</span> javax.servlet.FilterConfig; <span class="hljs-keyword">import</span> javax.servlet.ServletException; <span class="hljs-keyword">import</span> javax.servlet.ServletRequest; <span class="hljs-keyword">import</span> javax.servlet.ServletResponse; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletRequest; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletRequestWrapper; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletResponse; <span class="hljs-javadoc">/** *<span class="hljs-javadoctag"> @ClassName</span>: DirtyFilter *<span class="hljs-javadoctag"> @Description</span>: 敏感词过滤器 *<span class="hljs-javadoctag"> @author</span>: 孤傲苍狼 *<span class="hljs-javadoctag"> @date</span>: 2014-9-6 上午10:43:11 * */</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DirtyFilter</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Filter</span> {</span> <span class="hljs-keyword">private</span> FilterConfig config = <span class="hljs-keyword">null</span>; <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">init</span>(FilterConfig filterConfig) <span class="hljs-keyword">throws</span> ServletException { <span class="hljs-keyword">this</span>.config = filterConfig; } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doFilter</span>(ServletRequest req, ServletResponse resp, FilterChain chain) <span class="hljs-keyword">throws</span> IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; DirtyRequest dirtyrequest = <span class="hljs-keyword">new</span> DirtyRequest(request); chain.doFilter(dirtyrequest, response); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">destroy</span>() { } <span class="hljs-javadoc">/** *<span class="hljs-javadoctag"> @Method</span>: getDirtyWords *<span class="hljs-javadoctag"> @Description</span>: 获取敏感字符 *<span class="hljs-javadoctag"> @Anthor</span>:孤傲苍狼 * *<span class="hljs-javadoctag"> @return</span> */</span> <span class="hljs-keyword">private</span> List<String> <span class="hljs-title">getDirtyWords</span>(){ List<String> dirtyWords = <span class="hljs-keyword">new</span> ArrayList<String>(); String dirtyWordPath = config.getInitParameter(<span class="hljs-string">"dirtyWord"</span>); InputStream inputStream = config.getServletContext().getResourceAsStream(dirtyWordPath); InputStreamReader is = <span class="hljs-keyword">null</span>; <span class="hljs-keyword">try</span> { is = <span class="hljs-keyword">new</span> InputStreamReader(inputStream,<span class="hljs-string">"UTF-8"</span>); } <span class="hljs-keyword">catch</span> (UnsupportedEncodingException e2) { e2.printStackTrace(); } BufferedReader reader = <span class="hljs-keyword">new</span> BufferedReader(is); String line; <span class="hljs-keyword">try</span> { <span class="hljs-keyword">while</span> ((line = reader.readLine())!= <span class="hljs-keyword">null</span>) {<span class="hljs-comment">//如果 line为空说明读完了</span> dirtyWords.add(line); } } <span class="hljs-keyword">catch</span> (IOException e) { e.printStackTrace(); } <span class="hljs-keyword">return</span> dirtyWords; } <span class="hljs-javadoc">/** *<span class="hljs-javadoctag"> @ClassName</span>: DirtyRequest *<span class="hljs-javadoctag"> @Description</span>: 使用Decorator模式包装request对象,实现敏感字符过滤功能 *<span class="hljs-javadoctag"> @author</span>: 孤傲苍狼 *<span class="hljs-javadoctag"> @date</span>: 2014-9-6 上午11:56:35 * */</span> class DirtyRequest extends HttpServletRequestWrapper{ <span class="hljs-keyword">private</span> List<String> dirtyWords = getDirtyWords(); <span class="hljs-keyword">private</span> HttpServletRequest request; <span class="hljs-keyword">public</span> <span class="hljs-title">DirtyRequest</span>(HttpServletRequest request) { <span class="hljs-keyword">super</span>(request); <span class="hljs-keyword">this</span>.request = request; } <span class="hljs-comment">/* 重写getParameter方法,实现对敏感字符的过滤 * @see javax.servlet.ServletRequestWrapper#getParameter(java.lang.String) */</span> <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> String <span class="hljs-title">getParameter</span>(String name) { String value = <span class="hljs-keyword">this</span>.request.getParameter(name); <span class="hljs-keyword">if</span>(value==<span class="hljs-keyword">null</span>){ <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>; } <span class="hljs-keyword">for</span>(String dirtyWord : dirtyWords){ <span class="hljs-keyword">if</span>(value.contains(dirtyWord)){ System.out.println(<span class="hljs-string">"内容中包含敏感词:"</span>+dirtyWord+<span class="hljs-string">",将会被替换成****"</span>); <span class="hljs-comment">//替换敏感字符</span> value = value.replace(dirtyWord, <span class="hljs-string">"****"</span>); } } <span class="hljs-keyword">return</span> value; } } }</code>
在web.xml文件中配置DirtyFilter
<code class="hljs xml has-numbering"><span class="hljs-comment"><!--配置敏感字符过滤器--></span> <span class="hljs-tag"><<span class="hljs-title">filter</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-name</span>></span>DirtyFilter<span class="hljs-tag"></<span class="hljs-title">filter-name</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-class</span>></span>me.gacl.web.filter.DirtyFilter<span class="hljs-tag"></<span class="hljs-title">filter-class</span>></span> <span class="hljs-comment"><!-- 配置要过滤的敏感字符文件 --></span> <span class="hljs-tag"><<span class="hljs-title">init-param</span>></span> <span class="hljs-tag"><<span class="hljs-title">param-name</span>></span>dirtyWord<span class="hljs-tag"></<span class="hljs-title">param-name</span>></span> <span class="hljs-tag"><<span class="hljs-title">param-value</span>></span>/WEB-INF/DirtyWord.txt<span class="hljs-tag"></<span class="hljs-title">param-value</span>></span> <span class="hljs-tag"></<span class="hljs-title">init-param</span>></span> <span class="hljs-tag"></<span class="hljs-title">filter</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-mapping</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-name</span>></span>DirtyFilter<span class="hljs-tag"></<span class="hljs-title">filter-name</span>></span> <span class="hljs-tag"><<span class="hljs-title">url-pattern</span>></span>/*<span class="hljs-tag"></<span class="hljs-title">url-pattern</span>></span> <span class="hljs-tag"></<span class="hljs-title">filter-mapping</span>></span></code>
当用户填写的内容包含一些敏感字符时,在DirtyFilter过滤器中就会将这些敏感字符替换掉。
我们如果将上述的CharacterEncodingFilter、HtmlFilter、DirtyFilter这三个过滤器联合起来使用,那么就相当于是把request对象包装了3次,request对象的getParameter方法经过3次重写,使得getParameter方法的功能大大增强,可以同时解决中文乱码,html标签转义,敏感字符过滤这些需求。
在实际开发中完全可以将上述的三个过滤器合并成一个,让合并后的过滤器具有解决中文乱码,html标签转义,敏感字符过滤这些功能,例如:
<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> me.gacl.web.filter; <span class="hljs-keyword">import</span> java.io.BufferedReader; <span class="hljs-keyword">import</span> java.io.IOException; <span class="hljs-keyword">import</span> java.io.InputStream; <span class="hljs-keyword">import</span> java.io.InputStreamReader; <span class="hljs-keyword">import</span> java.io.UnsupportedEncodingException; <span class="hljs-keyword">import</span> java.util.ArrayList; <span class="hljs-keyword">import</span> java.util.List; <span class="hljs-keyword">import</span> javax.servlet.Filter; <span class="hljs-keyword">import</span> javax.servlet.FilterChain; <span class="hljs-keyword">import</span> javax.servlet.FilterConfig; <span class="hljs-keyword">import</span> javax.servlet.ServletException; <span class="hljs-keyword">import</span> javax.servlet.ServletRequest; <span class="hljs-keyword">import</span> javax.servlet.ServletResponse; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletRequest; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletRequestWrapper; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletResponse; <span class="hljs-javadoc">/** *<span class="hljs-javadoctag"> @ClassName</span>: AdvancedFilter *<span class="hljs-javadoctag"> @Description</span>: 这个过滤器是用来解决中文乱码,转义内容中的html标签,过滤内容中的敏感字符的 *<span class="hljs-javadoctag"> @author</span>: 孤傲苍狼 *<span class="hljs-javadoctag"> @date</span>: 2014-9-6 下午6:17:37 * */</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AdvancedFilter</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Filter</span> {</span> <span class="hljs-keyword">private</span> FilterConfig filterConfig = <span class="hljs-keyword">null</span>; <span class="hljs-comment">//设置默认的字符编码</span> <span class="hljs-keyword">private</span> String defaultCharset = <span class="hljs-string">"UTF-8"</span>; <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">init</span>(FilterConfig filterConfig) <span class="hljs-keyword">throws</span> ServletException { <span class="hljs-comment">//得到过滤器的初始化配置信息</span> <span class="hljs-keyword">this</span>.filterConfig = filterConfig; } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doFilter</span>(ServletRequest req, ServletResponse resp, FilterChain chain) <span class="hljs-keyword">throws</span> IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; <span class="hljs-comment">//得到在web.xml中配置的字符编码</span> String charset = filterConfig.getInitParameter(<span class="hljs-string">"charset"</span>); <span class="hljs-keyword">if</span>(charset==<span class="hljs-keyword">null</span>){ charset = defaultCharset; } request.setCharacterEncoding(charset); response.setCharacterEncoding(charset); response.setContentType(<span class="hljs-string">"text/html;charset="</span>+charset); AdvancedRequest requestWrapper = <span class="hljs-keyword">new</span> AdvancedRequest(request); chain.doFilter(requestWrapper, response); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">destroy</span>() { } class AdvancedRequest extends HttpServletRequestWrapper{ <span class="hljs-keyword">private</span> List<String> dirtyWords = getDirtyWords(); <span class="hljs-comment">//定义一个变量记住被增强对象(request对象是需要被增强的对象)</span> <span class="hljs-keyword">private</span> HttpServletRequest request; <span class="hljs-comment">//定义一个构造函数,接收被增强对象</span> <span class="hljs-keyword">public</span> <span class="hljs-title">AdvancedRequest</span>(HttpServletRequest request) { <span class="hljs-keyword">super</span>(request); <span class="hljs-keyword">this</span>.request = request; } <span class="hljs-comment">/* 覆盖需要增强的getParameter方法 * @see javax.servlet.ServletRequestWrapper#getParameter(java.lang.String) */</span> <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> String <span class="hljs-title">getParameter</span>(String name) { <span class="hljs-keyword">try</span>{ <span class="hljs-comment">//获取参数的值</span> String value= <span class="hljs-keyword">this</span>.request.getParameter(name); <span class="hljs-keyword">if</span>(value==<span class="hljs-keyword">null</span>){ <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>; } <span class="hljs-comment">//如果不是以get方式提交数据的,就直接返回获取到的值</span> <span class="hljs-keyword">if</span>(!<span class="hljs-keyword">this</span>.request.getMethod().equalsIgnoreCase(<span class="hljs-string">"get"</span>)) { <span class="hljs-comment">//调用filter转义value中的html标签</span> value= filter(value); }<span class="hljs-keyword">else</span>{ <span class="hljs-comment">//如果是以get方式提交数据的,就对获取到的值进行转码处理</span> value = <span class="hljs-keyword">new</span> String(value.getBytes(<span class="hljs-string">"ISO8859-1"</span>),<span class="hljs-keyword">this</span>.request.getCharacterEncoding()); <span class="hljs-comment">//调用filter转义value中的html标签</span> value= filter(value); } <span class="hljs-keyword">for</span>(String dirtyWord : dirtyWords){ <span class="hljs-keyword">if</span>(value.contains(dirtyWord)){ System.out.println(<span class="hljs-string">"内容中包含敏感词:"</span>+dirtyWord+<span class="hljs-string">",将会被替换成****"</span>); <span class="hljs-comment">//替换敏感字符</span> value = value.replace(dirtyWord, <span class="hljs-string">"****"</span>); } } <span class="hljs-keyword">return</span> value; }<span class="hljs-keyword">catch</span> (Exception e) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(e); } } } <span class="hljs-javadoc">/** *<span class="hljs-javadoctag"> @Method</span>: filter *<span class="hljs-javadoctag"> @Description</span>: 过滤内容中的html标签 *<span class="hljs-javadoctag"> @Anthor</span>:孤傲苍狼 *<span class="hljs-javadoctag"> @param</span> value *<span class="hljs-javadoctag"> @return</span> */</span> <span class="hljs-keyword">public</span> String <span class="hljs-title">filter</span>(String value) { <span class="hljs-keyword">if</span> (value == <span class="hljs-keyword">null</span>){ <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>; } <span class="hljs-keyword">char</span> content[] = <span class="hljs-keyword">new</span> <span class="hljs-keyword">char</span>[value.length()]; value.getChars(<span class="hljs-number">0</span>, value.length(), content, <span class="hljs-number">0</span>); StringBuffer result = <span class="hljs-keyword">new</span> StringBuffer(content.length + <span class="hljs-number">50</span>); <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < content.length; i++) { <span class="hljs-keyword">switch</span> (content[i]) { <span class="hljs-keyword">case</span> <span class="hljs-string">'<'</span>: result.append(<span class="hljs-string">"<"</span>); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> <span class="hljs-string">'>'</span>: result.append(<span class="hljs-string">">"</span>); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> <span class="hljs-string">'&'</span>: result.append(<span class="hljs-string">"&"</span>); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> <span class="hljs-string">'"'</span>: result.append(<span class="hljs-string">"""</span>); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">default</span>: result.append(content[i]); } } <span class="hljs-keyword">return</span> (result.toString()); } <span class="hljs-javadoc">/** *<span class="hljs-javadoctag"> @Method</span>: getDirtyWords *<span class="hljs-javadoctag"> @Description</span>: 获取敏感字符 *<span class="hljs-javadoctag"> @Anthor</span>:孤傲苍狼 * *<span class="hljs-javadoctag"> @return</span> */</span> <span class="hljs-keyword">private</span> List<String> <span class="hljs-title">getDirtyWords</span>(){ List<String> dirtyWords = <span class="hljs-keyword">new</span> ArrayList<String>(); String dirtyWordPath = filterConfig.getInitParameter(<span class="hljs-string">"dirtyWord"</span>); InputStream inputStream = filterConfig.getServletContext().getResourceAsStream(dirtyWordPath); InputStreamReader is = <span class="hljs-keyword">null</span>; <span class="hljs-keyword">try</span> { is = <span class="hljs-keyword">new</span> InputStreamReader(inputStream,defaultCharset); } <span class="hljs-keyword">catch</span> (UnsupportedEncodingException e2) { e2.printStackTrace(); } BufferedReader reader = <span class="hljs-keyword">new</span> BufferedReader(is); String line; <span class="hljs-keyword">try</span> { <span class="hljs-keyword">while</span> ((line = reader.readLine())!= <span class="hljs-keyword">null</span>) {<span class="hljs-comment">//如果 line为空说明读完了</span> dirtyWords.add(line); } } <span class="hljs-keyword">catch</span> (IOException e) { e.printStackTrace(); } <span class="hljs-keyword">return</span> dirtyWords; } }</code>
在web.xml文件中配置AdvancedFilter
<code class="hljs livecodeserver has-numbering"><<span class="hljs-built_in">filter</span>> <<span class="hljs-built_in">filter</span>-name>AdvancedFilter</<span class="hljs-built_in">filter</span>-name> <<span class="hljs-built_in">filter</span>-class>me.gacl.web.<span class="hljs-built_in">filter</span>.AdvancedFilter</<span class="hljs-built_in">filter</span>-class> <init-<span class="hljs-built_in">param</span>> <<span class="hljs-built_in">param</span>-name>charset</<span class="hljs-built_in">param</span>-name> <<span class="hljs-built_in">param</span>-<span class="hljs-built_in">value</span>>UTF-<span class="hljs-number">8</span></<span class="hljs-built_in">param</span>-<span class="hljs-built_in">value</span>> </init-<span class="hljs-built_in">param</span>> <init-<span class="hljs-built_in">param</span>> <<span class="hljs-built_in">param</span>-name>dirtyWord</<span class="hljs-built_in">param</span>-name> <<span class="hljs-built_in">param</span>-<span class="hljs-built_in">value</span>>/WEB-INF/DirtyWord.txt</<span class="hljs-built_in">param</span>-<span class="hljs-built_in">value</span>> </init-<span class="hljs-built_in">param</span>> </<span class="hljs-built_in">filter</span>> <<span class="hljs-built_in">filter</span>-mapping> <<span class="hljs-built_in">filter</span>-name>AdvancedFilter</<span class="hljs-built_in">filter</span>-name> <url-pattern><span class="hljs-comment">/*</url-pattern> </filter-mapping></span></code>
AdvancedFilter过滤器同时具有解决中文乱码,转义内容中的html标签,过滤内容中的敏感字符这些功能。
三、使用Decorator设计模式增强response对象
Servlet API 中提供了response对象的Decorator设计模式的默认实现类HttpServletResponseWrapper ,HttpServletResponseWrapper类实现了response接口中的所有方法,但这些方法的内部实现都是仅仅调用了一下所包装的的 response对象的对应方法,以避免用户在对response对象进行增强时需要实现response接口中的所有方法。
3.1、response增强案例——压缩响应正文内容
应用HttpServletResponseWrapper对象,压缩响应正文内容。
具体思路:通过filter向目标页面传递一个自定义的response对象。在自定义的response对象中,重写getOutputStream方法和getWriter方法,使目标资源调用此方法输出页面内容时,获得的是我们自定义的ServletOutputStream对象。在我们自定义的ServletOuputStream对象中,重写write方法,使写出的数据写出到一个buffer中。当页面完成输出后,在filter中就可得到页面写出的数据,从而我们可以调用GzipOuputStream对数据进行压缩后再写出给浏览器,以此完成响应正文件压缩功能。
编写压缩过滤器,代码如下:
<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> me.gacl.web.filter; <span class="hljs-keyword">import</span> java.io.ByteArrayOutputStream; <span class="hljs-keyword">import</span> java.io.IOException; <span class="hljs-keyword">import</span> java.io.OutputStreamWriter; <span class="hljs-keyword">import</span> java.io.PrintWriter; <span class="hljs-keyword">import</span> java.util.zip.GZIPOutputStream; <span class="hljs-keyword">import</span> javax.servlet.Filter; <span class="hljs-keyword">import</span> javax.servlet.FilterChain; <span class="hljs-keyword">import</span> javax.servlet.FilterConfig; <span class="hljs-keyword">import</span> javax.servlet.ServletException; <span class="hljs-keyword">import</span> javax.servlet.ServletOutputStream; <span class="hljs-keyword">import</span> javax.servlet.ServletRequest; <span class="hljs-keyword">import</span> javax.servlet.ServletResponse; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletRequest; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletResponse; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletResponseWrapper; <span class="hljs-javadoc">/** *<span class="hljs-javadoctag"> @ClassName</span>: GzipFilter *<span class="hljs-javadoctag"> @Description</span>: 压缩过滤器,将web应用中的文本都经过压缩后再输出到浏览器 *<span class="hljs-javadoctag"> @author</span>: 孤傲苍狼 *<span class="hljs-javadoctag"> @date</span>: 2014-9-7 上午10:52:42 * */</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">GzipFilter</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Filter</span> {</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doFilter</span>(ServletRequest req, ServletResponse resp, FilterChain chain) <span class="hljs-keyword">throws</span> IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; BufferResponse myresponse = <span class="hljs-keyword">new</span> BufferResponse(response); chain.doFilter(request, myresponse); <span class="hljs-comment">//拿出缓存中的数据,压缩后再打给浏览器</span> <span class="hljs-keyword">byte</span> out[] = myresponse.getBuffer(); System.out.println(<span class="hljs-string">"原始大小:"</span> + out.length); ByteArrayOutputStream bout = <span class="hljs-keyword">new</span> ByteArrayOutputStream(); <span class="hljs-comment">//压缩输出流中的数据</span> GZIPOutputStream gout = <span class="hljs-keyword">new</span> GZIPOutputStream(bout); gout.write(out); gout.close(); <span class="hljs-keyword">byte</span> gzip[] = bout.toByteArray(); System.out.println(<span class="hljs-string">"压缩后的大小:"</span> + gzip.length); response.setHeader(<span class="hljs-string">"content-encoding"</span>, <span class="hljs-string">"gzip"</span>); response.setContentLength(gzip.length); response.getOutputStream().write(gzip); } <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">destroy</span>() { } <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">init</span>(FilterConfig filterConfig) <span class="hljs-keyword">throws</span> ServletException { } } class BufferResponse extends HttpServletResponseWrapper{ <span class="hljs-keyword">private</span> ByteArrayOutputStream bout = <span class="hljs-keyword">new</span> ByteArrayOutputStream(); <span class="hljs-keyword">private</span> PrintWriter pw; <span class="hljs-keyword">private</span> HttpServletResponse response; <span class="hljs-keyword">public</span> <span class="hljs-title">BufferResponse</span>(HttpServletResponse response) { <span class="hljs-keyword">super</span>(response); <span class="hljs-keyword">this</span>.response = response; } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> ServletOutputStream <span class="hljs-title">getOutputStream</span>() <span class="hljs-keyword">throws</span> IOException { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> MyServletOutputStream(bout); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> PrintWriter <span class="hljs-title">getWriter</span>() <span class="hljs-keyword">throws</span> IOException { pw = <span class="hljs-keyword">new</span> PrintWriter(<span class="hljs-keyword">new</span> OutputStreamWriter(bout,<span class="hljs-keyword">this</span>.response.getCharacterEncoding())); <span class="hljs-keyword">return</span> pw; } <span class="hljs-keyword">public</span> <span class="hljs-keyword">byte</span>[] <span class="hljs-title">getBuffer</span>(){ <span class="hljs-keyword">try</span>{ <span class="hljs-keyword">if</span>(pw!=<span class="hljs-keyword">null</span>){ pw.close(); } <span class="hljs-keyword">if</span>(bout!=<span class="hljs-keyword">null</span>){ bout.flush(); <span class="hljs-keyword">return</span> bout.toByteArray(); } <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>; }<span class="hljs-keyword">catch</span> (Exception e) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(e); } } } class MyServletOutputStream extends ServletOutputStream{ <span class="hljs-keyword">private</span> ByteArrayOutputStream bout; <span class="hljs-keyword">public</span> <span class="hljs-title">MyServletOutputStream</span>(ByteArrayOutputStream bout){ <span class="hljs-keyword">this</span>.bout = bout; } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">write</span>(<span class="hljs-keyword">int</span> b) <span class="hljs-keyword">throws</span> IOException { <span class="hljs-keyword">this</span>.bout.write(b); } }</code>
在web.xml中配置压缩过滤器
<code class="hljs xml has-numbering"><span class="hljs-tag"><<span class="hljs-title">filter</span>></span> <span class="hljs-tag"><<span class="hljs-title">description</span>></span>配置压缩过滤器<span class="hljs-tag"></<span class="hljs-title">description</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-name</span>></span>GzipFilter<span class="hljs-tag"></<span class="hljs-title">filter-name</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-class</span>></span>me.gacl.web.filter.GzipFilter<span class="hljs-tag"></<span class="hljs-title">filter-class</span>></span> <span class="hljs-tag"></<span class="hljs-title">filter</span>></span> <span class="hljs-comment"><!--jsp文件的输出的内容都经过压缩过滤器压缩后才输出 --></span> <span class="hljs-tag"><<span class="hljs-title">filter-mapping</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-name</span>></span>GzipFilter<span class="hljs-tag"></<span class="hljs-title">filter-name</span>></span> <span class="hljs-tag"><<span class="hljs-title">url-pattern</span>></span>*.jsp<span class="hljs-tag"></<span class="hljs-title">url-pattern</span>></span> <span class="hljs-comment"><!-- 配置过滤器的拦截方式--></span> <span class="hljs-comment"><!-- 对于在Servlet中通过 request.getRequestDispatcher("jsp页面路径").forward(request, response) 方式访问的Jsp页面的要进行拦截 --></span> <span class="hljs-tag"><<span class="hljs-title">dispatcher</span>></span>FORWARD<span class="hljs-tag"></<span class="hljs-title">dispatcher</span>></span> <span class="hljs-comment"><!--对于直接以URL方式访问的jsp页面进行拦截,过滤器的拦截方式默认就是 REQUEST--></span> <span class="hljs-tag"><<span class="hljs-title">dispatcher</span>></span>REQUEST<span class="hljs-tag"></<span class="hljs-title">dispatcher</span>></span> <span class="hljs-tag"></<span class="hljs-title">filter-mapping</span>></span> <span class="hljs-comment"><!--js文件的输出的内容都经过压缩过滤器压缩后才输出 --></span> <span class="hljs-tag"><<span class="hljs-title">filter-mapping</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-name</span>></span>GzipFilter<span class="hljs-tag"></<span class="hljs-title">filter-name</span>></span> <span class="hljs-tag"><<span class="hljs-title">url-pattern</span>></span>*.js<span class="hljs-tag"></<span class="hljs-title">url-pattern</span>></span> <span class="hljs-tag"></<span class="hljs-title">filter-mapping</span>></span> <span class="hljs-comment"><!--css文件的输出的内容都经过压缩过滤器压缩后才输出 --></span> <span class="hljs-tag"><<span class="hljs-title">filter-mapping</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-name</span>></span>GzipFilter<span class="hljs-tag"></<span class="hljs-title">filter-name</span>></span> <span class="hljs-tag"><<span class="hljs-title">url-pattern</span>></span>*.css<span class="hljs-tag"></<span class="hljs-title">url-pattern</span>></span> <span class="hljs-tag"></<span class="hljs-title">filter-mapping</span>></span> <span class="hljs-comment"><!--html文件的输出的内容都经过压缩过滤器压缩后才输出 --></span> <span class="hljs-tag"><<span class="hljs-title">filter-mapping</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-name</span>></span>GzipFilter<span class="hljs-tag"></<span class="hljs-title">filter-name</span>></span> <span class="hljs-tag"><<span class="hljs-title">url-pattern</span>></span>*.html<span class="hljs-tag"></<span class="hljs-title">url-pattern</span>></span> <span class="hljs-tag"></<span class="hljs-title">filter-mapping</span>></span></code>
3.2、response增强案例——缓存数据到内存
对于页面中很少更新的数据,例如商品分类,为避免每次都要从数据库查询分类数据,因此可把分类数据缓存在内存或文件中,以此来减轻数据库压力,提高系统响应速度。
编写缓存数据的过滤器,代码如下:
<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> me.gacl.web.filter; <span class="hljs-keyword">import</span> java.io.ByteArrayOutputStream; <span class="hljs-keyword">import</span> java.io.IOException; <span class="hljs-keyword">import</span> java.io.OutputStreamWriter; <span class="hljs-keyword">import</span> java.io.PrintWriter; <span class="hljs-keyword">import</span> java.util.HashMap; <span class="hljs-keyword">import</span> java.util.Map; <span class="hljs-keyword">import</span> javax.servlet.Filter; <span class="hljs-keyword">import</span> javax.servlet.FilterChain; <span class="hljs-keyword">import</span> javax.servlet.FilterConfig; <span class="hljs-keyword">import</span> javax.servlet.ServletException; <span class="hljs-keyword">import</span> javax.servlet.ServletOutputStream; <span class="hljs-keyword">import</span> javax.servlet.ServletRequest; <span class="hljs-keyword">import</span> javax.servlet.ServletResponse; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletRequest; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletResponse; <span class="hljs-keyword">import</span> javax.servlet.http.HttpServletResponseWrapper; <span class="hljs-javadoc">/** *<span class="hljs-javadoctag"> @ClassName</span>: WebResourceCachedFilter *<span class="hljs-javadoctag"> @Description</span>: Web资源缓存过滤器 *<span class="hljs-javadoctag"> @author</span>: 孤傲苍狼 *<span class="hljs-javadoctag"> @date</span>: 2014-9-8 上午12:20:16 * */</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebResourceCachedFilter</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Filter</span> {</span> <span class="hljs-javadoc">/** *<span class="hljs-javadoctag"> @Field</span>: map * 缓存Web资源的Map容器 */</span> <span class="hljs-keyword">private</span> Map<String,<span class="hljs-keyword">byte</span>[]> map = <span class="hljs-keyword">new</span> HashMap<String,<span class="hljs-keyword">byte</span>[]>(); <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">init</span>(FilterConfig filterConfig) <span class="hljs-keyword">throws</span> ServletException { } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doFilter</span>(ServletRequest req, ServletResponse resp, FilterChain chain) <span class="hljs-keyword">throws</span> IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; <span class="hljs-comment">//1.得到用户请求的uri</span> String uri = request.getRequestURI(); <span class="hljs-comment">//2.看缓存中有没有uri对应的数据</span> <span class="hljs-keyword">byte</span> b[] = map.get(uri); <span class="hljs-comment">//3.如果缓存中有,直接拿缓存的数据打给浏览器,程序返回</span> <span class="hljs-keyword">if</span>(b!=<span class="hljs-keyword">null</span>){ <span class="hljs-comment">//根据字节数组和指定的字符编码构建字符串</span> String webResourceHtmlStr = <span class="hljs-keyword">new</span> String(b,response.getCharacterEncoding()); System.out.println(webResourceHtmlStr); response.getOutputStream().write(b); <span class="hljs-keyword">return</span>; } <span class="hljs-comment">//4.如果缓存没有,让目标资源执行,并捕获目标资源的输出</span> BufferResponse myresponse = <span class="hljs-keyword">new</span> BufferResponse(response); chain.doFilter(request, myresponse); <span class="hljs-comment">//获取缓冲流中的内容的字节数组</span> <span class="hljs-keyword">byte</span> out[] = myresponse.getBuffer(); <span class="hljs-comment">//5.把资源的数据以用户请求的uri为关键字保存到缓存中</span> map.put(uri, out); <span class="hljs-comment">//6.把数据打给浏览器</span> response.getOutputStream().write(out); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">destroy</span>() { } class BufferResponse extends HttpServletResponseWrapper{ <span class="hljs-keyword">private</span> ByteArrayOutputStream bout = <span class="hljs-keyword">new</span> ByteArrayOutputStream(); <span class="hljs-comment">//捕获输出的缓存</span> <span class="hljs-keyword">private</span> PrintWriter pw; <span class="hljs-keyword">private</span> HttpServletResponse response; <span class="hljs-keyword">public</span> <span class="hljs-title">BufferResponse</span>(HttpServletResponse response) { <span class="hljs-keyword">super</span>(response); <span class="hljs-keyword">this</span>.response = response; } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> ServletOutputStream <span class="hljs-title">getOutputStream</span>() <span class="hljs-keyword">throws</span> IOException { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> MyServletOutputStream(bout); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> PrintWriter <span class="hljs-title">getWriter</span>() <span class="hljs-keyword">throws</span> IOException { pw = <span class="hljs-keyword">new</span> PrintWriter(<span class="hljs-keyword">new</span> OutputStreamWriter(bout,<span class="hljs-keyword">this</span>.response.getCharacterEncoding())); <span class="hljs-keyword">return</span> pw; } <span class="hljs-keyword">public</span> <span class="hljs-keyword">byte</span>[] <span class="hljs-title">getBuffer</span>(){ <span class="hljs-keyword">try</span>{ <span class="hljs-keyword">if</span>(pw!=<span class="hljs-keyword">null</span>){ pw.close(); } <span class="hljs-keyword">return</span> bout.toByteArray(); }<span class="hljs-keyword">catch</span> (Exception e) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(e); } } } class MyServletOutputStream extends ServletOutputStream{ <span class="hljs-keyword">private</span> ByteArrayOutputStream bout; <span class="hljs-keyword">public</span> <span class="hljs-title">MyServletOutputStream</span>(ByteArrayOutputStream bout){ <span class="hljs-comment">//接收数据写到哪里</span> <span class="hljs-keyword">this</span>.bout = bout; } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">write</span>(<span class="hljs-keyword">int</span> b) <span class="hljs-keyword">throws</span> IOException { bout.write(b); } } }</code>
在web.xml中配置Web资源缓存过滤器
<code class="hljs xml has-numbering"><span class="hljs-tag"><<span class="hljs-title">filter</span>></span> <span class="hljs-tag"><<span class="hljs-title">description</span>></span>Web资源缓存过滤器<span class="hljs-tag"></<span class="hljs-title">description</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-name</span>></span>WebResourceCachedFilter<span class="hljs-tag"></<span class="hljs-title">filter-name</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-class</span>></span>me.gacl.web.filter.WebResourceCachedFilter<span class="hljs-tag"></<span class="hljs-title">filter-class</span>></span> <span class="hljs-tag"></<span class="hljs-title">filter</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-mapping</span>></span> <span class="hljs-tag"><<span class="hljs-title">filter-name</span>></span>WebResourceCachedFilter<span class="hljs-tag"></<span class="hljs-title">filter-name</span>></span> <span class="hljs-comment"><!-- 映射需要缓存输出的JSP页面,这几个页面都只是单纯作为输入UI,不会有太多的变化,因此可以缓存输出 --></span> <span class="hljs-tag"><<span class="hljs-title">url-pattern</span>></span>/login.jsp<span class="hljs-tag"></<span class="hljs-title">url-pattern</span>></span> <span class="hljs-tag"><<span class="hljs-title">url-pattern</span>></span>/test.jsp<span class="hljs-tag"></<span class="hljs-title">url-pattern</span>></span> <span class="hljs-tag"><<span class="hljs-title">url-pattern</span>></span>/test2.jsp<span class="hljs-tag"></<span class="hljs-title">url-pattern</span>></span> <span class="hljs-tag"></<span class="hljs-title">filter-mapping</span>></span></code>