简体   繁体   English

ByteArrayOutputStream到PrintWriter(Java Servlet)

[英]ByteArrayOutputStream to PrintWriter (Java Servlet)

Writing generated PDF (ByteArrayOutputStream) in a Servlet to PrintWriter. 将生成的PDF(ByteArrayOutputStream)写入Servlet中的PrintWriter。

I am desperately looking for a way to write a generated PDF file to the response PrintWriter. 我正在拼命寻找将生成的PDF文件写入响应PrintWriter的方法。 Since a Filter up the hierarchy chain has already called response.getWriter() I can't get response.getOutputStream(). 由于过滤层次结构链已经调用了response.getWriter(),因此我无法获得response.getOutputStream()。

I do have a ByteArrayOutputStream where I generated the PDF into. 我有一个ByteArrayOutputStream,我在其中生成PDF。 Now all I need is a way to output the content of this ByteArrayOutputStream to the PrintWriter. 现在我需要的是一种将此ByteArrayOutputStream的内容输出到PrintWriter的方法。 If anyone could give me a helping hand would be very much appreciated! 如果有人能帮助我,我将非常感激!

If something else has already called getWriter , it may well have already written some text to the response. 如果其他东西已经调用了getWriter ,它可能已经在响应中写了一些文本。 Besides, PrintWriter is for text - you want to send arbitrary binary data... getOutputStream is definitely the way forward, so I would try to find the filter which has called getWriter and fix that instead. 此外, PrintWriter用于文本 - 你想发送任意二进制数据... getOutputStream肯定是前进的方式,所以我会尝试找到调用getWriter的过滤器并修改它。

Do you know what's the encoding of PrintWriter? 你知道PrintWriter的编码是什么吗? If it's Latin-1, you can simply convert the byte array to Latin-1 and write to the PrintWriter, 如果它是Latin-1,你可以简单地将字节数组转换为Latin-1并写入PrintWriter,

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

Of course, this assumes the filter doesn't really write anything. 当然,这假设过滤器实际上没有写任何东西。

Here's a somewhat crazy idea, but i would probably solve it like this. 这是一个有点疯狂的想法,但我可能会这样解决它。

If you really can't touch the broken Filter ( really? ), write another filter that you place before the broken Filter. 如果你真的无法触摸破碎的过滤器( 真的? ),请在破碎的过滤器之前写下另一个过滤器。

This looks more complex than it is, but that's only because of Java's verbosity, so please bear with me. 这看起来比它复杂,但这只是因为Java的冗长,所以请耐心等待。

Basically what it does is that it uses HttpServletResponseWrapper to wrap/"override" response.getWriter() in filters and the servlet following it in the chain. 基本上它的作用是它使用HttpServletResponseWrapper来包装/“覆盖”过滤器中的response.getWriter()以及链中跟随它的servlet。

So when your broken Filter calls response.getWriter() , it will instead get a proxy PrintWriter that only calls the real response.getWriter() the first time it is actually written to. 因此,当你破碎的Filter调用response.getWriter() ,它将获得一个代理PrintWriter,它只在第一次实际写入时调用真实的response.getWriter()

Then it no longer matters if the broken Filter calls response.getWriter() without writing to it. 然后,如果破坏的Filter调用response.getWriter()而不写入它就不再重要了。

I haven't actually tested this code, but i believe it should work. 我实际上没有测试过这段代码,但我相信它应该可行。

Note that this assumes that the broken Filter calls response.getWriter() without actually writing something. 请注意,这假定破坏的Filter调用response.getWriter()而不实际写入内容。 The output would be corrupt anyway if the broken filter wrote something and then you tried to write a PDF to it as well. 如果破碎的过滤器写了一些东西,然后你也试图写一个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;
        }

    }
}

I was getting error like: 我得到的错误如下:

nothing below this lineError 500: java.lang.IllegalStateException: SRVE0199E: OutputStream already obtained 此行下面没有错误错误500:java.lang.IllegalStateException:SRVE0199E:已获取OutputStream

Solved by setting: 通过设置解决:

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

Now output becomes: 现在输出变为:

nothing below this line 没有这条线以下

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM