隨筆-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 閱讀(7174) 評論(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
          這本書是我寫的,呵呵,做個廣告  回復  更多評論
            
          主站蜘蛛池模板: 商水县| 三门峡市| 泰兴市| 沁源县| 乌苏市| 许昌县| 民勤县| 锡林浩特市| 广灵县| 讷河市| 定兴县| 宝山区| 屏山县| 绿春县| 舞阳县| 七台河市| 垣曲县| 富平县| 天峨县| 松溪县| 海伦市| 镇坪县| 新蔡县| 青龙| 南昌县| 黑山县| 鲁山县| 星座| 东港市| 茌平县| 师宗县| 故城县| 龙口市| 那坡县| 宁南县| 安岳县| 马公市| 平昌县| 淮阳县| 锦州市| 论坛|