当前位置 : 主页 > 编程语言 > java >

用HttpServletResponseWrappper 获取jsp 输出内容

来源:互联网 收集:自由互联 发布时间:2021-06-25
代码1:在不跳转下访问目标jsp。 就是利用RequestDispatcher.include(ServletRequest request, ServletResponse response)。该方法把RequestDispatcher指向的目标页面写到response中。 代码1 public static StringgetJspO

代码1:在不跳转下访问目标jsp。就是利用RequestDispatcher.include(ServletRequest request, ServletResponse response)。该方法把RequestDispatcher指向的目标页面写到response中。

代码1
  1. public static String getJspOutput(String jsppath, HttpServletRequest request, HttpServletResponse response)      
  2. throws Exception      
  3. {      
  4. WrapperResponse wrapperResponse = new WrapperResponse(response);      
  5. request.getRequestDispatcher(jsppath).include(request, wrapperResponse);      
  6. return wrapperResponse.getContent();      
  7. }   

此处一个自定义类WrapperResponse封装了HttpServletResponse,具体请看一下代码

代码2:HttpServletResponse的封装类,继承自HttpServletResponseWrapper。其核心是构建一个OutputStream,且让HttpServletResponse获得的jsp内容输入到这个OutputStream。

java 代码2
  1. import java.io.ByteArrayOutputStream;     
  2. import java.io.IOException;     
  3. import java.io.PrintWriter;     
  4. import java.io.UnsupportedEncodingException;     
  5. import javax.servlet.http.HttpServletResponse;     
  6. import javax.servlet.http.HttpServletResponseWrapper;     
  7. public class WrapperResponse extends HttpServletResponseWrapper {     
  8.    private MyPrintWriter tmpWriter;     
  9.    private ByteArrayOutputStream output;     
  10.    public WrapperResponse(HttpServletResponse httpServletResponse) {     
  11.       super(httpServletResponse);     
  12.       output = new ByteArrayOutputStream();     
  13.       tmpWriter = new MyPrintWriter(output);     
  14.    }     
  15.    public void finalize() throws Throwable {     
  16.       super.finalize();     
  17.       output.close();     
  18.       tmpWriter.close();     
  19.    }     
  20.    public String getContent() {     
  21.       try {     
  22.          tmpWriter.flush();   //刷新该流的缓冲,详看java.io.Writer.flush()     
  23.          String s = tmpWriter.getByteArrayOutputStream().toString("UTF-8");     
  24.          //此处可根据需要进行对输出流以及Writer的重置操作     
  25.        //比如tmpWriter.getByteArrayOutputStream().reset()     
  26.          return s;     
  27.       } catch (UnsupportedEncodingException e) {     
  28.          return "UnsupportedEncoding";     
  29.       }     
  30.    }     
  31.     
  32.    //覆盖getWriter()方法,使用我们自己定义的Writer     
  33.    public PrintWriter getWriter() throws IOException {     
  34.       return tmpWriter;     
  35.    }     
  36.    public void close() throws IOException {     
  37.       tmpWriter.close();     
  38.    }     
  39.     
  40.    //自定义PrintWriter,为的是把response流写到自己指定的输入流当中     
  41.    //而非默认的ServletOutputStream     
  42.    private static class MyPrintWriter extends PrintWriter {     
  43.       ByteArrayOutputStream myOutput;   //此即为存放response输入流的对象     
  44.     
  45.       public MyPrintWriter(ByteArrayOutputStream output) {     
  46.          super(output);     
  47.          myOutput = output;     
  48.       }     
  49.       public ByteArrayOutputStream getByteArrayOutputStream() {     
  50.          return myOutput;     
  51.       }     
  52.    }     
  53. }    

转引结束

利用上面的WrapperResponse 类,写了一个filter,实现在jsp展现之前,获取即将展现的jsp的全部内容

获取这个内容的好处不多说(如果不知道就不用看下去了)

下面的代码利用filter,实现对字符串""的过滤,并转换成"邪教"显示

java 代码
  1. import java.io.IOException;     
  2.     
  3. import javax.servlet.Filter;     
  4. import javax.servlet.FilterChain;     
  5. import javax.servlet.FilterConfig;     
  6. import javax.servlet.ServletException;     
  7. import javax.servlet.ServletRequest;     
  8. import javax.servlet.ServletResponse;     
  9. import javax.servlet.http.HttpServletRequest;     
  10. import javax.servlet.http.HttpServletResponse;     
  11.     
  12. public class GavinFilter implements Filter      
  13. {     
  14.     
  15.     public void destroy()     
  16.     {     
  17.     // TODO 自动生成方法存根     
  18.          
  19.     }     
  20.     
  21.     public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain) throws IOException, ServletException     
  22.     {     
  23.          
  24.     HttpServletRequest request = (HttpServletRequest)arg0;     
  25.     HttpServletResponse response = (HttpServletResponse)arg1;     
  26.     WrapperResponse wrapperResponse = new WrapperResponse(response);     
  27.     chain.doFilter(request, wrapperResponse);     
  28.     String html = wrapperResponse.getContent();     
  29.     response.getWriter().print(html.replaceAll("""邪教"));     
  30.          
  31.     }     
  32.     
  33.     public void init(FilterConfig arg0) throws ServletException     
  34.     {     
  35.     // TODO 自动生成方法存根     
  36.          
  37.     }     
  38.          
  39.     public static String getJspOutput(String jsppath, HttpServletRequest request, HttpServletResponse response) throws Exception     
  40.     {     
  41.     WrapperResponse wrapperResponse = new WrapperResponse(response);     
  42.     request.getRequestDispatcher(jsppath).include(request, wrapperResponse);     
  43.     return wrapperResponse.getContent();     
  44.     }     
  45.     
  46.     
  47. }   
这么做的原因是:

Web服务器接收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象、和代表响应的response对象。
request和response对象既然代表请求和响应,那么我们要获取客户机提交过来的数据,只需要找request对象,就行了。要向客户机输出数据,只需要找response对象就行了。

HttpServletRequest封装客户端相关信息,服务器Servlet程序可以通过request对象操作客户端信息
HttpServletResponse封装服务器向客户端发送响应数据信息,Servlet程序通过response对象向客户端发送响应

response
1.response常用API
setStatus:设置响应行当中的状态码
setHeader:设置响应头信息
getOutputStream:获得字节流 --- 输出响应体内容
getWriter:获得字符流 --- 输出响应体内容
2.HttpServletResponse继承ServletResponse接口,ServletResponse并没有提供与HTTP协议相关API,HttpServletResponse添加了与协议相关API
JavaEE API 中并没有提供HttpServletResponse实现类---实现类由tomcat服务器提供的
3.常用状态码:200 302 304 404 500
200 请求处理成功
302 客户端重定向
304 客户端访问资源没有被修改,客户端访问本地缓存
404 访问资源不存在
500 服务器内部出错


因为WrapperResponse extends HttpServletResponseWrapper extends ServletResponseWrapper,ServletResponseWrapper的getWriter()方法实现:

    public PrintWriter getWriter() throws IOException {
        return this.response.getWriter();
    }


如果一个类继承了父类,并且重写这个方法,用于自己的逻辑。




  1. package   cc.mzone.test   ;
  2.  
  3. import   java.io.CharArrayWriter   ;
  4. import   java.io.PrintWriter   ;
  5.  
  6. import   javax.servlet.http.HttpServletResponse   ;
  7. import   javax.servlet.http.HttpServletResponseWrapper   ;
  8.  
  9. /**
  10.  * 自定义一个响应结果包装器,将在这里提供一个基于内存的输出器来存储所有
  11.  * 返回给客户端的原始HTML代码。
  12.  *
  13.  * @author 铁木箱子
  14.  *
  15.  */
  16. public   class  ResponseWrapper   extends  HttpServletResponseWrapper   {
  17. private   PrintWriter  cachedWriter   ;
  18. private   CharArrayWriter  bufferedWriter   ;
  19.  
  20. public  ResponseWrapper   (HttpServletResponse response   )   {
  21. super   (response   )   ;
  22. // 这个是我们保存返回结果的地方
  23. bufferedWriter   =   new   CharArrayWriter   (   )   ;
  24. // 这个是包装PrintWriter的,让所有结果通过这个PrintWriter写入到bufferedWriter中
  25. cachedWriter   =   new   PrintWriter   (bufferedWriter   )   ;
  26. }
  27.  
  28. @Override
  29. public   PrintWriter  getWriter   (   )   {
  30. return  cachedWriter   ;
  31. }
  32.  
  33. /**
  34. * 获取原始的HTML页面内容。
  35. * @return
  36. */
  37. public   String  getResult   (   )   {
  38. return  bufferedWriter.   toString   (   )   ;
  39. }
  40. }

      然后再写一个过滤器来截获内容并处理:

 
   
  1. package   cc.mzone.test   ;
  2.  
  3. import   java.io.IOException   ;
  4. import   java.io.PrintWriter   ;
  5.  
  6. import   javax.servlet.Filter   ;
  7. import   javax.servlet.FilterChain   ;
  8. import   javax.servlet.FilterConfig   ;
  9. import   javax.servlet.ServletException   ;
  10. import   javax.servlet.ServletRequest   ;
  11. import   javax.servlet.ServletResponse   ;
  12. import   javax.servlet.http.HttpServletResponse   ;
  13.  
  14. public   class  MyServletFilter   implements  Filter   {
  15.  
  16. @Override
  17. public   void  destroy   (   )   {
  18. // TODO Auto-generated method stub
  19.  
  20. }
  21.  
  22. @Override
  23. public   void  doFilter   (ServletRequest request, ServletResponse response,
  24. FilterChain chain   )   throws   IOException, ServletException   {
  25. // 使用我们自定义的响应包装器来包装原始的ServletResponse
  26. ResponseWrapper wrapper   =   new  ResponseWrapper   (   (HttpServletResponse   )response   )   ;
  27. // 这句话非常重要,注意看到第二个参数是我们的包装器而不是response
  28. chain.   doFilter   (request, wrapper   )   ;
  29. // 处理截获的结果并进行处理,比如替换所有的“名称”为“铁木箱子”
  30. String  result   =  wrapper.   getResult   (   )   ;
  31. result   =  result.   replace   (   "名称",   "铁木箱子"   )   ;
  32. // 输出最终的结果
  33. PrintWriter  out   =  response.   getWriter   (   )   ;
  34. out.   write   (result   )   ;
  35. out.   flush   (   )   ;
  36. out.   close   (   )   ;
  37. }
  38.  
  39. @Override
  40. public   void  init   (FilterConfig filterConfig   )   throws  ServletException   {
  41. // TODO Auto-generated method stub
  42.  
  43. }
  44.  
  45. }

      然后将该servlet配置在web.xml文件中,如下:

 
   
  1. >
  2. >myFilter   >
  3. >cc.mzone.test.MyServletFilter   >
  4. >
  5. >
  6. >myFilter   >
  7. >*.jsp   >
  8. >

      我们上面配置的是只过滤访问后缀为.jsp的url地址,当然你可以根据自己的需要修改成其他的过滤模式。然后我们在web应用根目录下建立一个jsp文件test.jsp,内容如下:

 
   
  1. <%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" %>
  2. >
  3. >
  4. <span style="color: rgb(0, 0, 0); font-weight: bold;">></span></span></span>页面返回结果过滤测试<span style="color: rgb(0, 153, 0);"><span style="color: rgb(0, 0, 0); font-weight: bold;">>   >
  5. >
  6. >
  7. 你好,我叫“名称”。
  8. >
  9. >

          配置完后,部署到tomcat,然后访问应用下的test.jsp文件,就可以发现返回的内容变成了:

     
           
    1. 你好,我叫“铁木箱子”

          而不是页面中原始的内容:

     
           
    1. 你好,我叫“名称”

          从而也就达到了我们想要的效果了。在文章开头我也提到了说有一个问题,那就是有可能在运行的过程中页面只输出一部分,尤其是在使用多个框架后(比如sitemesh)出现的可能性非常大,在探究了好久之后终于发现原来是响应的ContentLength惹的祸。因为在经过多个过滤器或是框架处理后,很有可能在其他框架中设置了响应的输出内容的长度,导致浏览器只根据得到的长度头来显示部分内容。知道了原因,处理起来就比较方便了,我们在处理结果输出前重置一下ContentLength即可,如下:

     
           
    1. // 重置响应输出的内容长度
    2. response.   setContentLength   (   -   1   )   ;
    3. // 输出最终的结果
    4. PrintWriter  out   =  response.   getWriter   (   )   ;
    5. out.   write   (result   )   ;
    6. out.   flush   (   )   ;
    7. out.   close   (   )   ;

          这样处理后就不会再出现只出现部分页面的问题了!

网友评论