随笔-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 阅读(6990) 评论(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
这本书是我写的,呵呵,做个广告  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: