您的位置:首页 > 其它

Looking for an example for inserting content into the response using a servlet filter

2015-09-01 05:42 639 查看
I’ve been searching the net and stackoverflow for an example of somebody inserting content into the response using a servlet filter, but can only find examples of people capturing/compressing the output and/or changing the headers. My goal is to append a chunk of HTML just before the closing
</body>
of all HTML responses.

I’m working on a solution that extends the
HttpServletResponseWrapper
to use my own
PrintWriter
, then overriding the
write
methods thereon. Inside the write method I’m storing the last 7 characters to see if it’s equal to the closing body tag, and then I write my HTML chunk plus the closing body tag, before continuing normal write operations for the rest of the document.

I feel that somebody must have solved this problem already, and probably more elegantly than I will. I’d appreciate any examples of how to use a servlet filter to insert content into a response.

UPDATED

Responding to a comment, I am also trying to implement the
CharResponseWrapper
from http://www.oracle.com/technetwork/java/filters-137243.html. Here is my code:

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();


I am also wrapping the request, but that code works and shouldn’t affect the response.

The codebase I am using, calls the
getOutputStream
method, instead of
getWriter
when it processes the response, so the examples included in the other answer doesn’t help.

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);
}
}
}


One important note: you need to use
HttpServletResponse.setContentLength
method to update response header according to your response body change, otherwise mismatch may lead to unknown behavior on client.

Servlet:

protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {

response.getWriter().println("Test");

}


Filter:

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 (exactly as the article)

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>


理解要修改resonse的关键是提供一个假的输出流替换response的输出流
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: