目录

最近公司业务需要用到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. 【python实现卷积神经网络】池化层实现

    代码来源:https://github.com/eriklindernoren/ML-From-Scratch 卷积神经网络中卷积层Conv2D(带stride.padding)的具体实现:https ...

  2. 基于 Njmon + InfluxDB + Grafana 实现性能指标实时可视监控

    引言 最近逛 nmon 官网时,发现了一个新工具 njmon,功能与 nmon 类似,但输出为 JSON 格式,可以用于服务器性能统计. 可以使用 njmon 来向 InfluxDB 存储服务器性能统 ...

  3. D. Minimax Problem Codeforces 1288D binary_search+二进制

    题目大意:n*m的矩阵中,找到两行数,可以形成两个一维数组,数组1的位置i和数组2的位置i去最大构成新数组b的元素b[i],最终目的要使数组b中最小的数尽可能的大 题解: m的范围是(1,8),比较小 ...

  4. Linux命令:chown

    说明: 将指定文件的拥有者改为指定的用户或组. 语法: chown [-cfhvR] [--help] [--version] user[:group] file... 参数: user : 新的文件 ...

  5. Java SE —— 专栏总集篇

    前言: Java 语言,是相对于其他语言而言,门槛低,而且功能还强大的一门编程语言,本人十分看好这一门语言,但是,它也是有深度的,看过本人的<数据结构与算法>专栏的同学们有福了,因为本人在 ...

  6. thinkphp 5 一些常见问题

    ##  请求缓存 request_cache        

  7. VHD VHDX 区别

    A Virtual hard disk is saved either with VHD or VHDX file extension. VHD is the older while VHDX is ...

  8. java stream中Collectors的用法

    目录 简介 Collectors.toList() Collectors.toSet() Collectors.toCollection() Collectors.toMap() Collectors ...

  9. docker 部署FastDFS

    教程:https://blog.csdn.net/fangchao2011/article/details/103202591 教程:https://www.jianshu.com/p/3f80cba ...

  10. SSH公钥登录和RSA非对称加密

    SSH登录方式 接触过Linux服务器的同学肯定用过SSH协议登录系统,通常SSH协议都有两种登录方式:密码口令登录和公钥登陆. 一.密码口令(类似于账号密码登录) 1.客户端连接服务器,服务器把公钥 ...