mybatis-plus 罗列实现模版,导入,导出

[复制链接]
发表于 2025-9-19 03:03:41 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
基于上一篇的罗列利用扩展一下
1.导出模版
excel类
  1. package sjgjtask.databasetest.util;
  2. import cn.hutool.core.collection.CollUtil;
  3. import com.alibaba.excel.EasyExcelFactory;
  4. import com.alibaba.excel.annotation.ExcelProperty;
  5. import com.alibaba.excel.write.builder.ExcelWriterBuilder;
  6. import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
  7. import org.springframework.http.HttpHeaders;
  8. import javax.servlet.http.HttpServletResponse;
  9. import java.io.IOException;
  10. import java.lang.reflect.Field;
  11. import java.net.URLEncoder;
  12. import java.nio.charset.StandardCharsets;
  13. import java.util.ArrayList;
  14. import java.util.Arrays;
  15. import java.util.List;
  16. import java.util.stream.Collectors;
  17. public class ExcelUtil {
  18.     /**
  19.      * 通过class获取实体类中ExcelProperty注解设置的excel表头名称
  20.      *
  21.      * @param clazz
  22.      * @return
  23.      */
  24.     public static List<String> getExcelHeadListByEntityExcelProperty(Class clazz) {
  25.         List<String> result = new ArrayList<>();
  26.         //获取类中所有的属性
  27.         for (Field declaredField : clazz.getDeclaredFields()) {
  28.             declaredField.setAccessible(true);
  29.             //获取根据注解的方式获取ExcelProperty修饰的字段
  30.             ExcelProperty excelProperty = declaredField.getAnnotation(ExcelProperty.class);
  31.             if (excelProperty != null) {
  32.                 String[] values = excelProperty.value();
  33.                 StringBuilder value = new StringBuilder();
  34.                 for (String s : values) {
  35.                     value.append(s);
  36.                 }
  37.                 result.add(value.toString());
  38.             }
  39.         }
  40.         return result;
  41.     }
  42.     public static <T> void templateExport(HttpServletResponse response, String name, Class<T> clazz) throws IOException {
  43.         templateExport(response, name + "导入模板", clazz, null);
  44.     }
  45.     public static <T> void templateExport(HttpServletResponse response, String name, Class<T> clazz, List<T> dataList) throws IOException {
  46.         if (CollUtil.isEmpty(dataList)) {
  47.             dataList = new ArrayList<>();
  48.         }
  49.         Field[] fields = clazz.getDeclaredFields();
  50.         List<SelectItem> selectItemData = new ArrayList<>();
  51.         int excelIndex = 0;
  52.         for (int i = 0; i < fields.length; i++) {
  53.             Field field = fields[i];
  54.             field.setAccessible(true);
  55.             if (field.isAnnotationPresent(ExcelProperty.class)) {
  56.                 excelIndex++;
  57.                 // 确保 fieldType 是 Enum 类型并且实现了 IBaseEnum 接口
  58.                 Class<?> fieldType = field.getType();
  59.                 if (!isImplementingInterface(fieldType, IBaseEnum.class)) {
  60.                     continue;
  61.                 }
  62.                 @SuppressWarnings("unchecked")
  63.                 Class<? extends IBaseEnum<?>> enumType = (Class<? extends IBaseEnum<?>>) fieldType;
  64.                 IBaseEnum<?>[] enums = enumType.getEnumConstants();
  65.                 if (enums != null) {
  66.                     selectItemData = new ArrayList<>();
  67.                     SelectItem selectItem = new SelectItem(excelIndex - 1);
  68.                     List<String> enumMessages = Arrays.stream(enums)
  69.                             .map(enumObject -> enumObject.getMessage().toString())
  70.                             .collect(Collectors.toList());
  71.                     selectItem.addDataItem(enumMessages);
  72.                     selectItemData.add(selectItem);
  73.                 }
  74.             }
  75.         }
  76. //        if (selectItemData.size() > 0) {
  77. //            selectWriteHandler = new SelectWriteHandler(selectItemData);
  78. //        }
  79.         response.setContentType("application/octet-stream");
  80.         response.addHeader(HttpHeaders.CONTENT_DISPOSITION, String.format("attachment;filename*=%s", URLEncoder.encode(name, StandardCharsets.UTF_8.toString()) + ".xlsx"));
  81.         // 下拉框数据
  82.         ExcelWriterBuilder excelWriterBuilder = EasyExcelFactory.write(response.getOutputStream(), clazz).inMemory(Boolean.TRUE)
  83.                 .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
  84.                 .registerWriteHandler(new SheetHeaderCommentWriteHandler(clazz));
  85.         if (!selectItemData.isEmpty()) {
  86.             excelWriterBuilder.registerWriteHandler(new SelectWriteHandler(selectItemData));
  87.         }
  88.         excelWriterBuilder.sheet(name + "配置数据").doWrite(dataList);
  89.     }
  90.     public static <T> void export(HttpServletResponse response, String name, List<T> dataList) throws IOException {
  91.         if (CollUtil.isEmpty(dataList)) {
  92.             throw new IOException("无数据");
  93.         }
  94.         Class<T> t = (Class<T>) dataList.get(0).getClass();
  95.         templateExport(response, name, t, dataList);
  96.     }
  97.     private static boolean isImplementingInterface(Class<?> clazz, Class<?> interfaceClass) {
  98.         if (clazz == null || interfaceClass == null || !interfaceClass.isInterface()) {
  99.             return false;
  100.         }
  101.         // 检查当前类是否实现了接口
  102.         if (Arrays.asList(clazz.getInterfaces()).contains(interfaceClass)) {
  103.             return true;
  104.         }
  105.         // 递归检查父类
  106.         return clazz.getSuperclass() != null && isImplementingInterface(clazz.getSuperclass(), interfaceClass);
  107.     }
  108. }
复制代码
罗列下拉框类
  1. package sjgjtask.databasetest.util;
  2. import cn.hutool.core.lang.Assert;
  3. import lombok.Data;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. import java.util.UUID;
  7. /**
  8. * excel下拉框数据项
  9. */
  10. @Data
  11. public class SelectItem {
  12.     /**
  13.      * 下拉框所在列的索引,从0开始
  14.      */
  15.     private Integer columnIndex;
  16.     /**
  17.      * 下拉框的值列表
  18.      */
  19.     private List<DataItem> dataItems;
  20.     /**
  21.      * 子级对应的下拉框数据
  22.      */
  23.     private SelectItem subSelect;
  24.     public SelectItem(Integer columnIndex) {
  25.         this.columnIndex = columnIndex;
  26.     }
  27.     public void addDataItem(List<String> values) {
  28.         this.addDataItem("_" + UUID.randomUUID().toString().replaceAll("-", ""), values);
  29.     }
  30.     public void addDataItem(String mappingKey, List<String> values) {
  31.         if (this.dataItems == null) {
  32.             this.dataItems = new ArrayList<>();
  33.         }
  34.         this.dataItems.add(new DataItem(mappingKey, values));
  35.     }
  36.     @Data
  37.     public static class DataItem {
  38.         /**
  39.          * 关联上级的key
  40.          */
  41.         private String mappingKey;
  42.         /**
  43.          * 当前下拉框的值
  44.          */
  45.         private List<String> values;
  46.         /**
  47.          * 当前下拉框的引用,隐藏页单元格地址
  48.          */
  49.         private String hiddenFormulaRef;
  50.         public DataItem(String mappingKey, List<String> values) {
  51.             Assert.notBlank(mappingKey, "mappingKey is not blank");
  52.             Assert.notEmpty(values, "values is not empty");
  53.             this.mappingKey = mappingKey;
  54.             this.values = values;
  55.         }
  56.     }
  57. }
复制代码
下拉框填写类
  1. package sjgjtask.databasetest.util;
  2. import cn.hutool.core.lang.Assert;
  3. import com.alibaba.excel.write.handler.CellWriteHandler;
  4. import com.alibaba.excel.write.handler.SheetWriteHandler;
  5. import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
  6. import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
  7. import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
  8. import com.alibaba.excel.write.metadata.style.WriteFont;
  9. import org.apache.poi.ss.usermodel.*;
  10. import org.apache.poi.ss.util.CellRangeAddressList;
  11. import org.apache.poi.ss.util.CellReference;
  12. import java.util.HashSet;
  13. import java.util.List;
  14. import java.util.Set;
  15. public class SelectWriteHandler implements SheetWriteHandler, CellWriteHandler {
  16.     // 下拉框从哪一行结束
  17.     private static final int ROW_SIZE = 10000;
  18.     // 红色字体
  19.     private final WriteFont redFont;
  20.     // 下拉框数据
  21.     private final List<SelectItem> selectItems;
  22.     // 下拉框数据隐藏sheet名称
  23.     private final String HIDDEN_SHEET_NAME = "hidden_sheet";
  24.     // 拉框所在列的索引,从0开始
  25.     private final Set<Integer> selectColumns = new HashSet<>();
  26.     private boolean isLoadSelectColumns = false;
  27.     private int rowIndex = 0;
  28.     public SelectWriteHandler(List<SelectItem> selectItems) {
  29.         Assert.notEmpty(selectItems, "selectItems can not be empty");
  30.         this.selectItems = selectItems;
  31.         redFont = getRedFont();
  32.     }
  33.     @Override
  34.     public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
  35.         Workbook workbook = writeWorkbookHolder.getWorkbook();
  36.         Sheet hiddenSheet = workbook.getSheet(HIDDEN_SHEET_NAME);
  37.         if (hiddenSheet != null) {
  38.             return;
  39.         }
  40.         hiddenSheet = workbook.createSheet(HIDDEN_SHEET_NAME);
  41.         workbook.setSheetHidden(workbook.getSheetIndex(hiddenSheet), true);
  42.         Sheet sheet = writeSheetHolder.getSheet();
  43.         for (SelectItem selectItem : selectItems) {
  44.             buildHiddenSheetSelectRef(workbook, sheet, hiddenSheet, selectItem, null);
  45.         }
  46.         if (!isLoadSelectColumns) {
  47.             isLoadSelectColumns = true;
  48.         }
  49.     }
  50.     private void buildHiddenSheetSelectRef(Workbook workbook, Sheet sheet, Sheet hiddenSheet, SelectItem selectItem, String formulaRef) {
  51.         if (!isLoadSelectColumns) {
  52.             selectColumns.add(selectItem.getColumnIndex());
  53.         }
  54.         List<SelectItem.DataItem> dataItems = selectItem.getDataItems();
  55.         for (SelectItem.DataItem dataItem : dataItems) {
  56.             setDataAndName(workbook, hiddenSheet, dataItem);
  57.         }
  58.         // 单元格地址引用
  59.         if (formulaRef == null || formulaRef.isEmpty()) {
  60.             formulaRef = dataItems.get(0).getHiddenFormulaRef();
  61.         }
  62.         // 创建检验器
  63.         DataValidation dataValidation = getDataValidation(sheet, selectItem, formulaRef);
  64.         sheet.addValidationData(dataValidation);
  65.         SelectItem subSelect = selectItem.getSubSelect();
  66.         if (subSelect != null) {
  67.             buildHiddenSheetSelectRef(workbook, sheet, hiddenSheet, subSelect, getInDirectFormulaRef(selectItem.getColumnIndex()));
  68.         }
  69.     }
  70.     private DataValidation getDataValidation(Sheet sheet, SelectItem selectItem, String formulaRef) {
  71.         DataValidationHelper helper = sheet.getDataValidationHelper();
  72.         DataValidationConstraint constraint = helper.createFormulaListConstraint(formulaRef);
  73.         CellRangeAddressList rangeAddressList = new CellRangeAddressList(1, ROW_SIZE, selectItem.getColumnIndex(), selectItem.getColumnIndex());
  74.         DataValidation dataValidation = helper.createValidation(constraint, rangeAddressList);
  75.         dataValidation.setShowErrorBox(true);
  76.         return dataValidation;
  77.     }
  78.     private void setDataAndName(Workbook workbook, Sheet hiddenSheet, SelectItem.DataItem dataItem) {
  79.         // 构建隐藏数据
  80.         Row row = hiddenSheet.createRow(rowIndex);
  81.         List<String> values = dataItem.getValues();
  82.         for (int i = 0; i < values.size(); i++) {
  83.             row.createCell(i).setCellValue(values.get(i));
  84.         }
  85.         // 创建名称命名器
  86.         Name name = workbook.createName();
  87.         name.setNameName(dataItem.getMappingKey());
  88.         name.setRefersToFormula(getFormulaRef(row));
  89.         dataItem.setHiddenFormulaRef(name.getRefersToFormula());
  90.         rowIndex++;
  91.     }
  92.     private String getInDirectFormulaRef(Integer columnIndex) {
  93.         CellReference slectCellReference = new CellReference(1, columnIndex);
  94.         return "INDIRECT(" + joinFormulaRef(slectCellReference, false) + ")";
  95.     }
  96.     @Override
  97.     public void afterCellDispose(CellWriteHandlerContext context) {
  98.         if (!context.getHead()) {
  99.             Integer columnIndex = context.getColumnIndex();
  100.             if (selectColumns.contains(columnIndex)) {
  101.                 // 设置红色字体
  102.                 context.getFirstCellData().getOrCreateStyle().setWriteFont(redFont);
  103.             }
  104.         }
  105.         CellWriteHandler.super.afterCellDispose(context);
  106.     }
  107.     private String getFormulaRef(Row prvRow) {
  108.         Cell startCell = prvRow.getCell(prvRow.getFirstCellNum());
  109.         Cell endCell = prvRow.getCell(prvRow.getLastCellNum() - 1);
  110.         return HIDDEN_SHEET_NAME + "!" + joinFormulaRef(new CellReference(startCell), true) + ":" + joinFormulaRef(new CellReference(endCell), true);
  111.     }
  112.     public String joinFormulaRef(CellReference cellReference, boolean isAbsolute) {
  113.         StringBuilder sb = new StringBuilder();
  114.         String[] refs = cellReference.getCellRefParts();
  115.         for (int i = refs.length - 1; i >= 1; i--) {
  116.             if (isAbsolute) {
  117.                 sb.append("$");
  118.             }
  119.             sb.append(refs[i]);
  120.         }
  121.         return sb.toString();
  122.     }
  123.     /**
  124.      * 返回一个红色字体
  125.      *
  126.      * @return
  127.      */
  128.     private WriteFont getRedFont() {
  129.         WriteFont redFont = new WriteFont();
  130.         redFont.setColor(IndexedColors.RED.getIndex());
  131.         return redFont;
  132.     }
  133. }
复制代码
表头填写类
  1. package sjgjtask.databasetest.util;
  2. import com.alibaba.excel.write.handler.RowWriteHandler;
  3. import com.alibaba.excel.write.handler.context.RowWriteHandlerContext;
  4. import org.apache.poi.ss.usermodel.*;
  5. import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
  6. import org.apache.poi.xssf.usermodel.XSSFRichTextString;
  7. /**
  8. * excel表头批注
  9. */
  10. public class SheetHeaderCommentWriteHandler implements RowWriteHandler {
  11.     private Class clazz;
  12.     public SheetHeaderCommentWriteHandler(Class clazz) {
  13.         this.clazz = clazz;
  14.     }
  15.     @Override
  16.     public void afterRowDispose(RowWriteHandlerContext context) {
  17.     }
  18.     public void writeComment(RowWriteHandlerContext context, int i, String commentInfo) {
  19.         Sheet sheet = context.getWriteSheetHolder().getSheet();
  20.         Drawing<?> drawingPatriarch = sheet.createDrawingPatriarch();
  21.         // 在第一行 第二列创建一个批注
  22.         Comment comment = drawingPatriarch.createCellComment(
  23.                 new XSSFClientAnchor(0, 0, 0, 0, (short) i, 0, (short) i + 1, 1)
  24.         );
  25.         // 输入批注信息
  26.         comment.setString(new XSSFRichTextString(commentInfo));
  27.         // 确保表头行存在
  28.         Row headerRow = sheet.getRow(0);
  29.         if (headerRow == null) {
  30.             headerRow = sheet.createRow(0);
  31.         }
  32.         // 确保单元格存在
  33.         Cell cell = headerRow.getCell(i);
  34.         if (cell == null) {
  35.             cell = headerRow.createCell(i);
  36.         }
  37.         // 将批注添加到单元格对象中
  38.         cell.setCellComment(comment);
  39.     }
  40. }
复制代码
实体类
  1. package sjgjtask.databasetest.entity;
  2. import com.alibaba.excel.annotation.ExcelProperty;
  3. import com.baomidou.mybatisplus.annotation.TableField;
  4. import com.baomidou.mybatisplus.annotation.TableName;
  5. import lombok.Data;
  6. import sjgjtask.databasetest.enums.Type;
  7. import sjgjtask.databasetest.util.EnumTypeHandler;
  8. import java.util.List;
  9. @Data
  10. @TableName("newtable")
  11. public class NewTable {
  12.     @ExcelProperty("唯一序列")
  13.     private String id;
  14.     @ExcelProperty("名称")
  15.     private String name; // 名称
  16.     @ExcelProperty("类型")
  17.     private Type type; // 修改为枚举类型
  18.     @ExcelProperty("类型数组")
  19.     @TableField(typeHandler = EnumTypeHandler.class)
  20.     private List<Type> arr; // 修改为枚举类型
  21. }
复制代码
最后导出方法类
  1. /**
  2.      * 利用ExcelUtil导出模板
  3.      */
  4.     @GetMapping("/template")
  5.     public void template(HttpServletResponse response) throws IOException {
  6.         ExcelUtil.templateExport(response, "newtable", NewTable.class);
  7.     }
复制代码
导出结果如下

2.导出数据
未完待续

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表