压缩资源过滤器
按照过滤器的执行顺序:执行完目标资源,过滤器后面的代码还会执行。所以,我们在过滤器中可以获取执行完目标资源后的response对象!
我们知道sun公司提供的response对象调用write()方法,是直接把数据返回给浏览器的。我们要想实现压缩的功能,write()方法就不能直接把数据写到浏览器上!
这和上面是类似的,过滤器传递给目标资源的response对象就需要被我们增强,使得目标资源调用writer()方法的时候不把数据直接写到浏览器上!
增强response对象
response对象可能会使用PrintWriter或者ServletOutputStream对象来调用writer()方法的,所以我们增强response对象的时候,需要把getOutputSteam和getWriter()重写
class MyResponse extends HttpServletResponseWrapper{ HttpServletResponse response; public MyResponse(HttpServletResponse response) { super(response); this.response = response; } @Override public ServletOutputStream getOutputStream() throws IOException { return super.getOutputStream(); } @Override public PrintWriter getWriter() throws IOException { return super.getWriter(); } }
接下来,ServletOutputSteam要调用writer()方法,使得它不会把数据写到浏览器上。这又要我们增强一遍了!
增强ServletOutputSteam
/*增强ServletOutputSteam,让writer方法不把数据直接返回给浏览器*/ class MyServletOutputStream extends ServletOutputStream{ private ByteArrayOutputStream byteArrayOutputStream; public MyServletOutputStream(ByteArrayOutputStream byteArrayOutputStream) { this.byteArrayOutputStream = byteArrayOutputStream; } //当调用write()方法的时候,其实是把数据写byteArrayOutputSteam上 @Override public void write(int b) throws IOException { this.byteArrayOutputStream.write(b); } }
增强PrintWriter
PrintWriter对象就好办了,它本来就是一个包装类,看它的构造方法,我们直接可以把ByteArrayOutputSteam传递给PrintWriter上。
@Override public PrintWriter getWriter() throws IOException { printWriter = new PrintWriter(new OutputStreamWriter(byteArrayOutputStream, this.response.getCharacterEncoding())); return printWriter; }
获取缓存数据
我们把数据都写在了ByteArrayOutputSteam上了,应该提供方法给外界过去缓存中的数据!
public byte[] getBuffer() { try { //防止数据在缓存中,要刷新一下! if (printWriter != null) { printWriter.close(); } if (byteArrayOutputStream != null) { byteArrayOutputStream.flush(); return byteArrayOutputStream.toByteArray(); } } catch (IOException e) { e.printStackTrace(); } return null; }
增强response的完整代码
class MyResponse extends HttpServletResponseWrapper{ private ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); private PrintWriter printWriter ; private HttpServletResponse response; public MyResponse(HttpServletResponse response) { super(response); this.response = response; } @Override public ServletOutputStream getOutputStream() throws IOException { //这个的ServletOutputSteam对象调用write()方法的时候,把数据是写在byteArrayOutputSteam上的 return new MyServletOutputStream(byteArrayOutputStream); } @Override public PrintWriter getWriter() throws IOException { printWriter = new PrintWriter(new OutputStreamWriter(byteArrayOutputStream, this.response.getCharacterEncoding())); return printWriter; } public byte[] getBuffer() { try { //防止数据在缓存中,要刷新一下! if (printWriter != null) { printWriter.close(); } if (byteArrayOutputStream != null) { byteArrayOutputStream.flush(); return byteArrayOutputStream.toByteArray(); } } catch (IOException e) { e.printStackTrace(); } return null; } }
过滤器
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; MyResponse myResponse = new MyResponse(response); //把被增强的response对象传递进去,目标资源调用write()方法的时候就不会直接把数据写在浏览器上了 chain.doFilter(request, myResponse); //得到目标资源想要返回给浏览器的数据 byte[] bytes = myResponse.getBuffer(); //输出原来的大小 System.out.println("压缩前:"+bytes.length); //使用GZIP来压缩资源,再返回给浏览器 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream); gzipOutputStream.write(bytes); //得到压缩后的数据 byte[] gzip = byteArrayOutputStream.toByteArray(); System.out.println("压缩后:" + gzip.length); //还要设置头,告诉浏览器,这是压缩数据! response.setHeader("content-encoding", "gzip"); response.setContentLength(gzip.length); response.getOutputStream().write(gzip); }
测试
- 在Servlet上输出一大段文字:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().write("fdshfidsuhfidusfhuidsfhuidshdsuifhsd" + "uifhsduifffffdshfidsuhfidusfhuidsfhuidshdsuif" + "hsduifhsduifffffdshfidsuhfidusfhuidsfhuidshd" + "suifhsduifhsduifffffdshfidsuhfidusfhuidsfhuidsh" + "dsuifhsduifhsduifffffdshfidsuhfidusfhuidsfhuids" + "hdsuifhsduifhsduifffffdshfidsuhfidusfhuidsfhuid" + "shdsuifhsduifhsduiffdshfidsuhfidusfhuidsfhuids" + "hdsuifhsduifhsduifffffdshfidsuhfidusfhuidsfhui" + "dshdsuifhsduifhsduifffffdshfidsuhfidusfhuidsfh" + "uidshdsuifhsduifhsduifffffdshfidsuhfidusfhuids" + "fhuidshdsuifhsduifhsduifffffdshfidsuhfidusfhuid" + "sfhuidshdsuifhsduifhsduifffffdshfidsuhfidusfhui" + "dsfhuidshdsuifhsduifhsduifffffdshfidsuhfidusfh" + "uidsfhuidshdsuifhsduifhsduifffffdshfidsuhfidusf" + "huidsfhuidshdsuifhsduifhsduifffffdshfidsuhfidus" + "fhuidsfhuidshdsuifhsduifhsduifffffdshfidsuhfid" + "usfhuidsfhuidshdsuifhsduifhsduifffffdshfidsuhf" + "idusfhuidsfhuidshdsuifhsduifhsd" + "uifffffdshfidsuhfidusfhuidsfhuidshdsuifhsduifhsduifffffff"); }
效果:
HTML转义过滤器
只要把getParameter()获取得到的数据转义一遍,就可以完成功能了。
增强request
class MyHtmlRequest extends HttpServletRequestWrapper{ private HttpServletRequest request; public MyHtmlRequest(HttpServletRequest request) { super(request); this.request = request; } @Override public String getParameter(String name) { String value = this.request.getParameter(name); return this.Filter(value); } public String Filter(String message) { if (message == null) return (null); char content[] = new char[message.length()]; message.getChars(0, message.length(), content, 0); StringBuffer result = new StringBuffer(content.length + 50); for (int i = 0; i < content.length; i++) { switch (content[i]) { case '<': result.append("<"); break; case '>': result.append(">"); break; case '&': result.append("&"); break; case '"': result.append("""); break; default: result.append(content[i]); } } return (result.toString()); } }