• Spring Boot集成EasyExcel实现数据导出


            在本文中,我们将探讨如何使用Spring Boot集成EasyExcel库来实现数据导出功能。我们将学习如何通过EasyExcel库生成Excel文件,并实现一些高级功能,如支持列下拉和自定义单元格样式,自适应列宽、行高,动态表头 ,以及如何同时导出多个sheet页的数据。

    引入依赖

            首先,我们需要在pom.xml文件中添加EasyExcel和相关的依赖项

    1. <dependency>
    2. <groupId>org.apache.poigroupId>
    3. <artifactId>poi-ooxmlartifactId>
    4. <version>4.1.2version>
    5. dependency>
    6. <dependency>
    7. <groupId>com.alibabagroupId>
    8. <artifactId>easyexcelartifactId>
    9. <version>3.2.1version>
    10. dependency>
    11. <dependency>
    12. <groupId>org.apache.poigroupId>
    13. <artifactId>poiartifactId>
    14. <version>4.1.2version>
    15. dependency>

    创建参数类

     动态生成EXCEL参数类

            支持sheet名称、模版类、动态表头、数据集、下拉列、单元格样式定义。

    1. import lombok.Data;
    2. import java.io.Serializable;
    3. import java.util.List;
    4. import java.util.Map;
    5. /**
    6. *

      导出动态参数

    7. */
    8. @Data
    9. public class EasyExcelExportDynamicParam implements Serializable {
    10. /**
    11. * sheet名称
    12. */
    13. private String sheetName;
    14. /**
    15. * 模版
    16. */
    17. private Class template;
    18. /**
    19. * 数据集
    20. */
    21. private List dataList;
    22. /**
    23. * 动态表头
    24. */
    25. private List> dynamicHeaderList;
    26. /**
    27. * 单元格样式map,key为行下标,
    28. * Map key为列下标
    29. */
    30. private Map> styleMap;
    31. /**
    32. * 下拉选项 key为列下标
    33. */
    34. private Map selectedMap;
    35. }

    单元格样式参数类

            支持字体颜色、背景颜色、字体、字体大小、单元格内容对齐方式。

    1. import lombok.AllArgsConstructor;
    2. import lombok.Builder;
    3. import lombok.Data;
    4. import lombok.NoArgsConstructor;
    5. import org.apache.poi.ss.usermodel.HorizontalAlignment;
    6. import java.io.Serializable;
    7. /**
    8. *

      EasyExcel导出动态单元格样式

    9. */
    10. @Data
    11. @Builder
    12. @AllArgsConstructor
    13. @NoArgsConstructor
    14. public class EasyExcelExportDynamicStyleParam implements Serializable {
    15. /**
    16. * 字体颜色 IndexedColors.WHITE.getIndex()
    17. */
    18. private Short fontColor;
    19. /**
    20. * 背景颜色
    21. */
    22. private Short bgColor;
    23. /**
    24. * 字体
    25. */
    26. private String fontName;
    27. /**
    28. * 字体大小
    29. */
    30. private Short fontSize;
    31. /**
    32. * 单元格内容对齐方式
    33. */
    34. private HorizontalAlignment alignment;
    35. }

     单元格添加下拉列表配置

            支持注解方式设置单元格下拉列表,起始行、结束行、固定下拉内容、动态下拉内容。

    1. import java.lang.annotation.*;
    2. /**
    3. *

      excel动态下拉框数据填充

    4. */
    5. @Documented
    6. @Target({ElementType.FIELD})
    7. @Retention(RetentionPolicy.RUNTIME)
    8. public @interface ExcelSelected {
    9. /**
    10. * 固定下拉内容
    11. */
    12. String[] source() default {};
    13. /**
    14. * 动态下拉内容服务类
    15. */
    16. String dynamicData() default "";
    17. /**
    18. * 动态下拉内容参数
    19. *
    20. * @return
    21. */
    22. String dynamicParam() default "";
    23. /**
    24. * 设置下拉框的起始行,默认为第二行
    25. */
    26. int firstRow() default 1;
    27. /**
    28. * 设置下拉框的结束行,默认10000行
    29. */
    30. int lastRow() default 5000;
    31. }
    32. /**
    33. *

      excel动态下拉框数据服务提供者

    34. */
    35. @Target(ElementType.TYPE)
    36. @Retention(RetentionPolicy.RUNTIME)
    37. public @interface ExcelDynamicData {
    38. /**
    39. * 提供数据的服务名
    40. *
    41. * @return
    42. */
    43. String name();
    44. }
    45. /**
    46. *

    47. */
    48. public interface ExcelDynamicSelectHandler {
    49. /**
    50. * 获取动态生成的下拉框可选数据
    51. * @return 动态生成的下拉框可选数据
    52. */
    53. String[] getSource(String param);
    54. }
    55. @Slf4j
    56. @Component
    57. public class ExcelDynamicDataStrategyFactory {
    58. /**
    59. * 初始化BEAN_MAP,获取ExcelDynamicSelectService接口下所有实现类
    60. */
    61. private static Map BEAN_MAP;
    62. /**
    63. * 执行策略
    64. *
    65. * @param name
    66. * @return
    67. */
    68. public static ExcelDynamicSelectHandler doStrategy(String name) {
    69. if(CollectionUtils.isEmpty(BEAN_MAP)){
    70. BEAN_MAP = SpringUtils.getBeansOfType(ExcelDynamicSelectHandler.class);
    71. }
    72. // 1:ExcelDynamicSelect接口实现类为空
    73. if (StringUtils.isBlank(name) || CollectionUtils.isEmpty(BEAN_MAP)) {
    74. log.warn("策略实现类不存在,type = {}", name);
    75. return null;
    76. }
    77. try {
    78. // 2:循环ExcelDynamicSelect接口实现类
    79. for (Map.Entry entry : BEAN_MAP.entrySet()) {
    80. Class targetClass = AopUtils.getTargetClass(entry.getValue());
    81. // 3:获取类上的excel动态下拉框数据服务策略注解
    82. ExcelDynamicData annotation = targetClass.getAnnotation(ExcelDynamicData.class);
    83. if (null == annotation) {
    84. continue;
    85. }
    86. // 4:当前name等注解指定的name时返回实现类
    87. if (name.equals(annotation.name())) {
    88. return entry.getValue();
    89. }
    90. }
    91. } catch (Exception e) {
    92. log.error("获取excel动态下拉框数据服务策略实现类失败,name = {}", name, e);
    93. }
    94. return null;
    95. }
    96. }
    97. import com.alibaba.excel.annotation.ExcelProperty;
    98. import com.yt.bi.goods.common.annotation.ExcelSelected;
    99. import lombok.Data;
    100. import lombok.extern.slf4j.Slf4j;
    101. import java.lang.reflect.Field;
    102. import java.util.*;
    103. /**
    104. *

      自定义ExcelSelected注解解析

    105. */
    106. @Data
    107. @Slf4j
    108. public class ExcelSelectedResolve {
    109. /**
    110. * 下拉内容
    111. */
    112. private String[] source;
    113. /**
    114. * 设置下拉框的起始行,默认为第二行
    115. */
    116. private int firstRow = 1;
    117. /**
    118. * 设置下拉框的结束行
    119. */
    120. private int lastRow = 2000;
    121. /**
    122. * 解析表头类中的下拉注解
    123. *
    124. * @param head 表头类
    125. * @return Map<下拉框列索引, 下拉框内容> map
    126. */
    127. public static Map resolveSelectedAnnotation(Class head) {
    128. Map selectedMap = new HashMap<>();
    129. if (Objects.isNull(head)) {
    130. return selectedMap;
    131. }
    132. // getDeclaredFields(): 返回全部声明的属性;getFields(): 返回public类型的属性
    133. Field[] fields = head.getDeclaredFields();
    134. for (int i = 0; i < fields.length; i++) {
    135. Field field = fields[i];
    136. // 解析注解信息
    137. ExcelSelected selected = field.getAnnotation(ExcelSelected.class);
    138. ExcelProperty property = field.getAnnotation(ExcelProperty.class);
    139. if (selected == null) {
    140. continue;
    141. }
    142. String[] source = resolveSelectedSource(selected);
    143. if (source == null || source.length == 0) {
    144. continue;
    145. }
    146. ExcelSelectedResolve excelSelectedResolve = new ExcelSelectedResolve();
    147. excelSelectedResolve.setSource(source);
    148. excelSelectedResolve.setFirstRow(selected.firstRow());
    149. excelSelectedResolve.setLastRow(selected.lastRow());
    150. if (property != null && property.index() >= 0) {
    151. selectedMap.put(property.index(), excelSelectedResolve);
    152. } else {
    153. selectedMap.put(i, excelSelectedResolve);
    154. }
    155. }
    156. return selectedMap;
    157. }
    158. /**
    159. * 解析表头类中的配置注解
    160. *
    161. * @param head 表头类
    162. */
    163. public static List> resolvePropertyAnnotation(Class head) {
    164. List> list = new ArrayList<>();
    165. if (Objects.isNull(head)) {
    166. return list;
    167. }
    168. // getDeclaredFields(): 返回全部声明的属性;getFields(): 返回public类型的属性
    169. Field[] fields = head.getDeclaredFields();
    170. for (Field field : fields) {
    171. ExcelProperty property = field.getAnnotation(ExcelProperty.class);
    172. if (property != null) {
    173. list.add(Arrays.asList(property.value()));
    174. }
    175. }
    176. return list;
    177. }
    178. /**
    179. * 获取下拉框选项值
    180. *
    181. * @param excelSelected
    182. * @return
    183. */
    184. private static String[] resolveSelectedSource(ExcelSelected excelSelected) {
    185. if (excelSelected == null) {
    186. return null;
    187. }
    188. // 获取固定下拉框的内容
    189. String[] source = excelSelected.source();
    190. if (source.length > 0) {
    191. return source;
    192. }
    193. // 获取动态下拉框的内容
    194. ExcelDynamicSelectHandler excelDynamicSelectHandler = ExcelDynamicDataStrategyFactory.doStrategy(excelSelected.dynamicData());
    195. if (Objects.nonNull(excelDynamicSelectHandler)) {
    196. return excelDynamicSelectHandler.getSource(excelSelected.dynamicParam());
    197. }
    198. return null;
    199. }
    200. }

    创建导出功能工具类

            为了实现高内聚和低耦合的设计,我们可以创建一个导出功能的工具类EasyExcelUtil,支持动态表头生成、多sheet、下拉列等功能

    1. import cn.hutool.core.collection.CollectionUtil;
    2. import com.alibaba.excel.EasyExcel;
    3. import com.alibaba.excel.ExcelWriter;
    4. import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
    5. import lombok.extern.slf4j.Slf4j;
    6. import javax.servlet.http.HttpServletResponse;
    7. import java.io.IOException;
    8. import java.net.URLEncoder;
    9. import java.util.List;
    10. import java.util.Map;
    11. @Slf4j
    12. public class EasyExcelUtil {
    13. /**
    14. * 生成多个sheet
    15. *
    16. * @param response
    17. * @param paramList
    18. * @param fileName
    19. * @throws IOException
    20. */
    21. public static void exportExcel(HttpServletResponse response, List paramList, String fileName) throws IOException {
    22. response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    23. response.setCharacterEncoding("utf-8");
    24. fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
    25. response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
    26. response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName);
    27. try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build()) {
    28. for (EasyExcelExportDynamicParam param : paramList) {
    29. ExcelWriterSheetBuilder writerSheetBuilder = EasyExcel.writerSheet(param.getSheetName())
    30. .head(param.getDynamicHeaderList())
    31. .head(param.getTemplate());
    32. // 样式
    33. Map> styleMap = param.getStyleMap();
    34. if (CollectionUtil.isNotEmpty(styleMap)) {
    35. writerSheetBuilder.registerWriteHandler(new CellStyleSheetWriteHandler(styleMap));
    36. }
    37. // 下拉选择
    38. Map selectedMap =
    39. CollectionUtil.isNotEmpty(param.getSelectedMap()) ? param.getSelectedMap() : ExcelSelectedResolve.resolveSelectedAnnotation(param.getTemplate());
    40. if (CollectionUtil.isNotEmpty(selectedMap)) {
    41. writerSheetBuilder.registerWriteHandler(new SelectedSheetWriteHandler(selectedMap));
    42. }
    43. excelWriter.write(param.getDataList(), writerSheetBuilder.build());
    44. }
    45. excelWriter.finish();
    46. }
    47. }
    48. }

    使用CellWriteHandler实现自定义单元格样式

            EasyExcel提供了CellWriteHandler接口,其中的afterCellDispose方法在单元格写操作完成并销毁后被调用。我们可以通过实现该接口并重写afterCellDispose方法来实现自定义单元格样式。

            在重写的afterCellDispose方法中,我们可以获取到已经创建好的单元格,并添加自定义的样式。这个方法在每个单元格写操作完成后都会被调用,因此我们可以根据需要对特定的单元格或整个表格进行样式处理。

    1. import cn.hutool.core.collection.CollectionUtil;
    2. import com.alibaba.excel.metadata.Head;
    3. import com.alibaba.excel.metadata.data.WriteCellData;
    4. import com.alibaba.excel.util.StyleUtil;
    5. import com.alibaba.excel.write.handler.CellWriteHandler;
    6. import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
    7. import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
    8. import com.alibaba.excel.write.metadata.style.WriteCellStyle;
    9. import lombok.AllArgsConstructor;
    10. import lombok.Data;
    11. import org.apache.commons.lang3.StringUtils;
    12. import org.apache.poi.ss.usermodel.*;
    13. import org.springframework.util.CollectionUtils;
    14. import java.util.List;
    15. import java.util.Map;
    16. import java.util.Objects;
    17. /**
    18. *

      excel设置动态列样式处理器

    19. */
    20. @Data
    21. @AllArgsConstructor
    22. public class CellStyleSheetWriteHandler implements CellWriteHandler {
    23. private static final short DEFAULT_FONT_SIZE = 14;
    24. private static final String DEFAULT_FONT_NAME = "宋体";
    25. private static final short DEFAULT_FONT_COLOR = 8;
    26. private static final short DEFAULT_BG_COLOR = 22;
    27. private Map> styleMap;
    28. @Override
    29. public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
    30. List> cellDataList, Cell cell, Head head, Integer relativeRowIndex,
    31. Boolean isHead) {
    32. int rowIndex = cell.getRowIndex();
    33. Sheet sheet = cell.getSheet();
    34. Workbook workbook = sheet.getWorkbook();
    35. Row row = sheet.getRow(rowIndex);
    36. int columnIndex = cell.getColumnIndex();
    37. if (isHead) {
    38. // 表头设置自适应列宽
    39. // 获取单元格内容长度(以字符为单位)
    40. String stringCellValue = cell.getStringCellValue();
    41. int contentLength = stringCellValue.length();
    42. // 计算自动调整后的列宽(加上一些额外空间)
    43. int newWidth = contentLength > 10 ? (contentLength + 35) * 256 : (contentLength + 12) * 256;
    44. sheet.setColumnWidth(columnIndex, newWidth);
    45. // 表头设置自适应行高
    46. String[] split = stringCellValue.split("\\n");
    47. if (split != null && split.length > 0) {
    48. setRowHeight(row, (short) ((split.length + 1.2) * 256));
    49. }
    50. }
    51. if (CollectionUtil.isEmpty(styleMap)) {
    52. return;
    53. }
    54. Map indexes = styleMap.get(rowIndex);
    55. if (CollectionUtils.isEmpty(indexes)) {
    56. return;
    57. }
    58. // 自定义样式
    59. setCellStyle(row, cell, workbook, indexes.get(columnIndex));
    60. }
    61. /**
    62. * 自定义样式
    63. *
    64. * @param cell
    65. * @param workbook
    66. * @param styleParam
    67. */
    68. private void setCellStyle(Row row, Cell cell, Workbook workbook, EasyExcelExportDynamicStyleParam styleParam) {
    69. if (Objects.isNull(styleParam)) {
    70. return;
    71. }
    72. // 字体
    73. Font font = workbook.createFont();
    74. font.setFontName(StringUtils.isNotBlank(styleParam.getFontName()) ? styleParam.getFontName() : DEFAULT_FONT_NAME);
    75. font.setFontHeightInPoints(Objects.nonNull(styleParam.getFontSize()) ? styleParam.getFontSize() : DEFAULT_FONT_SIZE);
    76. font.setBold(true);
    77. font.setColor(Objects.nonNull(styleParam.getFontColor()) ? styleParam.getFontColor() : DEFAULT_FONT_COLOR);
    78. WriteCellStyle writeCellStyle = new WriteCellStyle();
    79. writeCellStyle.setFillForegroundColor(Objects.nonNull(styleParam.getBgColor()) ? styleParam.getBgColor() : DEFAULT_BG_COLOR);
    80. writeCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
    81. writeCellStyle.setWrapped(true);
    82. CellStyle cellStyle = workbook.createCellStyle();
    83. // 克隆原有样式属性
    84. cellStyle.cloneStyleFrom(cell.getCellStyle());
    85. CellStyle newCellStyle = StyleUtil.buildCellStyle(workbook, cellStyle, writeCellStyle);
    86. newCellStyle.setFont(font);
    87. if (Objects.nonNull(styleParam.getAlignment())) {
    88. newCellStyle.setAlignment(styleParam.getAlignment());
    89. }
    90. // 设置新样式
    91. cell.setCellStyle(newCellStyle);
    92. }
    93. /**
    94. * 设置行高
    95. *
    96. * @param row
    97. * @param height
    98. */
    99. private void setRowHeight(Row row, short height) {
    100. if (row != null) {
    101. row.setHeight(height);
    102. }
    103. }
    104. /**
    105. * 写入器排序问题AbstractCellWriteHandler使用的默认序号是0,
    106. * EasyExcel自己的样式填充器FillStyleCellWriteHandler使用序号是50000(可在OrderConstant类中查到),
    107. * 也就是说我们在这个类中重写样式时又被easy excel重写回去了。
    108. * 解决方法是重写order方法使其大于50000 即可。
    109. *
    110. * @return
    111. */
    112. @Override
    113. public int order() {
    114. return 1000000;
    115. }

     使用SheetWriteHandler实现自定义下拉列表处理

            建一个名为SelectedSheetWriteHandler的类,并实现com.alibaba.excel.write.handler.SheetWriteHandler接口。这个接口中定义了一些回调方法,允许你在生成Excel文件的过程中进行自定义处理。
            重写afterSheetCreate方法:在SelectedSheetWriteHandler类中,实现afterSheetCreate方法。这个方法会在每个Sheet创建完成后被调用,我们可以在这里进行下拉列表的处理。我们可以在每个Sheet创建完成后,为指定的单元格添加下拉列表,并设置数据源。这样,我们就能更好地控制用户在Excel中输入的数据,提高数据的准确性和一致性。

    1. import cn.hutool.core.collection.CollectionUtil;
    2. import com.alibaba.excel.write.handler.SheetWriteHandler;
    3. import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
    4. import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
    5. import lombok.AllArgsConstructor;
    6. import lombok.Data;
    7. import org.apache.poi.ss.usermodel.DataValidation;
    8. import org.apache.poi.ss.usermodel.DataValidationConstraint;
    9. import org.apache.poi.ss.usermodel.DataValidationHelper;
    10. import org.apache.poi.ss.usermodel.Sheet;
    11. import org.apache.poi.ss.util.CellRangeAddressList;
    12. import java.util.Map;
    13. import java.util.Objects;
    14. /**
    15. *

      excel设置下拉选项处理器

    16. */
    17. @Data
    18. @AllArgsConstructor
    19. public class SelectedSheetWriteHandler implements SheetWriteHandler {
    20. private final Map selectedMap;
    21. @Override
    22. public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
    23. if (CollectionUtil.isEmpty(selectedMap)) {
    24. return;
    25. }
    26. // 这里可以对cell进行任何操作
    27. Sheet sheet = writeSheetHolder.getSheet();
    28. DataValidationHelper helper = sheet.getDataValidationHelper();
    29. selectedMap.forEach((k, v) -> {
    30. if (Objects.isNull(v)) {
    31. return;
    32. }
    33. // 设置下拉列表的行: 首行,末行,首列,末列
    34. CellRangeAddressList rangeList = new CellRangeAddressList(v.getFirstRow(), v.getLastRow(), k, k);
    35. // 设置下拉列表的值
    36. DataValidationConstraint constraint = helper.createExplicitListConstraint(v.getSource());
    37. // 设置约束
    38. DataValidation validation = helper.createValidation(constraint, rangeList);
    39. // 阻止输入非下拉选项的值
    40. validation.setErrorStyle(DataValidation.ErrorStyle.STOP);
    41. validation.setShowErrorBox(true);
    42. validation.setSuppressDropDownArrow(true);
    43. validation.createErrorBox("提示", "请输入下拉选项中的内容");
    44. sheet.addValidationData(validation);
    45. });
    46. }
    47. }

    使用示例

    示例一(多sheet页固定表头,支持动态下拉列表)

    1:定义模版类

    1. import com.alibaba.excel.annotation.ExcelProperty;
    2. import com.yt.bi.goods.common.annotation.ExcelSelected;
    3. import com.yt.bi.goods.common.constant.ExcelConstants;
    4. import io.swagger.annotations.ApiModelProperty;
    5. import lombok.Data;
    6. import java.io.Serializable;
    7. @Data
    8. public class ProductSkuUpdateBasicsTemplateDTO implements Serializable {
    9. private static final long serialVersionUID = 1L;
    10. // 字符串的头背景设置成黄色 IndexedColors.PINK.getIndex()
    11. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "*SKU"}, index = 0)
    12. private String sku;
    13. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "产品名称"}, index = 1)
    14. private String productName;
    15. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "末级品类编码"}, index = 2)
    16. private String categoryCodeLast;
    17. @ExcelSelected(dynamicData = "bi_dict", dynamicParam = "product_origin_receiving", firstRow = 3)
    18. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "头程方式"}, index = 3)
    19. private String originReceiving;
    20. @ApiModelProperty("是否有配件 1是 0否")
    21. @ExcelSelected(source = {"是", "否"}, firstRow = 3)
    22. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "是否包含配件"}, index = 4)
    23. private String haveParts;
    24. @ApiModelProperty("是否反倾销 1=是; 0=否;")
    25. @ExcelSelected(source = {"是", "否"}, firstRow = 3)
    26. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "是否反倾销"}, index = 5)
    27. private String antiDumpingFlag;
    28. @ApiModelProperty("是否带电 1是 0否")
    29. @ExcelSelected(source = {"是", "否"}, firstRow = 3)
    30. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "是否带电"}, index = 6)
    31. private String electrifyFlag;
    32. @ApiModelProperty("主项目组")
    33. @ExcelSelected(dynamicData = "erp_dict", dynamicParam = "main_project_team", firstRow = 3)
    34. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "主项目组"}, index = 7)
    35. private String mainProjectTeam;
    36. @ApiModelProperty("输入电压")
    37. @ExcelSelected(dynamicData = "sku_voltage", firstRow = 3)
    38. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "输入电压"}, index = 8)
    39. private String voltage;
    40. @ApiModelProperty("产品开发人员")
    41. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "产品开发人员工号(多个人员请用&隔开)"}, index = 9)
    42. private String productDeveloper;
    43. }
    44. import com.alibaba.excel.annotation.ExcelProperty;
    45. import com.alibaba.excel.annotation.write.style.ColumnWidth;
    46. import com.alibaba.excel.annotation.write.style.ContentRowHeight;
    47. import com.alibaba.excel.annotation.write.style.HeadFontStyle;
    48. import com.alibaba.excel.annotation.write.style.HeadRowHeight;
    49. import com.alibaba.excel.enums.BooleanEnum;
    50. import lombok.Data;
    51. import java.io.Serializable;
    52. @HeadFontStyle(
    53. fontName = "宋体",
    54. color = Short.MAX_VALUE,
    55. fontHeightInPoints = 14
    56. )
    57. @HeadRowHeight(value = 30)
    58. @ContentRowHeight(value = 20)
    59. @ColumnWidth(value = 15)
    60. @Data
    61. public class DeveloperTemplateDTO implements Serializable {
    62. @ExcelProperty({"工号"})
    63. private String accountName;
    64. @ExcelProperty({"人员名称"})
    65. private String userName;
    66. }
    其中ProductSkuUpdateBasicsTemplateDTO模版类种的haveParts等字段为固定值下拉列表,mainProjectTeam等字段为动态值下拉列表,动态下拉列表数据提供示例如下:
    1. /**
    2. * ERP数据字典处理类
    3. */
    4. @Slf4j
    5. @Component
    6. @ExcelDynamicData(name = "erp_dict")
    7. public class ErpDictDataRpcHandle implements ExcelDynamicSelectHandler {
    8. /**
    9. * 查询字典信息
    10. *
    11. * @param param
    12. * @return
    13. */
    14. @Override
    15. public String[] getSource(String dictType) {
    16. if (StringUtils.isBlank(param)) {
    17. return new String[0];
    18. }
    19. ErpDictDataQuery query = new ErpDictDataQuery();
    20. query.setTopFlag(Constants.ZERO);
    21. query.setDictType(dictType);
    22. List dictDataDTOList = erpDictList(query);// 查询数据库或其他方式获取数据
    23. if (CollectionUtils.isNotEmpty(dictDataDTOList)) {
    24. return dictDataDTOList.stream().map(ErpDictDataDTO::getDictLabel).toArray(String[]::new);
    25. }
    26. return new String[0];
    27. }
    28. }

    2:构建导出参数

    1. public void batchUpdateSkuImportTemplate(HttpServletResponse response) throws IOException {
    2. // 导入数据页
    3. List paramList = new ArrayList<>();
    4. EasyExcelExportDynamicParam param = new EasyExcelExportDynamicParam();
    5. param.setSheetName("导入数据页");
    6. param.setTemplate(ProductSkuUpdateBasicsTemplateDTO.class);
    7. param.setDataList(new ArrayList<>());
    8. // 构建样式,第三行,第一列背景色黄色,字体红色
    9. buildStyle(param);
    10. paramList.add(param);
    11. // 人员对照表
    12. EasyExcelExportDynamicParam developerParam = new EasyExcelExportDynamicParam();
    13. developerParam.setSheetName("人员对照表");
    14. developerParam.setTemplate(DeveloperTemplateDTO.class);
    15. List templateDTOList = new ArrayList<>();
    16. developerParam.setDataList(templateDTOList);
    17. paramList.add(developerParam);
    18. EasyExcelUtil.exportExcel(response, paramList, "多sheet页导出");
    19. }
    20. /**
    21. * 样式
    22. *
    23. * @param param
    24. */
    25. private void buildStyle(EasyExcelExportDynamicParam param) {
    26. Map> rowStyleMap = new HashMap<>();
    27. Map oneRowMap = new HashMap<>();
    28. Map twoRowMap = new HashMap<>();
    29. Map threeRowMap = new HashMap<>();
    30. EasyExcelExportDynamicStyleParam oneRowParam = EasyExcelExportDynamicStyleParam.builder()
    31. .bgColor(IndexedColors.WHITE.getIndex()).alignment(HorizontalAlignment.LEFT)
    32. .build();
    33. oneRowMap.put(0, oneRowParam);
    34. EasyExcelExportDynamicStyleParam twoRowParam = EasyExcelExportDynamicStyleParam.builder()
    35. .bgColor(IndexedColors.PALE_BLUE.getIndex())
    36. .build();
    37. twoRowMap.put(0, twoRowParam);
    38. EasyExcelExportDynamicStyleParam threeRowParam = EasyExcelExportDynamicStyleParam.builder()
    39. .bgColor(IndexedColors.YELLOW.getIndex())
    40. .fontColor(IndexedColors.RED.getIndex())
    41. .build();
    42. threeRowMap.put(0, threeRowParam);
    43. rowStyleMap.put(0, oneRowMap);
    44. rowStyleMap.put(1, twoRowMap);
    45. rowStyleMap.put(2, threeRowMap);
    46. param.setStyleMap(rowStyleMap);
    47. }

     3:导出结果示例

     示例二(多sheet页固定+动态表头,支持动态下拉列表,动态设置单元格格式)

    1:定义固定表头模版类

    1. import com.alibaba.excel.annotation.ExcelProperty;
    2. import com.alibaba.excel.annotation.write.style.*;
    3. import com.alibaba.excel.enums.BooleanEnum;
    4. import com.alibaba.excel.enums.poi.FillPatternTypeEnum;
    5. import com.yt.bi.goods.common.annotation.ExcelSelected;
    6. import com.yt.bi.goods.common.constant.ExcelConstants;
    7. import io.swagger.annotations.ApiModelProperty;
    8. import lombok.Data;
    9. import java.io.Serializable;
    10. @Data
    11. public class ProductAddNormalSkuBasicsTemplateDTO implements Serializable {
    12. private static final long serialVersionUID = 1L;
    13. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "*国家"}, index = 0)
    14. private String country;
    15. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "*序列"}, index = 1)
    16. private String series;
    17. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "*产品名称"}, index = 2)
    18. private String productName;
    19. @ExcelSelected(dynamicData = "bi_dict", dynamicParam = "product_origin_receiving", firstRow = 3)
    20. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "*头程方式"}, index = 3)
    21. private String originReceiving;
    22. @ApiModelProperty("是否有配件 1是 0否")
    23. @ExcelSelected(source = {"是", "否"}, firstRow = 3)
    24. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "*是否包含配件"}, index = 4)
    25. private String haveParts;
    26. @ApiModelProperty("是否反倾销 1=是; 0=否;")
    27. @ExcelSelected(source = {"是", "否"}, firstRow = 3)
    28. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "*是否反倾销"}, index = 5)
    29. private String antiDumpingFlag;
    30. @ApiModelProperty("主项目组")
    31. @ExcelSelected(dynamicData = "erp_dict", dynamicParam = "main_project_team", firstRow = 3)
    32. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "*主项目组"}, index = 6)
    33. private String mainProjectTeam;
    34. @ApiModelProperty("是否带电 1是 0否")
    35. @ExcelSelected(source = {"是", "否"}, firstRow = 3)
    36. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "*是否带电"}, index = 7)
    37. private String electrifyFlag;
    38. @ExcelSelected(dynamicData = "sku_voltage", firstRow = 3)
    39. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "输入电压"}, index = 8)
    40. private String voltage;
    41. @ApiModelProperty("产品开发人员")
    42. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "产品开发人员工号(多个人员请用&隔开)"}, index = 9)
    43. private String productDeveloper;
    44. @ApiModelProperty("备注")
    45. @ExcelProperty(value = {"导入说明:\n" +, "基础信息", "备注"}, index = 10)
    46. private String remark;
    47. }
    48. @HeadFontStyle(
    49. fontName = "宋体",
    50. color = Short.MAX_VALUE,
    51. fontHeightInPoints = 14
    52. )
    53. @HeadRowHeight(value = 30)
    54. @ContentRowHeight(value = 20)
    55. @ColumnWidth(value = 15)
    56. @Data
    57. public class DeveloperTemplateDTO implements Serializable {
    58. @ExcelProperty({"工号"})
    59. private String accountName;
    60. @ExcelProperty({"人员名称"})
    61. private String userName;
    62. }
    其中ProductAddNormalSkuBasicsTemplateDTO模版类种的haveParts等字段为固定值下拉列表,mainProjectTeam等字段为动态值下拉列表,动态下拉列表数据提供示例如下:
    1. /**
    2. * ERP数据字典处理类
    3. */
    4. @Slf4j
    5. @Component
    6. @ExcelDynamicData(name = "erp_dict")
    7. public class ErpDictDataRpcHandle implements ExcelDynamicSelectHandler {
    8. /**
    9. * 查询字典信息
    10. *
    11. * @param param
    12. * @return
    13. */
    14. @Override
    15. public String[] getSource(String dictType) {
    16. if (StringUtils.isBlank(param)) {
    17. return new String[0];
    18. }
    19. ErpDictDataQuery query = new ErpDictDataQuery();
    20. query.setTopFlag(Constants.ZERO);
    21. query.setDictType(dictType);
    22. List dictDataDTOList = erpDictList(query);// 查询数据库或其他方式获取数据
    23. if (CollectionUtils.isNotEmpty(dictDataDTOList)) {
    24. return dictDataDTOList.stream().map(ErpDictDataDTO::getDictLabel).toArray(String[]::new);
    25. }
    26. return new String[0];
    27. }
    28. }

    2:构建导出参数

    1. public void batchAddSkuImportTemplate(HttpServletResponse response) {
    2. List paramList = new ArrayList<>();
    3. EasyExcelExportDynamicParam param = new EasyExcelExportDynamicParam();
    4. // 生成基础信息表头
    5. List> listList = ExcelSelectedResolve.resolvePropertyAnnotation(ProductAddNormalSkuBasicsTemplateDTO.class);
    6. // 查询品类属性
    7. ProductCategoryAttributeValueDTO attributeValueDTO = productCategoryAttributeService.queryCategoryAttributeByCategoryCode(categoryCodeLast);
    8. // 生成规格属性表头
    9. List specAttributeList = attributeValueDTO.getSpecAttributeList();
    10. if (CollectionUtil.isNotEmpty(specAttributeList)) {
    11. List> attributeNameList = specAttributeList.stream().map(x -> Arrays.asList("导入说明:\n" +, "产品属性-规格属性", attributeNameRequiredFlag(x))).collect(Collectors.toList());
    12. listList.addAll(attributeNameList);
    13. }
    14. // 生成销售属性表头
    15. List salesAttributeList = attributeValueDTO.getSalesAttributeList();
    16. if (CollectionUtil.isNotEmpty(salesAttributeList)) {
    17. List> attributeNameList = salesAttributeList.stream().map(x -> Arrays.asList("导入说明:\n" +, "产品属性-销售属性", attributeNameRequiredFlag(x))).collect(Collectors.toList());
    18. listList.addAll(attributeNameList);
    19. }
    20. // 生成标签属性表头
    21. List tagAttributeList = attributeValueDTO.getTagAttributeList();
    22. if (CollectionUtil.isNotEmpty(tagAttributeList)) {
    23. List> attributeNameList = tagAttributeList.stream().map(x -> Arrays.asList("导入说明:\n" +, "产品属性-标签属性", attributeNameRequiredFlag(x))).collect(Collectors.toList());
    24. listList.addAll(attributeNameList);
    25. }
    26. // 设置颜色
    27. Map> styleMap = new HashMap<>();
    28. Map paramMap = new HashMap<>();
    29. // 判断第三行带*号列明都加上颜色
    30. Integer num = Constants.ZERO;
    31. for (List line : listList) {
    32. String secondLineName = line.get(2);
    33. if (secondLineName.startsWith("*")) {
    34. EasyExcelExportDynamicStyleParam styleParam = EasyExcelExportDynamicStyleParam.builder()
    35. .bgColor(IndexedColors.YELLOW.getIndex())
    36. .fontColor(IndexedColors.RED.getIndex())
    37. .build();
    38. paramMap.put(num, styleParam);
    39. }
    40. num++;
    41. }
    42. styleMap.put(2, paramMap);
    43. Map one = new HashMap<>();
    44. EasyExcelExportDynamicStyleParam oneParam = EasyExcelExportDynamicStyleParam.builder()
    45. .bgColor(IndexedColors.WHITE.getIndex())
    46. .alignment(HorizontalAlignment.LEFT)
    47. .build();
    48. one.put(0, oneParam);
    49. styleMap.put(0, one);
    50. param.setStyleMap(styleMap);
    51. param.setDataList(new ArrayList<>());
    52. param.setDynamicHeaderList(listList);
    53. // 生成基础信息下拉
    54. Map head = ExcelSelectedResolve.resolveSelectedAnnotation(clazz);
    55. param.setSelectedMap(head);
    56. param.setSheetName("导入数据页");
    57. paramList.add(param);
    58. // 人员对照表
    59. EasyExcelExportDynamicParam developerParam = new EasyExcelExportDynamicParam();
    60. developerParam.setSheetName("人员对照表");
    61. developerParam.setTemplate(DeveloperTemplateDTO.class);
    62. List templateDTOList = new ArrayList<>();
    63. developerParam.setDataList(templateDTOList);
    64. paramList.add(developerParam);
    65. EasyExcelUtil.exportExcel(response, paramList, "多sheet页导出");
    66. }

     3:导出结果示例

    注意:当使用动态表头和固定表头组合生成时,需要统一把表头单元格字段内容写入到List> 当中。 

  • 相关阅读:
    如何使用 ABAP 代码发送邮件到指定邮箱试读版
    宽瞬时带宽放大器SKY66051-11、SKY66052-11、SKY66041-11、SKY66317-11(RF)适用于通讯网络
    Python爬虫:aiohttp的介绍和基本使用
    live555 音视频处理相关文档解读,
    1、2快速生成
    论文浅尝 | 训练语言模型遵循人类反馈的指令
    基于ubuntu 22, jdk 8x64搭建图数据库环境 hugegraph
    深入理解JVM虚拟机第九篇:详细介绍JVM中的双亲委派机制工作原理和机制
    scrapy数据提取-实战-起点
    Java多线程按顺序输出10以内的奇偶数
  • 原文地址:https://blog.csdn.net/Ascend1977/article/details/132835270