zoukankan      html  css  js  c++  java
  • 过滤器与请求封装器实现字符替换

    背景

      假设有个留言版程序已经上线并正常运作中,但是现在发现,有些用户会在留言中输入一些HTML标签。基于安全性的考量,不希望用户输入的HTML标签直接出现在留言中而被浏览器当作HTML的一部分。例如,并不希望用户在留言中输入com.sina.com.cn这样的信息,你不想信息在留言显示中直接变成超链接,让用户有机会在留言版中打广告,希望将一些HTML过滤掉,如将<、>角括号置换为HTML实体字符&lt;与&gt;。
      使用<、>角括号与&lt;与&gt;的区别:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <a href="www.baidu.com">点击我</a><br>
        &lt;a href=&quot;www.baidu.com&quot;&gt;点击我&lt;/a&gt;
    </body>
    </html>
    Html Code

      上面的html文件直接使用浏览器打开后如下所示:

    点击我
    <a href="www.baidu.com">点击我</a>


    实现分析

       1、使用过滤器来过滤请求参数。

       2、但虽然可以使用HttpServletRequest的getParameter()取得请求参数值,但就是没有一个像setParameter()的方法,可以将处理过后的请求参数重新设置给HttpServletRequest。你也许会想要亲自实现HttpServletRequest接口,让getParameter()返回过滤后的请求参数值,但这么做的话,HttpServletRequest接口定义的方法都要实现,实现所有方法非常麻烦。所幸,有个HttpServletRequestWrapper帮忙实现了HttpServletRequest接口,只要继承HttpServletRequestWrapper类,并编写想要重新定义的方法即可。相对应于ServletRequest接口,也有个ServletRequestWrapper类可以使用。


    代码实现

      1、添加jar包,这里直接使用Apache Commons Lang包中的方法来实现替换字符。

    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.4</version>
    </dependency>
    pom.xml

      2、请求封装器

    package com.test;
    
    import org.apache.commons.lang3.StringEscapeUtils;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    
    public class MyRequestWrapper extends HttpServletRequestWrapper {
        // 构造方法不可少,且在方法内部必须调用父类的构造方法
        public MyRequestWrapper(HttpServletRequest request) {
            super(request);
        }
        @Override
        public String getParameter(String name) {
            String parameter = getRequest().getParameter(name);
            // 使用Apache Commons Lang程序库中StringEscapeUtils类提供的escapeHtml()方法来进行字符替换
            return StringEscapeUtils.escapeHtml3(parameter);
        }
    }
    java Code 

      代码中定义了一个接受HttpServletRequest的构造器,真正的HttpServletRequest将通过此构造器传入,必须使用super(request)调用父类(装饰类)的构造方法,父类(装饰类)会将它赋值给一个成员变量。之后如果要取得被封装的HttpServletRequest,则可以调用getRequest()方法。

    String parameter = getRequest().getParameter(name); // 被装饰对象,即原始的请求对象的方法被调用。
    return StringEscapeUtils.escapeHtml3(parameter);       // 添加新功能

      3、拦截器

    package com.test;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    @WebFilter("/*")
    public class RequestStringFilter implements Filter {
        private FilterConfig filterConfig;
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            this.filterConfig = filterConfig;
        }
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            MyRequestWrapper myRequestWrapper = new MyRequestWrapper(request);
            chain.doFilter(myRequestWrapper, response);
        }
        public void destroy() { }
    }
    java Code

      4、页面

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <form action="hello" method="post">
            <textarea rows="5" cols="100" name="message"></textarea><br>
            <input type="submit" value="提交">
        </form>
    </body>
    </html>
    Html Code

      5、servlet

    package com.test;
    
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    @WebServlet(urlPatterns = "/hello")
    public class MyServlet extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
            doPost(request, response);
        }
    
        public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
            request.setCharacterEncoding("UTF-8");
            String message = request.getParameter("message");
    
            response.setContentType("text/html");
            response.setCharacterEncoding("UTF-8");
            PrintWriter writer = response.getWriter();
    
            writer.println("<!DOCTYPE html>");
            writer.println("<html>");
            writer.println("<head>");
            writer.println("<meta charset="UTF-8">");
            writer.println("<title>Title</title>");
            writer.println("</head>");
            writer.println("<body>");
            writer.print(message);
            writer.println("</body>");
            writer.println("</html>");
            writer.close();
        }
    }
    java Code

    测试方法

      1、访问页面 http://127.0.0.1/index.html

      2、在页面中的大文本框输入:<a href="www.baidu.com">点击我</a>

      3、点击提交 

     

  • 相关阅读:
    也谈用反射实现Enum→String映射:一种重视性能的方法【转载】
    C#对象的浅拷贝,深拷贝【转载】
    int转byte[],byte[]转int
    TF31003:您的用户帐户没有连接到 Team Foundation Server 的权限
    关于枚举的双语显示问题
    浅析C#深拷贝与浅拷贝
    反射枚举变量
    C#路径/文件/目录/I/O常见操作汇总(二)
    【转】正确理解ThreadLocal
    【转】JSP的九个隐含对象
  • 原文地址:https://www.cnblogs.com/Mike_Chang/p/10064800.html
Copyright © 2011-2022 走看看