Open zzmark opened 1 day ago
TemplateSheet目前没有分组的功能,建议直接使用ListSheet或者SimpleSheet,使用ListSheet时需要先处理一次数据即可,将row这一层提出,并将group转换为row一样的格式即可。
List<Item> list = new ArrayList<>();
for (List<Group> group : groupList) {
// 将Group转为Item
Item item = new Item();
item.setNo(group.getGroup());
list.add(item);
// 将row追加到Group之后
list.addAll(group.getRow());
}
TemplateSheet目前没有分组的功能,建议直接使用ListSheet或者SimpleSheet,使用ListSheet时需要先处理一次数据即可,将row这一层提出,并将group转换为row一样的格式即可。
有点难,输出的表格是个报告单,格式相当复杂,分组表格只是中间的一部分,上下还有其它内容。 若是使用 ListSheet或者SimpleSheet,其它部分需要通过代码编写,成本有点高。 目前的业务场景使用 TemplateSheet 类似技术是唯一方案。
除此之外其实还要有根据值修改样式的需要,这部分我自行改了些代码实现。 复杂key反射这个也自行实现了。 但分组和多行这两个点实在没研究明白
如果不需要做成通用功能的话则可以只配置row这一行,重写TemplateSheet#getNodeValue方法,将group转为单独的对象不移动下标
如果不需要做成通用功能的话则可以只配置row这一行,重写TemplateSheet#getNodeValue方法,将group转为单独的对象不移动下标
目前重写TemplateSheet#getNodeValue方法,配合表达式引擎,实现了复杂格式。 还在找方法实现多行,光靠已有的语法感觉不太够用
你说的多行是指group行吗?如果是的话可以按照我上面回复的重写TemplateSheet#getNodeValue方法,将group转为单独的对象不移动下标即可,我写一个示例可以参考
复制下面的代码并替换模版路径可运行
@Test public void groupTest() throws IOException {
List<ItemGroup> list = new ArrayList<>();
ItemGroup group1 = new ItemGroup();
group1.group = "G1";
group1.row = Arrays.asList(new Item("1", "A"), new Item("2", "B"));
list.add(group1);
ItemGroup group2 = new ItemGroup();
group2.group = "G2";
group2.row = Arrays.asList(new Item("3", "C"), new Item("4", "D"));
list.add(group2);
new Workbook()
.addSheet(new MyGroupTemplateSheet(defaultTestPath.resolve("template测试.xlsx"))
.setData("list", list))
.writeTo(defaultTestPath.resolve("result.xlsx"));
}
public static class ItemGroup {
private String group;
List<Item> row;
}
public static class Item {
private String no;
private String code;
public Item() { }
public Item(String no, String code) {
this.no = no;
this.code = code;
}
}
public static class MyGroupTemplateSheet extends TemplateSheet {
// i 记录Group下标
// ii 记录子集下标
// ri 记录row下标
private int i = 0, ii = -1, ri;
public MyGroupTemplateSheet(Path templatePath) {
super(templatePath);
}
@Override
protected void fillValue(Row row, Cell cell, PreCell pn, Column emptyColumn) {
if (ri == 0) ri = row.index;
else if (ri < row.index) {
ri = row.index;
ii++; // 移动子集游标
}
super.fillValue(row, cell, pn, emptyColumn);
}
@Override
protected Object getNodeValue(Node node) {
// 纯文本
if ((node.option & 1) == 0) return node.val;
ValueWrapper vw = namespaceMapper.get(node.namespace);
Object e = null;
if (vw != null) {
Object o = vw.list != null && i < vw.list.size() ? vw.list.get(i) : null; // <- 注意这里不使用ValueWrapper的游标
// ItemGroup对象特殊处理
if (o instanceof ItemGroup) {
ItemGroup sub = (ItemGroup) o;
// Group行
if (ii < 0) {
// Group名放到序号列
e = "row.no".equals(node.val) ? sub.group : null;
} else {
List<Item> rows = sub.row;
// Group结束
if (ii >= rows.size()) {
ii = -1;
i++;
// 判断是否已全部结束,全部结束后将option标记为-1
if (i >= vw.list.size()) vw.option = -1;
// 取下一个分组
else e = getNodeValue(node);
} else {
// FIXME 这里我只是简单取值,实际场景自行处理,提前将子集的反射属性放入accessibleObjectMap即可
Item item = rows.get(ii);
try {
Field field = item.getClass().getDeclaredField(node.val.substring(4));
field.setAccessible(true);
e = field.get(item);
} catch (Exception ex) {
// Ignore
}
}
}
// 重置ValueWrapper游标,不然会跳过整个group
vw.i = i - 1; // 父类resetBlockData方法会在写完整行后将游标向后移动一次,所以-1为了避免跳过最后一组
} else e = super.getNodeValue(node);
}
return e;
}
}
模板如下
序号: | 编码 |
---|---|
${list.row.no} | ${list.row.code} |
good,晚点我尝试一下
问题有两个,
现在的逻辑,标记list是namespace整个标记,没法识别里面的结构 如何支持这样的逻辑