工作日志,Excel导入树结构数据
1. 前言
最近做了一个比较有趣的需求。需要把树结构的目录通过Excel的方式导入到系统中,并且该目录层级可以是多级且不确定的。这可能是一个常见又不太常见的需求,一般目录都是在界面上操作创建,或者是系统初始化生成。很少在系统使用一段时间后还有导入新目录的需求。
2. 需求分析
2.1 需求难点
这个需求最大的难点就是如何找到父级节点。包括
1)如何让一个Excel表格实现不确定目录层级功能?
2)如何让子个节点能正确找到其父级节点?
3)如何在遍历完一个分枝后,还能从根节点继续遍历另外一个分枝?
2.2 解决难点
1)我们可以将目录层级作为用户输入项,由用户决定该数据处于第几层目录。解决目录层级不确定的需求。
2)我们可以用树节点深度遍历的思想,遍历一个个节点,使其找到其父节点。
3)我们同样可以用深度遍历的思想再结合先进后出操作,重新找回之前的根节点。
2.3 表格设计
我们可以用Level作为目录所在层级,一级目录的Level就是1,同理N级目录的Level就是N。且数据从上至下可以形成一个完整树分枝。
表格设计如下:
分类名称 | 级别Level | 其他字段 |
---|---|---|
A栋 | 1 | |
A栋-1楼 | 2 | |
B栋 | 1 | |
B栋-1楼 | 2 | |
B栋-1楼-A区 | 3 | |
B栋-2楼 | 2 | |
B栋-2楼-A区 | 3 | |
B栋-2楼-B区 | 3 |
从表格中,我们应该可以得出以下结论:
1)A栋和B栋属于一级目录
2)A栋有一个子目录,A栋-1楼
3)B栋有两个子目录,分别是:B栋-1楼、B栋-2楼
4)B栋-1楼有一个子目录,B栋-1楼-A区
5)B栋-2楼有两个子目录,分别是:B栋-2楼-A区、B栋-2楼-B区
3. 功能实现
我们对需求做了简单的分析,现在就用代码来实现。从易到难,从一个分枝再到多个分枝来实现。
3.1 一个分枝
一个分枝的Level排序应该是:1-2-3-N
这种情况是最简单的,孤零零的一条直线。其父节点就是当前节点的上一个元素。
伪代码如下:
var categoryPathStack = mutableListOf<EquipmentCategory>()
for (i in sheet.firstRowNum..sheet.lastRowNum) {
val categoryName = row.getCell(0).stringCellValue
val categoryLevel = row.getCell(1).stringCellValue.toInt()
var parentCategory: EquipmentCategory? = null
if (categoryLevel > 1) {
parentCategory = categoryPathStack.last()
}
// todo save or update
categoryPathStack.add(equipmentCategory)
}
3.2 一个分枝多个树叶
一个分支多个树叶的Level排序应该是:1-2-3-3-3-3
这种情况稍微复杂了一点,如果只是获取当前节点的上一个元素是很难找到其父级节点的。我们需要把同一层的兄弟节点都剔除掉。
伪代码如下:
var categoryPathStack = mutableListOf<EquipmentCategory>()
for (i in sheet.firstRowNum..sheet.lastRowNum) {
val categoryName = row.getCell(0).stringCellValue
val categoryLevel = row.getCell(1).stringCellValue.toInt()
var parentCategory: EquipmentCategory? = null
// 将集合中大于或等于当前层级的数据剔除掉
while (categoryPathStack.isNotEmpty() && categoryPathStack.last().level >= categoryLevel) {
categoryPathStack = categoryPathStack.subList(0, categoryPathStack.size-1).toMutableList()
}
if (categoryLevel > 1) {
parentCategory = categoryPathStack.last()
}
// todo save or update
categoryPathStack.add(equipmentCategory)
}
3.3 多个分枝多个树叶
多个分支多个树叶的Level排序应该是:1-2-3-3-3-3-2-3-1-2-3
这种场景依然可以用一个分支多个树叶的代码实现,而后面来的1就像一个分割线,将前面先进来的数据隔离开。
4. 代码事例
4.1 目录实体结构
目录实体添加临时字段level方便逻辑判断。字段code是方便后期通过code作为StartingWith的查询条件,从而减少递归查询所有子级目录带来的性能损耗。code的生成规则是:父节点code拼接当前节点id,
class Category: AuditModel() {
var name: String? = null
var description: String? = null
var isLeaf: Boolean = true
var parentId: String? = null
@Column(columnDefinition = "TEXT")
var code: String? = null
@Transient
var level: Int = 0
}
4.2 Excel导入代码
以下只是删减过后的代码,具体业务场景会有具体的逻辑代码。
@Transactional
fun importCategoryData(file: MultipartFile, request: HttpServletRequest): OperateStatus {
// fileUtil.getExcelWorkbook 只是简单封装的读取excel方法
val work = fileUtil.getExcelWorkbook(file.inputStream, file.originalFilename!!)
// todo 清空旧数据
val sheet: Sheet = work.getSheetAt(0)
var categoryPathStack = mutableListOf<Category>()
for (i in sheet.firstRowNum..sheet.lastRowNum) {
val row = sheet.getRow(i)
if (row == null || row.rowNum == 0) {
continue
}
// todo 数据校验
val categoryName = row.getCell(0).stringCellValue
val categoryLevel = row.getCell(1).stringCellValue.toInt()
var parentCategory: Category? = null
while (categoryPathStack.isNotEmpty() && categoryPathStack.last().level >= categoryLevel) {
categoryPathStack = categoryPathStack.subList(0, categoryPathStack.size-1).toMutableList()
}
if (categoryLevel > 1) {
parentCategory = categoryPathStack.last()
}
var category = Category()
category.name = categoryName
category.parentId = parentCategory?.id
category = categoryRepository.save(category)
if (parentCategory == null) {
category.code = category.id
} else {
category.code = "${parentCategory.code}-${category.id}"
category.isLeaf = true
parentCategory.isLeaf = false
categoryRepository.save(parentCategory)
}
categoryRepository.save(category)
category.level = categoryLevel
categoryPathStack.add(category)
}
work.close()
return OperateStatus("Import Category Success")
}
文章到这里就结束了,感谢观看。ITDragon博客
工作日志,Excel导入树结构数据的更多相关文章
- [办公自动化] 再读《让EXCEL飞》(从excel导入access数据时,union联合查询,数据源中没有包含可见的表格)
一年多以前就买了@Mrexcel的<让excel飞>这本书.整体思路是利用access结合excel,大幅度提高数据分析效率. 最近又拿出来看了看.第十五章,比高级筛选更“高级”,P241 ...
- PHP 清除 Excel 导入的数据空格
处理excel中的数据时,遇到了页面中显示为空格,审查元素时却显示为换行,使用replace函数也不管用,反正就是不知道是什么东西,看起来像空格 中文空格这里面有好几种:没有简单的解决问题的方式,比如 ...
- Talend 从Excel导入Saleforce数据(二) TMAP是精髓
TMap LookUp 经过测试的结果: ------------------------------------------ LookUp最好从CSV读数据,这样是最快了(20万记录1s).从Sal ...
- Talend 从Excel导入Saleforce数据(一) 直接从salesforce lookup 性能的噩梦
速度的瓶颈是在查询Sales force是否有该电话号码的联系人资料. TMap属性的 lookup Model, 如果用Load Once, 则会把SaleForce的contact全部load下来 ...
- excel导入mysql数据
excel加载mysql数据 1.第一步,选择从mysql导入数据 2.单击会出现弹框: 3.可能有的同学的,这里缺少插件,例如: 4.去下载 这个 插件安装即可.https://dev.mysql. ...
- 将Excel导入到数据中
常用的方式的有两种: 1. 通过 Microsoft.Jet.OLEDB.4.0 或 Microsoft.ACE.OLEDB.12.0 Microsoft.ACE.OLEDB.12.0 需要安装 A ...
- JeeSite中Excel导入导出
在各种管理系统中,数据的导入导出是经常用到的功能,通常导入导出以Excel.CSV格式居多.如果是学习的过程中,最好是自己实现数据导入与导出的功能,然而在项目中,还是调用现成的功能比较好.近期一直使用 ...
- java利用jxl实现Excel导入功能
本次项目实践基于Spring+SpringMvc+MyBatis框架,简单实现了Excel模板导出.和Excel批量导入的功能.实现过程如下:. 1.maven导入所需jar包 <depende ...
- 将datagrid中数据导出到excel中 -------<<工作日志2014-6-6>>
前台datagrid数据绑定 #region 导出到excel中 /// <summary> /// 2014-6-6 /// </summary> / ...
随机推荐
- date成字符串
//获取当前时间 Date date=new Date(); System.out.println("当前date: "+date); //将时间转化成yyyy-MM-dd格式的字 ...
- maven笔记--持续更新
笔记: 在创建maven项目的时候,如果用到servlet的时候,需要导入包,这时候,需要导入本地仓库的jar包,即依赖包.语法如下 <dependency> <groupId> ...
- centos 7上openJdk 安装
为什么不安装Oracle版本 oracle jdk 现在下载太恶心了会被登陆拦截.于是就安装openjdk. 步骤 下载 yum -y install java-1.8.0-openjdk java- ...
- npm注册源的配置
npm注册源的更换 在墙内久了,难免会碰到撞墙的时候,所幸国内也有众多 NPM 镜像可供选择,在大多数情况下我们可以使用国内的源(比如 淘宝 NPM 镜像)去替换官方的源以加快下载包的速度.不过呢,我 ...
- uWSGI, send_file and Python 3.5
当你的Flask项目通过Nginx+uWSGI成功部署的时候,当你很高兴你Flask里面的接口成功跑通的时候,你会发现真高兴!好牛逼! 然后当你写了其他几个接口的时候,在启动uWSGI服务的时候,死活 ...
- 遍历tree
1.解决方法 filterData (arr) { var newArr = [] arr.map((item) => { var childrenArr if (item.children ! ...
- vue+webpack工程环境搭建
使用Vue-cli脚手架(属于vue全家桶)快速构建一个项目: [1]首先需要安装好node.js; [2]安装webpack,指令$npm install -g webpack; //如果之前有安装 ...
- getBoundingClientRect的实用场景
在用vue开发项目时候,遇到一个问题,首页有代办列表,是固定定位,滚动时候需要监听距离页面顶部的距离,如果很接近顶部则将代办列表展示,首页隐藏,如果再网上翻动则又回到首页. 因为是是fixed定位,所 ...
- 【猫狗数据集】利用tensorboard可视化训练和测试过程
数据集下载地址: 链接:https://pan.baidu.com/s/1l1AnBgkAAEhh0vI5_loWKw提取码:2xq4 创建数据集:https://www.cnblogs.com/xi ...
- Django Queryset增加manager
**#定义一个新的过滤规则,这里是过滤状态为发布的帖子** **class PublishedManager(models.Manager):** **def get_queryset( ...