九:Decorator设计模式
二、使用Decorator设计模式增强request对象
Servlet API 中提供了一个request对象的Decorator设计模式的默认实现类HttpServletRequestWrapper,HttpServletRequestWrapper 类实现了request 接口中的所有方法,但这些方法的内部实现都是仅仅调用了一下所包装的的 request 对象的对应方法,以避免用户在对request对象进行增强时需要实现request接口中的所有方法。
2.1、使用Decorator模式包装request对象解决get和post请求方式下的中文乱码问题
编写一个用于处理中文乱码的过滤器CharacterEncodingFilter,代码如下:
package me.gacl.web.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; public class CharacterEncodingFilter implements Filter { private FilterConfig filterConfig = null; //设置默认的字符编码 private String defaultCharset = "UTF-8"; public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; //得到在web.xml中配置的字符编码 String charset = filterConfig.getInitParameter("charset"); if(charset==null){ charset = defaultCharset; } request.setCharacterEncoding(charset); response.setCharacterEncoding(charset); response.setContentType("text/html;charset="+charset); MyCharacterEncodingRequest requestWrapper = new MyCharacterEncodingRequest(request); chain.doFilter(requestWrapper, response); } public void init(FilterConfig filterConfig) throws ServletException { //得到过滤器的初始化配置信息 this.filterConfig = filterConfig; } public void destroy() { } } class MyCharacterEncodingRequest extends HttpServletRequestWrapper{ //定义一个变量记住被增强对象(request对象是需要被增强的对象) private HttpServletRequest request; //定义一个构造函数,接收被增强对象 public MyCharacterEncodingRequest(HttpServletRequest request) { super(request); this.request = request; } /* 覆盖需要增强的getParameter方法 * @see javax.servlet.ServletRequestWrapper#getParameter(java.lang.String) */ @Override public String getParameter(String name) { try{ //获取参数的值 String value= this.request.getParameter(name); if(value==null){ return null; } //如果不是以get方式提交数据的,就直接返回获取到的值 if(!this.request.getMethod().equalsIgnoreCase("get")) { return value; }else{ //如果是以get方式提交数据的,就对获取到的值进行转码处理 value = new String(value.getBytes("ISO8859-1"),this.request.getCharacterEncoding()); return value; } }catch (Exception e) { throw new RuntimeException(e); } } }
在web.xml文件中配置CharacterEncodingFilter
<!--配置字符过滤器,解决get、post请求方式下的中文乱码问题--> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>me.gacl.web.filter.CharacterEncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
三、使用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对数据进行压缩后再写出给浏览器,以此完成响应正文件压缩功能。
编写压缩过滤器,代码如下:
package me.gacl.web.filter; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.zip.GZIPOutputStream; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; public class GzipFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; BufferResponse myresponse = new BufferResponse(response); chain.doFilter(request, myresponse); //拿出缓存中的数据,压缩后再打给浏览器 byte out[] = myresponse.getBuffer(); System.out.println("原始大小:" + out.length); ByteArrayOutputStream bout = new ByteArrayOutputStream(); //压缩输出流中的数据 GZIPOutputStream gout = new GZIPOutputStream(bout); gout.write(out); gout.close(); byte gzip[] = bout.toByteArray(); System.out.println("压缩后的大小:" + gzip.length); response.setHeader("content-encoding", "gzip"); response.setContentLength(gzip.length); response.getOutputStream().write(gzip); } public void destroy() { } public void init(FilterConfig filterConfig) throws ServletException { } } class BufferResponse extends HttpServletResponseWrapper{ private ByteArrayOutputStream bout = new ByteArrayOutputStream(); private PrintWriter pw; private HttpServletResponse response; public BufferResponse(HttpServletResponse response) { super(response); this.response = response; } @Override public ServletOutputStream getOutputStream() throws IOException { return new MyServletOutputStream(bout); } @Override public PrintWriter getWriter() throws IOException { pw = new PrintWriter(new OutputStreamWriter(bout,this.response.getCharacterEncoding())); return pw; } public byte[] getBuffer(){ try{ if(pw!=null){ pw.close(); } if(bout!=null){ bout.flush(); return bout.toByteArray(); } return null; }catch (Exception e) { throw new RuntimeException(e); } } } class MyServletOutputStream extends ServletOutputStream{ private ByteArrayOutputStream bout; public MyServletOutputStream(ByteArrayOutputStream bout){ this.bout = bout; } @Override public void write(int b) throws IOException { this.bout.write(b); } }
在web.xml中配置压缩过滤器
<filter> <description>配置压缩过滤器</description> <filter-name>GzipFilter</filter-name> <filter-class>me.gacl.web.filter.GzipFilter</filter-class> </filter> <!--jsp文件的输出的内容都经过压缩过滤器压缩后才输出 --> <filter-mapping> <filter-name>GzipFilter</filter-name> <url-pattern>*.jsp</url-pattern> <!-- 配置过滤器的拦截方式--> <!-- 对于在Servlet中通过 request.getRequestDispatcher("jsp页面路径").forward(request, response) 方式访问的Jsp页面的要进行拦截 --> <dispatcher>FORWARD</dispatcher> <!--对于直接以URL方式访问的jsp页面进行拦截,过滤器的拦截方式默认就是 REQUEST--> <dispatcher>REQUEST</dispatcher> </filter-mapping> <!--js文件的输出的内容都经过压缩过滤器压缩后才输出 --> <filter-mapping> <filter-name>GzipFilter</filter-name> <url-pattern>*.js</url-pattern> </filter-mapping> <!--css文件的输出的内容都经过压缩过滤器压缩后才输出 --> <filter-mapping> <filter-name>GzipFilter</filter-name> <url-pattern>*.css</url-pattern> </filter-mapping> <!--html文件的输出的内容都经过压缩过滤器压缩后才输出 --> <filter-mapping> <filter-name>GzipFilter</filter-name> <url-pattern>*.html</url-pattern> </filter-mapping>