Looking for an example for inserting content into the response using a servlet filter
我一直在搜索net和stackoverflow,寻找一个使用servlet过滤器将内容插入响应的示例,但只能找到捕获/压缩输出和/或更改头的示例。我的目标是在所有HTML响应的结束&60;/body&62;之前附加一块HTML。
我正在开发一个扩展httpservletresponsewrapper的解决方案,以使用我自己的printwriter,然后覆盖上面的写入方法。在write方法中,我将存储最后7个字符,以查看它是否等于结束体标记,然后在继续对文档其余部分进行正常写入操作之前,先编写HTML块和结束体标记。
我觉得一定有人已经解决了这个问题,也许比我更优雅。对于如何使用servlet过滤器将内容插入响应的任何示例,我都表示感谢。
更新的
在回应评论时,我还试图从http://www.oracle.com/technetwork/java/filters-137243.html实现charresponsewrapper。这是我的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | PrintWriter out = response.getWriter(); CharResponseWrapper wrappedResponse = new CharResponseWrapper( (HttpServletResponse)response); chain.doFilter(wrappedRequest, wrappedResponse); String s = wrappedResponse.toString(); if (wrappedResponse.getContentType().equals("text/html") && StringUtils.isNotBlank(s)) { CharArrayWriter caw = new CharArrayWriter(); caw.write(s.substring(0, s.indexOf("</body>") - 1)); caw.write("WTF</body></html>"); response.setContentLength(caw.toString().length()); out.write(caw.toString()); } else { out.write(wrappedResponse.toString()); } out.close(); |
我也在包装请求,但是代码可以工作,不应该影响响应。
我使用的代码基在处理响应时调用getOutputStream方法,而不是getWriter,因此其他答案中包含的示例没有帮助。这里有一个更完整的答案,它同时适用于outputstream和printwriter,即使在两次访问writer时出错也是正确的。这是从使用javax.servlet.filter的转储请求和响应这个很好的例子中派生出来的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class MyFilter implements Filter { private FilterConfig filterConfig = null; private static class ByteArrayServletStream extends ServletOutputStream { ByteArrayOutputStream baos; ByteArrayServletStream(ByteArrayOutputStream baos) { this.baos = baos; } public void write(int param) throws IOException { baos.write(param); } } private static class ByteArrayPrintWriter { private ByteArrayOutputStream baos = new ByteArrayOutputStream(); private PrintWriter pw = new PrintWriter(baos); private ServletOutputStream sos = new ByteArrayServletStream(baos); public PrintWriter getWriter() { return pw; } public ServletOutputStream getStream() { return sos; } byte[] toByteArray() { return baos.toByteArray(); } } public class CharResponseWrapper extends HttpServletResponseWrapper { private ByteArrayPrintWriter output; private boolean usingWriter; public CharResponseWrapper(HttpServletResponse response) { super(response); usingWriter = false; output = new ByteArrayPrintWriter(); } public byte[] getByteArray() { return output.toByteArray(); } @Override public ServletOutputStream getOutputStream() throws IOException { // will error out, if in use if (usingWriter) { super.getOutputStream(); } usingWriter = true; return output.getStream(); } @Override public PrintWriter getWriter() throws IOException { // will error out, if in use if (usingWriter) { super.getWriter(); } usingWriter = true; return output.getWriter(); } public String toString() { return output.toString(); } } public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; } public void destroy() { filterConfig = null; } public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { CharResponseWrapper wrappedResponse = new CharResponseWrapper( (HttpServletResponse)response); chain.doFilter(request, wrappedResponse); byte[] bytes = wrappedResponse.getByteArray(); if (wrappedResponse.getContentType().contains("text/html")) { String out = new String(bytes); // DO YOUR REPLACEMENTS HERE out = out.replace("</head>","WTF</head>"); response.getOutputStream().write(out.getBytes()); } else { response.getOutputStream().write(bytes); } } } |
您需要实现httpservletresponsewrapper来修改响应。请参阅本文档过滤器的要点,它有一个转换响应的示例,这比您想要的要多
编辑
我尝试过一个简单的带有响应过滤器的servlet,它工作得很好。servlet输出字符串
我在ApacheTomcat7上运行了下面的代码,它毫无例外地工作。
Servlet:
1 2 3 4 5 6 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().println("Test"); } |
过滤器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("BEFORE filter"); PrintWriter out = response.getWriter(); CharResponseWrapper responseWrapper = new CharResponseWrapper( (HttpServletResponse) response); chain.doFilter(request, responseWrapper); String servletResponse = new String(responseWrapper.toString()); out.write(servletResponse +" filtered"); // Here you can change the response System.out.println("AFTER filter, original response:" + servletResponse); } |
CharResponseWrapper(与文章完全相同)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class CharResponseWrapper extends HttpServletResponseWrapper { private CharArrayWriter output; public String toString() { return output.toString(); } public CharResponseWrapper(HttpServletResponse response) { super(response); output = new CharArrayWriter(); } public PrintWriter getWriter() { return new PrintWriter(output); } } |
Web.XML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <servlet> <servlet-name>TestServlet</servlet-name> <servlet-class>TestServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>TestServlet</servlet-name> <url-pattern>/TestServlet</url-pattern> </servlet-mapping> <filter> <filter-name>TestFilter</filter-name> <filter-class>MyFilter</filter-class> </filter> <filter-mapping> <filter-name>TestFilter</filter-name> <url-pattern>/TestServlet/*</url-pattern> </filter-mapping> |
ITECH的回答对我有部分作用,这是基于那个回答。
但您必须注意,似乎有些Web服务器(和AppEngine标准)在过滤器内部第一次调用chain.dofilter后关闭输出流。
因此,当您需要在预先保存的printwriter上写入时,流将关闭,您将得到一个空白屏幕。(我甚至没有错误地意识到发生了什么)。
所以我的解决方案是创建一个"虚拟"servletoutputstream,并返回到responsewrapper的getoutputstream方法中。
这些更改加上ITECH的解决方案允许我在JSON响应中插入HTML中完全呈现的JSP响应(正确地转义引号之类的冲突字符)。
这是我的代码:
My滤波器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | @WebFilter({"/json/*"}) public class Myfilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //Save original writer PrintWriter out = response.getWriter(); //Generate a response wrapper with a different output stream ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) response); //Process all in the chain (=get the jsp response..) chain.doFilter(request, responseWrapper); //Parse the response out.write("BEFORE"+responseWrapper.toString()+"AFTER"); //Just + for clear display, better use a StringUtils.concat } @Override public void destroy() {} } |
我的责任人:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | public class ResponseWrapper extends HttpServletResponseWrapper { private StringWriter output; public String toString() { return output.toString(); } public ResponseWrapper(HttpServletResponse response) { super(response); //This creates a new writer to prevent the old one to be closed output = new StringWriter(); } public PrintWriter getWriter() { return new PrintWriter(output,false); } @Override public ServletOutputStream getOutputStream() throws IOException { //This is the magic to prevent closing stream, create a"virtual" stream that does nothing.. return new ServletOutputStream() { @Override public void write(int b) throws IOException {} @Override public void setWriteListener(WriteListener writeListener) {} @Override public boolean isReady() { return true; } }; } } |