JDK 1.6、JSF 2.1、PrimeFaces 2.2.1、POI 3.2、およびApache Tomcat 7の使用
ユーザーの選択に基づいてExcelファイルをダウンロードできるようにサーブレットをセットアップしようとしています。 Excelドキュメントは実行時に作成されます。
エラーはなく、コードはサーブレットに入ります。
ボタンをクリックしても何も起こりません。 Excelドキュメントのデータで並べ替えとカスタムの書式設定を行う必要があるため、PrimeFacesが使用するデータテーブルエクスポートを使用していません。
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>
2つの問題があります。
最初の問題は、_<p:commandButton>
_がデフォルトでAjaxリクエストを送信することです。このリクエストはJavaScriptコードによって発生します。ただし、JavaScriptはファイルのダウンロードを含む応答では何もできません。セキュリティ上の制限により、JavaScriptはSave Asダイアログなどを生成できません。応答は基本的に完全に無視されます。
_ajax="false"
_を_<p:commandButton>
_に追加してajaxをオフにしてボタンが通常の同期HTTPリクエストを起動するようにするか、標準の_<h:commandButton>
_に置き換える必要があります。
_<p:commandButton ajax="false" ... />
_
または
_<h:commandButton ... />
_
2番目の問題は、サーブレットがExcelファイルを応答にまったく書き込まず、サーバーの作業ディレクトリに保存されているローカルファイルに書き込むことです。基本的に、HTTP応答にはnothingが含まれます。 HttpServletResponse#getOutputStream()
をWorkBook#write()
メソッドに渡す必要があります。
_workbook.write(response.getOutputStream());
_
無関係なことに、ここでサーブレットがどのように役立つのか疑問に思います。 JSF外で再利用しますか?そうでない場合は、必ずしもサーブレットにディスパッチする必要はなく、Beanのアクションメソッドで同じコードを実行するだけです。その空のcatch
ブロックもまた素敵ではありません。メソッドでthrows
として宣言するか、少なくともnew FacesException(e)
として再スローします。
pdateコメントどおり、サーブレットにまったく興味がないようです。次に、JSFアクションメソッドでプログラム的にExcelファイルを送信する方法を簡単に書き直します。
_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();
}
_
ここに私が前に書いたものと作業ケースがあります。
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);
}
}
PrimeFaces FileDownloadの使用も検討することをお勧めします。あなたの構造に応じて、これは非常に簡単になります。 ContentStream
を提供できるマネージドBeanだけをサーブレットに作成する必要はありません。
ただし、サーブレットはすでに作成されているため、変更する必要はありません。