JXLS (Excel導入、導出工具使用)
1:簡介:
jxls是一個簡單的、輕量級的excel導出庫,使用特定的標記在excel模板文件中來定義輸出格式和布局。java中成熟的excel導出工具有pol、jxl,但他們都是使用java代碼的方式來導出excel,編碼效率很低且不方便維護。
還可以使用一些工具很輕松的實現模板導出。這些工具現在還在維護,而且做得比較好的國內的有easyPOI,國外的就是這個JXLS了。
比較:
項目中有很多復雜的報表(大量單元格合並和單元格樣式),easyPOI處理合並單元格時候容易出現殘損的情況,poi代碼維護成本高。
2:maven依賴:
<dependency>
<groupId>org.jxls</groupId>
<artifactId>jxls</artifactId>
<version>[2.6.0-SNAPSHOT,)</version>
</dependency>
<dependency>
<groupId>org.jxls</groupId>
<artifactId>jxls-poi</artifactId>
<version>[1.2.0-SNAPSHOT,)</version>
</dependency>
<dependency>
<groupId>org.jxls</groupId>
<artifactId>jxls-jexcel</artifactId>
<version>[1.0.8,)</version>
</dependency>
<dependency>
<groupId>org.jxls</groupId>
<artifactId>jxls-reader</artifactId>
<version>[2.0.5,)</version>
</dependency>
2:下面先做一個簡單導出的實現:
1: 創建model:

2:先用office創建一個xlsx的模板

可以看到這里有一些cell 的文本批注,office中添加批注快捷鍵(Shit + F2),批注中的類容這里先不做解釋,下面會講到
3:工具類JxlsUtils.java
public class JxlsUtils{ private static final String TEMPLATE_PATH="jxls-template"; public static void exportExcel(InputStream is, OutputStream os, Map<String, Object> model) throws IOException{ Context context = new Context(); if (model != null) { for (String key : model.keySet()) { context.putVar(key, model.get(key)); } } JxlsHelper jxlsHelper = JxlsHelper.getInstance(); Transformer transformer = jxlsHelper.createTransformer(is, os); JexlExpressionEvaluator evaluator = (JexlExpressionEvaluator)transformer.getTransformationConfig().getExpressionEvaluator(); Map<String, Object> funcs = new HashMap<String, Object>(); // funcs.put("utils", new JxlsUtils()); //添加自定義功能 // evaluator.getJexlEngine().setFunctions(funcs); jxlsHelper.processTemplate(context, transformer); } public static void exportExcel(File xls, File out, Map<String, Object> model) throws FileNotFoundException, IOException { exportExcel(new FileInputStream(xls), new FileOutputStream(out), model); } public static void exportExcel(String templateName, OutputStream os, Map<String, Object> model) throws FileNotFoundException, IOException { File template = getTemplate(templateName); if(template!=null){ exportExcel(new FileInputStream(template), os, model); } } //獲取jxls模版文件 public static File getTemplate(String name){ String templatePath = JxlsUtils.class.getClassLoader().getResource(TEMPLATE_PATH).getPath(); File template = new File(templatePath, name); if(template.exists()){ return template; } return null; } // 日期格式化 public String dateFmt(Date date, String fmt) { if (date == null) { return ""; } try { SimpleDateFormat dateFmt = new SimpleDateFormat(fmt); return dateFmt.format(date); } catch (Exception e) { e.printStackTrace(); } return ""; } // if判斷 public Object ifelse(boolean b, Object o1, Object o2) { return b ? o1 : o2; } }
上面注釋中的自定義功能可以先注釋到,我們后面在講
入口ObjectCollectionDemo.java
public class ObjectCollectionDemo { static Logger logger = LoggerFactory.getLogger(ObjectCollectionDemo.class); public static void main(String[] args) throws ParseException, IOException { logger.info("Running Object Collection demo"); List<Employee> employees = generateSampleEmployeeData(); OutputStream os = new FileOutputStream("target/object_collection_output.xls"); Map<String , Object> model=new HashMap<String , Object>(); model.put("employees", employees); model.put("nowdate", new Date()); JxlsUtils.exportExcel("object_collection_template.xls", os, model); os.close(); } public static List<Employee> generateSampleEmployeeData() throws ParseException { List<Employee> employees = new ArrayList<Employee>(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MMM-dd", Locale.US); employees.add( new Employee("Elsa", dateFormat.parse("1970-Jul-10"), 1500, 0.15) ); employees.add( new Employee("Oleg", dateFormat.parse("1973-Apr-30"), 2300, 0.25) ); employees.add( new Employee("Neil", dateFormat.parse("1975-Oct-05"), 2500, 0.00) ); employees.add( new Employee("Maria", dateFormat.parse("1978-Jan-07"), 1700, 0.15) ); employees.add( new Employee("John", dateFormat.parse("1969-May-30"), 2800, 0.20) ); return employees; } }
生成效果:

好的,這樣就很輕松的導出了是不是很簡單
3:下面講一下導出的細節,注意事項:
1:模板中的批注:
注意如果模板中對單元格加了批注,但是沒有批注信息的話可能會報錯:



1-1:bean屬性標記
jxls使用 Apache JEXL表達式語言來解析定義在excel模板中的表達式。JEXL與JSTL相似,並對JSTL進行了擴展。eg:
${department.chief.age} //屬性可以是無限深度
${utils:dateFmt(date,"yyyy-MM-dd")} //自定義工具函數
1-2:XLS Area定義標記
XLS Area 是JxlsPlus中的一個重要概念,它代表excel模板中需要被解析的矩形區域,由A1到最后一個單元格表示,有利於加快解析速度。
XLS Area 使用excel注釋標注表示,它需要被定義在excel 模板的第一個單元格(A1):
jx:area(lastCell = "<AREA_LAST_CELL>")

1-3:XLS Command表示標記
XLS Command 使用excel注釋標注表示,命令格式如下:
jx:<command_name>(attr1='val1' attr2='val2' ... attrN='valN' lastCell=<last_cell> areas=["<command_area1>", "<command_area2",
... "<command_areaN>"])
<command_name> 是庫自帶的命名或是用戶自定義並注冊到XlsCommentAreaBuilder的命令。
each 命令是最常用的XLS命令,形如:
jx:each(items="employees" var="employee" lastCell="D4")
eg:

each 可以有如下一些屬性:
- items 上下文中集合的變量名;
- var 在遍歷集合的時候每一條記錄的變量名;
- area 該XLS Command的解析區域;
- direction 數據在excel中填充的方向,默認(DOWN)向下;
- select 其值為一個表達式,用來過濾數據
橫向遍歷顯示list的數據:
jx:each(items="data" var="dat" lastCell="A3" direction="RIGHT")
1-4:jexl自定義工具函數:
如果你需要自定jexl來處理數據,你可以從Transformer對象獲取JexlEngine引用,並對其配置。
下面的例子實現了將一個自定義jexl函數注冊到utils命名空間下:
JxlsHelper jxlsHelper = JxlsHelper.getInstance(); Transformer transformer = jxlsHelper.createTransformer(is, os); JexlExpressionEvaluator evaluator = (JexlExpressionEvaluator)transformer.getTransformationConfig().getExpressionEvaluator(); Map<String, Object> funcs = new HashMap<String, Object>(); funcs.put("utils", new JxlsUtils()); //添加自定義功能 evaluator.getJexlEngine().setFunctions(funcs);
1-5:單元格合並命令:
Excel注釋語法
jx:merge( lastCell =“合並單元格范圍” [,cols =“合並的列數”] [,rows =“合並的行數”] [,minCols =“要合並的最小列數”] [,minRows = “要合並的最小行數”] )
注意:此命令只能用於尚未合並的單元格。如果合並單元格的合並單元格范圍存在,則會發生異常。
官方文檔:http://jxls.sourceforge.net/reference/excel_markup.html
官方文檔打不開?下個加速器就可以了:http://www.youxia66.com/
參考博客:https://www.cnblogs.com/klguang/p/6425422.html
博客源碼:
demo工程源碼下載:http://files.cnblogs.com/files/klguang/jxlsdemo.zip
