Excel下拉框超长和二级联动的问题

背景

在日常开发中,经常会有生成数据excel的需求,像什么数据导出,导入模板等等,单纯的数据导出没什么难度,只是一个数据展示,但是导入模板的话,难度就会高一些,会有一些选择下拉框,或者数据联动的问题。
之前碰到问题都是百度一下,但是百度出来的信息杂且乱,让人难受的一批(这里真的想吐槽下百度),所以决定自己来总结下,省得下次还要百度。

问题

选择下拉框数据超长的问题

一般设置下拉框选项数据只需要:

//设置下拉框数据
final DataValidation dataValidation = validationHelper.createValidation(constraint, regions);
sheet.addValidationData(dataValidation);

但是这里会有一个问题:当下拉选项的数据过长时,超过255就会报一个异常:

2023-07-14 09:42:17.001 ERROR 17872 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: String literals in formulas can't be bigger than 255 characters ASCII] with root cause

java.lang.IllegalArgumentException: String literals in formulas can't be bigger than 255 characters ASCII
	at org.apache.poi.ss.formula.ptg.StringPtg.<init>(StringPtg.java:61) ~[poi-4.1.2.jar:4.1.2]
	at org.apache.poi.hssf.usermodel.DVConstraint.createListFormula(DVConstraint.java:419) ~[poi-4.1.2.jar:4.1.2]
	at org.apache.poi.hssf.usermodel.DVConstraint.createFormulas(DVConstraint.java:391) ~[poi-4.1.2.jar:4.1.2]
	at org.apache.poi.hssf.usermodel.HSSFDataValidation.createDVRecord(HSSFDataValidation.java:211) ~[poi-4.1.2.jar:4.1.2]
	at org.apache.poi.hssf.usermodel.HSSFSheet.addValidationData(HSSFSheet.java:476) ~[poi-4.1.2.jar:4.1.2]
	at cn.hutool.poi.excel.ExcelWriter.addValidationData(ExcelWriter.java:668) ~[hutool-all-5.7.16.jar:na]
	at cn.hutool.poi.excel.ExcelWriter.addSelect(ExcelWriter.java:657) ~[hutool-all-5.7.16.jar:na]
	at cn.hutool.poi.excel.ExcelWriter.addSelect(ExcelWriter.java:631) ~[hutool-all-5.7.16.jar:na]
	at com.example.demo.controller.ExcelController.create(ExcelController.java:39) ~[classes/:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.19.jar:5.3.19]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.19.jar:5.3.19]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.19.jar:5.3.19]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.19.jar:5.3.19]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.19.jar:5.3.19]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.19.jar:5.3.19]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) ~[spring-webmvc-5.3.19.jar:5.3.19]

这个时候就需要将下拉数据写入到excel的某个区域中,然后将这块区域数据作为下拉选项的数据,像这样:

		// 创建一个name,excel中的这种下拉都是以name形式来表示的,这个在二级联动中很重要
		Name namedCell = wbCreat.createName();
		// 设置名称
        namedCell.setNameName("hidden" + hiddenIndex);
        // 设置数据源(从第一行第一列到第一行第N列)
        namedCell.setRefersToFormula("hidden" + hiddenIndex + "!$A$1:$A$" + array.length);
        DVConstraint constraint = DVConstraint.createFormulaListConstraint("hidden" + hiddenIndex);
        final DataValidationHelper validationHelper = sheet.getDataValidationHelper();
        // 这个下拉框数据作用的单元格
        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
        // 这个就跟之前一样了
        DataValidation validation = validationHelper.createValidation(constraint, regions);
        sheet.addValidationData(validation);

这样就可以避免因为下拉数据过长而抛异常出来了。

二级联动

二级联动的时候,一般会多一个sheet来保存联动的数据,难点是怎么把这些数据变成可以二级联动的数据。
要是在excel中设置过这种二级联动的数据,就会知道我们需要新建一个叫“名称管理器”的东西。
这个东西在叫法上就和上面的Name对象是一样的,所以我感觉这两个就是同一个东西。
那么问题就变成了:生成多个Name对象,每个Name对象是一个一级,然后指定对应的二级数据。
在生成业务数据的时候,循环生成Name对象:

for (int i = 0; i < list.size(); i++) {
	String col = getCol(i);
	// 每一列是一个一级,一列数据都生成一个Name
    Name name = workbook.createName();
     name.setNameName("name" + i);
     // 指定数据范围
     String formula = dataSheet.getSheetName() + "!$" + col + "$2:$" + col + "$" + (temp.size() + 1);
     name.setRefersToFormula(formula);
}

这样每一个一级都生成了一个Name,然后分别设置一级联动和二级联动就可以了:

// 一级联动
Name nameA = workbook.createName();
nameA .setNameName("nameA");
nameA .setRefersToFormula("勿动!$A$1:$M$1");
DVConstraint constraint = DVConstraint.createFormulaListConstraint("nameA");
final DataValidationHelper validationHelper = mainSheet.getDataValidationHelper();
CellRangeAddressList regions = new CellRangeAddressList(1, 50002, 0, 0);
DataValidation validation = validationHelper.createValidation(constraint, regions);
mainSheet.addValidationData(validation);
// 二级联动数据
final DataValidationHelper validationHelper1 = mainSheet.getDataValidationHelper();
// 指定二级联动数据作用的单元格
DataValidationConstraint formulaListConstraint = validationHelper1.createFormulaListConstraint(("INDIRECT($A1)"));
CellRangeAddressList regions1 = new CellRangeAddressList(1, 50002, 1, 1);
DataValidation validation1 = validationHelper1.createValidation(formulaListConstraint, regions1);
mainSheet.addValidationData(validation1);

这样就ok了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值