|
@@ -0,0 +1,596 @@
|
|
|
+package org.springblade.manager.controller;
|
|
|
+
|
|
|
+import com.aspose.cells.LoadFormat;
|
|
|
+import com.aspose.cells.LoadOptions;
|
|
|
+import com.aspose.cells.SaveFormat;
|
|
|
+import org.apache.poi.ss.usermodel.*;
|
|
|
+import org.apache.poi.ss.util.CellRangeAddress;
|
|
|
+import org.apache.poi.ss.util.RegionUtil;
|
|
|
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
|
+import org.jsoup.Jsoup;
|
|
|
+import org.jsoup.nodes.Document;
|
|
|
+import org.jsoup.nodes.Element;
|
|
|
+import org.jsoup.select.Elements;
|
|
|
+import org.springblade.core.tool.utils.IoUtil;
|
|
|
+import org.springblade.core.tool.utils.StringUtil;
|
|
|
+import org.springblade.manager.utils.FileUtils;
|
|
|
+
|
|
|
+import java.io.*;
|
|
|
+import java.util.*;
|
|
|
+import java.util.regex.Matcher;
|
|
|
+import java.util.regex.Pattern;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+public class HtmlTableToExcelConverter {
|
|
|
+
|
|
|
+// public static void main(String[] args) throws Exception {
|
|
|
+// String html = "D:\\tools\\html\\1892816666778140672.html";
|
|
|
+//
|
|
|
+//
|
|
|
+// InputStream inputStreamByUrl = FileUtils.getInputStreamByUrl(html);
|
|
|
+// String htmlString = IoUtil.readToString(inputStreamByUrl);
|
|
|
+//
|
|
|
+// convertHtmlTableToExcel(htmlString, "D:\\tools\\html\\123.xlsx");
|
|
|
+//
|
|
|
+//
|
|
|
+// }
|
|
|
+
|
|
|
+ public static Workbook convertHtmlTableToExcel(String html) throws Exception {
|
|
|
+ Document doc = Jsoup.parse(html);
|
|
|
+ Element table = doc.select("table").first();
|
|
|
+
|
|
|
+ // 创建Excel工作簿
|
|
|
+ Workbook workbook = new XSSFWorkbook();
|
|
|
+ Sheet sheet = workbook.createSheet("Sheet1");
|
|
|
+
|
|
|
+ // 设置默认列宽(字符宽度)
|
|
|
+ sheet.setDefaultColumnWidth(10);
|
|
|
+
|
|
|
+ // 存储列宽(单位:字符)
|
|
|
+ Map<Integer, Float> columnWidths = new HashMap<>();
|
|
|
+
|
|
|
+ // 样式缓存
|
|
|
+ Map<String, CellStyle> styleCache = new HashMap<>();
|
|
|
+ Map<String, Font> fontCache = new HashMap<>();
|
|
|
+ // 预解析CSS样式
|
|
|
+ Map<String, String> cssRules = parseCssRules(doc);
|
|
|
+
|
|
|
+ // 合并区域跟踪列表
|
|
|
+ List<CellRangeAddress> mergedRegions = new ArrayList<>();
|
|
|
+ // 单元格占用跟踪器
|
|
|
+ Map<Integer, Set<Integer>> occupiedCells = new HashMap<>();
|
|
|
+
|
|
|
+ int excelRowNum = 0;
|
|
|
+ for (Element tr : table.select("tr")) {
|
|
|
+ // 跳过空行
|
|
|
+ if (tr.children().isEmpty()) {
|
|
|
+ excelRowNum++;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建行并设置默认行高(比默认值小)
|
|
|
+ Row excelRow = sheet.createRow(excelRowNum);
|
|
|
+
|
|
|
+
|
|
|
+ // 初始化当前行占用集合
|
|
|
+ occupiedCells.putIfAbsent(excelRowNum, new HashSet<>());
|
|
|
+
|
|
|
+ int excelColNum = 0;
|
|
|
+
|
|
|
+
|
|
|
+ //是否设置行高
|
|
|
+ Boolean isHeight = false;
|
|
|
+
|
|
|
+ for (Element td : tr.select("td")) {
|
|
|
+
|
|
|
+ //设置行高
|
|
|
+ String style1 = td.attr("style");
|
|
|
+ if (!isHeight && StringUtil.isNotBlank(style1)) {
|
|
|
+ List<String> collect = Arrays.stream(style1.split(";")).collect(Collectors.toList());
|
|
|
+ HashMap<String, String> map = new HashMap<>();
|
|
|
+ collect.forEach(s -> {
|
|
|
+ map.put(s.split(":")[0], s.split(":")[1]);
|
|
|
+ });
|
|
|
+
|
|
|
+ String height = map.get("height");
|
|
|
+ Float rowHeight = 16f; // 默认16点
|
|
|
+ if (StringUtil.isNotBlank(height)) {
|
|
|
+ isHeight = true;
|
|
|
+ height = height.replace("px", "");
|
|
|
+ try {
|
|
|
+ Float px = Float.valueOf(height);
|
|
|
+ rowHeight = px * 0.75f; // 像素转点 (1px ≈ 0.75pt)
|
|
|
+ } catch (Exception ignored) {
|
|
|
+ ignored.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
+ excelRow.setHeightInPoints(rowHeight);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 跳过已被占用的单元格
|
|
|
+ while (isCellOccupied(occupiedCells, excelRowNum, excelColNum)) {
|
|
|
+ excelColNum++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理列跨度和行跨度
|
|
|
+ int colspan = getSpan(td, "colspan");
|
|
|
+ int rowspan = getSpan(td, "rowspan");
|
|
|
+
|
|
|
+ // 获取单元格内容
|
|
|
+ String cellText = extractCellText(td);
|
|
|
+
|
|
|
+ // 创建单元格
|
|
|
+ Cell cell = excelRow.createCell(excelColNum);
|
|
|
+ cell.setCellValue(cellText);
|
|
|
+
|
|
|
+ // 应用样式
|
|
|
+ String styleKey = getCellStyleKey(td, cssRules);
|
|
|
+ if (!styleCache.containsKey(styleKey)) {
|
|
|
+ CellStyle style = createCellStyle(workbook, td, cssRules, fontCache);
|
|
|
+ styleCache.put(styleKey, style);
|
|
|
+
|
|
|
+ // 检查是否需要自动换行
|
|
|
+ if (shouldWrapText(td, cssRules,cellText)) {
|
|
|
+ style.setWrapText(true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ cell.setCellStyle(styleCache.get(styleKey));
|
|
|
+
|
|
|
+ // 记录列宽(优先使用HTML中的宽度)
|
|
|
+ if (td.hasAttr("width")) {
|
|
|
+ String widthStr = td.attr("width").replace("px", "");
|
|
|
+ try {
|
|
|
+ float px = Float.parseFloat(widthStr);
|
|
|
+ float charWidth = px / 7f; // 像素转字符宽度 (1字符≈7px)
|
|
|
+
|
|
|
+ // 考虑跨列情况:总宽度分配到各列
|
|
|
+ for (int i = 0; i < colspan; i++) {
|
|
|
+ int colIdx = excelColNum + i;
|
|
|
+ float perColWidth = charWidth / colspan;
|
|
|
+
|
|
|
+ // 取最大宽度作为列宽
|
|
|
+ columnWidths.putIfAbsent(colIdx, 0f);
|
|
|
+ if (perColWidth > columnWidths.get(colIdx)) {
|
|
|
+ columnWidths.put(colIdx, perColWidth);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (NumberFormatException ignored) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 标记当前单元格占据的所有位置
|
|
|
+ markCellsAsOccupied(occupiedCells, excelRowNum, excelColNum, rowspan, colspan);
|
|
|
+
|
|
|
+ // 创建合并区域
|
|
|
+ if (colspan > 1 || rowspan > 1) {
|
|
|
+ CellRangeAddress region = new CellRangeAddress(
|
|
|
+ excelRowNum,
|
|
|
+ excelRowNum + rowspan - 1,
|
|
|
+ excelColNum,
|
|
|
+ excelColNum + colspan - 1
|
|
|
+ );
|
|
|
+
|
|
|
+ // 检查是否与现有区域重叠
|
|
|
+ if (!isOverlapping(mergedRegions, region)) {
|
|
|
+ sheet.addMergedRegion(region);
|
|
|
+ mergedRegions.add(region);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ excelColNum += colspan;
|
|
|
+ }
|
|
|
+ excelRowNum++;
|
|
|
+ }
|
|
|
+ // 修复合并单元格边框问题
|
|
|
+ fixMergedRegionBorders(workbook, sheet, mergedRegions);
|
|
|
+
|
|
|
+ // 应用列宽
|
|
|
+ for (Map.Entry<Integer, Float> entry : columnWidths.entrySet()) {
|
|
|
+ int colIdx = entry.getKey();
|
|
|
+ float width = entry.getValue();
|
|
|
+
|
|
|
+ // 限制列宽范围(0.5-100字符)
|
|
|
+ if (width < 0.5f) width = 0.5f;
|
|
|
+ if (width > 100f) width = 100f;
|
|
|
+
|
|
|
+ // 转换字符宽度为Excel单位(1字符=256单位)
|
|
|
+ sheet.setColumnWidth(colIdx, (int) (width * 256));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 自动调整未设置宽度的列
|
|
|
+ int maxColumn = columnWidths.keySet().stream().max(Integer::compare).orElse(0) + 1;
|
|
|
+ for (int i = 0; i < maxColumn; i++) {
|
|
|
+ if (!columnWidths.containsKey(i)) {
|
|
|
+ sheet.autoSizeColumn(i);
|
|
|
+ // 限制自动调整的最大宽度
|
|
|
+ int currentWidth = sheet.getColumnWidth(i);
|
|
|
+ if (currentWidth > 30 * 256) {
|
|
|
+ sheet.setColumnWidth(i, 30 * 256);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 调整行高以适应换行文本
|
|
|
+ adjustRowHeights(sheet);
|
|
|
+
|
|
|
+ // 写入文件
|
|
|
+// try (FileOutputStream fos = new FileOutputStream(outputPath)) {
|
|
|
+// workbook.write(fos);
|
|
|
+// }
|
|
|
+// workbook.close();
|
|
|
+
|
|
|
+ return workbook;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 修复合并单元格边框问题
|
|
|
+ private static void fixMergedRegionBorders(Workbook workbook, Sheet sheet, List<CellRangeAddress> mergedRegions) {
|
|
|
+ for (CellRangeAddress region : mergedRegions) {
|
|
|
+ // 设置合并区域的外边框
|
|
|
+ RegionUtil.setBorderTop(BorderStyle.THIN, region, sheet);
|
|
|
+ RegionUtil.setBorderRight(BorderStyle.THIN, region, sheet);
|
|
|
+ RegionUtil.setBorderBottom(BorderStyle.THIN, region, sheet);
|
|
|
+ RegionUtil.setBorderLeft(BorderStyle.THIN, region, sheet);
|
|
|
+
|
|
|
+ RegionUtil.setTopBorderColor(IndexedColors.BLACK.getIndex(), region, sheet);
|
|
|
+ RegionUtil.setRightBorderColor(IndexedColors.BLACK.getIndex(), region, sheet);
|
|
|
+ RegionUtil.setBottomBorderColor(IndexedColors.BLACK.getIndex(), region, sheet);
|
|
|
+ RegionUtil.setLeftBorderColor(IndexedColors.BLACK.getIndex(), region, sheet);
|
|
|
+
|
|
|
+ // 特殊处理:确保内部单元格边框完整
|
|
|
+ int firstRow = region.getFirstRow();
|
|
|
+ int lastRow = region.getLastRow();
|
|
|
+ int firstCol = region.getFirstColumn();
|
|
|
+ int lastCol = region.getLastColumn();
|
|
|
+
|
|
|
+ // 对于多行多列的合并区域,需要额外设置内部边框
|
|
|
+ if (lastRow - firstRow > 0 || lastCol - firstCol > 0) {
|
|
|
+ // 设置内部水平边框
|
|
|
+ for (int row = firstRow; row <= lastRow; row++) {
|
|
|
+ Row excelRow = sheet.getRow(row);
|
|
|
+ if (excelRow == null) continue;
|
|
|
+
|
|
|
+ for (int col = firstCol; col <= lastCol; col++) {
|
|
|
+ Cell cell = excelRow.getCell(col);
|
|
|
+ if (cell == null) continue;
|
|
|
+
|
|
|
+ CellStyle style = cell.getCellStyle();
|
|
|
+
|
|
|
+ // 设置顶部边框(如果是区域的第一行)
|
|
|
+ if (row == firstRow) {
|
|
|
+ style.setBorderTop(BorderStyle.THIN);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置底部边框(如果是区域的最后一行)
|
|
|
+ if (row == lastRow) {
|
|
|
+ style.setBorderBottom(BorderStyle.THIN);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置左侧边框(如果是区域的第一列)
|
|
|
+ if (col == firstCol) {
|
|
|
+ style.setBorderLeft(BorderStyle.THIN);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置右侧边框(如果是区域的最后一列)
|
|
|
+ if (col == lastCol) {
|
|
|
+ style.setBorderRight(BorderStyle.THIN);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置内部边框
|
|
|
+ if (row < lastRow) {
|
|
|
+ style.setBorderBottom(BorderStyle.THIN);
|
|
|
+ }
|
|
|
+ if (col < lastCol) {
|
|
|
+ style.setBorderRight(BorderStyle.THIN);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 新增方法:检查是否需要自动换行
|
|
|
+ private static boolean shouldWrapText(Element td, Map<String, String> cssRules,String cellText) {
|
|
|
+ // 1. 检查内联样式
|
|
|
+ String style = td.attr("style");
|
|
|
+ if (style != null && style.toLowerCase().contains("overflow-wrap") ||
|
|
|
+ style != null && style.toLowerCase().contains("word-wrap") ||
|
|
|
+ style != null && style.toLowerCase().contains("white-space") ||
|
|
|
+ style != null && style.toLowerCase().contains("line-break") ||
|
|
|
+ style != null && style.toLowerCase().contains("hyphens")) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 检查CSS类样式
|
|
|
+ String classes = td.attr("class");
|
|
|
+ for (String cls : classes.split(" ")) {
|
|
|
+ String selector = "." + cls;
|
|
|
+ if (cssRules.containsKey(selector)) {
|
|
|
+ String css = cssRules.get(selector).toLowerCase();
|
|
|
+ if (css.contains("overflow-wrap") ||
|
|
|
+ css.contains("word-wrap") ||
|
|
|
+ css.contains("white-space") ||
|
|
|
+ css.contains("line-break") ||
|
|
|
+ css.contains("hyphens")) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 默认不自动换行(除非内容中有换行符)
|
|
|
+ return cellText.contains("\n");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 新增方法:调整行高以适应换行文本
|
|
|
+ private static void adjustRowHeights(Sheet sheet) {
|
|
|
+ for (int rowNum = 0; rowNum <= sheet.getLastRowNum(); rowNum++) {
|
|
|
+ Row row = sheet.getRow(rowNum);
|
|
|
+ if (row == null) continue;
|
|
|
+
|
|
|
+ // 计算该行所需的最大行高
|
|
|
+ int maxLines = 1;
|
|
|
+ for (Cell cell : row) {
|
|
|
+ if (cell.getCellStyle().getWrapText()) {
|
|
|
+ String text = cell.getStringCellValue();
|
|
|
+ if (text != null) {
|
|
|
+ int lines = text.split("\n").length;
|
|
|
+ if (lines > maxLines) maxLines = lines;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据行数调整行高(每行约16点)
|
|
|
+ if (maxLines > 1) {
|
|
|
+ float newHeight = row.getHeightInPoints() * (maxLines * 0.8f);
|
|
|
+ row.setHeightInPoints(Math.max(row.getHeightInPoints(), newHeight));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ // 辅助方法:检查单元格是否被占用
|
|
|
+ private static boolean isCellOccupied(Map<Integer, Set<Integer>> occupiedCells, int row, int col) {
|
|
|
+ if (!occupiedCells.containsKey(row)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return occupiedCells.get(row).contains(col);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 辅助方法:标记占用单元格
|
|
|
+ private static void markCellsAsOccupied(Map<Integer, Set<Integer>> occupiedCells,
|
|
|
+ int startRow, int startCol,
|
|
|
+ int rowspan, int colspan) {
|
|
|
+ for (int r = startRow; r < startRow + rowspan; r++) {
|
|
|
+ for (int c = startCol; c < startCol + colspan; c++) {
|
|
|
+ occupiedCells.putIfAbsent(r, new HashSet<>());
|
|
|
+ occupiedCells.get(r).add(c);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助方法:检查区域重叠
|
|
|
+ private static boolean isOverlapping(List<CellRangeAddress> existingRegions, CellRangeAddress newRegion) {
|
|
|
+ for (CellRangeAddress region : existingRegions) {
|
|
|
+ if (region.intersects(newRegion)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助方法:获取跨行/跨列值
|
|
|
+ private static int getSpan(Element element, String attr) {
|
|
|
+ String span = element.attr(attr);
|
|
|
+ return span.isEmpty() ? 1 : Integer.parseInt(span);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助方法:提取单元格文本内容
|
|
|
+ private static String extractCellText(Element td) {
|
|
|
+ // 优先获取直接文本内容
|
|
|
+ if (!td.ownText().isEmpty()) {
|
|
|
+ return td.ownText().trim();
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助方法:解析CSS规则
|
|
|
+ private static Map<String, String> parseCssRules(Document doc) {
|
|
|
+ Map<String, String> rules = new HashMap<>();
|
|
|
+ Elements styles = doc.select("style");
|
|
|
+
|
|
|
+ for (Element style : styles) {
|
|
|
+ String css = style.data();
|
|
|
+ // 简化解析:提取类样式
|
|
|
+ Pattern pattern = Pattern.compile("(\\.[^{]+)\\s*\\{([^}]+)\\}");
|
|
|
+ Matcher matcher = pattern.matcher(css);
|
|
|
+
|
|
|
+ while (matcher.find()) {
|
|
|
+ String selector = matcher.group(1).trim();
|
|
|
+ String properties = matcher.group(2).trim();
|
|
|
+ rules.put(selector, properties);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return rules;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助方法:获取单元格样式键
|
|
|
+ private static String getCellStyleKey(Element td, Map<String, String> cssRules) {
|
|
|
+ StringBuilder key = new StringBuilder();
|
|
|
+ String classes = td.attr("class");
|
|
|
+
|
|
|
+ for (String cls : classes.split(" ")) {
|
|
|
+ String selector = "." + cls;
|
|
|
+ if (cssRules.containsKey(selector)) {
|
|
|
+ key.append(cssRules.get(selector)).append(";");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ key.append(td.attr("style"));
|
|
|
+ return key.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 修改后的辅助方法:创建Excel单元格样式
|
|
|
+ private static CellStyle createCellStyle(Workbook workbook, Element td,
|
|
|
+ Map<String, String> cssRules,
|
|
|
+ Map<String, Font> fontCache) {
|
|
|
+ CellStyle style = workbook.createCellStyle();
|
|
|
+ Font font = workbook.createFont();
|
|
|
+
|
|
|
+ // 设置默认字体(避免过大)
|
|
|
+ font.setFontName("宋体");
|
|
|
+
|
|
|
+ String classes = td.attr("class");
|
|
|
+
|
|
|
+ // 应用CSS类样式
|
|
|
+ for (String cls : classes.split(" ")) {
|
|
|
+ String selector = "." + cls;
|
|
|
+ if (cssRules.containsKey(selector)) {
|
|
|
+// applyCssStyle(style, font, cssRules.get(selector));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 应用内联样式
|
|
|
+ applyCssStyle(style, font, td.attr("style"));
|
|
|
+
|
|
|
+ // 限制最大字体大小
|
|
|
+ if (font.getFontHeightInPoints() > 16) {
|
|
|
+ font.setFontHeightInPoints((short) 16);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 字体缓存
|
|
|
+ String fontKey = font.getFontName() + font.getFontHeightInPoints() + font.getBold();
|
|
|
+ if (!fontCache.containsKey(fontKey)) {
|
|
|
+ Font newFont = workbook.createFont();
|
|
|
+ newFont.setFontName(font.getFontName());
|
|
|
+ newFont.setFontHeightInPoints(font.getFontHeightInPoints());
|
|
|
+ newFont.setBold(font.getBold());
|
|
|
+ fontCache.put(fontKey, newFont);
|
|
|
+ }
|
|
|
+ style.setFont(fontCache.get(fontKey));
|
|
|
+
|
|
|
+ // 设置边框(细线)
|
|
|
+ style.setBorderTop(BorderStyle.THIN);
|
|
|
+ style.setBorderBottom(BorderStyle.THIN);
|
|
|
+ style.setBorderLeft(BorderStyle.THIN);
|
|
|
+ style.setBorderRight(BorderStyle.THIN);
|
|
|
+ style.setTopBorderColor(IndexedColors.BLACK.getIndex());
|
|
|
+ style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
|
|
|
+ style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
|
|
|
+ style.setRightBorderColor(IndexedColors.BLACK.getIndex());
|
|
|
+
|
|
|
+ return style;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助方法:应用CSS样式
|
|
|
+ private static void applyCssStyle(CellStyle style, Font font, String css) {
|
|
|
+ if (css == null || css.isEmpty()) return;
|
|
|
+
|
|
|
+ // 解析CSS属性
|
|
|
+ String[] properties = css.split(";");
|
|
|
+ for (String prop : properties) {
|
|
|
+ String[] parts = prop.split(":");
|
|
|
+ if (parts.length < 2) continue;
|
|
|
+
|
|
|
+ String key = parts[0].trim();
|
|
|
+ String value = parts[1].trim();
|
|
|
+
|
|
|
+ switch (key) {
|
|
|
+ case "background-color":
|
|
|
+// setBackgroundColor(style, value);
|
|
|
+ break;
|
|
|
+ case "font-family":
|
|
|
+ font.setFontName(value);
|
|
|
+ break;
|
|
|
+ case "font-size":
|
|
|
+ setFontSize(font, value);
|
|
|
+ break;
|
|
|
+ case "font-weight":
|
|
|
+ if ("bold".equalsIgnoreCase(value)) {
|
|
|
+ font.setBold(true);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case "text-align":
|
|
|
+ setAlignment(style, value);
|
|
|
+ break;
|
|
|
+ case "vertical-align":
|
|
|
+ setVerticalAlignment(style, value);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助方法:设置背景色
|
|
|
+ private static void setBackgroundColor(CellStyle style, String color) {
|
|
|
+ // 简化处理:只处理rgb格式
|
|
|
+ if (color.startsWith("rgb(")) {
|
|
|
+ String[] rgb = color.substring(4, color.length() - 1).split(",");
|
|
|
+ if (rgb.length == 3) {
|
|
|
+ // 实际应用中应使用IndexedColors或自定义颜色
|
|
|
+ style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
|
|
|
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 修改后的辅助方法:设置字体大小(添加上限)
|
|
|
+ private static void setFontSize(Font font, String size) {
|
|
|
+ if (size == null || size.isEmpty()) return;
|
|
|
+
|
|
|
+ if (size.endsWith("pt")) {
|
|
|
+ try {
|
|
|
+ float pt = Float.parseFloat(size.substring(0, size.length() - 2));
|
|
|
+ // 限制最大字体大小为16pt
|
|
|
+ if (pt > 16) pt = 16;
|
|
|
+ font.setFontHeightInPoints((short) pt);
|
|
|
+ } catch (NumberFormatException ignored) {
|
|
|
+ }
|
|
|
+ } else if (size.endsWith("px")) {
|
|
|
+ try {
|
|
|
+ float px = Float.parseFloat(size.substring(0, size.length() - 2));
|
|
|
+ // 将像素转换为点 (1pt ≈ 1.33px)
|
|
|
+ float pt = px / 1.33f;
|
|
|
+ if (pt > 16) pt = 16;
|
|
|
+ font.setFontHeightInPoints((short) pt);
|
|
|
+ } catch (NumberFormatException ignored) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助方法:设置水平对齐
|
|
|
+ private static void setAlignment(CellStyle style, String align) {
|
|
|
+ switch (align.toLowerCase()) {
|
|
|
+ case "center":
|
|
|
+ style.setAlignment(HorizontalAlignment.CENTER);
|
|
|
+ break;
|
|
|
+ case "left":
|
|
|
+ style.setAlignment(HorizontalAlignment.LEFT);
|
|
|
+ break;
|
|
|
+ case "right":
|
|
|
+ style.setAlignment(HorizontalAlignment.RIGHT);
|
|
|
+ break;
|
|
|
+ case "justify":
|
|
|
+ style.setAlignment(HorizontalAlignment.JUSTIFY);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助方法:设置垂直对齐
|
|
|
+ private static void setVerticalAlignment(CellStyle style, String align) {
|
|
|
+ switch (align.toLowerCase()) {
|
|
|
+ case "center":
|
|
|
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
+ break;
|
|
|
+ case "top":
|
|
|
+ style.setVerticalAlignment(VerticalAlignment.TOP);
|
|
|
+ break;
|
|
|
+ case "bottom":
|
|
|
+ style.setVerticalAlignment(VerticalAlignment.BOTTOM);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|