JAVA POI excel 添加下拉字典的方式与案例 以及图文详解及个人理解

news2024/11/23 19:42:19

场景

原有的Excel 某一个 sheet 页中某些列需要添加指定的字典下拉,而这些字典的值又是确认的。

有两种思路
一、如果给定的下拉字典值是确定的而且关联原有列的位置也不会变,那么这些数据可以固定写死在代码中,也是最简单的一种场景

二、如果给定的字典值数量以及关联原有列的位置这些都是会改变的,那么就是第二种比较复杂的场景,变量增多计算增多,但这样的代码也有更强的兼容性,但理解需要一定时间。

这里我以第二种更加兼容的方式来讲解也是实战中我个人的遇到的场景,理解可能会花费一些时间,但一旦理解看起来就没有那么复杂了。

1. 首先需要理解 Excel 中人工添加下拉的动作是什么

例如我的第一个sheet第二个sheet 分别如下
在这里插入图片描述
如果我要在 sheet1 中的第二和第四列标题下分别添加 sheet2 中的两个字典,那么实际操作时其实是这样的

  1. 先选中原有的单元格
    在这里插入图片描述
  2. 然后点击添加数据验证
    在这里插入图片描述
  3. 在校验中指定为序列,并指定来源为Sheet2的三个框,来源的公式可以不自己手输,点击来源右侧的图标后可以通过光标拖拽指定需要的单元格,完成后点击确定
    在这里插入图片描述
  4. 效果如下
    在这里插入图片描述
    另一个字典也是如上操作;

代码中的实现步骤其实与实际操作的顺序是类似的,即:

  1. 首先要先将字典在自己指定的Sheet 中创建出来
  2. 然后每一个字典的公式的值需要我们自己计算出来,并通过自定义的集合将字典和公式记录下来
  3. 然后通过数据校验将公式的值关联到第一个 Sheet 的指定单元格列上即可

实际代码中操作示例

前提:需要先理解基本的Excel 操作代码,包括sheet 和 row 以及 cell 最基本操作。

  1. 这里我先设置自己的第一个用于存放所有数据的sheet 页名称为 sheet1
    在这里插入图片描述
    (setDefaultColumnWidth 为设置默认的列宽度,不需要可以不设置)

  2. 设置第二个sheet 作为字典sheet 我命名为templateDic在这里插入图片描述
    (setDefaultColumnWidth 为设置默认的列宽度,不需要可以不设置)

  3. 然后我们需要将自己需要的字典整理出来(根据自己的业务自行组装所有字典的数据集合)。

  4. 然后写入到这个字典sheet 中。由于向单元格(cell)中写入数据时需要先指定行,但行需要先创建出来才能继续,所以这里我的思路是取出字典值最多的一项,并在字典值最长的长度上加 3 (这里加3只是为了兼容第一行的标题行和额外两行作为容错行)做为要创建的行数。
    这里我们可以将所有的字典值转为 List< String> 的集合,然后依次写入
    我的代码大致如下:

    /**
     * 获取最大的字典长度,并在sheet中创建对应长度的 row
     * @param templateDicSheet 字典sheet
     * @param list 所有字典集合
     */
    private void getCreateRowsByDicList(Sheet templateDicSheet, List<MyExcelDicModel> list) {
        Integer maxLength = 1;
        // MyExcelDicModel 为我自己定义的excel字典类,里面包含了
        for (MyExcelDicModel myExcelDicModel : list) {
        	// SourceList 为当前字典的所有字典值 List<String>
            List<String> sourceList = myExcelDicModel.getSourceList();
            if (CollectionUtils.isNotEmpty(sourceList) && sourceList.size() >= maxLength) {
                maxLength = sourceList.size();
            }
        }
        // 额外加3 容错
        maxLength += 3;

        for (Integer index = 0; index < maxLength; index++) {
             templateDicSheet.createRow(index);
        }
    }

MyExcelDicModel 定义大致可以如下参考:

    /**
     * 字典所属属性中文名
     */
    private String chinese;

    /**
     * 字典所属属性英文名
     */
    private String english;

    /**
     * 所有下拉值
     */
    private List<String> sourceList;

    /**
     * 在Excel 中的列名
     */
    private String excelColumnName;

    /**
     * 字典在 Excel 中的范围起始行
     */
    private Integer startExcelNum;

    /**
     * 字典在 Excel 中的范围结束行
     */
    private Integer endExcelNum;

    /**
     * 回填数据的sheet页 字典所在列索引
     */
    private Integer metaSheetColumnIndex;

为了获取指定字典范围的公式中的值
在这里插入图片描述
其中 startExcelNum 由于在Excel 中的第一行我固定用于放置表头,所有从第二行开始,第二行在Excel 中的认为 2 所以固定给与 2 即可。
在这里插入图片描述
对应的 endExcelNum 为 1 + 字典的所有值 sourceList 的长度。

  1. 接下来将准备把字典的表头以及数据写入字典的sheet 中,同时上面的公式中 指定的Excel 列名是字母 A-Z 然后AA-AZ 以此类推向后加入的,这个列名同样需要我们计算出来并赋值给定义好的 MyExcelDicModel 中的 excelColumnName,即通过列索引 0 - 某一个数值计算出表头的英文字符是多少,用于最终公式的组装
        // 表头写入   allDicList 即为我所有的字典集合
        for (int i = 0; i < allDicList.size(); i++) {
            MyExcelDicModel myExcelDicModel = allDicList.get(i);
            // 表头名称
            String chinese = myExcelDicModel.getChinese();
            // 当前列在excel 中的列名    getExcelColIndex方法见下方方法
            governanceExcelDicModel.setExcelColumnName(this.getExcelColIndex(i));
            // 获取上面已经创建好的行
            Row row = templateDicSheet.getRow(0);
            // 在当前行的指定列索引 即指定单元格内写入
            row.createCell(i).setCellValue(chinese);
        }

通过索引计算英文列名

    /**
     * 将index转为excel的索引,如 A  AA  BA
     * 列名开始时从A-Z 再次出现时为AA AB - AZ 继续重复时为BA - BZ 以此类推
     * @param index 当前列的值
     * @return 当前列在Excel 中的列名
     */
    private String getExcelColIndex(int index) {
        String result = "";
        if (index / 26 != 0) {
            char x = (char) ('A' + (index / 26 - 1));
            result += x;
        }
        char l = (char) ('A' + (index % 26));
        result += l;
        return result;
    }

表头完成后开始写入所有字典的值,并同时通过 Excel POI 提供的名称管理器组装该字典对应的公式

        // 字典值写入单元格中
        for (int dicIndex = 0; dicIndex < allDicList.size(); dicIndex++) {
            // 当前字典
            MyExcelDicModel myExcelDicModel = allDicList.get(dicIndex);
            // 当前这一字典所有值
            List<String> sourceList = myExcelDicModel.getSourceList();
            for (int labelIndex = 0; labelIndex < sourceList.size(); labelIndex++) {
                Row row = templateDicSheet.getRow(labelIndex + 1);
                // 给到当前行当前列单元格的值
                row.createCell(dicIndex).setCellValue(sourceList.get(labelIndex));
            }

            // 给与字典多个命名空间范围  
            Name name = templateDicSheet.getWorkbook().createName();
            name.setNameName(myExcelDicModel.getEnglish());
            // excel 中公式需要的范围值
            String excelColumnName = myExcelDicModel.getExcelColumnName();
            Integer startExcelNum = myExcelDicModel.getStartExcelNum();
            Integer endExcelNum = myExcelDicModel.getEndExcelNum();
            // 字典下拉值在Excel 中的表达式 =sheet名称!$A$1:$A$10  前面英文字母标识在Excel 中的列名,后面为excel中的行号 两段加起来表示一个范围,最前方为sheet的名字 !$ 为固定写法
            name.setRefersToFormula("templateDic!$"+excelColumnName+"$"+startExcelNum+":"+"$"+excelColumnName+"$"+endExcelNum);
        }
        // 到此给Name 赋值完成即可 没有其他操作 后面即可直接引用,需要注意的是一定要在正确的sheet 对象下创建Name

(如果你的字典只有一列 那么就不用循环了 一遍写完 一个Name即可)

Name name = templateDicSheet.getWorkbook().createName();
这里的 Nameexcel的名称(命名)管理器 这里通过将字典的英文名赋值给这个命名对象,并将这个这个字典的公式通过 setRefersToFormula (指代公式)将公式挂在这个命名对象上,当我们后面再使用这个命名对象时 通过字典英文名称就可以自己关联到这个公式上。

到此字典的 Sheet 就完成了!

但我们定义的excel 中还需要补充一个属性,我们人工在操作Excel 的下拉时(见最上方人工操作)就是在两边的 sheet 创建完成后,先选中了需要给与下拉的所有单元格范围
在这里插入图片描述
这里我们一般的范围是某一列都需要,在每一行都是这一列,如果你的列是固定的那么直接指定固定的列所在索引即可,在我定义的类 MyExcelDicModel 中,指定这一列索引的值属性名为 metaSheetColumnIndex
如果你的列不是固定在这里的,那么需要再从第一个sheet 中计算得出列的索引并赋值。

  1. 将字典的公式关联到指定单元格的方式
    先使用要关联的 sheet 创建数据验证助手对象 XSSFDataValidationHelper,即类似于页面上如下步骤:
    在这里插入图片描述
    创建数据校验助手对象,通过主要填写数据的 sheet
XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper((XSSFSheet) sheet);

通过遍历我们之前自定义的

        for (MyExcelDicModel myExcelDicModel : dicSheetCreateList) {
            String english = myExcelDicModel.getEnglish();
            // 通过之前指定的字典英文名 关联之前定义的公式
            StringBuilder formula = new StringBuilder("=INDIRECT(\"" + english + "\"");
            formula.append(")");
            // 数据校验约束对象
            XSSFDataValidationConstraint dvConstraint =
                    new XSSFDataValidationConstraint(3, formula.toString());

            // 单元格范围指定
            Integer metaSheetColumnIndex = myExcelDicModel.getMetaSheetColumnIndex();
            // 四个入参分别为开始行,结束行,开始列,结束列 指定单元格范围 startRow,endRow 均为正整数表示开始行与结束行
            CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(startRow, endRow, metaSheetColumnIndex,
                    metaSheetColumnIndex);
            // 创建校验 将校验的单元格与约束绑定到一起创建对象
            DataValidation validation = dvHelper.createValidation(dvConstraint, cellRangeAddressList);
            // 将创建好的数据校验添加到主sheet 中即完成了校验和单元格的绑定,指定单元格此时将获得字典下拉
            sheet.addValidationData(validation);
        }

相当于这个过程并确定绑定
在这里插入图片描述

到此绑定字典下拉完成。

剩下的就是在主sheet 中写入要写入的数据了,均为正常的在单元格写入操作,不做多余描述 与写表头类似,在row 中 createCell 并 setCellValue 即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/589373.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

身份集权设施保护之Kerberos协议

一、Kerberos协议介绍 Kerberos是一种由MIT&#xff08;麻省理工大学&#xff09;提出的一种网络身份验证协议。它旨在通过使用密钥加密技术为客户端/服务器应用程序提供强身份验证。该认证过程的实现不依赖于主机操作系统的认证&#xff0c;无需基于主机地址的信任&#xff0…

Live800:新的消费趋势下,企业在线客服需哪些改变?

从2021到2023&#xff0c;新模式、新业态、新产业层出不穷&#xff0c;新兴习惯也不断涌现&#xff0c;我们见证了消费品牌的“新物种爆炸”&#xff0c;见证了各行业的线上迁移。 这一切催化消费市场持续更新&#xff0c;消费趋势演变的路径也发生了变化&#xff0c;从以前的…

“数字”厨电成新宠?“小米卷出光学拍摄“天花板”?|3C数码行业SMI社媒心智品牌榜

手机行业SMI社媒心智品牌榜核心解读 智能手机“乍暖还寒”&#xff0c;龙头品牌仍稳占消费者心智 比拼屏幕、赶超系统、迭代形态、拓展概念&#xff1f;眼花缭乱过后&#xff0c;产品精益求精&#xff0c;建立稳固的消费者认知&#xff0c;才是“保鲜”关键。在最新发布的数说…

趣味LFS实验部署

LFS文件准备 LFS项目官方网站&#xff1a;https://www.linuxfromscratch.org/ 查找宿主系统必须安装的软件包 https://www.linuxfromscratch.org/lfs/downloads/stable/LFS-BOOK-11.1-NOCHUNKS.html 安装依赖&#xff1a; #先来看看我此处的Yum仓库环境&#xff1a; CentOS-…

ArcGis系列-java调用GP分析

1,实现流程 创建GPServer,使用ArcgisPro添加GP工具运行,然后使用共享web服务发布运行成功的GP任务根据发布成功的GPServer发布地址&#xff0c;解析出GP服务的输入参数和输出参数前端输入gp服务需要的参数&#xff0c;发送给后端来异步提交后端提交后创建轮询任务等待执行结果…

3D知识入门

3D场景必备&#xff1a;scene, renderer, light, camera, model 一个基本代码: <script src"https://cdn.bootcdn.net/ajax/libs/three.js/r127/three.min.js"></script>var scene new THREE.Scene();var camera new THREE.PerspectiveCamera(75,windo…

【EKS】基于Amazon EKS搭建kubernetes集群

文章目录 前言 | 亚马逊云科技 re:Invent前沿资讯一、介绍篇&#x1f3a8;什么是AWS 云计算什么是Amazon EKS 二、部署篇&#x1f528;1、创建集群VPC2、创建集群子网3、创建IGW网关4、创建路由表与子网绑定5、EKS集群创建6、创建kubeconfig配置文件7、添加计算节点组8、查看EK…

IC卡水表大多都用在什么项目上?有什么功能特点吗?

IC卡水表是一种先进的计量仪表&#xff0c;广泛应用于许多项目&#xff0c;其功能特点使其在许多领域得到广泛应用。 首先&#xff0c;IC卡水表可以应用于自来水的计量&#xff0c;它可以高精度地测量水的流量&#xff0c;提供给用户准确的用水量信息&#xff0c;从而有助于用户…

分片架构,Redis Cluster 分析

分片架构解决的问题 通过堆机器&#xff0c;提升读写性能&#xff0c;与存储性能 分片架构设计要点 分片规则 选择Cardinality大的作为分片键&#xff0c;尽可能保证数据分布均匀 常见分片键&#xff1a; 基于主键&#xff08;业务型数据&#xff09;&#xff0c;基于时间…

JavaScript高级四、高阶技巧

零、文章目录 JavaScript高级四、高阶技巧 1、深浅拷贝 首先浅拷贝和深拷贝只针对引用类型 &#xff08;1&#xff09;浅拷贝 浅拷贝&#xff1a;拷贝对象的属性的值&#xff08;简单类型存的值就是值本身&#xff0c;引用类型存的值是对象的堆地址&#xff09;&#xff0c…

windows里怎么杀死一个进程?

我们可以使用 taskkill 命令&#xff0c;可以使用该工具按照进程 ID (PID) 或映像名称终止任务。 显示帮助消息&#xff1a; taskkill /?参数列表&#xff1a; /S&#xff1a;system&#xff1a;指定要连接的远程系统。/U&#xff1a;[domain\]user&#xff1a;指定应该在哪…

【ESP-01S / ESP8266 AT指令连接阿里云物联网平台】

ESP-01S / ESP8266 AT指令连接阿里云物联网平台 阿里云物联网平台新建设备获取AT参数 AT指令介绍连接阿里云AT指令介绍MQTT固件固件下载硬件连接固件烧录 串口助手调试硬件连接测试指令 AT_Command移植总结问题排查 源码获取 关注星标公众号&#xff0c;不错过精彩内容 作者 | …

【简单实用框架】【十大排序算法直接调用】【可移植】

☀️博客主页&#xff1a;CSDN博客主页&#x1f4a8;本文由 萌萌的小木屋 原创&#xff0c;首发于 CSDN&#x1f4a2;&#x1f525;学习专栏推荐&#xff1a;面试汇总❗️游戏框架专栏推荐&#xff1a;游戏实用框架专栏⛅️点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd;&#…

JeecgBoot企业级开发中实现自定义导出EXCEL的前端表格字段功能

文章目录 如何在后端实现导出前端列表字段到Excel功能需求前端的实现1. 提供一个导出的点击函数2.引入组件中的userMethod3.tableProps中导出中添加对应的查询参数4. 编写导出函数 后端逻辑的实现1.Controller层2.创建Modal类3.Sevice层 检验成果总结 如何在后端实现导出前端列…

【Android Gradle 插件】更新依赖方式,同时解决github三方库引用无法使用问题

首先看一下完整的 settings.gradle 依赖介绍 /* pluginManagement 脚本块,用于配置Gradle插件的Maven仓库,配置的是构建过程中,使用的仓库 ; pluginManagement 脚本块中的 repositories 配置 , 对应之前的 buildscript 中的 repositories 配置 ; */ pluginManagement {reposit…

技术分享 | 一文了解 MySQL Optimizer Trace 的神奇功效

作者&#xff1a;Mutlis CSDN & 阿里云 & 知乎 等平台优质作者&#xff0c;擅长Oracle & MySQL等主流数据库系统的维护和管理等 本文来源&#xff1a;原创投稿 前言 对于 MySQL 5.6 以及之前的版本来说&#xff0c;查询优化器就像是一个黑盒子一样&#xff0c;…

迪赛智慧数——柱状图(基本柱状图):购买雪糕考虑的因素

效果图 冰淇淋季节来袭&#xff0c;因其细腻凉爽的口感和浓郁的口味被广大消费者所钟爱&#xff0c;近年来已经从一款传统的解暑冷冻饮品转变为一种原料丰富、口味多元、追求健康、愉悦和高品质生活方式的休闲食品。据数据显示&#xff0c;82.2&#xff05;女性、82.3%男性消费…

chatgpt赋能python:Python中乘方的介绍

Python中乘方的介绍 在Python中&#xff0c;乘方运算指数运算&#xff0c;常用符号为“”&#xff08;例如2的3次方为23&#xff09;。使用乘方运算可以快速地进行数值计算&#xff0c;尤其是在科学和工程领域中。 为什么要使用乘方运算&#xff1f; 乘方运算主要用于处理大…

NeRF算法

Instant-ngp Instant-ngp简单介绍 Instant-ngp论文链接 英伟达实现的github链接 taichi实现Instant-ngp taichi实现的github链接 渲染 采用体素渲染方法&#xff0c;从相机光线出发&#xff0c;逐步采样3D场景中的三维坐标点的颜色&#xff0c;即可渲染出3D画面。如果直接将3…

进阶神册,Redis+Nginx+设计模式+Spring全家桶+Dubbo核心技术笔记

最近花了很长的时间去搜罗Java核心技术好文&#xff0c;我把每个Java核心技术的优选文章都整理成了一个又一个的文档。昨天也是终于全部整理好了&#xff0c;今天就把这些东西分享给老铁们&#xff0c;也能为老铁们省去不少麻烦&#xff0c;想学什么技能了&#xff0c;遇到哪方…