java - 如何在生成文件时处理 Spring Controller 上的异常

标签 java spring-mvc exception io outputstream

我已经实现了一个 Spring Controller ,它可以生成 PDF 文件,并使用我的服务层。问题是,当方法执行过程中抛出一些异常时,即使我用 try-catch block 得到异常,spring 也会尝试根据当前 URL 解析 View 。

老实说,我不知道是什么导致了这种行为。

    @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

更新

我尝试更改方法的返回类型,现在看起来像这样:

    @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;
    }

但这对我的代码没有影响。 我认为这不会影响代码,因为输出流在服务上使用。看看:

@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();

        }
    }

最佳答案

这是我为解决该问题所做的操作:

我生成一个 byteArray 并将其返回到 Controller ,而不是 Autowiring 服务上的响应并从那里导出 pdf:

@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");
        }
    }
}

Controller 将响应作为 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:/");
    }

关于java - 如何在生成文件时处理 Spring Controller 上的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56655744/

相关文章:

java - 如何获取数组数组的单个数组名称作为字符串

java - JDBC 将警告视为数据截断错误

java - 多次声明相同的检查异常

java - Spring 数据 REST : custom methods validation

java - 什么是Spring MVC中的@Service

java - 具有 Spring Security 的 AngularJS Web 应用程序

java - 执行捕获异常中的前面步骤

java - 在java中用另一个字符串替换字符串

java - Sonar 3.7 : Unable to execute wih maven

java - 使用 java 从 MS Word 文件读取形状(矩形、正方形、圆形、箭头等)、剪贴画