|
@@ -12,18 +12,19 @@ import cn.idev.excel.util.ClassUtils;
|
|
|
import cn.idev.excel.write.handler.SheetWriteHandler;
|
|
import cn.idev.excel.write.handler.SheetWriteHandler;
|
|
|
import cn.idev.excel.write.metadata.holder.WriteSheetHolder;
|
|
import cn.idev.excel.write.metadata.holder.WriteSheetHolder;
|
|
|
import cn.idev.excel.write.metadata.holder.WriteWorkbookHolder;
|
|
import cn.idev.excel.write.metadata.holder.WriteWorkbookHolder;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
+import org.apache.poi.ss.usermodel.*;
|
|
|
|
|
+import org.apache.poi.ss.util.CellRangeAddressList;
|
|
|
|
|
+import org.apache.poi.ss.util.WorkbookUtil;
|
|
|
|
|
+import org.apache.poi.xssf.usermodel.XSSFDataValidation;
|
|
|
import com.vber.common.core.exception.ServiceException;
|
|
import com.vber.common.core.exception.ServiceException;
|
|
|
import com.vber.common.core.service.DictService;
|
|
import com.vber.common.core.service.DictService;
|
|
|
import com.vber.common.core.utils.SpringUtils;
|
|
import com.vber.common.core.utils.SpringUtils;
|
|
|
import com.vber.common.core.utils.StreamUtils;
|
|
import com.vber.common.core.utils.StreamUtils;
|
|
|
import com.vber.common.core.utils.StringUtils;
|
|
import com.vber.common.core.utils.StringUtils;
|
|
|
import com.vber.common.excel.annotation.ExcelDictFormat;
|
|
import com.vber.common.excel.annotation.ExcelDictFormat;
|
|
|
|
|
+import com.vber.common.excel.annotation.ExcelDynamicOptions;
|
|
|
import com.vber.common.excel.annotation.ExcelEnumFormat;
|
|
import com.vber.common.excel.annotation.ExcelEnumFormat;
|
|
|
-import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
-import org.apache.poi.ss.usermodel.*;
|
|
|
|
|
-import org.apache.poi.ss.util.CellRangeAddressList;
|
|
|
|
|
-import org.apache.poi.ss.util.WorkbookUtil;
|
|
|
|
|
-import org.apache.poi.xssf.usermodel.XSSFDataValidation;
|
|
|
|
|
|
|
|
|
|
import java.lang.reflect.Field;
|
|
import java.lang.reflect.Field;
|
|
|
import java.util.*;
|
|
import java.util.*;
|
|
@@ -34,7 +35,7 @@ import java.util.*;
|
|
|
* <p>
|
|
* <p>
|
|
|
* 即只有前1000行的数据可以用下拉框,超出的自行通过限制数据量的形式,第二次输出
|
|
* 即只有前1000行的数据可以用下拉框,超出的自行通过限制数据量的形式,第二次输出
|
|
|
*
|
|
*
|
|
|
- * @author Iwb
|
|
|
|
|
|
|
+ * @author Emil.Zhang
|
|
|
*/
|
|
*/
|
|
|
@Slf4j
|
|
@Slf4j
|
|
|
public class ExcelDownHandler implements SheetWriteHandler {
|
|
public class ExcelDownHandler implements SheetWriteHandler {
|
|
@@ -104,8 +105,8 @@ public class ExcelDownHandler implements SheetWriteHandler {
|
|
|
if (StringUtils.isNotBlank(dictType)) {
|
|
if (StringUtils.isNotBlank(dictType)) {
|
|
|
// 如果传递了字典名,则依据字典建立下拉
|
|
// 如果传递了字典名,则依据字典建立下拉
|
|
|
Collection<String> values = Optional.ofNullable(dictService.getAllDictByDictType(dictType))
|
|
Collection<String> values = Optional.ofNullable(dictService.getAllDictByDictType(dictType))
|
|
|
- .orElseThrow(() -> new ServiceException("字典 {} 不存在", dictType))
|
|
|
|
|
- .values();
|
|
|
|
|
|
|
+ .orElseThrow(() -> new ServiceException("字典 {} 不存在", dictType))
|
|
|
|
|
+ .values();
|
|
|
options = new ArrayList<>(values);
|
|
options = new ArrayList<>(values);
|
|
|
} else if (StringUtils.isNotBlank(converterExp)) {
|
|
} else if (StringUtils.isNotBlank(converterExp)) {
|
|
|
// 如果指定了确切的值,则直接解析确切的值
|
|
// 如果指定了确切的值,则直接解析确切的值
|
|
@@ -117,11 +118,21 @@ public class ExcelDownHandler implements SheetWriteHandler {
|
|
|
ExcelEnumFormat format = field.getDeclaredAnnotation(ExcelEnumFormat.class);
|
|
ExcelEnumFormat format = field.getDeclaredAnnotation(ExcelEnumFormat.class);
|
|
|
List<Object> values = EnumUtil.getFieldValues(format.enumClass(), format.textField());
|
|
List<Object> values = EnumUtil.getFieldValues(format.enumClass(), format.textField());
|
|
|
options = StreamUtils.toList(values, Convert::toStr);
|
|
options = StreamUtils.toList(values, Convert::toStr);
|
|
|
|
|
+ } else if (field.isAnnotationPresent(ExcelDynamicOptions.class)) {
|
|
|
|
|
+ // 处理动态下拉选项
|
|
|
|
|
+ ExcelDynamicOptions dynamicOptions = field.getDeclaredAnnotation(ExcelDynamicOptions.class);
|
|
|
|
|
+ // 获取提供者实例
|
|
|
|
|
+ ExcelOptionsProvider provider = SpringUtils.getBean(dynamicOptions.providerClass());
|
|
|
|
|
+ Set<String> providerOptions = provider.getOptions();
|
|
|
|
|
+ if (CollUtil.isNotEmpty(providerOptions)) {
|
|
|
|
|
+ options = new ArrayList<>(providerOptions);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
if (ObjectUtil.isNotEmpty(options)) {
|
|
if (ObjectUtil.isNotEmpty(options)) {
|
|
|
// 仅当下拉可选项不为空时执行
|
|
// 仅当下拉可选项不为空时执行
|
|
|
- if (options.size() > 20) {
|
|
|
|
|
- // 这里限制如果可选项大于20,则使用额外表形式
|
|
|
|
|
|
|
+ int totalCharacter = options.stream().mapToInt(String::length).sum() + options.size();
|
|
|
|
|
+ if (options.size() > 20 || totalCharacter > 255) {
|
|
|
|
|
+ // 这里限制如果可选项大于20 或 总字符数超过255,则使用额外表形式
|
|
|
dropDownWithSheet(helper, workbook, sheet, index, options);
|
|
dropDownWithSheet(helper, workbook, sheet, index, options);
|
|
|
} else {
|
|
} else {
|
|
|
// 否则使用固定值形式
|
|
// 否则使用固定值形式
|
|
@@ -186,7 +197,7 @@ public class ExcelDownHandler implements SheetWriteHandler {
|
|
|
for (int columnIndex = 0; columnIndex < firstOptions.size(); columnIndex++) {
|
|
for (int columnIndex = 0; columnIndex < firstOptions.size(); columnIndex++) {
|
|
|
String columnName = firstOptions.get(columnIndex);
|
|
String columnName = firstOptions.get(columnIndex);
|
|
|
firstRow.createCell(columnIndex)
|
|
firstRow.createCell(columnIndex)
|
|
|
- .setCellValue(columnName);
|
|
|
|
|
|
|
+ .setCellValue(columnName);
|
|
|
columnNames.add(columnName);
|
|
columnNames.add(columnName);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -196,9 +207,9 @@ public class ExcelDownHandler implements SheetWriteHandler {
|
|
|
name.setNameName(linkedOptionsSheetName);
|
|
name.setNameName(linkedOptionsSheetName);
|
|
|
// 以横向第一行创建一级下拉拼接引用位置
|
|
// 以横向第一行创建一级下拉拼接引用位置
|
|
|
String firstOptionsFunction = String.format("%s!$%s$1:$%s$1",
|
|
String firstOptionsFunction = String.format("%s!$%s$1:$%s$1",
|
|
|
- linkedOptionsSheetName,
|
|
|
|
|
- getExcelColumnName(0),
|
|
|
|
|
- getExcelColumnName(firstOptions.size())
|
|
|
|
|
|
|
+ linkedOptionsSheetName,
|
|
|
|
|
+ getExcelColumnName(0),
|
|
|
|
|
+ getExcelColumnName(firstOptions.size())
|
|
|
);
|
|
);
|
|
|
// 设置名称管理器的引用位置
|
|
// 设置名称管理器的引用位置
|
|
|
name.setRefersToFormula(firstOptionsFunction);
|
|
name.setRefersToFormula(firstOptionsFunction);
|
|
@@ -218,12 +229,12 @@ public class ExcelDownHandler implements SheetWriteHandler {
|
|
|
sonName.setNameName(thisFirstOptionsValue);
|
|
sonName.setNameName(thisFirstOptionsValue);
|
|
|
// 以第二行该列数据拼接引用位置
|
|
// 以第二行该列数据拼接引用位置
|
|
|
String sonFunction = String.format("%s!$%s$2:$%s$%d",
|
|
String sonFunction = String.format("%s!$%s$2:$%s$%d",
|
|
|
- linkedOptionsSheetName,
|
|
|
|
|
- firstOptionsColumnName,
|
|
|
|
|
- firstOptionsColumnName,
|
|
|
|
|
- // 二级选项存在则设置为(选项个数+1)行,否则设置为2行
|
|
|
|
|
- Math.max(Optional.ofNullable(secoundOptionsMap.get(thisFirstOptionsValue))
|
|
|
|
|
- .orElseGet(ArrayList::new).size(), 1) + 1
|
|
|
|
|
|
|
+ linkedOptionsSheetName,
|
|
|
|
|
+ firstOptionsColumnName,
|
|
|
|
|
+ firstOptionsColumnName,
|
|
|
|
|
+ // 二级选项存在则设置为(选项个数+1)行,否则设置为2行
|
|
|
|
|
+ Math.max(Optional.ofNullable(secoundOptionsMap.get(thisFirstOptionsValue))
|
|
|
|
|
+ .orElseGet(ArrayList::new).size(), 1) + 1
|
|
|
);
|
|
);
|
|
|
// 设置名称管理器的引用位置
|
|
// 设置名称管理器的引用位置
|
|
|
sonName.setRefersToFormula(sonFunction);
|
|
sonName.setRefersToFormula(sonFunction);
|
|
@@ -276,7 +287,7 @@ public class ExcelDownHandler implements SheetWriteHandler {
|
|
|
// 填充位置的部分不渲染
|
|
// 填充位置的部分不渲染
|
|
|
if (StrUtil.isNotBlank(rowValue)) {
|
|
if (StrUtil.isNotBlank(rowValue)) {
|
|
|
row.createCell(columnIndex)
|
|
row.createCell(columnIndex)
|
|
|
- .setCellValue(rowValue);
|
|
|
|
|
|
|
+ .setCellValue(rowValue);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
@@ -296,7 +307,7 @@ public class ExcelDownHandler implements SheetWriteHandler {
|
|
|
String tmpOptionsSheetName = OPTIONS_SHEET_NAME + "_" + currentOptionsColumnIndex;
|
|
String tmpOptionsSheetName = OPTIONS_SHEET_NAME + "_" + currentOptionsColumnIndex;
|
|
|
// 创建下拉数据表
|
|
// 创建下拉数据表
|
|
|
Sheet simpleDataSheet = Optional.ofNullable(workbook.getSheet(WorkbookUtil.createSafeSheetName(tmpOptionsSheetName)))
|
|
Sheet simpleDataSheet = Optional.ofNullable(workbook.getSheet(WorkbookUtil.createSafeSheetName(tmpOptionsSheetName)))
|
|
|
- .orElseGet(() -> workbook.createSheet(WorkbookUtil.createSafeSheetName(tmpOptionsSheetName)));
|
|
|
|
|
|
|
+ .orElseGet(() -> workbook.createSheet(WorkbookUtil.createSafeSheetName(tmpOptionsSheetName)));
|
|
|
// 将下拉表隐藏
|
|
// 将下拉表隐藏
|
|
|
workbook.setSheetHidden(workbook.getSheetIndex(simpleDataSheet), true);
|
|
workbook.setSheetHidden(workbook.getSheetIndex(simpleDataSheet), true);
|
|
|
// 完善纵向的一级选项数据表
|
|
// 完善纵向的一级选项数据表
|
|
@@ -304,10 +315,10 @@ public class ExcelDownHandler implements SheetWriteHandler {
|
|
|
int finalI = i;
|
|
int finalI = i;
|
|
|
// 获取每一选项行,如果没有则创建
|
|
// 获取每一选项行,如果没有则创建
|
|
|
Row row = Optional.ofNullable(simpleDataSheet.getRow(i))
|
|
Row row = Optional.ofNullable(simpleDataSheet.getRow(i))
|
|
|
- .orElseGet(() -> simpleDataSheet.createRow(finalI));
|
|
|
|
|
|
|
+ .orElseGet(() -> simpleDataSheet.createRow(finalI));
|
|
|
// 获取本级选项对应的选项列,如果没有则创建。上述采用多个sheet,默认索引为1列
|
|
// 获取本级选项对应的选项列,如果没有则创建。上述采用多个sheet,默认索引为1列
|
|
|
Cell cell = Optional.ofNullable(row.getCell(0))
|
|
Cell cell = Optional.ofNullable(row.getCell(0))
|
|
|
- .orElseGet(() -> row.createCell(0));
|
|
|
|
|
|
|
+ .orElseGet(() -> row.createCell(0));
|
|
|
// 设置值
|
|
// 设置值
|
|
|
cell.setCellValue(value.get(i));
|
|
cell.setCellValue(value.get(i));
|
|
|
}
|
|
}
|
|
@@ -319,10 +330,10 @@ public class ExcelDownHandler implements SheetWriteHandler {
|
|
|
name.setNameName(nameName);
|
|
name.setNameName(nameName);
|
|
|
// 以纵向第一列创建一级下拉拼接引用位置
|
|
// 以纵向第一列创建一级下拉拼接引用位置
|
|
|
String function = String.format("%s!$%s$1:$%s$%d",
|
|
String function = String.format("%s!$%s$1:$%s$%d",
|
|
|
- tmpOptionsSheetName,
|
|
|
|
|
- getExcelColumnName(0),
|
|
|
|
|
- getExcelColumnName(0),
|
|
|
|
|
- value.size());
|
|
|
|
|
|
|
+ tmpOptionsSheetName,
|
|
|
|
|
+ getExcelColumnName(0),
|
|
|
|
|
+ getExcelColumnName(0),
|
|
|
|
|
+ value.size());
|
|
|
// 设置名称管理器的引用位置
|
|
// 设置名称管理器的引用位置
|
|
|
name.setRefersToFormula(function);
|
|
name.setRefersToFormula(function);
|
|
|
// 设置数据校验为序列模式,引用的是名称管理器中的别名
|
|
// 设置数据校验为序列模式,引用的是名称管理器中的别名
|
|
@@ -392,8 +403,8 @@ public class ExcelDownHandler implements SheetWriteHandler {
|
|
|
int thisCircleColumnIndex = columnIndex % 26;
|
|
int thisCircleColumnIndex = columnIndex % 26;
|
|
|
// 26一循环的次数大于0,则视为栏名至少两位
|
|
// 26一循环的次数大于0,则视为栏名至少两位
|
|
|
String columnPrefix = columnCircleCount == 0
|
|
String columnPrefix = columnCircleCount == 0
|
|
|
- ? StrUtil.EMPTY
|
|
|
|
|
- : StrUtil.subWithLength(EXCEL_COLUMN_NAME, columnCircleCount - 1, 1);
|
|
|
|
|
|
|
+ ? StrUtil.EMPTY
|
|
|
|
|
+ : StrUtil.subWithLength(EXCEL_COLUMN_NAME, columnCircleCount - 1, 1);
|
|
|
// 从26一循环内取对应的栏位名
|
|
// 从26一循环内取对应的栏位名
|
|
|
String columnNext = StrUtil.subWithLength(EXCEL_COLUMN_NAME, thisCircleColumnIndex, 1);
|
|
String columnNext = StrUtil.subWithLength(EXCEL_COLUMN_NAME, thisCircleColumnIndex, 1);
|
|
|
// 将二者拼接即为最终的栏位名
|
|
// 将二者拼接即为最终的栏位名
|