ByteArrayOutputStream в PrintWriter (сервлет Java)

Запись сгенерированного PDF (ByteArrayOutputStream) в сервлет для PrintWriter.

Я отчаянно ищу способ написать сгенерированный файл PDF в ответ PrintWriter. Поскольку фильтр по цепочке иерархии уже вызвал response.getWriter(), я не могу получить response.getOutputStream().

У меня есть ByteArrayOutputStream, в который я сгенерировал PDF. Теперь все, что мне нужно, — это способ вывода содержимого этого ByteArrayOutputStream в PrintWriter. Если бы кто-нибудь мог дать мне руку помощи, был бы очень признателен!


person Thomas    schedule 26.04.2010    source источник
comment
Я, к сожалению, не знаю - есть несколько фильтров, которые вызываются до того, как подойдет моя очередь. Их никак не трогать :(   -  person Thomas    schedule 26.04.2010
comment
Если фильтр что-то записал, ваш вывод будет поврежден. Если фильтр ничего не записал, он не должен был вызывать response.getWriter().   -  person Christoffer Hammarström    schedule 26.04.2010
comment
Но... волшебства нет. Есть просто код. Обычно вы сами определяете эти фильтры в файле web.xml. Или это сторонние фильтры? Не могли бы вы скопировать их <filter-class> имена сюда? Или они включены разработчиком, который ранее работал над проектом? Свяжитесь с разработчиком.   -  person BalusC    schedule 26.04.2010
comment
Кто-то должен знать, что делает Фильтр. В противном случае вы просто выполняете настройку Cargo Cult, и в этом случае фильтр следует удалить.   -  person Christoffer Hammarström    schedule 26.04.2010
comment
Спасибо всем за их вклад, очень ценно! Оказывается, есть исправление для фильтра, которое в конце концов должно избавить меня от проблем. Еще раз спасибо и ура, Томас   -  person Thomas    schedule 28.04.2010


Ответы (4)


Если что-то еще уже вызвало getWriter, вполне возможно, что оно уже написало какой-то текст в ответ. Кроме того, PrintWriter предназначен для текста — вы хотите отправить произвольные бинарные данные... getOutputStream — это определенно путь вперед, поэтому я бы попытался найти фильтр, который вызвал getWriter и исправьте это вместо этого.

person Jon Skeet    schedule 26.04.2010
comment
Согласитесь - все остальное (попытка принудительной отправки двоичных данных через PrintWriter) обязательно станет уродливым взломом. - person Jesper; 26.04.2010
comment
Хм, я вижу, спасибо за вашу помощь - ситуация кажется немного плохой, потому что я не могу прикасаться к фильтрам раньше ... какой-нибудь совет по уродливому взлому? - person Thomas; 26.04.2010
comment
@Thomas: Не совсем ... проталкивание двоичных данных через PrintWriter похоже на вставление квадратного колышка в круглое отверстие. Почему нельзя менять фильтры? Вы действительно ничего не можете с ними сделать? - person Jon Skeet; 26.04.2010
comment
Спасибо за четкую картинку. На самом деле это было решение, предложенное командой, которая внедрила фильтр - поскольку исправление ошибок, кажется, уже в пределах досягаемости, вся ситуация теперь более спокойна. Еще раз спасибо за вашу помощь, brds T - person Thomas; 28.04.2010

Вы знаете, какая кодировка у PrintWriter? Если это Latin-1, вы можете просто преобразовать массив байтов в Latin-1 и записать в PrintWriter,

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

Конечно, это предполагает, что фильтр на самом деле ничего не записывает.

person ZZ Coder    schedule 26.04.2010
comment
@Christoffer: исправьте только то, что вызовет исключение, поскольку response.getWriter() уже был вызван заранее. - person Thomas; 26.04.2010
comment
@Thomas: Тогда возникает вопрос, почему что-то вызвало getWriter() и ничего не написало. Это не имеет смысла и, по крайней мере, звучит как ошибка, ожидающая своего появления. - person Christoffer Hammarström; 26.04.2010

Вот несколько сумасшедшая идея, но я, вероятно, решил бы это так.

Если вы действительно не можете коснуться сломанного фильтра (правда?), напишите другой фильтр, который вы поместите перед сломанным фильтром.

Это выглядит сложнее, чем есть на самом деле, но это только из-за многословия Java, поэтому, пожалуйста, потерпите меня.

По сути, он использует HttpServletResponseWrapper для переноса/"переопределения" response.getWriter() в фильтрах и сервлете, следующем за ним в цепочке.

Таким образом, когда ваш сломанный фильтр вызывает response.getWriter(), вместо этого он получает прокси-принтер PrintWriter, который вызывает настоящий response.getWriter() только при первой фактической записи.

Тогда уже не имеет значения, вызывает ли сломанный фильтр response.getWriter() без записи в него.

Я на самом деле не тестировал этот код, но я считаю, что он должен работать.

Обратите внимание, что это предполагает, что сломанный фильтр вызывает 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;
        }

    }
}
person Christoffer Hammarström    schedule 26.04.2010

Я получал ошибку, например:

ничего ниже этой строки Ошибка 500: java.lang.IllegalStateException: SRVE0199E: OutputStream уже получен

Решается установкой:

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

Теперь вывод становится:

ничего ниже этой строки

person Syed Ali Raza    schedule 26.03.2014