前言:
此刻姐妹们对“js敏感词过滤器”可能比较关注,我们都需要知道一些“js敏感词过滤器”的相关文章。那么小编也在网摘上收集了一些对于“js敏感词过滤器””的相关资讯,希望姐妹们能喜欢,各位老铁们一起来学习一下吧!在上篇博文中,我们已经讲解了过滤器的基本概念,使用以及简单的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编码,得到中文数据!
在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上。
这里写图片描述
@Overridepublic 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()); }}
过滤器
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