Esportare in Excel JSF e PrimeFaces

Utilizzo di JDK 1.6, JSF 2.1, PrimeFaces 2.2.1, POI 3.2 e Apache Tomcat 7

Sto cercando di configurare un servlet per consentire il download di un file Excel basato sulla selezione dell’utente. Il documento excel viene creato in fase di runtime.

Nessun errore e il codice entra nel servlet.

Faccio clic sul pulsante e non succede nulla. Non utilizzo l’esportazione datatable utilizzata da PrimeFaces perché devo eseguire il riordino e la formattazione personalizzata dei dati nel documento 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

  

Ci sono due problemi.

Il primo problema è che invia per impostazione predefinita una richiesta Ajax. Questa richiesta è triggersta dal codice JavaScript. Tuttavia, JavaScript non può fare nulla con una risposta che contenga un download di file. A causa delle restrizioni di sicurezza, JavaScript non può generare un dialogo Salva con nome o qualcosa del genere. La risposta è fondamentalmente totalmente ignorata.

È necessario aggiungere ajax="false" a per distriggersre ajax in modo che il pulsante attivi una richiesta HTTP sincrona normale, oppure è necessario sostituirlo con lo standard .

  

o

  

Il secondo problema è che il vostro servlet non scrive affatto il file Excel nella risposta, ma piuttosto in un file locale che è memorizzato nella directory di lavoro del server. Fondamentalmente, la risposta HTTP non contiene nulla . È necessario passare HttpServletResponse#getOutputStream() al metodo HttpServletResponse#getOutputStream() di WorkBook#write() .

 workbook.write(response.getOutputStream()); 

Su una nota non correlata, mi chiedo come sia utile il servlet qui. Vuoi riutilizzarlo al di fuori di JSF? In caso contrario, non è necessario inviare nulla al servlet, ma è sufficiente eseguire lo stesso codice nel metodo di azione del bean. Anche quel blocco di catch vuoto non è bello. Lo dichiarerei solo come metodo o almeno come new FacesException(e) .


Aggiornamento come per i commenti non sembra affatto interessato al servlet. Ecco una piccola riscrittura su come è ansible inviare il file Excel a livello di codice in un metodo di azione 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(); } 

Ecco quello che ho scritto prima e il caso di lavoro;

xhtml;

     

Lato 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); } } 

Suggerirei anche di utilizzare il FileDownload di PrimeFaces. A seconda della struttura, potrebbe rendere tutto molto più semplice. Non sarebbe necessario creare un servlet solo un bean gestito in grado di fornire un ContentStream .

Dato che hai già scritto la servlet, non c’è motivo di cambiare, solo spunti di riflessione.