隨筆-193  評論-715  文章-1  trackbacks-0

          我們常常有需要在每一個頁面中加入一些內容,而這些內容又是固定的一些根據某些配置産生的內容,利如我們可以為每個頁面引入共用的編碼,引入共用的JavaScript等等。

          我們知道,利用JavaEE的Filter機制,可以截獲Request和Response,並對其進行修改。Filter實質上是一個Chain,對其原理的解釋,可以參考網路上的文章,有很多講得很好,大家有空可以看看。

          1、實現一個Filter,代碼如下:

          public class MyFilter implements Filter {

          public void doFilter(ServletRequest request, ServletResponse response,
          FilterChain filterChain) {
          CheckFrameHttpServletResponseWrapper wrapper = new CheckFrameHttpServletResponseWrapper(
          (HttpServletResponse) response);
          try {
          filterChain.doFilter(request, wrapper);
          } catch (Exception e) {
          e.printStackTrace();
          }
          }

          public void destroy() {

          }

          public void init(FilterConfig arg0) throws ServletException {

          }
          }


          2、實現一個HttpServletResponseWrapper

          public class CheckFrameHttpServletResponseWrapper extends
          HttpServletResponseWrapper {

          public CheckFrameHttpServletResponseWrapper(HttpServletResponse response) {

          super(response);
          }

          public PrintWriter getWriter() throws IOException{
          return new CheckFrameWriter(super.getWriter());
          }

          }

          3、實現一個Writer

          public class CheckFrameWriter extends PrintWriter {
          String checkString = "<script>\n if(window.top.frames.length==0){\n"
          + "window.location.href=\"https://aix:9080/sso/mainlayout.faces?"
          + "contentURL=http://aix:9080/security/paramsMaintain/"
          + "addParams.faces?roleId=0001\"\n" + "}\n</script>\n";

          public CheckFrameWriter(Writer out) {
          super(out);
          }

          public void write(int c) {
          super.write((char) c);
          }

          public void write(char buf[], int off, int len) {
          StringBuffer sb = new StringBuffer(len);
          for (int i = 0; i < len; i++) {
          sb.append(buf[off + i]);
          }
          String s = sb.toString();
          int bodyIndex = s.indexOf("<body>");
          if (bodyIndex > -1) {
          String part1 = s.substring(0, bodyIndex);
          String part2 = s.substring(bodyIndex );
          s = part1 + checkString + part2;
          }
          for (int i = 0; i < s.length(); i++) {
          write(s.charAt(i));
          }
          }

          public void write(String s, int off, int len) {
          for (int i = 0; i < len; i++) {
          write(s.charAt(off + i));
          }
          }
          }


          在Writer中,你便可以隨心所欲的修改Response的內容了。

          4、在Web.xml中加入相應的配置,對JSP進行攔截。


          問題:

          現在發現對於HTML後綴的請求,沒有辦法改寫,即使我配置Filter匹配為/*,HTML請求也有進行Filter,但還是無法改變其內容。目前還沒有想通是為什麼?如何改進?哪位大俠可以給予指點。

          posted on 2007-07-15 19:06 Robin's Programming World 閱讀(7178) 評論(4)  編輯  收藏 所屬分類: Java

          評論:
          # re: 利用Filter修改Response 2007-07-15 19:53 | xuefeng
          你的wrapper實現有問題。應當在內存中開辟一個ByteOutputStream,然后將攔截的響應寫入byte[],寫入完畢后,再將wrapper的byte[]寫入真正的response對象

          下面的例子是《Spring 2.0核心技術與最佳實踐》中的例子:

          package net.livebookstore.web.filter;

          import java.io.*;

          import javax.servlet.*;
          import javax.servlet.http.*;

          /**
          * This class is used for wrapped response for getting cached data.
          *
          * @author Xuefeng
          */
          class CachedResponseWrapper extends HttpServletResponseWrapper {

          /**
          * Indicate that getOutputStream() or getWriter() is not called yet.
          */
          public static final int OUTPUT_NONE = 0;

          /**
          * Indicate that getWriter() is already called.
          */
          public static final int OUTPUT_WRITER = 1;

          /**
          * Indicate that getOutputStream() is already called.
          */
          public static final int OUTPUT_STREAM = 2;

          private int outputType = OUTPUT_NONE;

          private int status = SC_OK;
          private ServletOutputStream output = null;
          private PrintWriter writer = null;
          private ByteArrayOutputStream buffer = null;

          public CachedResponseWrapper(HttpServletResponse resp) throws IOException {
          super(resp);
          buffer = new ByteArrayOutputStream();
          }

          public int getStatus() { return status; }

          public void setStatus(int status) {
          super.setStatus(status);
          this.status = status;
          }

          public void setStatus(int status, String string) {
          super.setStatus(status, string);
          this.status = status;
          }

          public void sendError(int status, String string) throws IOException {
          super.sendError(status, string);
          this.status = status;
          }

          public void sendError(int status) throws IOException {
          super.sendError(status);
          this.status = status;
          }

          public void sendRedirect(String location) throws IOException {
          super.sendRedirect(location);
          this.status = SC_MOVED_TEMPORARILY;
          }

          public PrintWriter getWriter() throws IOException {
          if(outputType==OUTPUT_STREAM)
          throw new IllegalStateException();
          else if(outputType==OUTPUT_WRITER)
          return writer;
          else {
          outputType = OUTPUT_WRITER;
          writer = new PrintWriter(new OutputStreamWriter(buffer, getCharacterEncoding()));
          return writer;
          }
          }

          public ServletOutputStream getOutputStream() throws IOException {
          if(outputType==OUTPUT_WRITER)
          throw new IllegalStateException();
          else if(outputType==OUTPUT_STREAM)
          return output;
          else {
          outputType = OUTPUT_STREAM;
          output = new WrappedOutputStream(buffer);
          return output;
          }
          }

          public void flushBuffer() throws IOException {
          if(outputType==OUTPUT_WRITER)
          writer.flush();
          if(outputType==OUTPUT_STREAM)
          output.flush();
          }

          public void reset() {
          outputType = OUTPUT_NONE;
          buffer.reset();
          }

          /**
          * Call this method to get cached response data.
          * @return byte array buffer.
          * @throws IOException
          */
          public byte[] getResponseData() throws IOException {
          flushBuffer();
          return buffer.toByteArray();
          }

          /**
          * This class is used to wrap a ServletOutputStream and
          * store output stream in byte[] buffer.
          */
          class WrappedOutputStream extends ServletOutputStream {

          private ByteArrayOutputStream buffer;

          public WrappedOutputStream(ByteArrayOutputStream buffer) {
          this.buffer = buffer;
          }

          public void write(int b) throws IOException {
          buffer.write(b);
          }

          public byte[] toByteArray() {
          return buffer.toByteArray();
          }
          }

          }

            回復  更多評論
            
          # re: 利用Filter修改Response 2007-07-15 20:00 | xuefeng
          在Filter中調用:

          public void doFilter(ServletRequest request, ServletResponse response,
          FilterChain chain) throws IOException, ServletException
          {
          HttpServletRequest httpRequest = (HttpServletRequest) request;
          HttpServletResponse httpResponse = (HttpServletResponse)response;
          CachedResponseWrapper wrapper = new CachedResponseWrapper(httpResponse);
          // 寫入wrapper:
          chain.doFilter(request, wrapper);
          // 首先判斷status, 只對200狀態處理:
          if(wrapper.getStatus()==HttpServletResponse.SC_OK) {
          // 對響應進行處理,這里是進行GZip壓縮:
          byte[] data = GZipUtil.gzip(wrapper.getResponseData());
          httpResponse.setContentType(getContentType());
          httpResponse.setContentLength(data.length);
          httpResponse.setHeader("Content-Encoding", "gzip");
          ServletOutputStream output = response.getOutputStream();
          output.write(data);
          output.flush();
          }
          }

          需要判斷狀態,正確設置Content-Length,具體可參考《Spring 2.0核心技術與最佳實踐》第十一章12節:利用Filter實現內存緩存和靜態文件緩存
            回復  更多評論
            
          # re: 利用Filter修改Response 2007-07-16 10:19 | Robin's Java World
          @xuefeng
          謝謝!
          有機會看看你推薦的書.  回復  更多評論
            
          # re: 利用Filter修改Response 2007-07-24 13:58 | xuefeng
          這本書是我寫的,呵呵,做個廣告  回復  更多評論
            
          主站蜘蛛池模板: 兴安盟| 绵竹市| 福贡县| 三亚市| 民乐县| 从化市| 玛曲县| 淮安市| 电白县| 景东| 和平区| 宜黄县| 伊川县| 绿春县| 南华县| 合山市| 修武县| 邵东县| 高青县| 塘沽区| 道孚县| 津市市| 津南区| 富平县| 九江县| 谢通门县| 黑水县| 双辽市| 黔南| 盐边县| 手游| 肥东县| 罗甸县| 翼城县| 永川市| 久治县| 河间市| 包头市| 宜昌市| 梅州市| 元谋县|