2011-10-19 14 views
16

Korzystanie z JDK 1.6, JSF 2.1, 2.2.1, PrimeFaces UM 3.2 i Apache Tomcat 7Eksport do Excela JSF i PrimeFaces

Próbuję konfiguracji serwletu, aby umożliwić pobieranie pliku excel oparte na wybór użytkownika. Dokument programu Excel jest tworzony w czasie wykonywania.

Brak błędów, a kod dostaje się do serwletu.

Klikam przycisk i nic się nie dzieje. Nie używam eksportu datatable używanego przez PrimeFaces, ponieważ muszę zmienić kolejność i niestandardowe formatowanie danych w dokumencie 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> 

Odpowiedz

25

Istnieją dwa problemy.

Pierwszy problem polega na tym, że <p:commandButton> wysyła domyślnie żądanie Ajax. To żądanie jest uruchamiane przez kod JavaScript. Jednak JavaScript nie może nic zrobić z odpowiedzią, która zawiera pobieranie pliku. Ze względu na ograniczenia bezpieczeństwa JavaScript nie może odrodzić się w dialogu lub coś podobnego. Odpowiedź jest zasadniczo całkowicie ignorowana.

Trzeba dodać ajax="false" do <p:commandButton> włączyć ajax się tak, że przycisk wystrzeliwuje normalne żądanie HTTP synchroniczny lub trzeba go zastąpić standardową <h:commandButton>.

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

lub

<h:commandButton ... /> 

Drugim problemem jest to, że aplet nie pisze plik Excel z odpowiedzią na wszystko, ale zamiast do pliku lokalnego, który jest przechowywany w katalogu roboczego serwera. Zasadniczo, odpowiedź HTTP zawiera nic. Musisz podać HttpServletResponse#getOutputStream() dla metody WorkBook#write().

workbook.write(response.getOutputStream()); 

W niezwiązanej uwadze, zastanawiam się, w jaki sposób serwlet jest przydatny tutaj. Czy chcesz użyć go ponownie poza JSF? Jeśli nie, to niekoniecznie musisz wysłać do serwletu, ale po prostu wykonaj ten sam kod w metodzie działania fasoli. Ten pusty blok catch również nie jest przyjemny. Właśnie zadeklarowałbym to jako throws w metodzie lub przynajmniej ponownie wyrzucił jako new FacesException(e).


Aktualizacja zgodnie komentarzach nie wydają się być zainteresowani serwletu w ogóle. Oto drobna przeróbka, w jaki sposób można programowo wysłać plik Excela w metodzie akcji 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

Nie chcę używać serwletu. myślałem, że ja też. Wyobraź sobie, że zmieniam to po tym, jak to działa. –

+1

W takim przypadku sprawdź aktualizację odpowiedzi pod kątem sugestii przepisywania. "ExternalContext" ma wiele metod delegowania. Wykorzystaj je. http://download.oracle.com/javaee/6/api/javax/faces/context/ExternalContext.html Ostatecznie chcesz skończyć z ** zero ** 'importami javax.servlet' w twoim kodzie JSF. – BalusC

+0

po prostu działało bez serwletu. naprawdę doceniam pomoc. –

0

Polecam również przy korzystaniu z pakietu plików PrimeFaces FileDownload. W zależności od twojej struktury może to wszystko znacznie ułatwić. Nie trzeba tworzyć serwletu tylko zarządzanego komponentu bean, który może zapewnić ContentStream.

Ponieważ już masz napisany serwlet, nie ma sensu się zmieniać, po prostu jedzenie do przemyślenia.

1

Oto, co napisałem przed i pracy;

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> 

Strona Java (z 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

Czy możesz zachować cały działający kod – spt

+0

@spt jego już działające dane, które są dodawane z tematem "Java side (z POI)" – newuserua

Powiązane problemy