在本文中,我们将探讨如何使用Spring Boot集成EasyExcel库来实现数据导出功能。我们将学习如何通过EasyExcel库生成Excel文件,并实现一些高级功能,如支持列下拉和自定义单元格样式,自适应列宽、行高,动态表头 ,以及如何同时导出多个sheet页的数据。
首先,我们需要在pom.xml
文件中添加EasyExcel和相关的依赖项
org.apache.poi
poi-ooxml
4.1.2
com.alibaba
easyexcel
3.2.1
org.apache.poi
poi
4.1.2
支持sheet名称、模版类、动态表头、数据集、下拉列、单元格样式定义。
import lombok.Data;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**
* 导出动态参数
*/
@Data
public class EasyExcelExportDynamicParam implements Serializable {
/**
* sheet名称
*/
private String sheetName;
/**
* 模版
*/
private Class> template;
/**
* 数据集
*/
private List> dataList;
/**
* 动态表头
*/
private List> dynamicHeaderList;
/**
* 单元格样式map,key为行下标,
* Map key为列下标
*/
private Map> styleMap;
/**
* 下拉选项 key为列下标
*/
private Map selectedMap;
}
支持字体颜色、背景颜色、字体、字体大小、单元格内容对齐方式。
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import java.io.Serializable;
/**
* EasyExcel导出动态单元格样式
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class EasyExcelExportDynamicStyleParam implements Serializable {
/**
* 字体颜色 IndexedColors.WHITE.getIndex()
*/
private Short fontColor;
/**
* 背景颜色
*/
private Short bgColor;
/**
* 字体
*/
private String fontName;
/**
* 字体大小
*/
private Short fontSize;
/**
* 单元格内容对齐方式
*/
private HorizontalAlignment alignment;
}
支持注解方式设置单元格下拉列表,起始行、结束行、固定下拉内容、动态下拉内容。
import java.lang.annotation.*;
/**
* excel动态下拉框数据填充
*/
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelSelected {
/**
* 固定下拉内容
*/
String[] source() default {};
/**
* 动态下拉内容服务类
*/
String dynamicData() default "";
/**
* 动态下拉内容参数
*
* @return
*/
String dynamicParam() default "";
/**
* 设置下拉框的起始行,默认为第二行
*/
int firstRow() default 1;
/**
* 设置下拉框的结束行,默认10000行
*/
int lastRow() default 5000;
}
/**
* excel动态下拉框数据服务提供者
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelDynamicData {
/**
* 提供数据的服务名
*
* @return
*/
String name();
}
/**
*
*/
public interface ExcelDynamicSelectHandler {
/**
* 获取动态生成的下拉框可选数据
* @return 动态生成的下拉框可选数据
*/
String[] getSource(String param);
}
import com.alibaba.excel.annotation.ExcelProperty;
import com.yt.bi.goods.common.annotation.ExcelSelected;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
import java.util.*;
/**
* 自定义ExcelSelected注解解析
*/
@Data
@Slf4j
public class ExcelSelectedResolve {
/**
* 下拉内容
*/
private String[] source;
/**
* 设置下拉框的起始行,默认为第二行
*/
private int firstRow = 1;
/**
* 设置下拉框的结束行
*/
private int lastRow = 2000;
/**
* 解析表头类中的下拉注解
*
* @param head 表头类
* @return Map<下拉框列索引, 下拉框内容> map
*/
public static Map resolveSelectedAnnotation(Class> head) {
Map selectedMap = new HashMap<>();
if (Objects.isNull(head)) {
return selectedMap;
}
// getDeclaredFields(): 返回全部声明的属性;getFields(): 返回public类型的属性
Field[] fields = head.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
// 解析注解信息
ExcelSelected selected = field.getAnnotation(ExcelSelected.class);
ExcelProperty property = field.getAnnotation(ExcelProperty.class);
if (selected == null) {
continue;
}
String[] source = resolveSelectedSource(selected);
if (source == null || source.length == 0) {
continue;
}
ExcelSelectedResolve excelSelectedResolve = new ExcelSelectedResolve();
excelSelectedResolve.setSource(source);
excelSelectedResolve.setFirstRow(selected.firstRow());
excelSelectedResolve.setLastRow(selected.lastRow());
if (property != null && property.index() >= 0) {
selectedMap.put(property.index(), excelSelectedResolve);
} else {
selectedMap.put(i, excelSelectedResolve);
}
}
return selectedMap;
}
/**
* 解析表头类中的配置注解
*
* @param head 表头类
*/
public static List> resolvePropertyAnnotation(Class> head) {
List> list = new ArrayList<>();
if (Objects.isNull(head)) {
return list;
}
// getDeclaredFields(): 返回全部声明的属性;getFields(): 返回public类型的属性
Field[] fields = head.getDeclaredFields();
for (Field field : fields) {
ExcelProperty property = field.getAnnotation(ExcelProperty.class);
if (property != null) {
list.add(Arrays.asList(property.value()));
}
}
return list;
}
/**
* 获取下拉框选项值
*
* @param excelSelected
* @return
*/
private static String[] resolveSelectedSource(ExcelSelected excelSelected) {
if (excelSelected == null) {
return null;
}
// 获取固定下拉框的内容
String[] source = excelSelected.source();
if (source.length > 0) {
return source;
}
// 获取动态下拉框的内容
ExcelDynamicSelectHandler excelDynamicSelectHandler = ExcelDynamicDataStrategyFactory.doStrategy(excelSelected.dynamicData());
if (Objects.nonNull(excelDynamicSelectHandler)) {
return excelDynamicSelectHandler.getSource(excelSelected.dynamicParam());
}
return null;
}
}
为了实现高内聚和低耦合的设计,我们可以创建一个导出功能的工具类EasyExcelUtil,支持动态表头生成、多sheet、下拉列等功能
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
@Slf4j
public class EasyExcelUtil {
/**
* 生成多个sheet
*
* @param response
* @param paramList
* @param fileName
* @throws IOException
*/
public static void exportExcel(HttpServletResponse response, List paramList, String fileName) throws IOException {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName);
try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build()) {
for (EasyExcelExportDynamicParam param : paramList) {
ExcelWriterSheetBuilder writerSheetBuilder = EasyExcel.writerSheet(param.getSheetName())
.head(param.getDynamicHeaderList())
.head(param.getTemplate());
// 样式
Map> styleMap = param.getStyleMap();
if (CollectionUtil.isNotEmpty(styleMap)) {
writerSheetBuilder.registerWriteHandler(new CellStyleSheetWriteHandler(styleMap));
}
// 下拉选择
Map selectedMap =
CollectionUtil.isNotEmpty(param.getSelectedMap()) ? param.getSelectedMap() : ExcelSelectedResolve.resolveSelectedAnnotation(param.getTemplate());
if (CollectionUtil.isNotEmpty(selectedMap)) {
writerSheetBuilder.registerWriteHandler(new SelectedSheetWriteHandler(selectedMap));
}
excelWriter.write(param.getDataList(), writerSheetBuilder.build());
}
excelWriter.finish();
}
}
}
EasyExcel提供了CellWriteHandler
接口,其中的afterCellDispose
方法在单元格写操作完成并销毁后被调用。我们可以通过实现该接口并重写afterCellDispose
方法来实现自定义单元格样式。
在重写的afterCellDispose
方法中,我们可以获取到已经创建好的单元格,并添加自定义的样式。这个方法在每个单元格写操作完成后都会被调用,因此我们可以根据需要对特定的单元格或整个表格进行样式处理。
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.util.StyleUtil;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* excel设置动态列样式处理器
*/
@Data
@AllArgsConstructor
public class CellStyleSheetWriteHandler implements CellWriteHandler {
private static final short DEFAULT_FONT_SIZE = 14;
private static final String DEFAULT_FONT_NAME = "宋体";
private static final short DEFAULT_FONT_COLOR = 8;
private static final short DEFAULT_BG_COLOR = 22;
private Map> styleMap;
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
List> cellDataList, Cell cell, Head head, Integer relativeRowIndex,
Boolean isHead) {
int rowIndex = cell.getRowIndex();
Sheet sheet = cell.getSheet();
Workbook workbook = sheet.getWorkbook();
Row row = sheet.getRow(rowIndex);
int columnIndex = cell.getColumnIndex();
if (isHead) {
// 表头设置自适应列宽
// 获取单元格内容长度(以字符为单位)
String stringCellValue = cell.getStringCellValue();
int contentLength = stringCellValue.length();
// 计算自动调整后的列宽(加上一些额外空间)
int newWidth = contentLength > 10 ? (contentLength + 35) * 256 : (contentLength + 12) * 256;
sheet.setColumnWidth(columnIndex, newWidth);
// 表头设置自适应行高
String[] split = stringCellValue.split("\\n");
if (split != null && split.length > 0) {
setRowHeight(row, (short) ((split.length + 1.2) * 256));
}
}
if (CollectionUtil.isEmpty(styleMap)) {
return;
}
Map indexes = styleMap.get(rowIndex);
if (CollectionUtils.isEmpty(indexes)) {
return;
}
// 自定义样式
setCellStyle(row, cell, workbook, indexes.get(columnIndex));
}
/**
* 自定义样式
*
* @param cell
* @param workbook
* @param styleParam
*/
private void setCellStyle(Row row, Cell cell, Workbook workbook, EasyExcelExportDynamicStyleParam styleParam) {
if (Objects.isNull(styleParam)) {
return;
}
// 字体
Font font = workbook.createFont();
font.setFontName(StringUtils.isNotBlank(styleParam.getFontName()) ? styleParam.getFontName() : DEFAULT_FONT_NAME);
font.setFontHeightInPoints(Objects.nonNull(styleParam.getFontSize()) ? styleParam.getFontSize() : DEFAULT_FONT_SIZE);
font.setBold(true);
font.setColor(Objects.nonNull(styleParam.getFontColor()) ? styleParam.getFontColor() : DEFAULT_FONT_COLOR);
WriteCellStyle writeCellStyle = new WriteCellStyle();
writeCellStyle.setFillForegroundColor(Objects.nonNull(styleParam.getBgColor()) ? styleParam.getBgColor() : DEFAULT_BG_COLOR);
writeCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
writeCellStyle.setWrapped(true);
CellStyle cellStyle = workbook.createCellStyle();
// 克隆原有样式属性
cellStyle.cloneStyleFrom(cell.getCellStyle());
CellStyle newCellStyle = StyleUtil.buildCellStyle(workbook, cellStyle, writeCellStyle);
newCellStyle.setFont(font);
if (Objects.nonNull(styleParam.getAlignment())) {
newCellStyle.setAlignment(styleParam.getAlignment());
}
// 设置新样式
cell.setCellStyle(newCellStyle);
}
/**
* 设置行高
*
* @param row
* @param height
*/
private void setRowHeight(Row row, short height) {
if (row != null) {
row.setHeight(height);
}
}
/**
* 写入器排序问题AbstractCellWriteHandler使用的默认序号是0,
* EasyExcel自己的样式填充器FillStyleCellWriteHandler使用序号是50000(可在OrderConstant类中查到),
* 也就是说我们在这个类中重写样式时又被easy excel重写回去了。
* 解决方法是重写order方法使其大于50000 即可。
*
* @return
*/
@Override
public int order() {
return 1000000;
}
建一个名为SelectedSheetWriteHandler的类,并实现com.alibaba.excel.write.handler.SheetWriteHandler接口。这个接口中定义了一些回调方法,允许你在生成Excel文件的过程中进行自定义处理。
重写afterSheetCreate方法:在SelectedSheetWriteHandler类中,实现afterSheetCreate方法。这个方法会在每个Sheet创建完成后被调用,我们可以在这里进行下拉列表的处理。我们可以在每个Sheet创建完成后,为指定的单元格添加下拉列表,并设置数据源。这样,我们就能更好地控制用户在Excel中输入的数据,提高数据的准确性和一致性。
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddressList;
import java.util.Map;
import java.util.Objects;
/**
* excel设置下拉选项处理器
*/
@Data
@AllArgsConstructor
public class SelectedSheetWriteHandler implements SheetWriteHandler {
private final Map selectedMap;
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
if (CollectionUtil.isEmpty(selectedMap)) {
return;
}
// 这里可以对cell进行任何操作
Sheet sheet = writeSheetHolder.getSheet();
DataValidationHelper helper = sheet.getDataValidationHelper();
selectedMap.forEach((k, v) -> {
if (Objects.isNull(v)) {
return;
}
// 设置下拉列表的行: 首行,末行,首列,末列
CellRangeAddressList rangeList = new CellRangeAddressList(v.getFirstRow(), v.getLastRow(), k, k);
// 设置下拉列表的值
DataValidationConstraint constraint = helper.createExplicitListConstraint(v.getSource());
// 设置约束
DataValidation validation = helper.createValidation(constraint, rangeList);
// 阻止输入非下拉选项的值
validation.setErrorStyle(DataValidation.ErrorStyle.STOP);
validation.setShowErrorBox(true);
validation.setSuppressDropDownArrow(true);
validation.createErrorBox("提示", "请输入下拉选项中的内容");
sheet.addValidationData(validation);
});
}
}
import com.alibaba.excel.annotation.ExcelProperty;
import com.yt.bi.goods.common.annotation.ExcelSelected;
import com.yt.bi.goods.common.constant.ExcelConstants;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
public class ProductSkuUpdateBasicsTemplateDTO implements Serializable {
private static final long serialVersionUID = 1L;
// 字符串的头背景设置成黄色 IndexedColors.PINK.getIndex()
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "*SKU"}, index = 0)
private String sku;
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "产品名称"}, index = 1)
private String productName;
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "末级品类编码"}, index = 2)
private String categoryCodeLast;
@ExcelSelected(dynamicData = "bi_dict", dynamicParam = "product_origin_receiving", firstRow = 3)
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "头程方式"}, index = 3)
private String originReceiving;
@ApiModelProperty("是否有配件 1是 0否")
@ExcelSelected(source = {"是", "否"}, firstRow = 3)
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "是否包含配件"}, index = 4)
private String haveParts;
@ApiModelProperty("是否反倾销 1=是; 0=否;")
@ExcelSelected(source = {"是", "否"}, firstRow = 3)
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "是否反倾销"}, index = 5)
private String antiDumpingFlag;
@ApiModelProperty("是否带电 1是 0否")
@ExcelSelected(source = {"是", "否"}, firstRow = 3)
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "是否带电"}, index = 6)
private String electrifyFlag;
@ApiModelProperty("主项目组")
@ExcelSelected(dynamicData = "erp_dict", dynamicParam = "main_project_team", firstRow = 3)
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "主项目组"}, index = 7)
private String mainProjectTeam;
@ApiModelProperty("输入电压")
@ExcelSelected(dynamicData = "sku_voltage", firstRow = 3)
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "输入电压"}, index = 8)
private String voltage;
@ApiModelProperty("产品开发人员")
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "产品开发人员工号(多个人员请用&隔开)"}, index = 9)
private String productDeveloper;
}
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadFontStyle;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import com.alibaba.excel.enums.BooleanEnum;
import lombok.Data;
import java.io.Serializable;
@HeadFontStyle(
fontName = "宋体",
color = Short.MAX_VALUE,
fontHeightInPoints = 14
)
@HeadRowHeight(value = 30)
@ContentRowHeight(value = 20)
@ColumnWidth(value = 15)
@Data
public class DeveloperTemplateDTO implements Serializable {
@ExcelProperty({"工号"})
private String accountName;
@ExcelProperty({"人员名称"})
private String userName;
}
其中ProductSkuUpdateBasicsTemplateDTO模版类种的haveParts等字段为固定值下拉列表,mainProjectTeam等字段为动态值下拉列表,动态下拉列表数据提供示例如下:
/**
* ERP数据字典处理类
*/
@Slf4j
@Component
@ExcelDynamicData(name = "erp_dict")
public class ErpDictDataRpcHandle implements ExcelDynamicSelectHandler {
/**
* 查询字典信息
*
* @param param
* @return
*/
@Override
public String[] getSource(String dictType) {
if (StringUtils.isBlank(param)) {
return new String[0];
}
ErpDictDataQuery query = new ErpDictDataQuery();
query.setTopFlag(Constants.ZERO);
query.setDictType(dictType);
List dictDataDTOList = erpDictList(query);// 查询数据库或其他方式获取数据
if (CollectionUtils.isNotEmpty(dictDataDTOList)) {
return dictDataDTOList.stream().map(ErpDictDataDTO::getDictLabel).toArray(String[]::new);
}
return new String[0];
}
}
public void batchUpdateSkuImportTemplate(HttpServletResponse response) throws IOException {
// 导入数据页
List paramList = new ArrayList<>();
EasyExcelExportDynamicParam param = new EasyExcelExportDynamicParam();
param.setSheetName("导入数据页");
param.setTemplate(ProductSkuUpdateBasicsTemplateDTO.class);
param.setDataList(new ArrayList<>());
// 构建样式,第三行,第一列背景色黄色,字体红色
buildStyle(param);
paramList.add(param);
// 人员对照表
EasyExcelExportDynamicParam developerParam = new EasyExcelExportDynamicParam();
developerParam.setSheetName("人员对照表");
developerParam.setTemplate(DeveloperTemplateDTO.class);
List templateDTOList = new ArrayList<>();
developerParam.setDataList(templateDTOList);
paramList.add(developerParam);
EasyExcelUtil.exportExcel(response, paramList, "多sheet页导出");
}
/**
* 样式
*
* @param param
*/
private void buildStyle(EasyExcelExportDynamicParam param) {
Map> rowStyleMap = new HashMap<>();
Map oneRowMap = new HashMap<>();
Map twoRowMap = new HashMap<>();
Map threeRowMap = new HashMap<>();
EasyExcelExportDynamicStyleParam oneRowParam = EasyExcelExportDynamicStyleParam.builder()
.bgColor(IndexedColors.WHITE.getIndex()).alignment(HorizontalAlignment.LEFT)
.build();
oneRowMap.put(0, oneRowParam);
EasyExcelExportDynamicStyleParam twoRowParam = EasyExcelExportDynamicStyleParam.builder()
.bgColor(IndexedColors.PALE_BLUE.getIndex())
.build();
twoRowMap.put(0, twoRowParam);
EasyExcelExportDynamicStyleParam threeRowParam = EasyExcelExportDynamicStyleParam.builder()
.bgColor(IndexedColors.YELLOW.getIndex())
.fontColor(IndexedColors.RED.getIndex())
.build();
threeRowMap.put(0, threeRowParam);
rowStyleMap.put(0, oneRowMap);
rowStyleMap.put(1, twoRowMap);
rowStyleMap.put(2, threeRowMap);
param.setStyleMap(rowStyleMap);
}
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.*;
import com.alibaba.excel.enums.BooleanEnum;
import com.alibaba.excel.enums.poi.FillPatternTypeEnum;
import com.yt.bi.goods.common.annotation.ExcelSelected;
import com.yt.bi.goods.common.constant.ExcelConstants;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
public class ProductAddNormalSkuBasicsTemplateDTO implements Serializable {
private static final long serialVersionUID = 1L;
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "*国家"}, index = 0)
private String country;
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "*序列"}, index = 1)
private String series;
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "*产品名称"}, index = 2)
private String productName;
@ExcelSelected(dynamicData = "bi_dict", dynamicParam = "product_origin_receiving", firstRow = 3)
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "*头程方式"}, index = 3)
private String originReceiving;
@ApiModelProperty("是否有配件 1是 0否")
@ExcelSelected(source = {"是", "否"}, firstRow = 3)
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "*是否包含配件"}, index = 4)
private String haveParts;
@ApiModelProperty("是否反倾销 1=是; 0=否;")
@ExcelSelected(source = {"是", "否"}, firstRow = 3)
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "*是否反倾销"}, index = 5)
private String antiDumpingFlag;
@ApiModelProperty("主项目组")
@ExcelSelected(dynamicData = "erp_dict", dynamicParam = "main_project_team", firstRow = 3)
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "*主项目组"}, index = 6)
private String mainProjectTeam;
@ApiModelProperty("是否带电 1是 0否")
@ExcelSelected(source = {"是", "否"}, firstRow = 3)
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "*是否带电"}, index = 7)
private String electrifyFlag;
@ExcelSelected(dynamicData = "sku_voltage", firstRow = 3)
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "输入电压"}, index = 8)
private String voltage;
@ApiModelProperty("产品开发人员")
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "产品开发人员工号(多个人员请用&隔开)"}, index = 9)
private String productDeveloper;
@ApiModelProperty("备注")
@ExcelProperty(value = {"导入说明:\n" +, "基础信息", "备注"}, index = 10)
private String remark;
}
@HeadFontStyle(
fontName = "宋体",
color = Short.MAX_VALUE,
fontHeightInPoints = 14
)
@HeadRowHeight(value = 30)
@ContentRowHeight(value = 20)
@ColumnWidth(value = 15)
@Data
public class DeveloperTemplateDTO implements Serializable {
@ExcelProperty({"工号"})
private String accountName;
@ExcelProperty({"人员名称"})
private String userName;
}
其中ProductAddNormalSkuBasicsTemplateDTO模版类种的haveParts等字段为固定值下拉列表,mainProjectTeam等字段为动态值下拉列表,动态下拉列表数据提供示例如下:
/**
* ERP数据字典处理类
*/
@Slf4j
@Component
@ExcelDynamicData(name = "erp_dict")
public class ErpDictDataRpcHandle implements ExcelDynamicSelectHandler {
/**
* 查询字典信息
*
* @param param
* @return
*/
@Override
public String[] getSource(String dictType) {
if (StringUtils.isBlank(param)) {
return new String[0];
}
ErpDictDataQuery query = new ErpDictDataQuery();
query.setTopFlag(Constants.ZERO);
query.setDictType(dictType);
List dictDataDTOList = erpDictList(query);// 查询数据库或其他方式获取数据
if (CollectionUtils.isNotEmpty(dictDataDTOList)) {
return dictDataDTOList.stream().map(ErpDictDataDTO::getDictLabel).toArray(String[]::new);
}
return new String[0];
}
}
public void batchAddSkuImportTemplate(HttpServletResponse response) {
List paramList = new ArrayList<>();
EasyExcelExportDynamicParam param = new EasyExcelExportDynamicParam();
// 生成基础信息表头
List> listList = ExcelSelectedResolve.resolvePropertyAnnotation(ProductAddNormalSkuBasicsTemplateDTO.class);
// 查询品类属性
ProductCategoryAttributeValueDTO attributeValueDTO = productCategoryAttributeService.queryCategoryAttributeByCategoryCode(categoryCodeLast);
// 生成规格属性表头
List specAttributeList = attributeValueDTO.getSpecAttributeList();
if (CollectionUtil.isNotEmpty(specAttributeList)) {
List> attributeNameList = specAttributeList.stream().map(x -> Arrays.asList("导入说明:\n" +, "产品属性-规格属性", attributeNameRequiredFlag(x))).collect(Collectors.toList());
listList.addAll(attributeNameList);
}
// 生成销售属性表头
List salesAttributeList = attributeValueDTO.getSalesAttributeList();
if (CollectionUtil.isNotEmpty(salesAttributeList)) {
List> attributeNameList = salesAttributeList.stream().map(x -> Arrays.asList("导入说明:\n" +, "产品属性-销售属性", attributeNameRequiredFlag(x))).collect(Collectors.toList());
listList.addAll(attributeNameList);
}
// 生成标签属性表头
List tagAttributeList = attributeValueDTO.getTagAttributeList();
if (CollectionUtil.isNotEmpty(tagAttributeList)) {
List> attributeNameList = tagAttributeList.stream().map(x -> Arrays.asList("导入说明:\n" +, "产品属性-标签属性", attributeNameRequiredFlag(x))).collect(Collectors.toList());
listList.addAll(attributeNameList);
}
// 设置颜色
Map> styleMap = new HashMap<>();
Map paramMap = new HashMap<>();
// 判断第三行带*号列明都加上颜色
Integer num = Constants.ZERO;
for (List line : listList) {
String secondLineName = line.get(2);
if (secondLineName.startsWith("*")) {
EasyExcelExportDynamicStyleParam styleParam = EasyExcelExportDynamicStyleParam.builder()
.bgColor(IndexedColors.YELLOW.getIndex())
.fontColor(IndexedColors.RED.getIndex())
.build();
paramMap.put(num, styleParam);
}
num++;
}
styleMap.put(2, paramMap);
Map one = new HashMap<>();
EasyExcelExportDynamicStyleParam oneParam = EasyExcelExportDynamicStyleParam.builder()
.bgColor(IndexedColors.WHITE.getIndex())
.alignment(HorizontalAlignment.LEFT)
.build();
one.put(0, oneParam);
styleMap.put(0, one);
param.setStyleMap(styleMap);
param.setDataList(new ArrayList<>());
param.setDynamicHeaderList(listList);
// 生成基础信息下拉
Map head = ExcelSelectedResolve.resolveSelectedAnnotation(clazz);
param.setSelectedMap(head);
param.setSheetName("导入数据页");
paramList.add(param);
// 人员对照表
EasyExcelExportDynamicParam developerParam = new EasyExcelExportDynamicParam();
developerParam.setSheetName("人员对照表");
developerParam.setTemplate(DeveloperTemplateDTO.class);
List templateDTOList = new ArrayList<>();
developerParam.setDataList(templateDTOList);
paramList.add(developerParam);
EasyExcelUtil.exportExcel(response, paramList, "多sheet页导出");
}
注意:当使用动态表头和固定表头组合生成时,需要统一把表头单元格字段内容写入到List> 当中。