Java Servlet:将 ByteArrayOutputStream 转换为 PrintWriter

3

如何将生成的PDF文件(ByteArrayOutputStream)写入Servlet的PrintWriter中。

我正在拼命寻找一种方法,将生成的PDF文件写入响应PrintWriter中。由于上层过滤器已经调用了response.getWriter(),因此无法获取response.getOutputStream()。

我有一个ByteArrayOutputStream,其中我生成了PDF文件。现在我只需要一种方法来将这个ByteArrayOutputStream的内容输出到PrintWriter中。如果有人能给我帮助,将不胜感激!


很不幸,我不知道 - 在轮到我之前会调用几个过滤器。没有办法触及这些过滤器 :( - Thomas
1
如果过滤器已经写入了任何内容,那么你的输出将会是损坏的。如果过滤器没有写入任何内容,它就不应该调用response.getWriter()。 - Christoffer Hammarström
1
但是... 没有魔法。只有代码。通常你会在 web.xml 中自己定义这些过滤器。或者它们是第三方过滤器吗?请在此处复制它们的 <filter-class> 名称。或者它们是之前参与该项目的开发人员所包含的吗?请联系开发人员。 - BalusC
必须有人知道过滤器的作用,否则你只是在进行“货物崇拜配置”,在这种情况下,应该删除过滤器。 - Christoffer Hammarström
感谢大家的贡献,非常感激! 结果发现筛选器有一个错误修复程序正在进行中,这应该能让我摆脱麻烦。 再次感谢,祝好,Thomas - Thomas
4个回答

7

如果已经有其他东西调用了getWriter,那么它很可能已经向响应中写入了一些文本。此外,PrintWriter是用于文本的 - 你想要发送任意的二进制数据... getOutputStream是明确正确的方法,所以我建议找到调用了getWriter的过滤器并进行修复。


同意 - 试图通过PrintWriter发送二进制数据等其他任何方式都注定成为丑陋的hack。 - Jesper
嗯,我明白了,感谢你的帮助。看起来有点糟糕,因为我无法在过滤器之前进行操作...你有什么关于丑陋的hack的建议吗? - Thomas
@Thomas:并不是这样的...通过PrintWriter推送二进制数据就像把方钉放入圆孔中一样。为什么你不能更改过滤器?难道真的没有任何办法可以解决吗? - Jon Skeet
感谢您提供清晰的图片。实际上,这正是过滤器实施团队提出的解决方案 - 由于修复错误似乎已经在掌握之中,整个情况现在更加轻松了。再次感谢您的帮助,敬礼。 - Thomas

0

你知道PrintWriter的编码是什么吗?如果是Latin-1,你可以简单地将字节数组转换为Latin-1并写入PrintWriter。

   String latin1 = byteStream.toString("ISO-8859-1");
   response.getWriter().write(latin1);

当然,这假设过滤器实际上并没有写任何东西。

@Christoffer:只有那个会抛出异常,因为之前已经调用了response.getWriter()。 - Thomas
@Thomas:那么问题就变成了为什么有东西叫做getWriter(),但是却没有写任何东西。这没有意义,最起码听起来像是等待出错的漏洞。 - Christoffer Hammarström

0

这里有一个有点疯狂的想法,但我可能会这样解决。

如果你真的不能触摸损坏的 Filter(真的吗?),那么写另一个过滤器放在损坏的 Filter 前面。

这看起来比它实际上更复杂,但那只是因为 Java 很啰嗦,所以请忍耐一下。

基本上,它使用 HttpServletResponseWrapper 在过滤器和其后面的 servlet 中包装/“覆盖”response.getWriter()

因此,当你的损坏的 Filter 调用 response.getWriter() 时,它将获得一个代理 PrintWriter,它仅在第一次实际写入时才调用真正的 response.getWriter()

然后,即使损坏的 Filter 在不写入的情况下调用 response.getWriter(),也不再重要了。

我实际上还没有测试过这段代码,但我相信它应该可以工作。

请注意,这假设损坏的 Filter 调用 response.getWriter() 而没有实际写入内容。如果损坏的过滤器写入了某些东西,然后你尝试向其写入 PDF,输出将是损坏的。

import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;

public class BrokenWriterGetterFixingFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, final ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        filterChain.doFilter(servletRequest, new BrokenWriterGetterFixingResponseWrapper((HttpServletResponse) servletResponse));
    }

    @Override
    public void destroy() {
    }

    private static class BrokenWriterGetterFixingResponseWrapper extends HttpServletResponseWrapper {
        public BrokenWriterGetterFixingResponseWrapper(HttpServletResponse response) {
            super(response);
        }

        @Override
        public PrintWriter getWriter() throws IOException {
            return new PrintWriter(new BrokenWriterGetterFixingWriter(getResponse()));
        }
    }

    private static class BrokenWriterGetterFixingWriter extends Writer {
        private PrintWriter responseWriter;
        private final ServletResponse response;

        public BrokenWriterGetterFixingWriter(ServletResponse response) {
            this.response = response;
        }

        @Override
        public void write(char[] cbuf, int off, int len) throws IOException {
            getResponseWriter().write(cbuf, off, len);
        }

        @Override
        public void flush() throws IOException {
            getResponseWriter().flush();
        }

        @Override
        public void close() throws IOException {
            getResponseWriter().close();
        }

        private PrintWriter getResponseWriter() throws IOException {
            if (null == responseWriter) {
                responseWriter = response.getWriter();
            }
            return responseWriter;
        }

    }
}

0

我遇到了以下错误:

这行下面没有任何内容Error 500: java.lang.IllegalStateException: SRVE0199E: OutputStream already obtained

通过设置解决:

response.getOutputStream().write(bytes);
response.setContentLength(bytes.length);

现在输出结果为:

此行以下没有任何内容


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接