EasyExcel 下拉扩展方案(支持字典 & 数据库字段)
目标:
在现有ExcelUtils(static 工具类)基础上
扩展支持:
- ✅ 原
@ExplicitConstraint - ✅ 类实现方式下拉
- ✅ 类似若依的
dictType查字典 - ✅ 指定
table + column查数据库字段 - ✅ 不破坏原结构
一、整体架构
原有逻辑:
@ExplicitConstraint → resolveExplicitConstraint → String[]
升级为:
1️⃣ ExplicitConstraint
2️⃣ DynamicConstraint
3️⃣ 统一返回 String[]
4️⃣ 写入 explicitListConstraintMap
5️⃣ SheetWriteHandler 生成下拉
二、新增注解:@DynamicConstraint
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DynamicConstraint {
/**
* 字典类型(优先)
*/
String dictType() default "";
/**
* 表名
*/
String table() default "";
/**
* 字段名
*/
String column() default "";
}
三、动态数据解析器(Spring Bean)
@Component
public class DynamicConstraintResolver {
@Autowired
private DictMapper dictMapper;
@Autowired
private CommonQueryMapper commonQueryMapper;
public String[] resolve(DynamicConstraint constraint) {
if (constraint == null) {
return null;
}
// 1️⃣ 字典查询
if (!constraint.dictType().isEmpty()) {
List<String> list =
dictMapper.selectDictByType(constraint.dictType());
return list.toArray(new String[0]);
}
// 2️⃣ 表字段查询
if (!constraint.table().isEmpty()
&& !constraint.column().isEmpty()) {
List<String> list =
commonQueryMapper.selectColumnData(
constraint.table(),
constraint.column()
);
return list.toArray(new String[0]);
}
return null;
}
}
四、SpringContextHolder(解决 static 注入问题)
因为 ExcelUtils 是 static 工具类,不能 @Autowired
@Component
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
context = applicationContext;
}
public static <T> T getBean(Class<T> clazz) {
return context.getBean(clazz);
}
}
五、修改 ExcelUtils.writeTemplate 核心逻辑
原代码:
ExplicitConstraint explicitConstraint = field.getAnnotation(ExplicitConstraint.class);
String[] explicitArray = resolveExplicitConstraint(explicitConstraint);
升级为 👇
Field[] declaredFields = zclass.getDeclaredFields();
for (int i = 0; i < declaredFields.length; i++) {
Field field = declaredFields[i];
String[] explicitArray = null;
// 1️⃣ 解析 ExplicitConstraint
ExplicitConstraint explicitConstraint =
field.getAnnotation(ExplicitConstraint.class);
if (explicitConstraint != null) {
explicitArray = resolveExplicitConstraint(explicitConstraint);
}
// 2️⃣ 解析 DynamicConstraint
if (explicitArray == null) {
DynamicConstraint dynamicConstraint =
field.getAnnotation(DynamicConstraint.class);
if (dynamicConstraint != null) {
DynamicConstraintResolver resolver =
SpringContextHolder.getBean(DynamicConstraintResolver.class);
explicitArray = resolver.resolve(dynamicConstraint);
}
}
// 3️⃣ 放入下拉集合
if (explicitArray != null && explicitArray.length > 0) {
explicitListConstraintMap.put(i, explicitArray);
}
}
六、DTO 使用方式
1️⃣ 固定枚举
@ExplicitConstraint(source = {"是", "否"})
private String enable;
2️⃣ 字典表方式(类似若依)
@DynamicConstraint(dictType = "device_status")
private String status;
3️⃣ 查任意表字段
@DynamicConstraint(
table = "device_info",
column = "device_name"
)
private String deviceName;
七、Mapper 示例
字典查询
@Select("""
select dict_label
from sys_dict_data
where dict_type = #{dictType}
""")
List<String> selectDictByType(String dictType);
表字段查询(⚠ 必须做白名单校验)
@Select("""
<script>
select distinct ${column}
from ${table}
where ${column} is not null
</script>
""")
List<String> selectColumnData(
@Param("table") String table,
@Param("column") String column
);
⚠ 生产环境必须做白名单验证,防 SQL 注入。
八、执行流程
当调用:
ExcelUtils.writeTemplate(...)
流程如下:
遍历字段
↓
找 ExplicitConstraint
↓
找 DynamicConstraint
↓
统一得到 String[]
↓
放入 Map<列索引, 下拉数组>
↓
SheetWriteHandler.afterSheetCreate
↓
生成 DataValidation
九、注意事项(生产必须知道)
1️⃣ Excel 255 字符限制
Excel 下拉字符串总长度 ≤ 255
如果:
- 字典数据 > 20 条
- 或字符串较长
会报错。
解决方案:
使用隐藏 Sheet + 公式引用
2️⃣ 必须做表字段白名单
防止:
@DynamicConstraint(table = "user;drop table")
建议:
private static final Set<String> TABLE_WHITE_LIST =
Set.of("device_info", "user_info");
3️⃣ 建议加缓存
避免每次导出都查数据库。
推荐 key:
excel:dict:device_status
excel:table:device_info:device_name
十、升级后的能力对比
| 功能 | 支持情况 |
|---|---|
| 原 ExplicitConstraint | ✅ |
| 类方式下拉 | ✅ |
| dictType 字典 | ✅ |
| 任意表字段 | ✅ |
| 保持 static 工具类 | ✅ |
| 类似若依写法 | ✅ |
十一、最终效果总结
你现在这套结构已经升级为:
✔ 通用下拉扩展框架
✔ 可扩展
✔ 兼容旧版本
✔ 结构清晰
✔ 可平滑升级为企业级版本

浙公网安备 33010602011771号