Экспорт в Excel JSF и PrimeFaces - PullRequest
       16

Экспорт в Excel JSF и PrimeFaces

16 голосов
/ 19 октября 2011

Использование JDK 1.6, JSF 2.1, PrimeFaces 2.2.1, POI 3.2 и Apache Tomcat 7

Я пытаюсь настроить сервлет, чтобы разрешить загрузку файла Excel на основе выбора пользователя.Документ Excel создается во время выполнения.

Нет ошибок, и код попадает в сервлет.

Я нажимаю кнопку и ничего не происходит.Я не использую экспорт данных, который использует 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();
}

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>

Ответы [ 3 ]

26 голосов
/ 19 октября 2011

Есть две проблемы.

Первая проблема заключается в том, что <p:commandButton> отправляет по умолчанию Ajax-запрос.Этот запрос запускается кодом JavaScript.Однако JavaScript не может ничего сделать с ответом, который содержит загрузку файла.Из-за ограничений безопасности JavaScript не может вызвать диалог Сохранить как или что-то еще.Ответ в основном полностью игнорируется.

Вам необходимо добавить ajax="false" к <p:commandButton>, чтобы отключить AJAX, чтобы кнопка запускала обычный синхронный HTTP-запрос, или вам нужно заменить его на стандартный <h:commandButton>.

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

или

<h:commandButton ... />

Вторая проблема заключается в том, что ваш сервлет вообще не записывает файл Excel в ответ, а вместо этого в локальный файл, который хранится в рабочем каталоге сервера.По сути, HTTP-ответ не содержит ничего .Вам нужно передать HttpServletResponse#getOutputStream() методу WorkBook#write().

workbook.write(response.getOutputStream());

На несвязанной ноте мне интересно, как здесь пригодится сервлет.Вы хотите использовать его за пределами JSF?Если нет, вам вовсе не обязательно отправлять сервлету, а просто выполнять тот же код в методе действия bean-компонента.Этот пустой блок catch тоже нехорошо.Я бы просто объявил это как throws в методе или, по крайней мере, отбросил бы его как new FacesException(e).


Обновите согласно комментариям, которые вас не интересуют в сервлете.совсем.Вот небольшая переписка того, как можно отправить файл Excel программным способом с помощью метода действия 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();
}
1 голос
/ 21 сентября 2012

Вот то, что я написал раньше и рабочий случай;

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>

Сторона Java (с 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 голосов
/ 19 октября 2011

Я бы также порекомендовал взглянуть на использование PrimeFaces FileDownload. В зависимости от вашей структуры это может сделать все это намного проще. Вам не нужно будет создавать сервлет только для управляемого компонента, который может обеспечить ContentStream.

Так как сервлет уже написан, менять нечего, просто пища для размышлений.

...