как бороться с исключениями на контроллере Spring при создании файла - PullRequest
0 голосов
/ 18 июня 2019

Я реализовал Spring-контроллер, который генерирует PDF-файл и использует мой сервисный слой. Проблема заключается в том, что, когда во время выполнения метода выдается какое-то исключение, даже если я получаю исключение с помощью блока try-catch, Spring пытается разрешить представление на основе текущего URL.

Я, честно говоря, понятия не имею, что является причиной такого поведения.

    @RequestMapping("/cliente")
    public void relatorioCliente(EdicaoMovimentacaoWrapper wrapper, @AuthenticationPrincipal Usuario usuario) {
        try {
            gerarReportService.relatorioParaCliente(wrapper.getContaId(), usuario);

        } catch (Exception e) {
            e.printStackTrace();
            // TODO alguma coisa
        }
    }

метод relatorioParaCliente создает PDF-файл и экспортирует его в OutputStream ответа.

Ожидается: исключение перехватывается, трассировка стека печатается и с пользователем ничего не происходит. Фактический результат: Spring перенаправляет пользователя на views/cliente.jsp

UPDATE

Я попытался изменить тип возвращаемого значения метода, чтобы он выглядел следующим образом:

    @RequestMapping("/cliente")
    public ModelAndView relatorioCliente(EdicaoCadastroMovimentacaoWrapper wrapper, @AuthenticationPrincipal Usuario usuario) {
        try {
            gerarReportService.relatorioParaCliente(wrapper.getContaId(), usuario);

        } catch (Exception e) {
            e.printStackTrace();
            return new ModelAndView("/contas/" + wrapper.getContaId());
        }
        return null;
    }

Но это не влияет на мой код. Я предполагаю, что это не влияет на код, потому что outputStream используется в сервисе. посмотрите:

@Service
public class ExportarReportPdfService {

    @Autowired
    private HttpServletResponse res;

    public void exportar(List<JasperPrint> jasperPrintList) throws IOException {

        JRPdfExporter exporter = new JRPdfExporter();

        exporter.setExporterInput(SimpleExporterInput.getInstance(jasperPrintList));

        exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(res.getOutputStream()));

        SimplePdfExporterConfiguration configuration = new SimplePdfExporterConfiguration();

        configuration.setCreatingBatchModeBookmarks(true);

        exporter.setConfiguration(configuration);

        res.setContentType("application/x-pdf");
        res.setHeader("Content-disposition", "inline; filename=relatorio.pdf" );


        try {
            exporter.exportReport();
        } catch (Exception e) {
            e.printStackTrace();
            throw new CriacaoReportException("Erro ao exportar para PDF");
        } finally {
            OutputStream out = res.getOutputStream();
            out.flush();
            out.close();

        }
    }

1 Ответ

0 голосов
/ 20 июня 2019

Вот что я сделал для решения проблемы:

вместо автоматической передачи ответа на сервис и экспорта оттуда pdf, я генерирую byteArray и возвращаю его в контроллер:

@Service
public class ExportarReportPdfService {

    public byte[] exportar(List<JasperPrint> jasperPrintList)  {

        final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        JRPdfExporter exporter = new JRPdfExporter();

        exporter.setExporterInput(SimpleExporterInput.getInstance(jasperPrintList));

        exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(outputStream));

        [OMITED CODE]

        try {
            exporter.exportReport();
            return outputStream.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
            throw new CriacaoReportException("Erro ao exportar para PDF");
        }
    }
}

И контроллер отправляет ответ как ResponseEntity:

        @RequestMapping("/geral")
        public ResponseEntity<InputStreamResource> relatorioAdministrador(EdicaoCadastroMovimentacaoWrapper wrapper, @AuthenticationPrincipal Usuario usuario) {

            byte[] arquivo = gerarReportService.relatorioParaAdmin(wrapper.getContaId(), usuario);

            return ResponseEntity
                    .ok()
                    .contentLength(arquivo.length)
                    .contentType(MediaType.parseMediaType("application/pdf"))
                    .header("Content-Disposition", "attachment; filename=relatorio.pdf")
                    .body(new InputStreamResource(new ByteArrayInputStream(arquivo)));
        }


Так что, если произойдет какое-либо исключение, оно будет зафиксировано в ExceptionHandler, как @cmoetzing объяснил в комментариях:

    @ExceptionHandler(CriacaoReportException.class)
    public ModelAndView trataGeracaoRelatorio(CriacaoReportException exception) {
        return new ModelAndView("redirect:/");
    }

...