gpt4 book ai didi

java - JasperReport 与 OutputStream 不导出为 PDF

转载 作者:行者123 更新时间:2023-12-02 02:45:03 26 4
gpt4 key购买 nike

我正在使用 JasperReport 将报告导出为 PDF。代码运行良好,控制台/日志中没有显示任何异常消息。但是,该报告不会导出到浏览器。换句话说,报告正在创建,我只是无法下载或访问它。

这是导出代码:

public void generatePDFReport(Map<String, Object> parameters, JRDataSource jrDataSource, String resource, String filename)
{
OutputStream os = null;
try{
FacesContext context = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
os = response.getOutputStream();

InputStream reportTemplate = this.getClass().getClassLoader().getResourceAsStream(resource);
byte[] pdf = null;

try {
JasperDesign masterDesign = JRXmlLoader.load(reportTemplate);
masterReport = JasperCompileManager.compileReport(masterDesign);
masterReport.setWhenNoDataType(WhenNoDataTypeEnum.ALL_SECTIONS_NO_DETAIL);
JasperPrint masterPrint = JasperFillManager.fillReport(masterReport, parameters, jrDataSource);
pdf = JasperExportManager.exportReportToPdf(masterPrint);
} catch (JRException e) {
log.error(e);
}
response.setContentType("application/pdf");
response.setContentLength(pdf.length);
response.setHeader("Content-disposition", "attachment; filename=\""+filename+"\"");

context.responseComplete();

os.write(pdf);

pdf = null;
}catch(Exception e){
log.error(e);
}finally{
try{
os.flush();
os.close();
}catch(IOException e){
log.error(e);
}
}
}

我几乎 100% 确定代码没有任何问题,因为它适用于不同的报告(我为其他几个报告运行相同的导出代码,除了这个之外,它对所有报告都按预期工作)。

了解到这一点,我想这一定与报告本身有关。该报告是 jrxml JasperReport 文件。该报告是使用 iReport 创建的。但是,我修改了上面的代码,只是将其保存到下载文件夹中,并且报告创建得非常好。

因此,问题在于报告已在后端成功创建,但未按预期发送到前端(浏览器)。

我愿意接受任何关于为什么此报告不起作用的建议。

最佳答案

在 bean 内运行代码是有问题的,因为:

  • 每个 HTTP 请求仅允许调用一次 getOutputStream
  • Web 框架 (J2EE/JSF) 可能已经编写了 HTTP header
  • JSF 页面可能已在临时缓冲区内以 HTML 形式写入(在调用 responseComplete() 时刷新)。
  • header 可以重置,但这对解决 getOutputStream 问题
  • 调用 responseComplete() 将所有 HTML 以及 PDF 内容刷新到浏览器

使用 servlet。 Servlet 的发送方法不必比以下内容更复杂:

protected void send(final byte[] content) throws IOException {
setContentLength(content.length);

try (final OutputStream out = getOutputStream()) {
out.write(content);
}
}

还要考虑设置缓存,以便不可能出现过时的报告:

protected void disableCache() {
// https://tools.ietf.org/html/rfc7234#section-7.1.3
setHeader(CACHE_CONTROL, "private, no-store, no-cache, must-revalidate");

// https://tools.ietf.org/html/rfc7234#section-5.3
setHeader(EXPIRES, "Thu, 01 Dec 1994 16:00:00 GMT");

// https://tools.ietf.org/html/rfc7234#section-5.4
setHeader(PRAGMA, "no-cache");

// https://tools.ietf.org/html/rfc7232#section-2.2
setHeader(LAST_MODIFIED, getServerTimestamp());
}

private String getServerTimestamp() {
final SimpleDateFormat rfc1123 = new SimpleDateFormat(DATE_RFC_1123, getDefault());

rfc1123.setTimeZone(getTimeZone("GMT"));

final Calendar calendar = Calendar.getInstance();
return rfc1123.format(calendar.getTime());
}

这意味着,例如:

@WebServlet(
name = "ReportServlet",
urlPatterns = {PATH_SERVLET + "ReportServlet"}
)
public class ReportServlet extends AbstractServlet {
}

然后使用常规 anchor 链接:

<h:outputLink value="/app/path/servlet/Reportservlet">Run Report</h:outputLink>

总之,不要通过拦截对 JSF 页面的请求来发送二进制报告数据;请改用 servlet。

Servlet 和 JSF 页面之间的通信可以通过以下方式进行:

  • session 变量(Servlet 端的 HTTPSession)
  • 网址参数

Servlet 的优点是完全避免了 JSF 开销,从用户的角度来看,这将使报表运行得更快。另外,不要编译报告——直接使用 .jasper 文件,这也会提高性能。 (我并不是想暗示使用 .jrxml 文件是问题所在,只是这不是一个必要的步骤。)

关于java - JasperReport 与 OutputStream 不导出为 PDF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44727792/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com