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

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

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

          1、實現(xiàn)一個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、實現(xiàn)一個HttpServletResponseWrapper

          public class CheckFrameHttpServletResponseWrapper extends
          HttpServletResponseWrapper {

          public CheckFrameHttpServletResponseWrapper(HttpServletResponse response) {

          super(response);
          }

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

          }

          3、實現(xiàn)一個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的內(nèi)容了。

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


          問題:

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

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

          評論:
          # re: 利用Filter修改Response 2007-07-15 19:53 | xuefeng
          你的wrapper實現(xiàn)有問題。應當在內(nèi)存中開辟一個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中調(diào)用:

          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狀態(tài)處理:
          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();
          }
          }

          需要判斷狀態(tài),正確設置Content-Length,具體可參考《Spring 2.0核心技術與最佳實踐》第十一章12節(jié):利用Filter實現(xiàn)內(nèi)存緩存和靜態(tài)文件緩存
            回復  更多評論
            
          # re: 利用Filter修改Response 2007-07-16 10:19 | Robin's Java World
          @xuefeng
          謝謝!
          有機會看看你推薦的書.  回復  更多評論
            
          # re: 利用Filter修改Response 2007-07-24 13:58 | xuefeng
          這本書是我寫的,呵呵,做個廣告  回復  更多評論
            
          主站蜘蛛池模板: 崇阳县| 松溪县| 子洲县| 雅江县| 观塘区| 丰县| 孝昌县| 冷水江市| 鹤山市| 驻马店市| 林口县| 通州市| 河津市| 阜宁县| 泰顺县| 梁河县| 榆林市| 明水县| 延长县| 涡阳县| 通渭县| 柘荣县| 乃东县| 潜山县| 理塘县| 西贡区| 平顺县| 潍坊市| 洪雅县| 元江| 鄂托克前旗| 丰都县| 弥渡县| 拜城县| 布尔津县| 沛县| 岫岩| 洱源县| 新宁县| 安溪县| 油尖旺区|