【发布时间】:2012-03-28 05:11:52
【问题描述】:
我正在尝试读取 FreemarkerView 渲染的结果:
View view = viewResolver.resolveViewName(viewName, locale);
view.render(model, request, mockResponse);
为了读取结果,我创建了mockResponse,它封装了HttpServletResponse:
public class HttpServletResponseEx extends HttpServletResponseWrapper {
ServletOutputStream outputStream;
public HttpServletResponseEx(HttpServletResponse response) throws IOException {
super(response);
outputStream = new ServletOutputStreamEx();
}
@Override
public ServletOutputStream getOutputStream() {
return outputStream;
}
@Override
public PrintWriter getWriter() throws IOException {
return new PrintWriter(new OutputStreamWriter(outputStream, "UTF-8"));
}
}
还有我的 ServletOutputStream,它使用 StringBuilder 构建字符串:
public class ServletOutputStreamEx extends ServletOutputStream {
StringBuilder stringBuilder;
public ServletOutputStreamEx() {
this.stringBuilder = new StringBuilder();
}
@Override
public void write(int b) throws IOException {
}
@Override
public void write(byte b[], int off, int len) throws IOException {
stringBuilder.append(new String(b, "UTF-8"));
}
@Override
public String toString() {
return stringBuilder.toString();
}
}
有了这些,我可以使用方法ServletOutputStreamEx.toString 轻松读取响应。
我的问题是 write 方法没有按正确的顺序调用,最后最终的 String 是混合的并且顺序不正确。这可能是由 Freemarker 中的并发引起的,但我不知道如何解决它。
【问题讨论】:
-
我确信在渲染阶段Freemarker以正确的顺序调用了write方法,否则会产生乱码结果。此外,Freemarker 不会同时执行。我认为问题在于您对
ServletOutputStreamEx的实施。您还没有覆盖所有的 write 方法及其 super 的方法。我没看到你打电话给super.write(int b),如果调用这个方法,它就什么也不做。 -
我不确定你的问题是什么,但如果你得到像两个
Strings 的结果ServletOutputStreamEx.write()电话混合在一起。使用StringBuffer而不是StringBuilder可以解决这个问题-因为StringBuffer是同步的- -
我不同意,StringBuffer 是应该被弃用的东西(如 Effective Java, 2nd Edition 中所述),并且使用 StringBuilder 很好,因为大多数时候单个请求(等等单个响应)由线程处理。
-
“Freemarker 中的并发”是什么意思?当从多个线程调用 FreeMarker 时,每个线程都会有自己的
Environment对象。 FreeMarker 写入输出的Writer对象是Environment对象的一部分,由 FreeMarker 的调用者提供。所以原则上可以在多个线程中给 FreeMarker 相同的Writer对象,但我无法想象为什么有人会这样做。
标签: java concurrency freemarker