public class ToHtml extends HttpServlet { public void service(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException { 
   String url = ""; 
   String name = "";    ServletContext sc = getServletContext();    String file_name = request.getParameter("file_name");// 你要访问的jsp文件名,如index,不包括扩展名 
   
   name ="E:\\"+ file_name + ".htm";
    RequestDispatcher rd = sc.getRequestDispatcher(url); 
   final ByteArrayOutputStream os = new ByteArrayOutputStream();    final PrintWriter pw = new PrintWriter(new OutputStreamWriter(os)); 

   HttpServletResponse rep = new HttpServletResponseWrapper(response) {     //这没有时,只新建一个index.htm,里面没有内容,且还有"This is my JSP page."
    public PrintWriter getWriter() { 
     //试一下会不会执行getOutputStream()
     System.out.print("执行了getWriter()");
     return pw; 
    } }; 
   
   rd.include(request, rep);
      //没有这句时,只会新建一个index.htm,里面没有内容,但没有"This is my JSP page."
   pw.flush(); 

   FileOutputStream fos = new FileOutputStream(name); // 把jsp输出的内容写到xxx.htm    os.writeTo(fos); 
   fos.close(); 
   PrintWriter out = response.getWriter();    out.print("<p align=center><font size=3 color=red>页面已经成功生成!single<br>http://www.agilejava.org/space/? 233</font></p>"); 
  } 
     
 } -----------------------
index.jsp里面只有一句"This is my JSP page."1.为什么HttpServletResponse rep 里面的getWriter() 会自动执行?
2.为什么必须要有getWriter() 和pw.flush(); 不然就会输出一个空的文件,两个都要,少一个都不行?
3.帮忙解释一下HttpServletResponseWrapper(response)做什么,还有什么是包装模式?上面的问题最好有例子

解决方案 »

  1.   

    1,使用了内部类,相当于new了一个response流来初始化HttpServletResponseWrapper(),以下为其构造器:
    HttpServletResponseWrapper(HttpServletResponse response) 
    所以如果不使用以上内部类来获取response,那么你在初始化HttpServletResponseWrapper之前,那么你要先创建一个HttpServletResponse 对象;
    2,getWriter() 和pw.flush(),一个获取流进行写操作,但只写进缓存,还没写进制定文件,因此需要你使用flush()方法,刷新该流的缓存;
    3,public   class   HttpServletResponseWrapper   extends   ServletResponseWrapper
          implements   HttpServletResponse ----------多参考一下api,你会懂的更多
      

  2.   

    看下这里http://blog.sina.com.cn/s/blog_4fe227ba0100j5af.html
    HttpServletResponseWrapper为我们实现对response对象的后处理提供了帮助——你只需编写一个HttpServletResponseWrapper的子类,加入自己的功能实现(修饰器模式)。那么子类化HttpServletResponseWrapper都需要重写那些方法呢?
    1、获取response对象,并将输出存放在自定义的流里面,那么关于输出流(outputStream、writer)的操作都是需要重写的了:
       1)以流的方式获取输出——重写getOutputStream()
       2)以字符方式获取输出——重写getWriter()
       3)刷新流——重写flushBuffer()
       4)重置流——重写reset()
    然后加入新增的获取输出数据的方法就ok了。
    2、定义response包装器WapperedResponse继承HttpServletResponseWrapper
    public class WapperedResponse extends HttpServletResponseWrapper {   
        private ByteArrayOutputStream buffer=null;   
        private ServletOutputStream out=null;   
        private PrintWriter writer=null;   
           
        public GZipResponse(HttpServletResponse resp) throws IOException{   
            super(resp);   
            buffer=new ByteArrayOutputStream();//真正存储数据的流   
            out=new WapperedOutputStream(buffer);   
            writer=new PrintWriter(new OutputStreamWriter(buffer,this.getCharacterEncoding()));   
        }   
        //重载父类获取outputstream的方法   
        @Override  
        public ServletOutputStream getOutputStream()throws IOException{   
            return out;   
        }   
        //重载父类获取writer的方法   
        @Override  
        public PrintWriter getWriter() throws UnsupportedEncodingException{   
            return writer;   
        }   
        //重载父类获取flushBuffer的方法   
        @Override  
        public void flushBuffer()throws IOException{   
            if(out!=null){   
                out.flush();   
            }   
            if(writer!=null){   
                writer.flush();   
            }   
        }   
        @Override  
        public void reset(){   
            buffer.reset();   
        }   
        public byte[] getResponseData()throws IOException{   
            flushBuffer();//将out、writer中的数据强制输出到WapperedResponse的buffer里面,否则取不到数据   
            return buffer.toByteArray();   
        }   
           
        //内部类,对ServletOutputStream进行包装   
        private class WapperedOutputStream extends ServletOutputStream{   
            private ByteArrayOutputStream bos=null;   
            public WapperedOutputStream(ByteArrayOutputStream stream) throws IOException{   
                bos=stream;   
            }   
            @Override  
            public void write(int b) throws IOException{   
                bos.write(b);   
            }   
        }   
    }  那么Servlet容器通过调用getOutputStream()方法获得的输出流将是我们自定义的包装流WapperedOutputStream。3、现在就可以在过滤器中使用WapperedResponse进行对response包装、处理了。public void doFilter(ServletRequest arg0, ServletResponse arg1,   
                FilterChain arg2) throws IOException, ServletException {   
            HttpServletResponse resp=(HttpServletResponse)arg1;   
            WapperedResponse wapper=new WapperedResponse(resp);   
            arg2.doFilter(arg0, wapper);   
            byte[] b1=wapper.getResponseData();   
            //do something with b1 here   
            byte[] b2=...;   
            //输出处理后的数据   
            ServletOutputStream output=arg1.getOutputStream();   
            output.write(b2);   
            output.flush();   
        }  
      

  3.   

    调用rd.include(request, rep);
    会将RequestDispatcher rd = sc.getRequestDispatcher(url);
    设置的URL资源,也就是"This is my JSP page." 写入 rep中。(通过调用res.getWriter())
    由于rep是一个HttpServletResponseWrapper匿名类,你重载了getWriter方法写到你定义的printWriter里去了,结果内容自然就写到文件中了。至于pw.flush(); 的问题,那是因为printWriter有缓冲机制,并不是每次写操作就直接写到outputstream去了,所以你要手动flush一下。HttpServletResponseWrapper是HttpServletResponse的一个包装类。所谓的包装模式就是就是在原有类的行为特性的基础上增加一层包装,以满足我们新的要求。
    在这里你就做了一个包装,是它写到你定制的输入流,而不是默认的写到客户端过来。