导出到Excel JSF和PrimeFaces

Ber*_*yan 16 java apache-poi primefaces jsf-2 tomcat7

使用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();
}
Run Code Online (Sandbox Code Playgroud)

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) {}
}
Run Code Online (Sandbox Code Playgroud)

的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>
Run Code Online (Sandbox Code Playgroud)

Bal*_*usC 26

有两个问题.

第一个问题是<p:commandButton>默认情况下发送Ajax请求.此请求由JavaScript代码触发.但是,JavaScript无法对包含文件下载的响应执行任何操作.由于安全限制,JavaScript无法生成" 另存为"对话框等.响应基本上完全被忽略了.

您需要添加ajax="false"<p:commandButton>关闭ajax以使按钮触发正常的同步HTTP请求,或者您需要将其替换为标准<h:commandButton>.

<p:commandButton ajax="false" ... />
Run Code Online (Sandbox Code Playgroud)

要么

<h:commandButton ... />
Run Code Online (Sandbox Code Playgroud)

第二个问题是您的servlet根本不会将Excel文件写入响应,而是写入存储在服务器工作目录中的本地文件.基本上,HTTP响应不包含任何内容.您需要传递HttpServletResponse#getOutputStream()给该WorkBook#write()方法.

workbook.write(response.getOutputStream());
Run Code Online (Sandbox Code Playgroud)

在一个不相关的说明中,我想知道servlet在这里是如何有用的.你想在JSF之外重用它吗?如果没有,您根本不需要调度到servlet,而只需在bean的action方法中执行相同的代码.那个空catch块也不好看.我只是将它声明为throws方法或至少重新抛出它new FacesException(e).


根据你似乎对servlet不感兴趣的评论进行更新.这是一个小改写如何在JSF操作方法中以编程方式发送Excel文件.

public void getReportData() throws IOException {
    HSSFWorkbook workbook = new HSSFWorkbook();
    HSSFSheet sheet = workbook.createSheet();
    HSSFRow row = sheet.createRow(0);
    HSSFCell cell = row.createCell(0);
    cell.setCellValue(0.0);

    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExternalContext externalContext = facesContext.getExternalContext();
    externalContext.setResponseContentType("application/vnd.ms-excel");
    externalContext.setResponseHeader("Content-Disposition", "attachment; filename=\"my.xls\"");

    workbook.write(externalContext.getResponseOutputStream());
    facesContext.responseComplete();
}
Run Code Online (Sandbox Code Playgroud)

  • 在这种情况下,请检查答案更新以获取重写建议。`ExternalContext` 有很多委托方法。充分利用它们。http://download.oracle.com/javaee/6/api/javax/faces/context/ExternalContext.html 您最终希望在 JSF 代码中以 **零** `javax.servlet` 导入结束。 (2认同)