我一直在网上和stackoverflow上搜索有人使用servlet过滤器将内容插入到响应中的示例,但只能找到捕获/压缩输出和/或更改标头的示例。我的目标是在关闭所有HTML响应之前添加一大块HTML。
我正在研究一种解决方案,它扩展HttpServletResponseWrapper以使用我自己的PrintWriter,然后覆盖其上的写方法。在write方法中,我存储最后7个字符,看看它是否等于结束body标记,然后写入HTML块加上结束body标记,然后继续对文档的其余部分执行正常的写操作。
我觉得一定有人已经解决了这个问题,而且可能比我更优雅。我非常感谢任何有关如何使用servlet过滤器将内容插入到响应中的示例。
已更新
作为对一条评论的回应,我也在尝试从http://www.oracle.com/technetwork/java/filters-137243.html实现CharResponseWrapper。下面是我的代码:
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();我也包装了请求,但代码可以正常工作,不会影响响应。
发布于 2013-02-07 07:57:45
我使用的代码库在处理响应时调用getOutputStream方法,而不是getWriter,因此另一个答案中包含的示例没有帮助。这是一个更完整的答案,既适用于OutputStream,也适用于PrintWriter,如果编写器被访问两次,甚至会出现错误。这是从一个很好的例子DUMP REQUEST AND RESPONSE USING JAVAX.SERVLET.FILTER派生出来的。
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);
}
}
}发布于 2013-02-07 03:08:28
您将需要实现HttpServletResponseWrapper来修改响应。请参阅本文档The Essentials of Filters,其中有一个转换响应的示例,该示例超出了您所需的范围
编辑
我试过一个简单的带有响应过滤器的Servlet,它工作得很好。Servlet输出字符串Test,响应过滤器向其附加字符串filtered,最后,当我从浏览器运行时,我得到了响应Test filtered,这正是您要实现的目标。
我确实在Apache Tomcat7上运行了下面的代码,并且运行正常。
Servlet:
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println("Test");
}过滤器:
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 (与本文完全相同)
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
<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>发布于 2018-03-13 23:37:08
iTech的回答在一定程度上对我起了作用,这是基于这个回答。
但是你必须注意到,一些web服务器(和AppEngine标准版)在第一次调用过滤器中的chain.doFilter后关闭了outputStream。
因此,当你需要在预先保存的PrintWritter上写东西时,流就会关闭,你会得到一个空白屏幕。(我甚至没有收到一个错误来意识到发生了什么)。
因此,我的解决方案是创建一个“虚拟的”ServletOutputStream,然后返回到我的ResponseWrapper的getOutputStream方法中。
这些更改加上iTech的解决方案允许我在json响应内的html中插入完全呈现的jsp响应(正确地转义像引号这样的冲突字符)。
这是我的代码:
Myfilter
@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() {}
}我的ResponseWrapper
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;
}
};
}
}https://stackoverflow.com/questions/14736328
复制相似问题