过滤器应用【编码、敏感词、压缩、转义过滤器】


声明:本文转载自https://my.oschina.net/u/3777556/blog/1620404,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

前言

在上篇博文中,我们已经讲解了过滤器的基本概念,使用以及简单的Servlet应用了。这篇博文主要讲解过滤器的高级应用。。

编码过滤器

目的:解决全站的乱码问题

开发过滤器

     public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {          //将request和response强转成http协议的         HttpServletRequest httpServletRequest = (HttpServletRequest) req;         HttpServletResponse httpServletResponse = (HttpServletResponse) resp;          httpServletRequest.setCharacterEncoding("UTF-8");         httpServletResponse.setCharacterEncoding("UTF-8");         httpServletResponse.setContentType("text/html;charset=UTF-8");                  chain.doFilter(httpServletRequest, httpServletResponse);     }   

第一次测试

Servlet1中向浏览器回应中文数据,没有出现乱码。

     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {          response.getWriter().write("看完博客点赞!");      }  

 

这里写图片描述

 

分析

上面的过滤器是不完善的,因为浏览器用get方式提交给服务器的中文数据,单单靠上面的过滤器是无法完成的!

那么我们需要怎么做呢??我们之前解决get方式的乱码问题是这样的:使用request获取传递过来的数据,经过ISO 8859-1反编码获取得到不是乱码的数据(传到Servlet上的数据已经被ISO 8859-1编码过了,反编码就可以获取原来的数据),再用UTF-8编码,得到中文数据!

参考我之前的博文:mp.weixin.qq.com/s?__biz=MzI…

在Servlet获取浏览器以GET方式提交过来的中文是乱码的根本原因是:getParameter()方法是以ISO 8859-1的编码来获取浏览器传递过来的数据的,得到的是乱码

既然知道了根本原因,那也好办了:过滤器传递的request对象,使用getParameter()方法的时候,获取得到的是正常的中文数据

也就是说,sun公司为我们提供的request对象是不够用的,因为sun公司提供的request对象使用getParameter()获取get方式提交过来的数据是乱码,于是我们要增强request对象(使得getParameter()获取得到的是中文)!

增强request对象

增强request对象,我们要使用包装设计模式!

包装设计模式的五个步骤:

  • **1、实现与被增强对象相同的接口 **
  • 2、定义一个变量记住被增强对象
  • 3、定义一个构造器,接收被增强对象
  • 4、覆盖需要增强的方法
  • 5、对于不想增强的方法,直接调用被增强对象(目标对象)的方法

sun公司也知道我们可能对request对象的方法不满意,于是提供了HttpServletRequestWrapper类给我们实现(如果实现HttpServletRequest接口的话,要实现太多的方法了!)

  	class MyRequest extends HttpServletRequestWrapper { 	 	    private HttpServletRequest request; 	 	    public MyRequest(HttpServletRequest request) { 	        super(request); 	        this.request = request; 	    } 	 	    @Override 	    public String getParameter(String name) { 	        String value = this.request.getParameter(name); 	 	        if (value == null) { 	            return null; 	        } 	 	        //如果不是get方法的,直接返回就行了 	        if (!this.request.getMethod().equalsIgnoreCase("get")) { 	            return null; 	        } 	 	        try { 	 	            //进来了就说明是get方法,把乱码的数据 	            value = new String(value.getBytes("ISO8859-1"), this.request.getCharacterEncoding()); 	            return value ; 	 	        } catch (UnsupportedEncodingException e) { 	            e.printStackTrace(); 	 	            throw new RuntimeException("不支持该编码"); 	        } 	 	    } 	}   

将被增强的request对象传递给目标资源,那么目标资源使用request调用getParameter()方法的时候,获取得到的就是中文数据,而不是乱码了!

         //将request和response强转成http协议的         HttpServletRequest httpServletRequest = (HttpServletRequest) req;         HttpServletResponse httpServletResponse = (HttpServletResponse) resp;          httpServletRequest.setCharacterEncoding("UTF-8");         httpServletResponse.setCharacterEncoding("UTF-8");         httpServletResponse.setContentType("text/html;charset=UTF-8");          MyRequest myRequest = new MyRequest(httpServletRequest);  		//传递给目标资源的request是被增强后的。         chain.doFilter(myRequest, httpServletResponse);  

第二次测试

  • 使用get方式传递中文数据给服务器
 <form action="${pageContext.request.contextPath}/Servlet1" method="get">      <input type="hidden" name="username" value="中国">           <input type="submit" value="提交"> </form> 


 

这里写图片描述

 

敏感词的过滤器

如果用户输入了敏感词(傻b、尼玛、操蛋等等不文明语言时),我们要将这些不文明用于屏蔽掉,替换成符号!

要实现这样的功能也很简单,用户输入的敏感词肯定是在getParameter()获取的,我们在getParameter()得到这些数据的时候,判断有没有敏感词汇,如果有就替换掉就好了!简单来说:也是要增强request对象

增强request对象

 	class MyDirtyRequest extends HttpServletRequestWrapper { 	 	    HttpServletRequest request; 	 	    //定义一堆敏感词汇 	    private List<String> list = Arrays.asList("傻b", "尼玛", "操蛋"); 	 	    public MyDirtyRequest(HttpServletRequest request) { 	        super(request); 	        this.request = request; 	    } 	 	    @Override 	    public String getParameter(String name) { 	 	        String value = this.request.getParameter(name); 	 	        if (value == null) { 	            return null; 	        } 	 	        //遍历list集合,看看获取得到的数据有没有敏感词汇 	        for (String s : list) { 	 	            if (s.equals(value)) { 	                value = "*****"; 	            } 	        } 	 	        return value ; 	    } 	}  

开发过滤器

     public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {          //将request和response强转成http协议的         HttpServletRequest httpServletRequest = (HttpServletRequest) req;         HttpServletResponse httpServletResponse = (HttpServletResponse) resp;          MyDirtyRequest dirtyRequest = new MyDirtyRequest(httpServletRequest);          //传送给目标资源的是被增强后的request对象         chain.doFilter(dirtyRequest, httpServletResponse);     }  

测试

 

这里写图片描述

 

压缩资源过滤器

按照过滤器的执行顺序:执行完目标资源,过滤器后面的代码还会执行。所以,我们在过滤器中可以获取执行完目标资源后的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("&lt;");                     break;                 case '>':                     result.append("&gt;");                     break;                 case '&':                     result.append("&amp;");                     break;                 case '"':                     result.append("&quot;");                     break;                 default:                     result.append(content[i]);             }         }         return (result.toString());              }      }  

过滤器

        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {            HttpServletRequest request = (HttpServletRequest) req;         HttpServletResponse response = (HttpServletResponse) resp;         MyHtmlRequest myHtmlRequest = new MyHtmlRequest(request);          //传入的是被增强的request!         chain.doFilter(myHtmlRequest, response);      }  

测试

jsp代码:

 	<form action="${pageContext.request.contextPath}/Servlet1" method="post"> 	 	 	    <input type="hidden" name="username" value="<h1>你好i好<h1>"> 	 	    <input type="submit" value="提交"> 	</form>  

Servlet代码:

     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {          String value = request.getParameter("username");         response.getWriter().write(value);      }  

 

这里写图片描述

 

缓存数据到内存中

在前面我们已经做过了,让浏览器不缓存数据【验证码的图片是不应该缓存的】。

现在我们要做的是:缓存数据到内存中【如果某个资源重复使用,不轻易变化,应该缓存到内存中】

这个和压缩数据的Filter非常类似的,因为让数据不直接输出给浏览器,把数据用一个容器(ByteArrayOutputSteam)存起来。如果已经有缓存了,就取缓存的。没有缓存就执行目标资源!

增强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;     } }   //增强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);      } } 

过滤器

      public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {          //定义一个Map集合,key为页面的地址,value为内存的缓存         Map<String, byte[]> map = new HashMap<>();          HttpServletRequest request = (HttpServletRequest) req;         HttpServletResponse response = (HttpServletResponse) resp;          //得到客户端想要请求的资源         String uri = request.getRequestURI();         byte[] bytes = map.get(uri);          //如果有缓存,直接返回给浏览器就行了,就不用执行目标资源了         if (bytes != null) {             response.getOutputStream().write(bytes);             return ;         }          //如果没有缓存,就让目标执行         MyResponse myResponse = new MyResponse(response);         chain.doFilter(request, myResponse);          //得到目标资源想要发送给浏览器的数据         byte[] b = myResponse.getBuffer();          //把数据存到集合中         map.put(uri, b);          //把数据返回给浏览器         response.getOutputStream().write(b);       }  

测试

尽管是刷新,获取得到的也是从缓存拿到的数据!

 

这里写图片描述

 

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章的同学,可以关注微信公众号:Java3y

 

本文发表于2018年02月09日 10:31
(c)注:本文转载自https://my.oschina.net/u/3777556/blog/1620404,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 2601 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

万稳万当,不如一默。任何一句话,你不说出来便是那句话的主人,你说了出来,便是那句话的奴隶。

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1