HttpServletRequestWrapper和HttpServletResponseWrapper详解( Servlet 高级部分)

  1. 概念解释:

Servlet规范中的filter引入了一个功能强大的拦截模式。Filter能在request到达servlet的服务方法之前拦截HttpServletRequest对象,而在服务方法转移控制后又能拦截HttpServletResponse对象

但是HttpServletRequest中的参数是无法改变的,若是手动执行修改request中的参数,则会抛出异常。且无法获取到HttpServletResponse中的输出流中的数据,因为HttpServletResponse中输出流的数据会写入到默认的输出端,你手动无法获取到数据。

我们可以利用HttpServletRequestWrapper包装HttpServletRequest,用HttpServletResponseWrapper包装HttpServletResponse,在Wrapper中实现参数的修改或者是response输出流的读取,然后用HttpServletRequestWrapper替换HttpServletRequest,HttpServletResponseWrapper替换HttpServletResponse。这样就实现了参数的修改设置和输出流的读取

 2.应用场景:

你可以使用filter来实现特定的任务,比如验证用户输入,以及压缩web内容。但HttpServletRequest对象的参数是不可改变的,这极大地缩减了filter的应用范围。至少在一半的时间里,你希望可以改变准备传送给 filter的对象。
幸运的是,尽管你不能改变不变对象本身,但你却可以通过使用装饰模式来改变其状态。

引入

实例的功能:对用户输入的敏感字眼进行过滤

应用场景:评论功能有时候需要对用户输入的某些敏感字眼进行过滤

实现架构:

模块一:前端页面:提供用户输入的界面,展示用户输入的内容

模块二:过滤器:对某些敏感字眼的过滤功能在此实现

模块三:servlet:在本实例中,因为用户的输入最终显示在用户输入的界面,因此servlet需要将用户输入的内容保存到request中,并且用requestDispatcher类请求转发到首页

示意图为:

源码:

首页index.jsp的源码如下:

<%@ page language="java" contentType="text/html" pageEncoding="GBK"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <title>意见反馈</title>
        <style type="text/css">
            body {
                margin: 0px;
                font-size: 12px;
            }
            td{
                font-size: 12px;
            }
            .div1{
                width: 1003px;
                height: 707px;
                background-image: url("images/bg.jpg");
            }
            .div2{
                width: 500px;
                margin-top:245px;
                margin-left:180px;
                text-align:left;
            }
            .tl{
                width: 500px;
                height: 20px;
                font-weight: bold;
                background: #A3C0C6;
                padding: 5px;
            }
            .ct{
                width: 500px;
                padding-left: 30px;
                padding-top: 5px;
                padding-bottom: 5px;
            }
            .tt{
                margin-left:5px;
                width: 70px;
                background: #A3C0C6;
                padding: 5px;
                font-weight: bold;
                font-size: 13px;
            }
        </style>
    </head>
 
    <body>
        <div align="center">
            <div class="div1">
                <div class="div2">
                    <%
                        String title = (String)request.getAttribute("title");
                        String content = (String)request.getAttribute("content");
                        if(title != null && !title.isEmpty()){
                            out.println("<span class='tl'>" + title + "</span>");
                        }
                        if(content != null && !content.isEmpty()){
                            out.println("<span class='ct'>" + content + "</span>");
                        }
                    %>
                    <span class="tl">谢谢你们</span>
                    <span class="ct">你们的公司服务态度非常好,谢谢你们!</span>
                    <span class="tl">谢谢你们</span>
                    <span class="ct">你们的公司服务态度非常好<br>但部分客服服务态度还要加强!</span>
                    <form action="filter" method="post">
                        <span class="tt">意见反馈</span>
                        <table border="0" width="500" align="center">
                            <tr>
                                <td align="right">标 题:</td>
                                <td><input type="text" name="title" size="30"></td>
                            </tr>
                            <tr>
                                <td align="right">内 容:</td>
                                <td>
                                    <textarea rows="5" cols="40" name="content"></textarea>
                                </td>
                            </tr>
                            <tr>
                                <td align="center" colspan="2">
                                    <input type="submit" value="提 交">
                                </td>
                            </tr>
                        </table>
                    </form>
                </div>
            </div>
        </div>
        
    </body>
</html>

过滤器MyFilterOne.java的代码如下:

 
  1. package com.ll.filter;

  2.  
  3. import java.io.IOException;

  4. import javax.servlet.Filter;

  5. import javax.servlet.FilterChain;

  6. import javax.servlet.FilterConfig;

  7. import javax.servlet.ServletException;

  8. import javax.servlet.ServletRequest;

  9. import javax.servlet.ServletResponse;

  10. import javax.servlet.annotation.WebFilter;

  11. import javax.servlet.http.HttpServletRequest;

  12. import javax.servlet.http.HttpServletRequestWrapper;

  13.  
  14. import org.apache.coyote.Request;

  15.  
  16. /**

  17. * Servlet Filter implementation class MyFilterOne

  18. */

  19. public class MyFilterOne implements Filter {

  20.  
  21. /**

  22. * Default constructor.

  23. */

  24. private String words[];//存放规定的敏感字

  25. private String encoding;//存放要使用的编码格式

  26. public MyFilterOne() {

  27. // TODO Auto-generated constructor stub

  28. }

  29.  
  30. /**

  31. * @see Filter#destroy()

  32. */

  33. public void destroy() {

  34. // TODO Auto-generated method stub

  35. this.words=null;

  36. this.encoding =null;

  37. }

  38.  
  39. /**

  40. * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)

  41. */

  42. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

  43. throws IOException, ServletException {

  44. // TODO Auto-generated method stub

  45. // place your code here

  46.  
  47. // pass the request along the filter chain

  48. if(encoding!=null) {

  49. request.setCharacterEncoding(encoding);//设置request字符编码

  50. request=new Request((HttpServletRequest)request);

  51. //将传递的ServletRequest对象转化为自定义的Request对象,即可实现非法字符的过滤

  52. response.setContentType("text/html;charset="+encoding);//设置response字符编码

  53. }

  54. chain.doFilter(request, response);

  55. }

  56.  
  57. /**

  58. * @see Filter#init(FilterConfig)

  59. */

  60. public void init(FilterConfig fConfig) throws ServletException {

  61. // TODO Auto-generated method stub

  62. words=new String[] {"糟糕","混蛋"};//定义敏感字符

  63. encoding=fConfig.getInitParameter("encoding");

  64. }

  65. class Request extends HttpServletRequestWrapper{

  66. /*创建内部类Request,

  67. 该类继承HttpServletRequestWrapper,

  68. 是HttpServletRequest的装饰类,

  69. 用来改变HttpServletRequest的状态,

  70. 从而达到对请求内容的过滤的功能*/

  71.  
  72. public Request(HttpServletRequest request) {

  73. super(request);

  74. // TODO 自动生成的构造函数存根

  75. }

  76. /*重写getParameter方法

  77. * 对请求结果进行过滤*/

  78. public String getParameter(String name) {

  79. return filter(super.getRequest().getParameter("name"));

  80. }

  81. /*重写getParameterValues方法

  82. * 通过循环取出每一个请求结果

  83. * 再对请求结果进行过滤*/

  84. public String[] getParameterValues(String name) {

  85. String values[]=super.getRequest().getParameterValues("name");

  86. for(int i=0;i<values.length;i++) {

  87. values[i]=filter(values[i]);

  88. }

  89. return values;

  90. }

  91. }

  92. /*创建过滤方法filter

  93. * 当敏感字不为空的时候,

  94. * 分别对每一个敏感字循环一次

  95. * 如果在param中发现敏感字则将其替换为“****” */

  96. public String filter(String param) {

  97. try{if(words!=null&&words.length>0) {

  98. for(int i=0;i<words.length;i++) {

  99. if(param.indexOf(words[i])!=-1) {

  100. param=param.replaceAll(words[i], "****");

  101. }

  102. }

  103. }}catch(Exception e) {

  104. e.printStackTrace();

  105. }

  106. return param;

  107. }

  108. }

servlet(MyServlet.java)的代码如下:

 
  1. package com.ll.servlet;

  2.  
  3. import java.io.IOException;

  4. import javax.servlet.ServletException;

  5. import javax.servlet.annotation.WebServlet;

  6. import javax.servlet.http.HttpServlet;

  7. import javax.servlet.http.HttpServletRequest;

  8. import javax.servlet.http.HttpServletResponse;

  9.  
  10. /**

  11. * Servlet implementation class MyServlet

  12. */

  13. @WebServlet("/MyServlet")

  14. public class MyServlet extends HttpServlet {

  15. private static final long serialVersionUID = 1L;

  16.  
  17. /**

  18. * @see HttpServlet#HttpServlet()

  19. */

  20. public MyServlet() {

  21. super();

  22. // TODO Auto-generated constructor stub

  23. }

  24.  
  25. /**

  26. * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)

  27. */

  28. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

  29. // TODO Auto-generated method stub

  30. // response.getWriter().append("Served at: ").append(request.getContextPath());

  31. }

  32.  
  33. /**

  34. * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)

  35. */

  36. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

  37. // TODO Auto-generated method stub

  38. // doGet(request, response);

  39. //先取出用户输入的内容

  40. String title=request.getParameter("title");

  41. String content=request.getParameter("content");

  42. //将用户输入的内容保存到request中

  43. request.setAttribute("title", title);

  44. request.setAttribute("content", content);

  45. //用RequestDispatcher对象请求转发至index.jsp页面

  46. request.getRequestDispatcher("index.jsp").forward(request, response);

  47. }

  48.  
  49. }

然后在web.xml文件中进行配置

 
  1. <?xml version="1.0" encoding="UTF-8"?>

  2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">

  3. <display-name>five</display-name>

  4. <welcome-file-list>

  5. <welcome-file>index.jsp</welcome-file>

  6. </welcome-file-list>

  7. <servlet>

  8. <servlet-name>MyServlet</servlet-name>

  9. <servlet-class>com.ll.servlet.MyServlet</servlet-class>

  10. </servlet>

  11. <servlet-mapping>

  12. <servlet-name>MyServlet</servlet-name>

  13. <url-pattern>/filter</url-pattern>

  14. </servlet-mapping>

  15. <filter>

  16. <filter-name>MyFilterOne</filter-name>

  17. <filter-class>com.ll.filter.MyFilterOne</filter-class>

  18. <init-param>

  19. <param-name>encoding</param-name>

  20. <param-value>GBK</param-value>

  21. </init-param>

  22. </filter>

  23. <filter-mapping>

  24. <filter-name>MyFilterOne</filter-name>

  25. <url-pattern>/*</url-pattern>

  26. </filter-mapping>

  27. </web-app>

HttpServletRequestWrapper类的使用

servlet规范中中引入的filter是非常有用的,因为它引入了一个功能强大的拦截模式。

filter是这样的一种java对象。它可以在request到达servlet之前拦截HttpServletRequest对象,也可以在服务方法转移控制后拦截HttpServletResponse对象。

我们可以使用filter对象完成的任务有:检查用户的输入、以及压缩web内容。

但是,当我们在使用filter的时候却会发现至少有一半的时间我们都想改变HttpServletRequest对象的参数。如:用filter在HttpServletRequest对象到达Servlet之前将用户输入的空格去掉。但是由于java.util.Map包装的HttpServletRequest对象的参数是不可改变的,那要怎么办呢?

幸运的是,尽管我们不能改变对象本身,但是可以通过装饰模式来改变其状态。

比如在上文中编写的内部类Request就是HttpServletRequest类的装饰类。

该类继承的HttpServletRequestWrapper类是HttpServletRequest类的装饰类。

这在jsp/servlet 中是非常有用的,web程序通过调用httpServletRequest对象的getParameter方法来处理表单,因此通过重写装饰类中的此方法就可以改变HttpServletRequest对象的状态。所以在上题的内部类Request中就重写了getParameter方法和getParameterValues方法。

因此,想要改变在httpServletRequest中的参数,可以通过httpServletRequest的装饰类HttpServletRequestWrapper来实现,只需要在装饰类中按照需要重写其getParameter(getParameterValues)方法即可。

参照资料:https://blog.csdn.net/qll19970326/article/details/80793465

https://blog.csdn.net/QH_JAVA/article/details/47908933

猜你喜欢

转载自blog.csdn.net/fight_man8866/article/details/81225129