目录

最近公司业务需要用到excel,并且要导出模板,今天为止所有的功能都已经实现了,在这里对出现的一些问题做一个总结。


效果图:

这是一个五级联动的数据,其中第一列是数字开头,实现了五级联动


问题1:

在做这一块的时候,碰到的第一个问题就是怎么实现级联,这方面资料很多我就不多赘述了,这里给大家推荐几个我找的觉得比较好的博客

https://www.cnblogs.com/atao/archive/2009/09/24/1572980.html

https://blog.csdn.net/it_zacard/article/details/77033095?utm_source=blogxgwz0

第一个博客对POI的基础覆盖的比较全面,很适合上手,第二篇主要解决三级联动问题2,一般的导出认值学习这两篇博客基本都能

解决,这也不是笔者写这篇文章的主要原因

问题2:

怎么解决数字级联的问题,放到我的业务需求中就是,现在我的分期是以数字开头的,怎么实现级联?

在查了很多文章都没有解决这个问题,最后我通过公式加隐藏列的方法实现了这个需求。

大致思路如下:

创建一个隐藏列,通过公式跟分期所在列关联,如果分期是以数字开头,隐藏隐藏列中的数据为:"_"+分期,否则隐藏列的数据为分

期。

    private void createDataValidationForSpace(Sheet sheet, int subCol) {
// 主数据所在列对应的字符
// 隐藏列对应字符
for (int i = 3; i < EnergyConstant.Excel.MAX_SIZE; i++) {
// 隐藏列公式:判断主数据所在单元格中的数据是否是以数字开头,以数字开头则隐藏列的数据为"_"+数据,否则为原数据
// EnergyConstant.Excel.STAGE_LETTER:常量,分期所在列对应字符,在这里就是"E"
String s1 = "IF(ISNUMBER(VALUE(LEFT(" + EnergyConstant.Excel.STAGE_LETTER + i + ",1)))," +
"CONCATENATE(\"_\"," + EnergyConstant.Excel.STAGE_LETTER + i + ")," + EnergyConstant.Excel.STAGE_LETTER + i + ")";
// 设置公式可读
sheet.setForceFormulaRecalculation(true);
// 设置单元格样式为公式
// EnergyConstant.Excel.HIDE_COL 隐藏列所在序号 我设置的是22
// EnergyConstant.Excel.HIDE_COL_LETTER 隐藏列对应字符 22对应字符为"W"
String s = "CONCATENATE(";
sheet.createRow(i - 1).createCell(EnergyConstant.Excel.HIDE_COL).setCellFormula(s1);
s += "$" + EnergyConstant.Excel.HIDE_COL_LETTER + "$" + i;
for (int j = EnergyConstant.Excel.STAGE_COL + 2; j < subCol; j++) {
s += ",$" + this.numberToLetter(j) + "$" + i;
}
s += ")";
s = "INDIRECT(" + s + ")";
DVConstraint energyItemConstraint = DVConstraint.createFormulaListConstraint(s);
CellRangeAddressList energyItemRegions = new CellRangeAddressList(i - 1, i - 1, subCol - 1, subCol - 1);
HSSFDataValidation dataValidate1 = new HSSFDataValidation(energyItemRegions, energyItemConstraint);
sheet.addValidationData(dataValidate1);
}
}

这里主要对公式进行说明,在EXCEL中对应公式为:=IF(ISNUMBER(VALUE(LEFT(E3,1))),CONCATENATE("_",E3),E3),POI对这些公式都是支持的,这个公式的作用就是,判断E3单元格zuo'b左边第一个字符是否是数字,如果是的话,当前单元格的数据为("_",E3)拼接的结果,如果不是数字开头,则为E3中的内容。当然也有更简单的做法,就是将隐藏列的公式,设置为CONCATENATE("_",E3),不管是否是数字开头都拼接下划线。但是笔者在业务中使用的是第一种做法。

问题3:

怎么用代码直接实现5级联动?

创建的数据结构如下:

@Component
public class DictDataService { @Resource
private EnergyClassifyService energyClassifyService; @Resource
private EnergyItemService energyItemService; @Reference
private ParkService parkService; @Reference
private ParkUnitService parkUnitService; @Reference
private ParkFloorService parkFloorService; @Reference
private ParkHouseService parkHouseService; /**
* 空间字典
*/
public static final String STAGE_BUILD = "stage_build";
public static final String STAGE_BUILD_UNIT = "stage_build_unit";
public static final String STAGE_BUILD_UNIT_GROUND = "stage_build_unit_ground";
public static final String STAGE_BUILD_UNIT_GROUND_HOUSE = "stage_build_unit_ground_house";
/**
* 空间名称id对应字典
*/
public static final String SPACE_NAME_ID = "space_name_id";
/**
* 主字典
*/
private Map<String, Object> dict = new HashMap(); public Object getDict(String condition) {
return dict.get(condition);
} public void setDict(String parkId) {
try { // 查询到所有的空间的信息
List<ParkHouse> parkHouses = parkHouseService.listParkHouses(parkHouse); // 分期跟楼栋的映射
Map<String, Set<String>> stage_build = new HashMap<>();
Map<String, Set<String>> stage_build_unit = new HashMap<>();
Map<String, Set<String>> stage_build_unit_ground = new HashMap<>();
Map<String, Set<String>> stage_build_unit_ground_house = new HashMap<>(parkHouses.size());
for (ParkHouse forExportSpace : parkHouses) {
String stageName = forExportSpace.getStageName();
String buildName = forExportSpace.getBuildName();
String unitNo = forExportSpace.getUnitNo() == null ? "" : forExportSpace.getUnitNo();
String groundNo = forExportSpace.getGroundNo() == null ? "" : forExportSpace.getGroundNo();
String houseName = forExportSpace.getHouseName();
this.createDict(stage_build, stageName, buildName);
this.createDict(stage_build_unit, stageName + buildName, unitNo);
this.createDict(stage_build_unit_ground, stageName + buildName + unitNo, groundNo);
this.createDict(stage_build_unit_ground_house, stageName + buildName + unitNo + groundNo, houseName); }
dict.put(STAGE_BUILD, stage_build);
dict.put(STAGE_BUILD_UNIT, stage_build_unit);
dict.put(STAGE_BUILD_UNIT_GROUND, stage_build_unit_ground);
dict.put(STAGE_BUILD_UNIT_GROUND_HOUSE, stage_build_unit_ground_house);
dict.put(SPACE_NAME_ID, ids);
} catch (Exception e) {
e.printStackTrace();
} } /**
* 创建从字典
*
* @param map
* @param name
*/
private void createDict(Map<String, Set<String>> map, String name, String name1) {
if (map.containsKey(name)) {
map.get(name).add(name1);
} else {
Set<String> names = new HashSet<>();
names.add(name1);
map.put(name, names);
}
}
}

大概就是将数据转换成:名称空间名称跟显示数据一一对应的结构,方便之后处理

细心的读者在看到解决数字级联后,我还拼了一段公式,实际就是为了实现多级级联,核心就是这部分代码

 String s = "CONCATENATE(";
sheet.createRow(i - 1).createCell(EnergyConstant.Excel.HIDE_COL).setCellFormula(s1);
s += "$" + EnergyConstant.Excel.HIDE_COL_LETTER + "$" + i;
for (int j = EnergyConstant.Excel.STAGE_COL + 2; j < subCol; j++) {
s += ",$" + this.numberToLetter(j) + "$" + i;
}
s += ")";
s = "INDIRECT(" + s + ")";
DVConstraint energyItemConstraint = DVConstraint.createFormulaListConstraint(s);
CellRangeAddressList energyItemRegions = new CellRangeAddressList(i - 1, i - 1, subCol - 1, subCol - 1);
HSSFDataValidation dataValidate1 = new HSSFDataValidation(energyItemRegions, energyItemConstraint);
sheet.addValidationData(dataValidate1);

这部分代码做的shi时间就是,通过从列所在的列数,跟第一列所在列数也就是分期所在列相差了几列,判断需要实现几级级联,通过indirect函数跳到指定名称空间。这部分主要麻烦在字符串的拼接。


有什么不对的希望大家多多指正,共同进步!

POI问题总结,关于数字级联及多级级联(三级以上)的更多相关文章

  1. 利用jquery.chained.remote实现多级级联

    多级级联一直是前端比较烦人的一个功能,本次用jquery的插件,chained.remote实现多级级联. 应用场景:至少有二个下拉框,下拉框的个数不定. 应用步骤: 1.引入js文件,当然这个插件需 ...

  2. 一款多功能的移动端滚动选择器,支持单选到多选、支持多级级联、提供自定义回调函数、提供update函数二次渲染、重定位函数、兼容pc端拖拽等等..

    https://github.com/onlyhom/mobileSelect.js/blob/master/docs/README-CN.md mobileSelect.js 一款多功能的移动端滚动 ...

  3. mybatis 多级级联(多级嵌套)

    注:笔者这里的嵌套可以用词有点欠缺,忘见谅 需求:用一个查询接口查出其结果集,这里就用伪代码标识要返回前端的类与类之间的关系. class 顶层{ String otherValue; LinkedL ...

  4. 自增特性,外键,级联更新与级联删除,表间关系,SELECT用法,GROUP BY

    自增特性 自动增长的作用: 问题:为数据表设置主键约束后,每次插入记录时,如果插入的值已经存在,会插入失败. 如何解决:为主键生成自动增长的值. 自动增长的语法: 字段名 数据类型 AUTO_INCR ...

  5. [NHibernate]一对多关系(级联删除,级联添加)

    目录 写在前面 文档与系列文章 一对多关系 一个例子 级联删除 级联保存 总结 写在前面 在前面的文章中,我们只使用了一个Customer类进行举例,而在客户.订单.产品中它们的关系,咱们并没有涉及, ...

  6. oracle系列--级联删除和级联更新

    必须声明:此博客转载于Oracle外键级联删除和级联更新http://www.2cto.com/database/201507/417496.html 鉴于此前收藏的精彩博客无料被删除了,很是痛心,所 ...

  7. EBS採购模块中的级联接收和级联接收事务

    EBS採购模块中的级联接收和级联接收事务 (版权声明,本人原创或者翻译的文章如需转载,如转载用于个人学习.请注明出处:否则请与本人联系.违者必究) 级联接收和级联接收事务 级联功能对来自于同一个供应商 ...

  8. sqlserver 级联删除、级联更新

    增加外键约束时,设置级联更新.级联删除:[ ON DELETE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ][ ON UPDATE { NO A ...

  9. 【Python】Django数据模型、级联删除、级联更新、ER图导出等

    在本文中,我们将向读者详细介绍如何在更新和删除父表数据的同时,触发有关子表数据的级联更新和删除操作.您将看到当使用InnoDB表的时候,借助于外键约束就可以轻松搞定这一过程. 一.利用外键约束更新并删 ...

随机推荐

  1. push和appendChild的区别

    概述:绑定事件(push和appendChild用法相似:但是一个是控制数组,一个是控制元素节点)用法:1.数组1的更改后的长度 = 数组1.push();//用来控制数组,在数组最后面插入项,返回数 ...

  2. AJ学IOS(35)UI之Quartz2D仿真支付宝手势解锁_代理获得密码。

    AJ分享,必须精品 效果: 实现步骤 其实这个实现起来不难 第一步先放好主要的UI,一张背景图和一个View 第二部就是把9个button放到view中,设置好按钮的默认和选中图片. 注意:创建时候的 ...

  3. Redis之ziplist源码分析

    一.ziplist简介 从上一篇分析我们知道quicklist的底层存储使用了ziplist(压缩列表),由于压缩列表本身也有不少内容,所以重新开了一篇,在正式源码之前,还是先看下ziplist的特点 ...

  4. 泛型方法或泛型类中的方法是内部调用、PInvoke 或是在 COM 导入类中定义的。

    泛型基类中引用Api函数定义时static extern,在子类中会提示: 未处理TypeLoadException 泛型方法或泛型类中的方法是内部调用.PInvoke 或是在 COM 导入类中定义的 ...

  5. stand up meeting for beta release plan 12/16/2015

    今天我们开会讨论一下beta版需要的feature,其中待定的feature是可选做的,如果有时间.其他都是必须实现的. 因为做插件的计划失败了,所以我们现在是pdf阅读器和取词查词加入生词本这两部分 ...

  6. G. 蚂蚁的镜像串

    单点时限: 1.0 sec 内存限制: 512 MB 一只聪明的蚂蚁在学习了回文串之后,一直觉得回文串不够优美,所以它决定自己定义一种新的字符串——镜像串 所谓镜像串,就是对一个字符串进行一整个完全的 ...

  7. JMeter分布式压测实战(2020年清明假期学习笔记)

    一.常用压力测试工具对比 简介:目前用的常用测试工具对比 1.loadrunner 性能稳定,压测结果及颗粒度大,可以自定义脚本进行压测,但是太过于重大,功能比较繁多. 2.Apache ab(单接口 ...

  8. python3_learn 实现文件夹内批量对图片重命名

    初衷 练习Python,提高动手能力. 珍藏的壁纸文件夹名命有点乱. 可以学习下一些基础的库 开始(.jpg,无筛选) First 首先找到OS库,寻找可以遍历文件名的.找到了OS.walk() os ...

  9. 如何用Github钩子做自动部署

    最近机缘巧合的购置了域名和服务器,不用实在是浪费,再加上一直没有属于自己的个人网站,所以打算用hexo在服务器上玩一下,这样也就不用再纠结用Github pages还是Gitee pages了.当然, ...

  10. Vue Cli 报错:You are using the runtime-only build of Vue where the template compiler is not availabl

    报错原因: 这里引用的是vue.runtime.esm.js,造成的不能正常运行. vue-cli 2.x 解决方法: 在webpack.base.conf.js配置文件中多加了一段代码,将 vue/ ...