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

场景

原有的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.mfbz.cn/a/24213.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

北邮22信通:利用BF算法解决实际问题:题目实战(超详解)设计函数 char *locatesubstr(char *str1,char *str2)

北邮22信通一枚~ 跟随课程进度每周更新数据结构与算法的代码和文章 持续关注作者 解锁更多邮苑信通专属代码~ 获取更多文章 请访问专栏~ 北邮22信通_青山如墨雨如画的博客-CSDN博客 目录 题干描述 解析 1.string库函数 2.使用KMP算法思想 注解1 注解2 注解3 题…

学懂缓存雪崩,缓存击穿,缓存穿透仅需一篇,基于Redis讲解

在了解缓存雪崩、击穿、穿透这三个问题前&#xff0c;我们需要知道为什么我们需要缓存。在了解这三个问题后&#xff0c;我们也必须知道使用Redis时&#xff0c;如何解决这些问题。 所以我将按照"为什么我们需要缓存"、"什么是缓存雪崩、击穿、穿透"、&qu…

​字创未来 方正字库第十二届“方正奖”设计大赛正式来袭

传承汉字文化精髓&#xff0c;方正字库在字体行业不断探索深耕。方正字库一直致力于弘扬中华汉字文化&#xff0c;不断促进行业字体设计创新发展。于2001年在行业最艰难的时候&#xff0c;怀揣着对字体设计未来的美好向往&#xff0c;首届“北大方正奖”印刷字体设计大赛&#…

家政服务预约APP的系统设计与实现

摘 要&#xff1a;针对家政行业蓬勃发展&#xff0c;老套的家政服务方式已经跟不上互联网时代的步伐这个问题。基于Android移动平台的分析和设计过程、C/S模式、Eclipse平台&#xff0c;采用Java语言进行开发设计&#xff0c;设计了基于MVC架构的实现方案。安卓客户端与服务器…

Flume系列:Flume通道拓扑结构

目录 Apache Hadoop生态-目录汇总-持续更新 1: 基础架构 2&#xff1a;简单串联 3&#xff1a;复制(Replicating)和多路复用(Multiplexing) 4&#xff1a;负载均衡和故障转移 5&#xff1a;聚合 Apache Hadoop生态-目录汇总-持续更新 系统环境&#xff1a;centos7 Java环境…

IDEA 创建 Springmvc 项目

一、概述 在18年的时候就开始接触 SpringBoot &#xff0c;然后就一直在使用它。众所周知 SpringBoot 内嵌 Tomcat&#xff0c;后续再也没有单独新建过Web 项目。作为IDEA 的用户&#xff0c;总想要用它来建一个Web 项目自己跑一跑&#xff0c;但建项目不是我最终目的~~ &…

好用的自动化框架-Allure

概述 报告主要包含总览、类别、测试套件、图表、时间刻度、功能、包等7大部分&#xff0c;支持自定义诸多信息&#xff0c;包括附件添加、缺陷链接、案例链接、测试步骤、Epic、Feature、Story、Title、案例级别等&#xff0c;相当强大。 allure与pytest的结合使用可以呈现完…

ProtoBuf 语法(一)

系列文章 ProtoBuf 语法&#xff08;二&#xff09; ProtoBuf 语法&#xff08;三&#xff09; 文章目录 前言一、字段规则二、消息类型的定义与使用2.1 定义2.2 使用 三、enum 类型3.1 定义规则3.2 注意事项 四、any 类型4.1 类型说明4.2 类型使用 五、oneof 类型六、map 类型…

【Vue】二:Vue核心处理---计算属性 监视属性

文章目录 1.计算属性示例2. 监听属性3.补充 1.计算属性示例 实际上计算属性与methods中定义方法基本上没有什么区别&#xff0c;只是计算属性基于响应式依赖缓存&#xff0c;只要数据没有发生改变&#xff0c;计算属性从缓存中取值&#xff0c;只有当数据发送改变&#xff0c;才…

安卓中集成高德地图

安卓中集成高德地图 1.高德地图的优缺点 高德开放平台 | 高德地图API 高德地图优点&#xff1a; 1、领先的地图渲染技术&#xff1a;性能提升10倍&#xff0c;所占空间降低80&#xff05;&#xff0c;比传统地图软件节省流量超过90&#xff05; 2、专业在线导航功能&#x…

idea模板配置

idea版本&#xff1a;2023.1 未设置模板的idea&#xff0c;新建类会自动生成类注释 格式如下&#xff1a; /*** author user* date 2023/5/20 0020 14:25*/ public class User {} 其中&#xff0c;user为当前用户名 这里&#xff0c;如果希望将类注释改写成如下&#xff0…

档案馆空气质量在线3D监控系统温湿度方案

档案馆库房八防温湿度空气质量一体化解决方案 档案库房是档案事业发展的基石&#xff0c;其主要任务是集中保管国家机构及个人等在各种形式下形成的具有一定价值和保存价值的各种载体档案&#xff0c;主要包括文书档案、科技档案、会计档案、人事档案、实物档案等。随着我国经济…

X2000 freeRTOS usb_bulk通信

例程 官方例程..\freertos\example\usb\device\gadget_generic_bulk.c&#xff0c;代码如下&#xff1a; #include <common.h> #include <usb/gadget_bulk.h> #include <os.h>static const struct gadget_id bulk_id {.vendor_id 0x1CBE,.product_id 0x…

【数据生成】——Semantic Image Synthesis via Diffusion Models语义分割数据集生成论文浅读

语义分割&#xff0c;数据生成 摘要 Denoising Diffusion Probabilistic Models (DDPMs) 在各种图像生成任务中取得了显著的成功&#xff0c;相比之下&#xff0c;生成对抗网络 (GANs) 的表现不尽如人意。最近的语义图像合成工作主要遵循事实上的基于 GAN 的方法&#xff0c;…

直流电机 PID 控制系统仿真研究(Simulink实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

python+vue高校网上跳蚤二手市场的设计与实现

商品信息是卖家供应用户必不可少的一个部分。在跳蚤市场发展的整个过程中&#xff0c;商品担负着最重要的角色。为满足如今日益复杂的管理需求&#xff0c;各类管理系统程序也在不断改进。本课题所设计的普通高校网上跳蚤市场&#xff0c;使用Django框架&#xff0c;Python语言…

【信号变化检测】使用新颖的短时间条件局部峰值速率特征进行信号变化/事件/异常检测(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

网络安全复习

目录 低层协议安全性 IP协议 ARP协议 TCP协议 NAT协议 单钥加密体制 DES算法 课后习题 双钥加密体制 &#x1f407;怎么说 欧几里得算法求逆 RSA算法 椭圆曲线加密 Diffie- Hellman 密钥交换算法 ElGamal签名机制 Schnorr签名机制 DSS签名算法——DSA 低层协…

HTML+CSS实训——Day02——仿一个网易云音乐的登陆界面

仓库链接:https://github.com/MengFanjun020906/HTML_SX 前言 今天要继续完成我们的音乐软件了&#xff0c;昨天写完了封面&#xff0c;今天该完成开屏广告和登陆界面了。 登陆界面代码 <!DOCTYPE html> <html lang"en"> <head><meta charse…

【P35】JMeter 包含控制器(Include Controller)

文章目录 一、包含控制器&#xff08;Include Controller&#xff09;参数说明二、准备工作三、测试计划设计3.1、保存测试片段3.2、使用测试片段 一、包含控制器&#xff08;Include Controller&#xff09;参数说明 可以将测试计划的某一部分提取为公用逻辑&#xff0c;这样…
最新文章