2017年2月8日 星期三

jxls

最近試了一下
http://jxls.sourceforge.net/
他應該是算一個產生 xls 的 framework~

覺得是還不錯用。背後可以接 蠻常用的 poi 實作。
http://jxls.sourceforge.net/getting_started.html
Currently Jxls supplies two implementations of this interface in separate modules based on the well-known Apache POI and Java Excel API libraries.
只要引用不同的 maven lib 就可以換實作。

然後他把 xlsx, xls 的 method 合而為一了~~在 poi 上這是分屬兩套不同的系統,所以有解決自己刻時各自寫一套的麻煩。

還有很重要的一點是支援 el 的語法。常用的 取 bean 屬性, if ,each,都有 \(^_^)/...
看起來他還可以換 el 的語法系統。不過因為內建的已經夠用就先降子~
 http://jxls.sourceforge.net/reference/expression_language.html

也有順便把 公式 統計算區間的部份給處理好了。(之前自己刻,在那邊算自己加了幾行,要怎麼下 xls 公式的區間的麻煩問題有幫解了。)

要入門的方式,應該是抓他的 sample code 來跑,是最方便的了。
http://jxls.sourceforge.net/source_code.html
https://bitbucket.org/leonate/jxls-demo
直接跑demo 修改跟看文件說明一起看就會清楚很多!因為這個要 xls template 和 java code 結合一起看才會準(那個文件貼圖是有貼到重點,但是...就還是手動操作一下上手比較快)


個人比較喜歡用 template 方式來做 xls,所以~最後選用全部mark-up 的方式。
http://jxls.sourceforge.net/reference/excel_markup.html
另外因為有多 sheet 的需求,demo 主要都是以單一sheet 的在放,所以我就小修了一下~

xls template 的設定~


最容易忘記的的大概就是一開始,jx:area 一定要設定...不然他不知道要幫你換多大的區塊...
還有就是當表有增刪欄位時,好好檢查一下區間的範圍~囧/
他裡面的 function, Context ,都是整個xls共用的,所以是只要給一次就好了~

另外是因為我做多sheet 測試,習慣就是 template sheet 對 產出 sheet 是一對一的方式,所以會刪掉做為 template 的原本的 sheet。
(當然是jxls的架構, template area 是可以一直重覆利用的。)

Java code:
        try(InputStream is = new FileInputStream(fullpath)) {
            try (OutputStream os = new FileOutputStream(output)) {
                //init 給定最主要的處理 transformer
                Transformer transformer = TransformerFactory.createTransformer(is, os);
               
                //register function 因為有用到method,一定要註冊才能用
                JexlExpressionEvaluator evaluator = (JexlExpressionEvaluator) transformer.getTransformationConfig().getExpressionEvaluator();
                Map<String, Object> functionMap = new HashMap<>();
                functionMap.put("fn", new ReportFunction());
                evaluator.getJexlEngine().setFunctions(functionMap);
               
                //set context 給物件資料
                Context context = new Context();
                context.putVar("data", data);
               
                //note comment: NEED define jx:area in the sheet beginning
                AreaBuilder areaBuilder = new XlsCommentAreaBuilder(transformer);
                XlsCommentAreaBuilder.addCommandMapping("groupRow", GroupRowCommand.class);
                List<Area> xlsAreaList = areaBuilder.build();
                //取有定義的區塊出來處理
                for(int i = 0 ; i < xlsAreaList.size() ; i++)  {
                    Area xlsArea = xlsAreaList.get(i);
                    String theSheetName = xlsArea.getAreaRef().getSheetName();
                   
                    //apply
                    if(sheetNames.containsKey(theSheetName))  {
                        CellRef newSheetCell = new CellRef(sheetNames.get(theSheetName), 0, 0);
                        //產出後的區塊,要寫到xls 的那邊
                        xlsArea.applyAt(newSheetCell, context);
                        //要跑小計,要記得叫他處理公式區間
                        xlsArea.processFormulas();
                    }
                    //刪除 做為 template 的 sheet
                    transformer.deleteSheet(theSheetName);
                }
                //write
                transformer.write();
               
            }
        }

結果大概就是長降子~
多張 sheet 有出來。

(他會自動把 符合語法的 註解清掉。但是不合的會留著XD...)

看一下 if 的作用,還不錯~