本文共 9123 字,大约阅读时间需要 30 分钟。
jxls2.4 是java对excel操作的工具包,可以很方便的实用模板输出excel,根据xml配置读取excel内容。
对比jxls1 现在的版本使用批注的模式运行指令,可以支持excel中使用公式,07的excel。 使用:org.jxls jxls 2.4.5 org.jxls jxls-poi 1.0.15 org.jxls jxls-jexcel 1.0.7
示例:jx:each((items="employees" var="employee" lastCell="D4" area="[A4:D4]" select="employee.payment > 2000"))
参数说明:参数名称 | 示例 | 必填 | 说明 |
---|---|---|---|
items | items="employees" | 必填 | 循环的集合对象 |
var | var="employee" | 必填 | 循环中的变量名,指定之后区域内可以使用该名称访问属性 |
lastCell | lastCell="D4" | 必填 | 指令对应的结束位置 |
direction | direction ="RIGHT" | 输出的方向向下(DOWN)或向右(RIGHT),默认为DOWN | |
area | areas=["A8:F8","A13:F13"] | 循环的区域,一次循环多行则需要填写,可以指定多个区域使用逗号分隔 | |
select | select="employee.payment>2000" | 过滤条件,不需要通过${}来取值 | |
groupBy | groupBy ="name" | jx:each(items="employees" var="nameGroup" groupBy="name" groupOrder="asc" lastCell="D7")依据employee中name进行分组,分组后的集合可通过nameGroup.items来获取,官网示例中后面还有一个each指定的items就是nameGroup.items | |
groupOrder | groupOrder ="asc" | 指定分组排序(‘desc’ or ‘asc’) | |
multisheet | multisheet ="sheets" | 循环的sheet名称集合,指定后会产生多个sheet,指定后each的维度会变为sheet,不需要指定area | |
shiftMode | shiftMode ="adjacent" | adjacent指定后通过添加行的方式向指定方向输出,inner:则为通过添加单元格的方式向指定方向输出,默认为inner | |
cellRefGenerator | ? | ? |
不指定shiftMode ="adjacent"的效果
示例:jx:if(condition="department.chief.name != 'Betsy' " lastCell="F4" areas=["A3:F4"])
参数名称 | 示例 | 必填 | 说明 |
---|---|---|---|
condition | condition="department.chief.name != 'Betsy' " | 必填 | 判断条件,字符串不需要通过${}来取值,直接访问传递对象的内容 |
ifArea | ifArea =["A3:F4"] | if指令影响的范围 condition结果为true则显示指定范围 | |
elseArea | elseArea=["A3:F4"] | if指令影响的范围 condition结果为false则显示指定范围 |
说明:主要用于动态修改模板中被循环包裹的的公式,demo中的相关例子在org.jxls.demo.SxssfDemo中
示例:jx:updateCell(lastCell="E4" updater="totalCellUpdater")参数名称 | 示例 | 必填 | 说明 |
---|---|---|---|
updater | updater="totalCellUpdater" | 必填 | 指定具体的操作类需实现CellDataUpdater接口 |
java代码示例:
static class TotalCellUpdater implements CellDataUpdater{ /** * cellData 批注对应的单元格 * targetCell 输出的单元格 * context 模板中的上下文通过getVar(变量名)来获取传入的对象 */ @Override public void updateCellData(CellData cellData, CellRef targetCell, Context context) { if( cellData.isFormulaCell() && cellData.getFormula().equals("SUM(E2)")){ String resultFormula = String.format("SUM(E2:E%d)", targetCell.getRow()); cellData.setEvaluationResult(resultFormula); } } }
说明:一次性输出一个表格包含表头表体,demo中的相关例子在org.jxls.demo.GridCommandDemo中
示例:jx:grid(lastCell="A4" headers="headers" data="data" areas=[A3:A3, A4:A4] formatCells="BigDecimal:C1,Date:D1")参数名称 | 示例 | 必填 | 说明 |
---|---|---|---|
headers | headers="headers" | 必填 | 循环的表头内容为List ,表头和表体没有必然的关系,可以多一列也可以少一列 |
data | data="data" | 必填 | 循环的表体内容为List/List,当为javabean时java代码中需指定读取的属性名称 |
formatCells | formatCells="BigDecimal:C1,Date:D1" | 指定单元格格式化方式 |
try(InputStream is = GridCommandDemo.class.getResourceAsStream("grid_template.xls")) { try(OutputStream os = new FileOutputStream("grid_output2.xls")) { Context context = new Context(); context.putVar("headers", Arrays.asList("Name", "Birthday", "Payment")); context.putVar("data", employees); //当循环的表体为javabean时指定读取的属性,Sheet2!A1表示输出开始的位置 JxlsHelper.getInstance().processGridTemplateAtCell(is, os, context, "name,birthDate,payment,bonus", "Sheet2!A1"); } }
说明:输出一张图片,demo中的相关例子在org.jxls.demo.ImageDemo中
示例:jx:image(lastCell="D10" src="image" imageType="PNG")参数名称 | 示例 | 必填 | 说明 |
---|---|---|---|
src | src="image" | 必填 | 输出的图片数据源byte[] |
imageType | imageType="PNG" | 输出的图片格式可不填 |
java代码示例:
public static void execute2() throws IOException { try(InputStream is = ImageDemo.class.getResourceAsStream(template2)) { try (OutputStream os = new FileOutputStream(output2)) { Context context = new Context(); InputStream imageInputStream = ImageDemo.class.getResourceAsStream("business.png"); byte[] imageBytes = Util.toByteArray(imageInputStream); Department department = new Department("Test Department"); department.setImage(imageBytes); context.putVar("dep", department); JxlsHelper.getInstance().processTemplate(is, os, context); } } }
使用 来 使 用 中 的 公 式 例 如 [ ] 来 使 用 e x c e l 中 的 公 式 例 如 " [B4(1+${bonus})]"输出后为"=B6(1+0.1)",可以使用excel函数如SUM如选择某一列只需指定变量对应单元格,输出会自动替换为该列,如下图
如公式中不需要访问传入属性直接写=SUM(B4)编译后也会自动替换为=SUM(B4:B8)
支持java手动增加公式详细例子请看demo中org.jxls.demo.FormulaExportDemo
函数和指令都可以进行扩展,需在导出前进行初始化,顺便吐槽一下百度用标题查居然第一个出来的是转发的第三个才是原文。
具体的内容可以参考大神写的这个项目
函数:在单元格中使用处理具体数据
JxlsHelper jxlsHelper = JxlsHelper.getInstance(); Transformer transformer = jxlsHelper.createTransformer(is, os); JexlExpressionEvaluator evaluator = (JexlExpressionEvaluator) transformer.getTransformationConfig().getExpressionEvaluator(); Mapfunctions = new HashMap<>(1); //添加自定义功能 functions.put("util", new JxlsUtil());//此处util为函数前缀,调用时在单元格中使用${util:函数名(参数)}来使用其中参数为当前上下文内容 evaluator.getJexlEngine().setFunctions(functions); jxlsHelper.processTemplate(context, transformer); is.close();
//JxlsUtil 格式化工具类public class JxlsUtil { /** * 日期格式化 * * @param date * @param fmt * @return */ public String dateFmt(Date date, String fmt) { if (date == null) { return null; } try { SimpleDateFormat dateFmt = new SimpleDateFormat(fmt); return dateFmt.format(date); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 返回第一个不为空的对象 * * @param objs * @return */ public Object defaultIfNull(Object... objs) { for (Object o : objs) { if (o != null) { return o; } } return null; } /** * if判断 * * @param b * @param o1 * @param o2 * @return */ public Object ifelse(boolean b, Object o1, Object o2) { return b ? o1 : o2; }}
指令:在批注中使用,可扩展原有jxls中的功能例如循环增加下标.
继承AbstractCommand//扩展指令public class ExEachCommand extends AbstractCommand {//处理内容public Size applyAt(CellRef cellRef, Context context) {}....}//在具体导出的类中增加静态代码块,由于只需要执行一次所以用静态代码块比较合适 static { //添加自定义指令(可覆盖jxls原指令) XlsCommentAreaBuilder.addCommandMapping("each",ExEachCommand.class); }
通过一个xml来对应excel中内容,读取时传入相应xml和excel来转换为javabean,
转换代码:try (InputStream xmlInputStream = EquipmentController.class.getResourceAsStream("/excelTemp/equipment_impot.xml")) { File tempfile = fileService.getFile(data, fileType, file); XLSReader reader = ReaderBuilder.buildFromXML(xmlInputStream); try (InputStream xlsInputStream = new FileInputStream(tempfile)) { Listequipments = new ArrayList<>(); Map beans = new HashMap<>(15); Map title = new HashMap<>(3); beans.put("equipments", equipments); beans.put("title", title); //碰到数据类型转换异常时跳过异常,例如数字类型但是单元格中为空,默认是会抛出异常的.设置之后就会设置为null ReaderConfig.getInstance().setSkipErrors(true);//从excel中读取对象,名称需和xml中对应 reader.read(xlsInputStream, beans); if (checkTitle(title)) { message = equipmentService.importEquipment(equipments, firmInfo); } else { throw new BusinessAjaxException(TEMPLET_ERROR); } if (StringUtils.isBlank(message)) { message = SUCCESS_CONTENT; } else { data.put("status", HttpStatus.UNPROCESSABLE_ENTITY.value()); } data.put("message", message); } } catch (BusinessAjaxException e) { throw e; } catch (XLSDataReadException e) { throw new BusinessAjaxException(String.format(JXLS_ERROR, e.getCellName()), e); } catch (Exception e) { throw new BusinessAjaxException(IMPORT_ERROR, e); }
对应xml文件:
title.eqCode title.origin title.remark equipment.eqCode equipment.eqName equipment.brand equipment.importBuyTime equipment.importSpecification equipment.price equipment.origin equipment.quantity equipment.process equipment.numberUsers equipment.equipmentTrip equipment.eqPrecision equipment.remark
注意事项:
转载地址:http://chykl.baihongyu.com/