Java - EasyExcel结合VBA实现Excel导出下拉多选框与单选框

article/2025/9/17 15:53:47

需求:导出一个带有单选下拉框与多选下拉框的excel模板

思路:1.使用VBA脚本设置带有多选框的模板2.使用EasyExcel给字段填充单选下拉框数据源

一、创建带有多选框宏的excel模板

*.xls:不管有没有宏程序的话都是xls文件 
*.xlsx文件:为无法使用宏的文件类型。
*.xlsm文件:基于XML且启用宏的Excel 2007工作簿。

*.xls是2003版本下的文件 ,不管有没有宏程序的话都是xls文件 。从2007开始做了区分,XLSM文件和XLSX文件都是excel2007及其以后 的文件,但前者是含有宏启用,Excel中默认情况下不自动启用宏,默认是XLSX。VBA中,如果不想保存代码,可以保存为xlsx,即可自动删除其中VBA代码,反之则保存为XLSM文件。

1.先创建一个*.xlsm文件,填入标题字段

我们需要在表格的__性别___(第三列)处设置__单选框__,值为:男/女
在__年级__(第四列)处设置__多选框__,值为数据库查询出的年级数据
在这里插入图片描述在这里插入图片描述
2.设置vba脚本
视图 ——》 宏 ——》 查看宏 ——》 创建 —— 》 选中启用宏的sheet对象 ——》 查看代码

在这里插入图片描述
此处给出脚本宏:

Sub Worksheet_Change(ByVal Target As Range)
'让数据有效性选择 可以多选,不可重复
Dim rngDV As Range
Dim oldVal As StringDim newVal As String
If Target.Count > 1 Then GoTo exitHandlerOn Error Resume Next
Set rngDV = Cells.SpecialCells(xlCellTypeAllValidation)
On Error GoTo exitHandlerIf rngDV Is Nothing Then GoTo exitHandlerIf Intersect(Target, rngDV) Is Nothing Then
'do nothingElse
Application.EnableEvents = False
newVal = Target.Value
If Target.Column = 3 Or Target.Column = 4 Then  '数字是你想要多选的列是多少,多个用or连接。 【注意:仅写数字是不行的,需要加上Target.Column = 数字】
Application.Undo
oldVal = Target.Value
Target.Value = newVal
If oldVal = "" Then
Else
If newVal = "" Then
Else '去除重复的字段If InStr(1, oldVal, newVal) <> 0 ThenIf InStr(1, oldVal, newVal) + Len(newVal) - 1 = Len(oldVal) Then '最后一个选项重复Target.Value = Left(oldVal, Len(oldVal) - Len(newVal) - 1)ElseTarget.Value = Replace(oldVal, newVal & ",", "") '不是最后一个选项重复的时候处理逗号End IfElse '不是重复选项就视同增加选项
Target.Value = oldVal _
& "," & newVal '可以是任意符号隔开
End If
End If
End If
End If
End If
exitHandler:
Application.EnableEvents = True
End Sub

到此,含有启用多选框宏的excel模板就完成了。

二、EasyExcel实现单选下拉框数据源填充

使用自定义注解,标识excel对象类中需要使用下拉数据集的的字段。下拉数据集数据可以为__固定__的,或是程序中__动态获取__的。

1.创建自定义注解 @DropDownSetField

/*** 标记导出excel的下拉数据集*/@Documented
// 作用在字段上
@Target(ElementType.FIELD)
// 运行时有效
@Retention(RetentionPolicy.RUNTIME)
public @interface DropDownSetField {// 固定下拉内容String[] source() default {};// 动态下拉内容Class[] sourceClass() default {};
}

2.excel对象类中标识需要下拉数据集的字段


@Data
public class StudentExcelExportResult{@ExcelProperty(value = "姓名")private String name;@ExcelProperty(value = "学号")private String code;@ExcelProperty(value = "性别")@DropDownSetField(source = {"男","女"})		// 固定数据源private String gender;@ExcelProperty(value = "年级")@DropDownSetField(sourceClass = DropDownSetImpl.class)		// 动态数据源private String gradeList;@ExcelProperty(value = "科目")private String subject;
}

3.动态下拉数据集接口与实现类

/*** 获得数据源的接口*/public interface DropDownSetInterface {/*** 获得年级下拉框数据源* @return*/String[] getGradeListSource(Integer sectionId);}

在实现类中注入service时,碰到了注入为null的问题。加上@Component标注与@Autowired也没解决。最终查询到的解决方法如下:
(1)静态初始化当前类
(2)在初始化service的方法上加上@PostConstruct注解,使得方法在Bean初始化之后被Spring容器执行
(3)通过类来调用

/*** 获得数据源的实现方法*/@Component
public class DropDownSetImpl implements DropDownSetInterface {// 注入service@Autowiredprivate GradeService gradeService;//静态初始化当前类private static DropDownSetImpl dropDownSet;/*** 获得年级下拉框数据源* @return*/@Overridepublic String[] getGradeListSource() {//调用service时,通过类来调用List<String> gradeList = dropDownSet.gradeService.getGradeList();if (gradeList != null && gradeList .size() > 0) {// list 转 String[]return gradeList .toArray(new String[gradeList .size()]);}return null;}// 在初始化service的方法上加上@PostConstruct注解,使得方法在Bean初始化之后被Spring容器执行@PostConstructpublic void init() {dropDownSet = this;dropDownSet.gradeService = this.gradeService;}
}

4.解析下拉数据集的工具类

/*** 解析下拉数据集工具** 获得数据源*/
public class ResoveDropAnnotationUtil {// 填充年级下拉框public static String[] dynamicListResove(DropDownSetField dropDownSetField, String fieldName) 				{if (!Optional.ofNullable(dropDownSetField).isPresent()) {return null;}// 获取固定下拉信息String[] source = dropDownSetField.source();if (source.length > 0) {return source;}// 获取动态的下拉数据Class<? extends DropDownSetInterface>[] classes = dropDownSetField.sourceClass();if (classes.length > 0) {try {DropDownSetInterface dropDownSetInterface = Arrays.stream(classes).findFirst().get().newInstance();// 获得数据源,可根据filedName,判断并调用对应的方法,填充数据源String[] dynamicSource = null;if ("gradeList".equals(fieldName)) {dynamicSource = dropDownSetInterface.getGradeListSource();} if (null != dynamicSource && dynamicSource.length > 0) {return dynamicSource;}} catch (Exception e) {e.printStackTrace();}}return null;}

6.自定义EasyExcel拦截器处理

/**** easyExcel 自定义拦截器* 对第n列的,第x行至第y行数据新增下拉框**/@Slf4j
public class CustomSheetWriteHandler implements SheetWriteHandler {private Map<Integer, String[]> map = null;public CustomSheetWriteHandler(Map<Integer, String[]> map) {this.map = map;}@Overridepublic void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {}@Overridepublic void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {//这里可以对cell进行任何操作Sheet sheet = writeSheetHolder.getSheet();DataValidationHelper helper = sheet.getDataValidationHelper();// k:存在下拉数据集的单元格下表;v:下拉数据集map.forEach((k, v) ->{//下拉列表约束数据DataValidationConstraint constraint = helper.createExplicitListConstraint(v);//设置下拉单元格的首行、末行、首列、末列CellRangeAddressList rangeList = new CellRangeAddressList(1, 65536, k, k);//设置约束DataValidation validation = helper.createValidation(constraint, rangeList);//阻止输入非下拉选项的值validation.setErrorStyle(DataValidation.ErrorStyle.STOP);validation.setShowErrorBox(true);validation.setSuppressDropDownArrow(true);validation.createErrorBox("提示", "此值与单元格定义格式不一致");validation.createPromptBox("填写说明", "填写内容只能为下拉数据集中的类型");sheet.addValidationData(validation);});}
}

7.生成带多选下拉框的Excel模板

/*** 下载学生信息模板*/public void getStudentTemplate(HttpServletResponse response, HttpServletRequest request) throws IOException {OutputStream outputStream = response.getOutputStream();// 获得模板输入流InputStream inputStream = new ClassPathResource("template/export_template.xlsm").getInputStream();try {String fileName = "学生信息模板";String fileName3 = URLEncoder.encode(fileName, "utf-8");// 注意导出的文件格式需要是.xlsmresponse.setHeader("Content-disposition", "attachment;filename*=utf-8''"+fileName3+".xlsm");response.setContentType("application/msexcel");// 定义输出类型response.setCharacterEncoding("UTF-8");//获取该类声明的所有字段Field[] fields = StudentExcelExportResult.class.getDeclaredFields();//响应字段对应的下拉集合Map<Integer, String[]> map = new HashMap<>();Field field = null;// 循环判断哪些字段有下拉数据集,并获取for (int i = 0; i < fields.length; i++) {field = fields[i];// 解析注解信息DropDownSetField dropDownSetField = field.getAnnotation(DropDownSetField.class);if (null != dropDownSetField) {//调用下拉框数据源的方法String[] source = ResoveDropAnnotationUtil.dynamicListResove(dropDownSetField, field.getName());if (null != source && source.length > 0) {// 记录字段位置,及数据源map.put(i, source);}}}ExcelWriter excelWriter = EasyExcel.write(outputStream).registerWriteHandler(new CustomSheetWriteHandler(map))	//使用拦截器填充数据源.withTemplate(inputStream)	// 使用模板输出.build();WriteSheet sheet = EasyExcel.writerSheet(0,"Sheet1").build();excelWriter.write(null, sheet);excelWriter.finish();outputStream.close();} catch (Exception e) {e.printStackTrace();}
}

以上就完成了含有下拉多选,以及单选的Excel表格生成。

ps:wps如果想启用宏,需要额外下载组件。

参考资料:

EasyExcel导出自定义下拉数据集的Excel模板文件 —— 搬砖盖楼.

Java Excel POI添加多选下拉框 —— Anntly.

EasyExcel · 语雀.

@Autowired注入service为null问题解决 —— 爱米酱.

EasyExcel自定义拦截器demo.


http://chatgpt.dhexx.cn/article/20yOWnTd.shtml

相关文章

Java Excel POI添加多选下拉框

给自己打个广告&#xff0c;最近弄了个Excel的工具&#xff0c;支持下拉框&#xff0c;级联下拉框&#xff0c;隐藏Sheet&#xff0c;多线程大数据量导出&#xff0c;生产者消费者模式读取&#xff0c;代码大部分都有注释&#xff0c;有兴趣的朋友可以看看&#xff0c;觉得不错…

php excel复选框,excel如何实现下拉框复选

excel如何实现下拉框复选? EXCEL选择下拉框实现复选 第一步:新建一个excel且设置数据有效性【选中X列--数据--有效性】 第二步:开发工具--查看代码--把代码复制进去保存就OK了 代码如下:Private Sub Worksheet_Change(ByVal Target As Range) Developed by Contextures In…

使用VBA实现Excel下拉多选

Excel的下拉多选 新项目需要excel导入时的下拉多选框 Excel表格下拉单选很简单&#xff0c;先给表格做成单选。参照 [excel怎么设置下拉选择项] (https://jingyan.baidu.com/article/1876c85255d929890a13767d.html) Excel要想做成多选首先需要启用宏&#xff0c;如果Excel中…

Excel VB脚本,下拉框多选

1.数据-数据验证&#xff0c;先做出单选效果 在弹出的数据验证窗口选择 序列&#xff0c;然后选择下拉的数据来源 2.开发者工具-VisualBasic 在打开的窗口里面&#xff0c;选择需要下拉的sheet页&#xff0c;然后双击sheet,打开VB的脚本窗口 在窗口输入一下。 3.开发者工具…

office中excel设置下拉框多选

我参照了这篇文章 https://www.php.cn/topic/excel/444717.html 这篇文章整体写得不错&#xff0c;但是有些小瑕疵 问题1&#xff1a;在模块1中保存。 这里并没有说清楚 具体是&#xff1a;VBA编辑器中--插入---模块 然后复制以下代码 Public ReLoad As Boolean 开关listb…

Excel怎么下拉框多选

打开Exlce&#xff0c; 确定&#xff0c;然后 右击查看代码&#xff0c;把这段代码复制到新建的文件里面 此时Excel会给出提示&#xff0c;选择否&#xff0c;&#xff0c;系统会提示保存&#xff0c;在保存的时候选择启用宏的工作簿然后保存&#xff0c;此时Excel下拉框多选就…

关于EXCLE 下拉框多选的设置

关于EXCLE 下拉框多选的设置。 本文转载于&#xff1a;https://www.cnblogs.com/boosasliulin/p/5970120.html 本文转载于&#xff1a;https://blog.csdn.net/qq_33269520/article/details/81173811 打开Exlce&#xff0c;设置数据有效性 确定&#xff0c;然后 右击查看代码…

php下拉多选框,excel下拉框多选打勾的设置方法

excel下拉框多选打勾的设置方法 一、显示“开发工具”选项卡。打开Excel2010,点击左上方“文件”图标。点击“选项”,弹出“Excel选项”对话框,在“自定义功能区”中勾选“开发工具”,点击确定。 二、设置下拉列表的选项内容。将工作表sheet2名称修改为“data”,并在A列输入…

Excel 设置下拉框多选

问题描述 Excel的下拉框无法多选 解决办法 为Excel文件添加VB代码&#xff0c;文件后缀需由.xlsx变为.xlsm&#xff0c;否则仍无法实现该功能 操作步骤 ① 选中当前Sheet ② 右键选择查看代码 ③ 将代码复制进去 ④ 再将文件保存为.xlsm格式的即可 附代码如下 Option Exp…

Excel下拉框多选(支持再次选择已选项会取消选择)

比如我做一个表格&#xff0c;其中一项是“部门类型”&#xff0c;这一项中&#xff0c;选项有&#xff1a;财务部&#xff0c;人事部&#xff0c;开发部&#xff0c;销售部 用户在选择的时候&#xff0c;可以选择&#xff1a;人事部&#xff0c;开发部 那么在“部门类型”这个…

Excel下拉框设置多选

Excel下拉框一般只能单选&#xff0c;但有时候需要多选&#xff0c;多选的方法如下&#xff1a; 以office 2016中的excel为例&#xff1a; 1、数据验证入口 2、设置数据 3、sheet页右击查看代码 4、复制下面代码进去&#xff1a; 5、效果如下&#xff1a; VB代码如下&#xf…

【已解决】如何做excel表的下拉框多选

最近因为项目需求&#xff0c;要制作一个excel导入的模板&#xff0c;模板中要求某几列的下拉框是多选的。。不得不临时研究了一下vba。其间各种心酸不多说。。。。。。 首先&#xff0c;这个是需要启用宏&#xff0c;在vb编辑器里写代码&#xff0c;所以你要确保你的excel是可…

Excel表格实现下拉复选框多选

Excel表格实现下拉复选框多选 文章目录 1准备数据源2开启“开发工具”3具体实现3.1插入列表框控件3.2设置列表框控件属性3.3编辑VBA代码实现功能3.4调试运行 1准备数据源 打开要实现的excel表格&#xff0c;将选项数据放到sheet2 2开启“开发工具” 开启“开发工具”步骤&…

【C语言】用循环语句输出菱形

//用循环语句输出菱形 #include <stdio.h> int main() {int i,j;for(i0;i<3;i) //上4行{for(j0;j<3;j) //上4行的左边{if(ij<2)printf(" ");elseprintf("*");}for(j4;j<6;j) //上4行的右边{if(j-i>4)printf(" ");…

用c语言输出一个菱形

这是一道课后题作业&#xff0c;针对菱形的空格我使用了" "的输出方式&#xff0c;应该还有更好的方法&#xff1f;是不是还有格式化字符能直接居中对正&#xff1f;待思考。 代码如下&#xff1a; #include<stdio.h>int main(){int i, j, k, a;printf("…

C语言输出菱形不是梦

如果对其他经典算法感兴趣&#xff0c;可以点击我的主页&#xff0c;有惊喜哟 给大家看看咱的诚意&#xff1a; 先来个流程图&#xff08;虽然只写了一半&#xff0c;但是下面的一半比猫画虎就行&#xff09; 废话不多说上代码&#xff08;欢迎交流哟&#xff09;&#xff1a…

[C语言]——利用循环输出菱形

题目要求如下&#xff1a; 用C语言输出以下图形&#xff1a;*************************************************************************************总体思路&#xff1a; 将菱形拆分开&#xff0c;一行一行看。 前七行是由递减的空格和递增符号组成&#xff0c; 后六行是由…

【C语言】输出“*”菱形图案

问题&#xff1a;在屏幕上输出一个菱形图案   目标图案&#xff1a;      实现思路&#xff1a;   由目标图案可知&#xff1a;该图案共有13行&#xff0c;每行除了有“&#xff0a;”外&#xff0c;第一个“&#xff0a;”之前还包括空格。我们可以把整个图案分为…

【c++】C语言之输入行数,输出实心菱形和空心菱形

输出菱形 编程自动输出如下图形&#xff0c;由屏幕输入指定行数&#xff08;奇数&#xff09;&#xff0c;实现后封装为函数&#xff0c;以行数作为参数值。 输入一个n,表示左边两个菱形图形&#xff08;实心和空心&#xff09;的行数&#xff08;或者一半行数&#xff09; 利…

<C语言程序实例>C语言实现菱形输出

<C语言程序实例>C语言实现菱形输出 前言 这一问题无论是在C语言还是别的编程语言的入门学习中都会遇到&#xff0c;还是比较常见的&#xff0c;要学一下的。 一、菱形 我们先要看一下我们要输出的菱形是什么样子的。这里举一个例子简单说明一下: 大家首先要知道一点…