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.Method; import java.lang.reflect.Modifier; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.*; /** * Created by vincent on 2/17/2024 */ @Slf4j public class ExcelUtil { 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(); } if (value != null) { if (value instanceof Date) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); row.createCell(cellIndex).setCellValue(sdf.format((Date) value)); } else { row.createCell(cellIndex).setCellValue(value.toString()); } } cellIndex++; } } } for (int i = 0; i <= fields.length; i++) { sheet.autoSizeColumn(i); } return workbook; } public static Workbook create(List list, List columns) { return create(list, columns, null); } public static Workbook create(List list, List columns, ReportMeta reportMeta) { XSSFWorkbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet("export"); List safeColumns = columns == null ? Collections.emptyList() : columns; int sheetColumnCount = safeColumns.size() + 1; configureA4PrintLayout(sheet); CellStyle titleStyle = createTitleStyle(workbook); CellStyle metaLabelStyle = createMetaLabelStyle(workbook); CellStyle metaValueStyle = createMetaValueStyle(workbook); CellStyle headerStyle = createHeaderStyle(workbook); CellStyle bodyStyle = createBodyStyle(workbook); CellStyle serialStyle = createCenteredBodyStyle(workbook); int rowIndex = 0; if (reportMeta != null) { Row titleRow = sheet.createRow(rowIndex++); titleRow.setHeightInPoints(28); Cell titleCell = titleRow.createCell(0); titleCell.setCellValue(StringUtils.defaultIfBlank(reportMeta.getTitle(), "报表")); titleCell.setCellStyle(titleStyle); sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, Math.max(0, sheetColumnCount - 1))); Row metaRow = sheet.createRow(rowIndex++); int metaCol = 0; metaCol = writeMetaPair(metaRow, metaCol, "报表日期", reportMeta.getReportDate(), metaLabelStyle, metaValueStyle); writeMetaPair(metaRow, metaCol, "打印人", reportMeta.getPrintedBy(), metaLabelStyle, metaValueStyle); rowIndex++; } int headerRowIndex = rowIndex; Row header = sheet.createRow(rowIndex++); Cell serialHeaderCell = header.createCell(0); serialHeaderCell.setCellValue("序号"); serialHeaderCell.setCellStyle(headerStyle); for (int i = 0; i < safeColumns.size(); i++) { ColumnMeta column = safeColumns.get(i); Cell headerCell = header.createCell(i + 1); headerCell.setCellValue( StringUtils.isBlank(column.getLabel()) ? column.getSource() : column.getLabel() ); headerCell.setCellStyle(headerStyle); } if (list != null) { int serialNo = 1; for (Object rowObj : list) { Row row = sheet.createRow(rowIndex++); Cell serialCell = row.createCell(0); serialCell.setCellValue(String.format("%03d", serialNo++)); serialCell.setCellStyle(serialStyle); for (int i = 0; i < safeColumns.size(); i++) { Object value = getColumnValue(rowObj, safeColumns.get(i).getSource()); Cell cell = row.createCell(i + 1); cell.setCellStyle(bodyStyle); if (value != null) { if (value instanceof Date) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); cell.setCellValue(sdf.format((Date) value)); } else { cell.setCellValue(value.toString()); } } } } } for (int i = 0; i <= safeColumns.size(); i++) { sheet.autoSizeColumn(i); sheet.setColumnWidth(i, Math.min(sheet.getColumnWidth(i) + 1024, 12000)); } sheet.setRepeatingRows(CellRangeAddress.valueOf((headerRowIndex + 1) + ":" + (headerRowIndex + 1))); return workbook; } private static void configureA4PrintLayout(Sheet sheet) { sheet.setAutobreaks(true); sheet.setFitToPage(true); sheet.setHorizontallyCenter(true); sheet.setDisplayGridlines(false); PrintSetup printSetup = sheet.getPrintSetup(); printSetup.setPaperSize(PrintSetup.A4_PAPERSIZE); printSetup.setLandscape(true); printSetup.setFitWidth((short) 1); printSetup.setFitHeight((short) 0); sheet.setMargin(Sheet.LeftMargin, 0.3); sheet.setMargin(Sheet.RightMargin, 0.3); sheet.setMargin(Sheet.TopMargin, 0.4); sheet.setMargin(Sheet.BottomMargin, 0.4); } private static int writeMetaPair(Row row, int startCol, String label, String value, CellStyle labelStyle, CellStyle valueStyle) { Cell labelCell = row.createCell(startCol); labelCell.setCellValue(label + ":"); labelCell.setCellStyle(labelStyle); Cell valueCell = row.createCell(startCol + 1); valueCell.setCellValue(StringUtils.defaultString(value)); valueCell.setCellStyle(valueStyle); return startCol + 2; } private static CellStyle createTitleStyle(Workbook workbook) { CellStyle style = workbook.createCellStyle(); style.setAlignment(HorizontalAlignment.CENTER); style.setVerticalAlignment(VerticalAlignment.CENTER); style.setBorderBottom(BorderStyle.THICK); Font font = workbook.createFont(); font.setBold(true); font.setFontHeightInPoints((short) 16); style.setFont(font); return style; } private static CellStyle createMetaLabelStyle(Workbook workbook) { CellStyle style = workbook.createCellStyle(); style.setAlignment(HorizontalAlignment.LEFT); style.setVerticalAlignment(VerticalAlignment.CENTER); style.setBorderBottom(BorderStyle.THIN); Font font = workbook.createFont(); font.setBold(true); style.setFont(font); return style; } private static CellStyle createMetaValueStyle(Workbook workbook) { CellStyle style = workbook.createCellStyle(); style.setAlignment(HorizontalAlignment.LEFT); style.setVerticalAlignment(VerticalAlignment.CENTER); style.setBorderBottom(BorderStyle.THIN); return style; } private static CellStyle createHeaderStyle(Workbook workbook) { CellStyle style = workbook.createCellStyle(); style.setAlignment(HorizontalAlignment.CENTER); style.setVerticalAlignment(VerticalAlignment.CENTER); style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); style.setFillPattern(FillPatternType.SOLID_FOREGROUND); Font font = workbook.createFont(); font.setBold(true); style.setFont(font); return style; } private static CellStyle createBodyStyle(Workbook workbook) { CellStyle style = workbook.createCellStyle(); style.setAlignment(HorizontalAlignment.LEFT); style.setVerticalAlignment(VerticalAlignment.CENTER); return style; } private static CellStyle createCenteredBodyStyle(Workbook workbook) { CellStyle style = workbook.createCellStyle(); style.setAlignment(HorizontalAlignment.CENTER); style.setVerticalAlignment(VerticalAlignment.CENTER); return style; } private static Object getColumnValue(Object rowObj, String source) { if (rowObj == null || StringUtils.isBlank(source)) { return null; } if (rowObj instanceof Map) { return getValueFromMap((Map) rowObj, source); } String extendFieldKey = extractExtendFieldKey(source); if (extendFieldKey != null) { Object extendFields = getBeanValue(rowObj, "extendFields"); if (extendFields instanceof Map) { return ((Map) extendFields).get(extendFieldKey); } return null; } return getBeanValue(rowObj, source); } private static Object getValueFromMap(Map rowObj, String source) { String extendFieldKey = extractExtendFieldKey(source); if (extendFieldKey != null) { Object extendFields = rowObj.get("extendFields"); if (extendFields instanceof Map) { return ((Map) extendFields).get(extendFieldKey); } return null; } return rowObj.get(source); } private static String extractExtendFieldKey(String source) { if (source == null || !source.startsWith("extendFields.[")) { return null; } int startIndex = source.indexOf('['); int endIndex = source.indexOf(']'); if (startIndex < 0 || endIndex <= startIndex) { return null; } return source.substring(startIndex + 1, endIndex); } private static Object getBeanValue(Object rowObj, String source) { Object value = invokeGetter(rowObj, source); if (value != null) { return value; } Field field = findField(rowObj.getClass(), source); if (field == null) { return null; } try { field.setAccessible(true); return field.get(rowObj); } catch (IllegalAccessException ignore) { return null; } } private static Object invokeGetter(Object target, String source) { String suffix = Character.toUpperCase(source.charAt(0)) + source.substring(1); String[] methodNames = new String[] { "get" + suffix, "is" + suffix }; for (String methodName : methodNames) { try { Method method = target.getClass().getMethod(methodName); return method.invoke(target); } catch (Exception ignore) { } } return null; } private static Field findField(Class clazz, String source) { Class current = clazz; while (current != null && current != Object.class) { try { return current.getDeclaredField(source); } catch (NoSuchFieldException ignore) { current = current.getSuperclass(); } } return null; } /** * 添加导入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; } public static class ColumnMeta { private String key; private String source; private String label; private Boolean extendField; public String getKey() { return key; } public ColumnMeta setKey(String key) { this.key = key; return this; } public String getSource() { return source; } public ColumnMeta setSource(String source) { this.source = source; return this; } public String getLabel() { return label; } public ColumnMeta setLabel(String label) { this.label = label; return this; } public Boolean getExtendField() { return extendField; } public ColumnMeta setExtendField(Boolean extendField) { this.extendField = extendField; return this; } } public static class ReportMeta { private String title; private String companyName; private String printedBy; private String reportDate; private String reportDateValue; public String getTitle() { return title; } public ReportMeta setTitle(String title) { this.title = title; return this; } public String getCompanyName() { return companyName; } public ReportMeta setCompanyName(String companyName) { this.companyName = companyName; return this; } public String getReportDate() { return reportDate; } public ReportMeta setReportDate(String reportDate) { this.reportDate = reportDate; return this; } public String getReportDateValue() { return reportDateValue; } public ReportMeta setReportDateValue(String reportDateValue) { this.reportDateValue = reportDateValue; return this; } public String getPrintedBy() { return printedBy; } public ReportMeta setPrintedBy(String printedBy) { this.printedBy = printedBy; return this; } } }