JExcelApiを使ってみる

まずはダウンロード
http://sourceforge.net/projects/jexcelapi/
プロジェクトのホームはここ
http://jexcelapi.sourceforge.net/

  • xlsファイルの作成
// encoding等の設定
WorkbookSettings ws = new WorkbookSettings();
ws.setLocale(new Locale("ja", "JP"));
ws.setEncoding("Windows-31J");

WritableWorkbook workbook = Workbook.createWorkbook(new File("filename"), ws);

// シートを作成して適当に書き込み
WritableSheet sheet = workbook.createSheet("シート1", 0);
Label label = new Label(0, 2, "ラベルレコード"); 
sheet.addCell(label); 

Number number = new Number(3, 4, 3.1459); 
sheet.addCell(number); 

workbook.write();
workbook.close();

日本語も特に問題なく書き込めた(WorkbookSettingsは設定しなくても日本語問題なし)。う〜ん、便利になった。

  • テンプレートを読込んで別ファイルへ保存
Workbook w1 = Workbook.getWorkbook(new File("template.xls"));
WritableWorkbook w2 = Workbook.createWorkbook(new File("clone.xls"), w1);
w2.write();
w2.close();

う〜ん、簡単だ。

  • テンプレートから読込んだ別ファイルにデータを書き込む
Workbook template = Workbook.getWorkbook(new File("template.xls"));
WritableWorkbook dst = Workbook.createWorkbook(new File("dst.xls"), template);
WritableSheet sheet = dst.getSheet(0);
Cell cell = sheet.getWritableCell(0, 1); // <- 書込み先が空の場合はBlankが返る

// テキストを書込むのでラベルセルを生成する
Label label = new Label(0, 1, "テキスト");
// 元のセルのフォーマット等を新しいセルに設定する
if (cell.getCellFeatures() != null) {
    label.setCellFeatures(new WritableCellFeatures(cell.getCellFeatures()));
}
label.setCellFormat(cell.getCellFormat());

// セルを上書き
sheet.addCell(label);
	    
dst.write();
dst.close();

実際はCellの型を判別して処理するんだろうなぁ…getWritableCellしてるわけだし。

  • メモ

・カラムの指定は(列, 行):0から開始
・使いそうなセルタイプ
 Boolean, DateTime, Label, Number
・セルタイプの判定はCellTypeを使うような感じだけど、CellType.Blankは何故かない
・行の挿入はあるがコピーはない
・Sheet#getRowで行のセルが配列で取得できる
 →罫線だけのセルは行としては認識されているが、CellType.Blankが存在しないこと
  からわかるようにBlankはCellとして扱われないため、空の配列が返ってくる
 →時間がないので行のコピーは諦めて、あらかじめ元となる行を沢山作っておいて、
  いらない行を削除することにする

使い方としていいのかは不明

例えばこんな感じで検索画面の初期情報を取得するActionを定義したとする。Formは特に必要ないのでactionタグのname属性は書かない(これっていいのかな?)。


  

これはこれでActionはちゃんと実行される。が、S2Strutsのオートバインディング機能が働いたときに、Formのnameがnull、当然scopeもnullなのだが、ActionExecuteProcessorImpl#setActionFormの以下の部分でelseの処理、つまりSessionへのFormのセットが実行されて

if (REQUEST.equals(mapping.getScope())) { // mapping.getScope()はnull
 request.setAttribute(mapping.getAttribute(), form);
} else {
  HttpSession session = request.getSession();
  session.setAttribute(mapping.getAttribute(), form); // mapping.getAttribute()もnull
}

エラーとなってしまう。

java.lang.IllegalArgumentException: setAttribute: nameパラメタはnullであってはいけません

なるほど...

  • Actionの実行結果を表示するJSPからPOJOFormを取ろうとしてもBeanValidatorFormだったのは、S2Strutsが元々のFormBeanをAction実行後にセットし直してるからなのか。先にソースを確認すべきだったorz
  • ActionプロパティのInport/Exportはnullの場合は行われない
  • ActionプロパティのExportをSessionに対して行うにはEXPORTアノテーションを使用する(ドキュメントには載ってない?)
public final static String プロパティ_EXPORT = BindingUtil.SESSION;

右括弧が消える原因判明

以下のSQLの場合、

INSERT INTO TABLE_NAME (NAME, AGE) VALUES (/*dto.name*/'SCOTT',/*dto.age*/20)

構文解析の際に

  1. INSERT INTO TABLE_NAME (NAME, AGE) VALUES (
  2. dto.name
  3. 'SCOTT'
  4. ,
  5. dto.age
  6. 20)

となってしまい、”20)”がスキップされて結果として右括弧のない

INSERT INTO TABLE_NAME (NAME, AGE) VALUES (/*dto.name*/'SCOTT',/*dto.age*/20

となってしまう。例えば、

INSERT INTO TABLE_NAME (NAME, AGE) VALUES (/*dto.name*/'SCOTT',/*dto.age*/'20')

とした場合は

  1. INSERT INTO TABLE_NAME (NAME, AGE) VALUES (
  2. dto.name
  3. 'SCOTT'
  4. ,
  5. dto.age
  6. 20
  7. )

となって正常にパースされる。ちなみに、

INSERT INTO TABLE_NAME (NAME, AGE) VALUES (/*dto.name*/'SCOTT',/*dto.age*/20
)

  1. INSERT INTO TABLE_NAME (NAME, AGE) VALUES (
  2. dto.name
  3. 'SCOTT'
  4. ,
  5. dto.age
  6. 20
  7. \r\n)

となるのでこれも正常にパースされる。

最後のページへのリンクが...

最後のページのデータ件数が、limitより少ない場合でも”次のXX件”のXXがlimit固定で表示しているので数が合わない。なのでこんな感じで修正してみた(該当箇所抜粋)。


↓修正前

次の

↓修正後

次の

  
    
  
  
    
  

S2Pagerとても便利(^^