【发布时间】:2019-08-28 09:19:05
【问题描述】:
Reproduction of the error here. 请在抛出异常之前移除 cmets 以查看问题。路径为: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>
编辑:如果我只是手动导航到完整的下载 URL,也会发生同样的事情。
Edit2:也在邮递员中尝试过。使用无效的报告 ID 会返回预期的 404 Json (ResourceNotFoundException),但继续使用代码总是返回 200 OK(即使我在 catch 块中手动将 HTTP 代码设置为 500)并且正文为空。
编辑3: 我尝试使用异常处理程序:
@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
public class JasperReportGenerationFailedException extends Exception {
public JasperReportGenerationFailedException() {
super();
}
public JasperReportGenerationFailedException(String message) {
super(message);
}
public JasperReportGenerationFailedException(String message, Throwable cause) {
super(message, cause);
}
public JasperReportGenerationFailedException(Throwable cause) {
super(cause);
}
protected JasperReportGenerationFailedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
@ExceptionHandler(JasperReportGenerationFailedException.class )
public ResponseEntity<String> handleJasperException(JasperReportGenerationFailedException ex) {
log.error("Salary Report generation failed.", ex);
return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
@GetMapping("/salary-report/{id}")
public void generateSalaryReport(@PathVariable("id") long salaryReportId, HttpServletResponse response) throws JasperReportGenerationFailedException {
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",
...
)
);
if (1 == 1/1) { // for testing, i always throw
throw new Exception("Test");
}
// Set report
jasperPrint = salaryReportJasperReport.render(parameters);
JasperExportManager.exportReportToPdfStream(jasperPrint, out);
} catch (Exception e) {
throw new JasperReportGenerationFailedException(e);
}
}
【问题讨论】:
标签: java spring-boot spring-mvc exception