导出到 Excel JSF 和 PrimeFaces
使用 JDK 1.6、JSF 2.1、PrimeFaces 2.2.1、POI 3.2 和 Apache Tomcat 7,
我尝试设置一个 servlet 以允许根据用户选择下载 excel 文件。 Excel 文档是在运行时创建的。
没有错误,代码确实进入了 servlet。
我点击按钮,但没有任何反应。我没有使用 PrimeFaces 使用的数据表导出,因为我需要对 Excel 文档中的数据进行重新排序和自定义格式设置。
ExportExcelReports.java
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment; filename=\"my.xls\"");
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet();
HSSFRow row = sheet.createRow(0);
HSSFCell cell = row.createCell(0);
cell.setCellValue(0.0);
FileOutputStream out = new FileOutputStream("my.xls");
workbook.write(out);
out.close();
}
ProjectReportBean.java
public void getReportData() {
try {
FacesContext ctx = FacesContext.getCurrentInstance();
ExternalContext ectx = ctx.getExternalContext();
HttpServletRequest request = (HttpServletRequest) ectx.getRequest();
HttpServletResponse response = (HttpServletResponse) ectx.getResponse();
RequestDispatcher dispatcher = request.getRequestDispatcher("/ExportExcelReports");
dispatcher.forward(request, response);
ctx.responseComplete();
} catch (Exception e) {}
}
index.xhtml
<h:form id="reportsForm">
<h:outputLabel for="report" value="Reports" /><br />
<h:selectOneMenu id="report" value="#{projectReportBean.selectedReport}" required="true" requiredMessage="Select Report">
<f:selectItem itemLabel="---" noSelectionOption="true" />
<f:selectItems value="#{projectReportBean.reports}" />
</h:selectOneMenu>
<p:commandButton action="#{projectReportBean.getReportData}" value="Export" update="revgrid" />
</h:form>
Using JDK 1.6, JSF 2.1, PrimeFaces 2.2.1, POI 3.2, and Apache Tomcat 7
I am trying to setup a servlet to allow a download of an excel file based on the user selection. The excel document is created at runtime.
No errors and the code does get into the servlet.
I click the button and nothing happens. I am not using the datatable export that PrimeFaces uses because I need to do reordering and custom formatting on the data in the Excel document.
ExportExcelReports.java
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment; filename=\"my.xls\"");
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet();
HSSFRow row = sheet.createRow(0);
HSSFCell cell = row.createCell(0);
cell.setCellValue(0.0);
FileOutputStream out = new FileOutputStream("my.xls");
workbook.write(out);
out.close();
}
ProjectReportBean.java
public void getReportData() {
try {
FacesContext ctx = FacesContext.getCurrentInstance();
ExternalContext ectx = ctx.getExternalContext();
HttpServletRequest request = (HttpServletRequest) ectx.getRequest();
HttpServletResponse response = (HttpServletResponse) ectx.getResponse();
RequestDispatcher dispatcher = request.getRequestDispatcher("/ExportExcelReports");
dispatcher.forward(request, response);
ctx.responseComplete();
} catch (Exception e) {}
}
index.xhtml
<h:form id="reportsForm">
<h:outputLabel for="report" value="Reports" /><br />
<h:selectOneMenu id="report" value="#{projectReportBean.selectedReport}" required="true" requiredMessage="Select Report">
<f:selectItem itemLabel="---" noSelectionOption="true" />
<f:selectItems value="#{projectReportBean.reports}" />
</h:selectOneMenu>
<p:commandButton action="#{projectReportBean.getReportData}" value="Export" update="revgrid" />
</h:form>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
有两个问题。
第一个问题是
默认发送 Ajax 请求。该请求由 JavaScript 代码触发。但是,JavaScript 无法对包含文件下载的响应执行任何操作。由于安全限制,JavaScript 无法生成“另存为”对话框或其他内容。响应基本上被完全忽略。您需要将
ajax="false"
添加到
来关闭 ajax,以便按钮触发正常的同步 HTTP 请求,或者您需要替换它由标准
实现。或
第二个问题是您的 servlet 根本不会将 Excel 文件写入响应,而是写入存储在服务器工作目录中的本地文件。基本上,HTTP 响应不包含任何内容。您需要将
HttpServletResponse#getOutputStream()
传递给WorkBook#write()
方法。顺便说一句,我想知道 servlet 在这里有何用处。您想在 JSF 之外重用它吗?如果没有,您根本不需要分派到 servlet,而只需在 bean 的 action 方法中执行相同的代码即可。空的
catch
块也不好。我只需在方法中将其声明为throws
,或者至少将其重新抛出为new FacesException(e)
。更新 根据评论,您似乎对 servlet 根本不感兴趣。下面是如何在 JSF 操作方法中以编程方式发送 Excel 文件的一个小重写。
There are two problems.
The first problem is that the
<p:commandButton>
sends by default an Ajax request. This request is fired by JavaScript code. However, JavaScript can't do anything with a response which contains a file download. Due to security restrictions JavaScript can't spawn a Save As dialogue or something. The response is basically totally ignored.You need to add
ajax="false"
to<p:commandButton>
to turn ajax off so that the button fires a normal synchronous HTTP request, or you need to replace it by standard<h:commandButton>
.or
The second problem is that your servlet doesn't write the Excel file to the response at all, but instead to a local file which is stored in server's working directory. Basically, the HTTP response contains nothing. You need to pass
HttpServletResponse#getOutputStream()
to theWorkBook#write()
method.On an unrelated note, I wonder how the servlet is useful here. Do you want to reuse it outside JSF? If not, you don't necessarily need to dispatch to the servlet at all, but just execute the same code in bean's action method. That empty
catch
block is also not nice. I'd just declare it asthrows
in method or at least rethrow it asnew FacesException(e)
.Update as per the comments you seem not be interested in the servlet at all. Here's a minor rewrite how you could send the Excel file programmatically in a JSF action method.
这是我之前写的工作案例;
xhtml;
Java端(带POI);
Here is the that i wrote before and working case ;
xhtml ;
Java side(with POI) ;
我还建议使用 PrimeFaces FileDownload。根据您的结构,它可以使这一切变得更加容易。您不必创建一个 Servlet,只需创建一个可以提供
ContentStream
的托管 Bean。由于您已经编写了 servlet,因此没有必要进行更改,只需思考一下即可。
I'd also recommend looking at using the PrimeFaces FileDownload. Depending on your structure it could make this all a whole lot easier. You wouldn't have to create a servlet just a managed bean that can provide a
ContentStream
.Since you already have the servlet written though, there's no point to change, just food for thought.