2011-10-19 50 views
16

El uso de JDK 1.6, JSF 2.1, 2.2.1 PrimeFaces, POI 3.2 y Apache Tomcat 7Exportación a Excel JSF y PrimeFaces

estoy tratando de configurar un servlet para permitir una descarga de un archivo de Excel basado en el selección del usuario El documento de Excel se crea en tiempo de ejecución.

No hay errores y el código entra en el servlet.

Hago clic en el botón y no pasa nada. No utilizo la exportación de tabla de datos que utiliza PrimeFaces porque necesito hacer un reordenamiento y un formateo personalizado en los datos del documento de 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> 

Respuesta

25

hay dos problemas.

El primer problema es que el <p:commandButton> envía por defecto una solicitud Ajax. Esta solicitud es activada por código JavaScript. Sin embargo, JavaScript no puede hacer nada con una respuesta que contiene una descarga de archivos. Debido a restricciones de seguridad, JavaScript no puede engendrar un diálogo Guardar como o algo así. La respuesta es básicamente ignorada por completo.

es necesario agregar ajax="false" a <p:commandButton> convertir ajax fuera para que el botón dispara una solicitud HTTP síncrona normal, o si tiene que reemplazarlo por la norma <h:commandButton>.

<p:commandButton ajax="false" ... /> 

o

<h:commandButton ... /> 

El segundo problema es que el servlet no escribe el archivo de Excel a la respuesta en absoluto, pero en lugar de un archivo local que se almacena en el directorio de trabajo del servidor. Básicamente, la respuesta HTTP contiene nada. Debe pasar HttpServletResponse#getOutputStream() al método WorkBook#write().

workbook.write(response.getOutputStream()); 

En una nota relacionada, me pregunto cómo el servlet es útil aquí. ¿Desea reutilizarlo fuera de JSF? De lo contrario, no es necesario que se envíe al servlet, sino que simplemente ejecute el mismo código en el método de acción de Bean. Ese bloque vacío catch tampoco es bueno. Simplemente lo declararía como throws en el método o al menos volveré a lanzarlo como new FacesException(e).


actualización de acuerdo con los comentarios que no parecen estar interesados ​​en el servlet en absoluto. Aquí hay una pequeña reescritura de cómo se puede enviar el archivo Excel programáticamente en un método de acción JSF.

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(); 
} 
+0

no quiero usar el servlet. pensé que también tenía. Mirando desafiante a cambiar eso después de que esto funcione. –

+1

En ese caso, verifique la actualización de respuesta para una sugerencia de reescritura. El 'ExternalContext' tiene muchos métodos de delegación. Haz uso de ellos. http://download.oracle.com/javaee/6/api/javax/faces/context/ExternalContext.html En última instancia, desea terminar con las importaciones ** zero ** 'javax.servlet' en su código JSF. – BalusC

+0

acaba de hacerlo funcionar sin el servlet. realmente aprecio la ayuda. –

0

También recomendaría mirar usando PrimeFaces FileDownload. Dependiendo de su estructura, esto podría hacer todo mucho más fácil. No tendría que crear un servlet solo un bean administrado que pueda proporcionar un ContentStream.

Sin embargo, como ya tiene el servlet escrito, no tiene sentido cambiarlo, solo es algo para pensar.

1

Aquí está el que escribí antes y el caso de trabajo;

xhtml;

<h:panelGrid id="viewCommand" style="float:right;" > 
         <p:commandButton value="Export Excel" icon="ui-icon-document" 
          ajax="false" actionListener="#{xxx.export2Excel}" 
          rendered="#{xxx.showTable}"> 
          <p:fileDownload value="#{xxx.exportFile}" 
           contentDisposition="attachment" /> 
         </p:commandButton></h:panelGrid> 

lado de Java (con POI);

protected void lOBExport2Excel(List table) throws Throwable { 
    Row row = null; 
    Cell cell = null; 
    try { 

     Workbook wb = new HSSFWorkbook(); 
     HSSFCellStyle styleHeader = (HSSFCellStyle) wb.createCellStyle(); 
     HSSFFont fontHeader = (HSSFFont) wb.createFont(); 
     fontHeader.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); 
     styleHeader.setFont(fontHeader); 
     Sheet sheet = wb.createSheet("sheet"); 
     row = sheet.createRow((short) 0); 

     for (int i = 0; i < columnNames.size(); i++) { 
      cell = row.createCell(i); 
      cell.setCellValue(columnNames.get(i)); 
      cell.setCellStyle(styleHeader); 
     } 

     int j = 1; 

     for (DBData[] temp : tabularData) { 
      row = sheet.createRow((short) j); 
      for (int k = 0; k < temp.length; k++) { 
       HSSFCellStyle styleRow = (HSSFCellStyle) wb.createCellStyle(); 
       HSSFFont fontRow = (HSSFFont) wb.createFont(); 
       fontRow.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL); 
       styleRow.setFont(fontRow); 
       cell = row.createCell(k); 
       setStyleFormat(temp[k].getDataType(), styleRow, wb); 
       cell.setCellValue(temp[k].toFullString()); 
       cell.setCellStyle(styleRow); 
      } 

      j++; 
     } 

     String excelFileName = getFileName("xls"); 

     FileOutputStream fos = new FileOutputStream(excelFileName); 
     wb.write(fos); 
     fos.flush(); 
     fos.close(); 

     InputStream stream = new BufferedInputStream(new FileInputStream(excelFileName)); 
     exportFile = new DefaultStreamedContent(stream, "application/xls", excelFileName); 


    } catch (Exception e) { 
     catchError(e); 
    } 

} 
+0

¿Se puede conservar el código de trabajo completo – spt

+0

@spt? Ya es datos de trabajo que se agrega con el asunto "lado de Java (con POI)" – newuserua

Cuestiones relacionadas