【问题标题】:Reading ServletOutputStream to String将 ServletOutputStream 读取为字符串
【发布时间】: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


【解决方案1】:

感谢您的回复:write(int b) 未实现,因为它从未被调用。问题到底是字节数组,里面也包含了前面的String。所以字符串需要创建为String(b, off, len, "UTF-8")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-24
    • 2013-02-13
    • 1970-01-01
    • 2013-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多