テンプレートでExcelドキュメントを生成するための自転車

通常、xlsでの複雑なレポートのプログラムによる生成では、実際のデータの代わりに「タグ」が適切な場所で置き換えられる「手動」で生成されたドキュメント(テンプレート)を使用することをお勧めします。 $ {userName}、$ {userAge}、およびテンプレートに入力するプロセスで、ドキュメントのテキスト内のタグを見つけて、対応する値に置き換えます。



しかし、最終ドキュメントのテンプレートからいくつかのページがあり、その逆の場合、他のページを数回「複製」して、異なるデータで埋めることができますか? そして、コードのマッピングタグ->値の退屈な充填を取り除く方法は?



ドキュメントのシートモデルについて説明しましょう。



public class SheetModel { private String sheetToClone; //,      private String sheetName; //    private Map<String, Object> mappings; //getters and setters }
      
      







次に、 Apache POIを使用して本に目を通し、sheetToCloneという名前のシートを見つけて、そのコピーを作成します。 したがって、SheetModelクラスのオブジェクトをいくつでも作成し、それらをループで調べて、最終的に元のドキュメントのシートとそのコピーを含むドキュメントを取得できます。 次に、「ソース」シートが削除されます。



 private void createNewSheets(List<SheetModel> sheetModelList){ for (SheetModel sheetModel: sheetModelList){ String sheetName=sheetModel.getSheetName(); String sheetToClone=sheetModel.getSheetToClone(); cloneSheet(sheetName, sheetToClone); } } private void cloneSheet(String sheetName,String sheetToClone ){ int sheetToCloneIdx=getSheetIndex(sheetToClone); cloneSheet(sheetToCloneIdx, sheetName); } private int getSheetIndex(String sheetName) throws SheetNotFoundException{ for (int i = 0; i < workbook.getNumberOfSheets(); i++) { if(workbook.getSheetAt(i).getSheetName().equals(sheetName) ) { return i; } } throw new SheetNotFoundException("Sheet '" + sheetName +"' not found" ); } public void cloneSheet(int index, String newSheetName) { HSSFSheet newSheet = workbook.cloneSheet(index); for (int i = 0; i < workbook.getNumberOfSheets(); i++) { if(newSheet.equals(workbook.getSheetAt(i))) { workbook.setSheetName(i, newSheetName); break; } } }
      
      







しかし、最も興味深いのはApache Commons JEXLライブラリです。



JEXLは、shell-scriptまたはECMAScriptで見られるほとんどの構造をサポートするJSTL Expression Languageの拡張に基づいてExpression Languageを実装します





以下は、サイトから少しやり直した例です。



  // Create or retrieve a JexlEngine JexlEngine jexl = new JexlEngine(); // Create an expression object String jexlExp = "user.name"; Expression e = jexl.createExpression( jexlExp ); // Create a context and add data JexlContext jc = new MapContext(); jc.set("user", new User("") ); // Now evaluate the expression, getting the result Object o = e.evaluate(jc); o.toString(); // ""
      
      







したがって、すべてのタグをJavaコードにリストして、実際のデータと一致するように設定する必要はありません。

オブジェクトにのみ対応を設定するだけで十分です。その後、「タグ」をその値に置き換えるタスクは「タグ」の検索に減り、Commons JEXLにフィードして、タグの付いたセルにライブラリの結果を書き込みます。 混oticとして判明したので、例で説明しようとします。

テンプレートに「$ {user.name}、$ {user.age}」のような「タグ」を追加します。 また、Javaコードでは、Userクラスのオブジェクトをマップに配置するだけで十分です。

その後、ドキュメントのすべてのセルをループ処理し、「$ {」および「}」で制限された行を見つけて、それらの値をCommons JEXLライブラリの結果に置き換えます



 private void fillSheet() { User user=new User("",25); //   Map<String,Object> mappings=new HashMap<String,Object>(); mappings.put("user",user); JexlEngine engine=new JexlEngine(); JexlContext context=new MapContext(mappings); for(Row row : sheet) { for(Cell cell : row) { if(cell.getCellType()==Cell.CELL_TYPE_STRING){ String exp=findExpression(cell); if(exp!=null){ Expression e=engine.createExpression(exp); Object o=e.evaluate(context); if(o!=null){ String result=o.toString(); cell.setCellValue(result); } } } } } }
      
      





findExpression()メソッドは、セルに含まれる文字列で「$ {」と「}」で囲まれた部分文字列を検索します



JETTプロジェクトに会ったときに、Apache Commons JEXLライブラリについて学びました。 プロジェクトに多数のライブラリを追加したくありませんでした(JETTはさらにいくつかのライブラリに依存しています)。また、JETTのすべての機能は必要ありません。 しかし、それがどのように内部にあるかを理解するために、面白く配置されました:) 少なくとも誰かがこの投稿を手伝ってくれたら嬉しいです。



All Articles