猿问

下载期间出现 Spring Boot 异常导致空文件

请删除异常抛出前的注释以查看问题。路径是:http://localhost:8080/api/download

原始问题: 我允许用户在 Angular7 应用程序中使用 JasperReports 下载报告,但问题仅与 Spring Boot 有关。报告生成有效,但我无法让文件下载按我的预期运行。

目前:下载链接与 一起使用href,链接与 一起使用target="_blank"。用户单击它,浏览器会打开一个新选项卡(在后台)并弹出窗口File Save As。如果一切正常,则文件保存没有问题。但是如果在PDF生成过程中某处出现异常,浏览器仍然会弹出窗口File Save As并允许用户保存文件,它会完成,但文件将是0 bytes.

应该是:当出现异常时,浏览器应该打开一个新选项卡,其中包含某种错误消息,但如果没有错误,则应该显示“文件另存为”窗口。

代码:

@GetMapping("/salary-report/{id}")

public void generateSalaryReport(@PathVariable("id") long salaryReportId, HttpServletResponse response) throws IOException, JRException, SQLException {

    JasperPrint jasperPrint;

    var salaryReport = salaryReportRepositoryEx.findById(salaryReportId).orElseThrow(ResourceNotFoundException::new);


    try (OutputStream out = response.getOutputStream()) {

        HashMap<String, Object> parameters = new HashMap<>();


        parameters.put("ReportId", salaryReport.getId());


        // Set meta data

        response.setContentType("application/x-download");

        response.setHeader(

            "Content-Disposition",

            String.format("attachment; filename=\"%s%s-report%s-%s-%s.pdf\"",

                .... parameters

            )

        );


        // Set report

        jasperPrint = salaryReportJasperReport.render(parameters); // exception usually here

        JasperExportManager.exportReportToPdfStream(jasperPrint, out);

    } catch (Exception e) {

        // I tried changing the content type on Exception, but the same

        response.setContentType("text/plain");

        response.setHeader("Content-Disposition", null);

        throw e;

    }

}

带有链接的 HTML 代码 (Angular7):


<td>

    <a [href]="serverApiUrl+'/jasper/salary-report/'+salaryReport.id"

       target="_blank"

    >

        PDF Download

    </a>

</td>


有只小跳蛙
浏览 282回答 3
3回答

饮歌长啸

这个问题并不能完全解决。不允许HttpServletResponse在设置后删除任何标头,因此我必须在响应更改之前(之前response.setHeader("Content-Disposition",..)移动渲染。这允许正常抛出异常。

杨魅力

问题是由于您没有以正确的方式处理异常,以便使用适合您的项目需求的正确方法。这是一个可能的解决方案。首先,您必须在您的方法中进行此更改。   @GetMapping("/salary-report/{id}")    public void generateSalaryReport(@PathVariable("id") long salaryReportId, HttpServletResponse response) throws IOException {        JasperPrint jasperPrint;        var salaryReport = salaryReportRepositoryEx.findById(salaryReportId).orElseThrow(ResourceNotFoundException::new);        try (OutputStream out = response.getOutputStream()) {            HashMap<String, Object> parameters = new HashMap<>();            parameters.put("ReportId", salaryReport.getId());            // Set meta data            response.setContentType("application/x-download");            response.setHeader(                "Content-Disposition",                String.format("attachment; filename=\"%s%s-report%s-%s-%s.pdf\"",                    .... parameters                )            );            // Set report            jasperPrint = salaryReportJasperReport.render(parameters); // exception usually here            JasperExportManager.exportReportToPdfStream(jasperPrint, out);        } catch (Exception e) {                    throw new IOException("Salary report generation failed for id: " + salaryReportId);        }    }他们将此方法添加到您的控制器中。@ExceptionHandler(IOException.class )public ResponseEntity<String> handleAccessDeniedException(IOException ex) {    //TODO Log your exception with a logging framework     return new ResponseEntity<String>(ex.getMessage, HttpStatus.INTERNAL_SERVER_ERROR); }

慕神8447489

尝试将响应 http 状态代码设置为某些代码 4xx 或 5xx 可能是 (500),这应该有效。
随时随地看视频慕课网APP

相关分类

Java
我要回答