ちょっと困ったことが起きたが最終的に目的の動作は確認できたので、その経過をメモしておく。(まだ実際のGAE/J環境で動作確認していない)
とりあえず"tutorial"を読みながら、
- 新規にExcel Workbookを作成
- シートを作成
- セルに値を入力
コードはこんな感じ。
ByteArrayOutputStream os = new ByteArrayOutputStream(); WritableWorkbook workbook = Workbook.createWorkbook(os); WritableSheet sheet = workbook.createSheet("SheetA", 0); Label label = new Label(0, 0, "ABC"); sheet.addCell(label); workbook.write(); workbook.close();ダウンロードしたファイルをExcelで開いてみると、ちゃんと[A1]のセルに"ABC"の文字が入っている。(^^)v
ここでポイントはWorkbookを作成するところで、"tutorial"では
Workbook.createWorkbook(new File("output.xls"));とFileオブジェクトを使用している代わりにByteArrayOutputStreamを使用しているところ。
GAE/JではファイルI/O関連の使用に制約がありファイル出力が行えない。したがってファイルへ出力する代わりにByteArrayOutputStreamでバイトストリームに出力する。
本来やりたかったことはテンプレートとなるExcelファイルを用意しておいて、特定のセルに処理結果の値を入力しダウンロードできるようにすること。
次はこの処理を試してみる。
"tutorial"の"Copying and Modifying Spreadsheets"の説明を参考にコードを書いてみた。
String templatePath = servletContext.getRealPath("/template/sample.xls"); File file = new File(templatePath); Workbook template = Workbook.getWorkbook(file); ByteArrayOutputStream os = new ByteArrayOutputStream(); WritableWorkbook workbook = Workbook.createWorkbook(os, template); WritableSheet sheet = workbook.getSheet(0); WritableCell cell = sheet.getWritableCell(1, 2); if (cell.getType() == CellType.LABEL) { Label l = (Label) cell; l.setString("modified cell"); } workbook.write(); workbook.close();さっそく実行してみると
java.lang.ArrayIndexOutOfBoundsException at java.lang.System.arraycopy(Native Method) at jxl.biff.StringHelper.getBytes(StringHelper.java:127) at jxl.write.biff.WriteAccessRecord.<init>(WriteAccessRecord.java:59) at jxl.write.biff.WritableWorkbookImpl.write(WritableWorkbookImpl.java:726) at jp.technosite.election.controller.pp.DlController.getExcelReport(DlController.java:73) at jp.technosite.election.controller.pp.DlController.run(DlController.java:41)とArrayIndexOutOfBoundsExceptionが発生してしまった。
JExcelAPI側で落ちてるし、セルへ値を設定せずにwriteしても同じ結果になったので、JExcelAPI側に問題がありそうだ。
ということでデバッガで追ってみる。
まずは
jxl.write.biff.WriteAccessRecord.<init>(WriteAccessRecord.java:59)
の部分...public WriteAccessRecord(String userName) { super(Type.WRITEACCESS); data = new byte[112]; String astring = userName == null ? (new StringBuilder()).append("Java Excel API v").append(Workbook.getVersion()).toString() : userName; StringHelper.getBytes(astring, data, 0); for(int i = astring.length(); i < data.length; i++) data[i] = 32; }"StringHelper.getBytes()"の箇所で落ちている。
ここでは astringを dataにコピーしていて、dataはサイズが112となっている。
ということはastringが怪しい。デバッガで内容を確認すると150byte以上あったのでこれが原因だ。
この元になっているのはメソッド引数 userNameなので呼び元の
jxl.write.biff.WritableWorkbookImpl.write(WritableWorkbookImpl.java:726)
を調べてみると、WriteAccessRecord wr = new WriteAccessRecord(settings.getWriteAccess());
となっていて settings.getWriteAccess()の値が使われている。userNameが'null'なら適当な値を設定してくれるので、settings.getWriteAccess()の値をnullになるようにすれば動きそうだ。
settingsはWorkbookSettingsクラスなのでJavadocで調べてみると、setWriteAccess(String)があって
setWriteAccess(null);
とすればよさそうだ。
結局、こんなコードになった。
String templatePath = servletContext.getRealPath("/template/sample.xls"); File file = new File(templatePath); Workbook template = Workbook.getWorkbook(file); ByteArrayOutputStream os = new ByteArrayOutputStream(); WorkbookSettings settings = new WorkbookSettings(); settings.setWriteAccess(null); WritableWorkbook workbook = Workbook.createWorkbook(os, template, settings); WritableSheet sheet = workbook.getSheet(0); WritableCell cell = sheet.getWritableCell(1, 2); if (cell.getType() == CellType.LABEL) { Label l = (Label) cell; l.setString("modified cell"); } workbook.write(); workbook.close();実行してみると、めでたくsample.xlsがコピーされたExcelファイルがダウンロードできた。\(^o^)/
後は日本語の扱いが気になるのでもう少し調べてみる必要があるな。
0 件のコメント:
コメントを投稿