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.