package com.vincent.rsf.server.common.utils; import cn.afterturn.easypoi.excel.annotation.Excel; import cn.afterturn.easypoi.excel.entity.ImportParams; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.vincent.rsf.framework.common.Cools; import com.vincent.rsf.framework.common.SpringUtils; import com.vincent.rsf.server.manager.entity.excel.MatnrsTemplate; import com.vincent.rsf.server.manager.entity.excel.annotation.ExcelComment; import com.vincent.rsf.server.system.entity.Fields; import com.vincent.rsf.server.system.service.FieldsService; import io.swagger.annotations.ApiModelProperty; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.ss.util.CellRangeAddress; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Created by vincent on 2/17/2024 */ @Slf4j public class ExcelUtil { private static final Pattern EXTEND_FIELD_SOURCE_PATTERN = Pattern.compile("^extendFields\\.\\[(.+)]$"); public static void build(Workbook workbook, HttpServletResponse response) { response.reset(); Http.cors(response); response.setContentType("application/octet-stream; charset=utf-8"); try { response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("export", "UTF-8")); workbook.write(response.getOutputStream()); } catch (IOException ignore) { } } public static Workbook create(List list, Class clz) { return create(list, clz, false); } public static Workbook create(List list, Class clz, boolean flagTemplate) { XSSFWorkbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet(clz.getSimpleName()); Row header = sheet.createRow(0); Field[] fields = Cools.getAllFields(clz); int headerIdx = 0; FieldsService itemService = SpringUtils.getBean(FieldsService.class); List sysFields = itemService.list(new LambdaQueryWrapper() .eq(Fields::getStatus, 1) .eq(Fields::getFlagEnable, 1)); for (Field field : fields) { if (Modifier.isFinal(field.getModifiers()) || Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers())) { continue; } String memo = "Undefined"; if (flagTemplate) { memo = field.getName(); } else { if (field.isAnnotationPresent(Excel.class)) { memo = field.getAnnotation(Excel.class).name(); } } if (field.isAnnotationPresent(ApiModelProperty.class)) { memo = field.getAnnotation(ApiModelProperty.class).value(); } header.createCell(headerIdx).setCellValue(memo); headerIdx++; } if (clz.equals(MatnrsTemplate.class)) { //添加扩展字段别名 if (!sysFields.isEmpty()) { for (Fields field : sysFields) { if (flagTemplate) { header.createCell(headerIdx).setCellValue(field.getFields()); } else { header.createCell(headerIdx).setCellValue(field.getFieldsAlise()); } headerIdx++; } } } int rowIndex = 1; if (!Objects.isNull(list)) { for (T t : list) { Row row = sheet.createRow(rowIndex++); int cellIndex = 0; for (Field field : fields) { if (Modifier.isFinal(field.getModifiers()) || Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers())) { continue; } // 此行很重要,特别是字段为private时 field.setAccessible(true); Object value = null; try { value = field.get(t); } catch (IllegalAccessException e) { e.printStackTrace(); } writeCellValue(row, cellIndex, value); cellIndex++; } } } for (int i = 0; i <= fields.length; i++) { sheet.autoSizeColumn(i); } return workbook; } public static Workbook create(List> rows, List columns) { return create(rows, columns, null); } public static Workbook create(List> rows, List columns, ExportMeta exportMeta) { XSSFWorkbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet("export"); int titleColumnCount = Math.max(columns.size(), 4); int currentRowIndex = 0; CellStyle titleStyle = createTitleStyle(workbook); CellStyle subHeaderStyle = createSubHeaderStyle(workbook); CellStyle headerStyle = createHeaderStyle(workbook); CellStyle bodyStyle = createBodyStyle(workbook); if (exportMeta != null && StringUtils.isNotBlank(exportMeta.getReportTitle())) { Row titleRow = sheet.createRow(currentRowIndex++); titleRow.setHeightInPoints(24); Cell titleCell = titleRow.createCell(0); titleCell.setCellValue(exportMeta.getReportTitle()); titleCell.setCellStyle(titleStyle); sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, titleColumnCount - 1)); Row subHeaderRow = sheet.createRow(currentRowIndex++); writeSubHeaderCell(subHeaderRow, 0, getSubHeaderText("报表日期", exportMeta.getReportDate()), subHeaderStyle); writeSubHeaderCell(subHeaderRow, 1, getSubHeaderText("打印人", exportMeta.getOperator()), subHeaderStyle); writeSubHeaderCell(subHeaderRow, 2, getSubHeaderText("打印时间", exportMeta.getPrintedAt()), subHeaderStyle); writeSubHeaderCell(subHeaderRow, 3, getSubHeaderText("记录数", String.valueOf(exportMeta.getCount())), subHeaderStyle); currentRowIndex++; } Row header = sheet.createRow(currentRowIndex++); for (int index = 0; index < columns.size(); index++) { Cell headerCell = header.createCell(index); headerCell.setCellValue(columns.get(index).getLabel()); headerCell.setCellStyle(headerStyle); } int rowIndex = currentRowIndex; for (Map rowData : rows) { Row row = sheet.createRow(rowIndex++); for (int columnIndex = 0; columnIndex < columns.size(); columnIndex++) { Object value = getRowValue(rowData, columns.get(columnIndex).getSource()); writeCellValue(row, columnIndex, value, bodyStyle); } } for (int columnIndex = 0; columnIndex < columns.size(); columnIndex++) { sheet.autoSizeColumn(columnIndex); } return workbook; } private static Object getRowValue(Map rowData, String source) { if (rowData == null || StringUtils.isBlank(source)) { return null; } if (rowData.containsKey(source)) { return rowData.get(source); } Matcher matcher = EXTEND_FIELD_SOURCE_PATTERN.matcher(source); if (matcher.matches()) { Object extendFields = rowData.get("extendFields"); if (extendFields instanceof Map extendFieldMap) { return extendFieldMap.get(matcher.group(1)); } } return rowData.get(source); } private static void writeCellValue(Row row, int cellIndex, Object value) { writeCellValue(row, cellIndex, value, null); } private static void writeCellValue(Row row, int cellIndex, Object value, CellStyle cellStyle) { Cell cell = row.createCell(cellIndex); if (cellStyle != null) { cell.setCellStyle(cellStyle); } if (value == null) { return; } if (value instanceof Date) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); cell.setCellValue(sdf.format((Date) value)); return; } cell.setCellValue(value.toString()); } private static void writeSubHeaderCell(Row row, int cellIndex, String value, CellStyle cellStyle) { Cell cell = row.createCell(cellIndex); cell.setCellValue(value); cell.setCellStyle(cellStyle); } private static String getSubHeaderText(String label, String value) { return label + ": " + StringUtils.defaultString(value); } private static CellStyle createTitleStyle(Workbook workbook) { CellStyle cellStyle = workbook.createCellStyle(); cellStyle.setAlignment(HorizontalAlignment.CENTER); cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); Font font = workbook.createFont(); font.setBold(true); font.setFontHeightInPoints((short) 14); cellStyle.setFont(font); return cellStyle; } private static CellStyle createSubHeaderStyle(Workbook workbook) { CellStyle cellStyle = workbook.createCellStyle(); cellStyle.setAlignment(HorizontalAlignment.LEFT); cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); Font font = workbook.createFont(); font.setFontHeightInPoints((short) 10); cellStyle.setFont(font); return cellStyle; } private static CellStyle createHeaderStyle(Workbook workbook) { CellStyle cellStyle = workbook.createCellStyle(); cellStyle.setAlignment(HorizontalAlignment.CENTER); cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); Font font = workbook.createFont(); font.setBold(true); font.setFontHeightInPoints((short) 10); cellStyle.setFont(font); return cellStyle; } private static CellStyle createBodyStyle(Workbook workbook) { CellStyle cellStyle = workbook.createCellStyle(); cellStyle.setAlignment(HorizontalAlignment.LEFT); cellStyle.setVerticalAlignment(VerticalAlignment.TOP); cellStyle.setWrapText(true); return cellStyle; } public static class ExportColumn { private final String source; private final String label; public ExportColumn(String source, String label) { this.source = source; this.label = label; } public String getSource() { return source; } public String getLabel() { return label; } } public static class ExportMeta { private final String reportTitle; private final String reportDate; private final String printedAt; private final String operator; private final int count; public ExportMeta(String reportTitle, String reportDate, String printedAt, String operator, int count) { this.reportTitle = reportTitle; this.reportDate = reportDate; this.printedAt = printedAt; this.operator = operator; this.count = count; } public String getReportTitle() { return reportTitle; } public String getReportDate() { return reportDate; } public String getPrintedAt() { return printedAt; } public String getOperator() { return operator; } public int getCount() { return count; } } /** * 添加导入excel配置参数 * 注:默认配置可满足当前需求 * * @return */ public static ImportParams getDefaultImportParams() { ImportParams importParams = new ImportParams(); importParams.setTitleRows(0); // importParams.setNeedVerify(true); importParams.setHeadRows(1); importParams.setSheetNum(1); return importParams; } /** * 根据 {@code tClass} 相关成员变量的 {@link ExcelComment#example()} 字段创建模拟数据,暂不支持 复杂类型 * * @param tClass * @return */ public static T mockData(Class tClass) { if (tClass == null) { return null; } T instance = null; try { instance = tClass.newInstance(); Field[] declaredFields = tClass.getDeclaredFields(); for (Field declaredField : declaredFields) { ExcelComment comment = declaredField.getAnnotation(ExcelComment.class); if (comment == null) { continue; } declaredField.setAccessible(true); Class fieldType = declaredField.getType(); String exampleValue = comment.example(); Object value = null; if (fieldType == int.class || fieldType == Integer.class) { value = StringUtils.isBlank(exampleValue) ? 0 : Integer.parseInt(exampleValue); } else if (fieldType == short.class || fieldType == Short.class) { value = StringUtils.isBlank(exampleValue) ? 0 : Short.parseShort(exampleValue); } else if (fieldType == long.class || fieldType == Long.class) { value = StringUtils.isBlank(exampleValue) ? 0 : Long.parseLong(exampleValue); } else if (fieldType == double.class || fieldType == Double.class) { value = StringUtils.isBlank(exampleValue) ? 0 : Double.parseDouble(exampleValue); } else if (fieldType == boolean.class || fieldType == Boolean.class) { value = StringUtils.isNotBlank(exampleValue) && Boolean.parseBoolean(exampleValue); } else if (fieldType == String.class) { value = exampleValue; } else if (fieldType == Date.class) { value = DateUtils.parse(exampleValue); } if (value == null && !isBaseType(fieldType)) { declaredField.set(instance, null); } else { declaredField.set(instance, value); } } } catch (Exception e) { log.error("数据构造失败,请查询详细信息", e); return instance; } return instance; } /** * 是否是基础数据类型 * * @param className * @return */ private static boolean isBaseType(Class className) { if (className.equals(java.lang.Integer.class) || className.equals(java.lang.Byte.class) || className.equals(java.lang.Long.class) || className.equals(java.lang.Double.class) || className.equals(java.lang.Float.class) || className.equals(java.lang.Character.class) || className.equals(java.lang.Short.class) || className.equals(java.lang.Boolean.class)) { return true; } return false; } }