有时候因为业务需要,导出的Excel模板里面的单元格下拉数据集可能是用户在系统中自定义的数据字典数据,我们需要通过接口拿到相应字段的对应数据集,导出类似下方这种模板:
EasyExcel的api地址:常见api · 语雀
主要处理方式是如下:
- 使用自定义注解的方式,来标识Entity中哪个字段是需要使用下拉数据集的,这个下拉数据集的数据是固定的 比如性别:{"男","女"},还是说是从我们的数据库中通过接口动态获取的,比如某个数据字典的值
- 自定义拦截器,实现下拉数据集的操作 官方的demo中其实有许多的实例,我们可以参考进行扩展操作,关于自定义拦截器,官方给出的demo地址:https://github.com/alibaba/easyexcel/blob/master/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomSheetWriteHandler.java
自定义注解:
/**
* 标记导出excel的下拉数据集
*/
@Documented
// 作用在字段上
@Target(ElementType.FIELD)
// 运行时有效
@Retention(RetentionPolicy.RUNTIME)
public @interface DropDownSetField {
// 固定下拉内容
String[] source() default {};
// 动态下拉内容
Class[] sourceClass() default {};
}
解析下拉数据集工具:
public class ResoveDropAnnotationUtil {
public static String[] resove(DropDownSetField dropDownSetField){
if(!Optional.ofNullable(dropDownSetField).isPresent()){
return null;
}
// 获取固定下拉信息
String[] source = dropDownSetField.source();
if(null != source && source.length > 0){
return source;
}
// 获取动态的下拉数据
Class<? extends DropDownSetInterface>[] classes = dropDownSetField.sourceClass();
if(null != classes && classes.length > 0){
try {
DropDownSetInterface dropDownSetInterface = Arrays.stream(classes).findFirst().get().newInstance();
String[] dynamicSource = dropDownSetInterface.getSource();
if(null != dynamicSource && dynamicSource.length > 0){
return dynamicSource;
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return null;
}
}
Entity中标识下拉数据集字段:
@Data
public class ProductModel {
@ExcelProperty(value = "商品名称")
private String name;
@ExcelProperty(value = "商品类型")
@DropDownSetField(source = {"固体","液体"})
private String type;
@ExcelProperty(value = "单位")
@DropDownSetField(sourceClass = DropDownSetImpl.class)
private String unit;
}
动态下拉数据集接口实现类(Entity中的单位下拉数据集来自DropDownSetImpl.class)
public interface DropDownSetInterface {
String[] getSource();
}
public class DropDownSetImpl implements DropDownSetInterface {
@Override
public String[] getSource() {
return new String[]{"g","kg","t","ml","l","米","千米"};
}
}
自定义拦截器处理:
public class ProductCellWriteHandler implements SheetWriteHandler {
private Map<Integer,String[]> map = null;
public ProductCellWriteHandler(Map<Integer,String[]> map){
this.map = map;
}
@Override
public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
}
@Override
public 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);
});
}
}
生成自定义模板代码:
@Test
public void export() throws IOException {
File file = new File("D:/商品导入模板.xlsx");
// 文件不存在即创建 存在即返回false
file.createNewFile();
FileOutputStream fileOutputStream = new FileOutputStream(file);
// 获取改类声明的所有字段
Field[] fields = ProductModel.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[] sources = ResoveDropAnnotationUtil.resove(dropDownSetField);
if(null != sources && sources.length > 0){
map.put(i,sources);
}
}
}
ExcelWriter excelWriter = EasyExcel.write(fileOutputStream,ProductModel.class)
.registerWriteHandler(new ProductCellWriteHandler(map)).build();
WriteSheet sheet = EasyExcel.writerSheet(0,"商品模板").build();
excelWriter.write(null,sheet);
//sheet = EasyExcel.writerSheet(1,"单位说明").build();
//excelWriter.write(null,sheet);
excelWriter.finish();
}