我使用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创建的。但是,我修改了上面的代码,只是将其保存到下载文件夹,并且报告创建得非常好。
因此,问题是报告在后端成功创建,但未按预期发送到前端(浏览器)。
我愿意接受有关此报告无效的原因的任何建议。
答案 0 :(得分:1)
在bean中运行代码是有问题的,因为:
getOutputStream
responseComplete()
时刷新)。getOutputStream
问题responseComplete()
将任何HTML以及PDF内容刷新到浏览器使用servlet。 servlet的send方法不需要比以下更复杂:
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 {
}
然后使用常规锚链接:
<h:outputLink value="/app/path/servlet/Reportservlet">Run Report</h:outputLink>
总之,不要通过拦截对JSF页面的请求来发送二进制报告数据;而是使用servlet。
servlet和JSF页面之间的通信可以通过以下方式进行:
Servlet具有完全避免JSF开销的优势,从用户的角度来看,这将使报告运行得更快。另外,不要编译报告 - 直接使用.jasper
文件,这也会提高性能。 (我并不是故意暗示使用.jrxml
文件是问题,只是说这不是必要的步骤。)
答案 1 :(得分:1)
我找到了解决问题的方法。最终,我发现报告生成代码或报告没有任何问题,但是有一个ajax问题阻止了输出流将报告导出到浏览器。