有時候因爲業務需要,導出的Excel模板裏面的單元格下拉數據集可能是用戶在系統中自定義的數據字典數據,我們需要通過接口拿到相應字段的對應數據集,導出類似下方這種模板:
EasyExcel的api地址:https://www.yuque.com/easyexcel/doc/api
主要處理方式是如下:
- 使用自定義註解的方式,來標識Entity中哪個字段是需要使用下拉數據集的,這個下拉數據集的數據是固定的 比如性別:{"男","女"},還是說是從我們的數據庫中通過接口動態獲取的,比如某個數據字典的值
- 自定義攔截器,實現下拉數據集的操作 官方的demo中其實有許多的實例,我們可以參考進行擴展操作,關於自定義攔截器,官方給出的demo地址:https://github.com/alibaba/easyexcel/blob/master/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();
}