From 8941a4e9f43174a44bae671d52038d6c43a0c4ea Mon Sep 17 00:00:00 2001 From: Raod <1130305001@qq.com> Date: Thu, 2 Sep 2021 09:27:06 +0800 Subject: [PATCH] =?UTF-8?q?excel=E5=AF=BC=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ReportExcelService.java | 3 + .../modules/reportexcel/util/MSExcelUtil.java | 28 + .../reportexcel/util/XlsSheetUtil.java | 888 ++++++++++++++++++ .../modules/reportexcel/util/XlsUtil.java | 453 +++++++++ 4 files changed, 1372 insertions(+) create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/MSExcelUtil.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/XlsSheetUtil.java create mode 100644 report-core/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/XlsUtil.java diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/service/ReportExcelService.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/service/ReportExcelService.java index 31d8e371..0bceb4b3 100644 --- a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/service/ReportExcelService.java +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/service/ReportExcelService.java @@ -16,6 +16,7 @@ public interface ReportExcelService extends GaeaBaseService cells_json = (List) dbObject.get("celldata"); + Map> cellMap = cellGroup(cells_json); + //循环每一行 + for (Integer r : cellMap.keySet()) { + Row row = sheet.createRow(r); + //循环每一列 + for (JSONObject col : cellMap.get(r)) { + createCell(wb, sheet, row, col); + } + } + } + + if (dbObject.containsKey("config") && dbObject.getJSONObject("config").containsKey("borderInfo")) { + JSONArray borderInfo = dbObject.getJSONObject("config").getJSONArray("borderInfo"); + setCellBoard(wb, borderInfo, sheet); + } + + + setColumAndRow(dbObject, sheet); + + } + + /** + * 每一个单元格 + * + * @param row + * @param dbObject + */ + private static void createCell(Workbook wb, Sheet sheet, Row row, JSONObject dbObject) { + if (dbObject.containsKey("c")) { + Integer c = getStrToInt(dbObject.get("c")); + if (c != null) { + Cell cell = row.createCell(c); + //取单元格中的v_json + if (dbObject.containsKey("v")) { + //获取v对象 + Object obj = dbObject.get("v"); + if (obj == null) { + //没有内容 + return; + } + //如果v对象直接是字符串 + if (obj instanceof String) { + if (((String) obj).length() > 0) { + cell.setCellValue(obj.toString()); + } + return; + } + + //转换v为对象(v是一个对象) + JSONObject v_json = (JSONObject) obj; + //样式 + CellStyle style = wb.createCellStyle(); + cell.setCellStyle(style); + + //bs 边框样式 //bc 边框颜色 + setBorderStyle(style, v_json, "bs", "bc"); + //bs_t 上边框样式 bc_t 上边框颜色 + setBorderStyle(style, v_json, "bs_t", "bc_t"); + //bs_b 下边框样式 bc_b 下边框颜色 + setBorderStyle(style, v_json, "bs_b", "bc_b"); + //bs_l 左边框样式 bc_l 左边框颜色 + setBorderStyle(style, v_json, "bs_l", "bc_l"); + //bs_r 右边框样式 bc_r 右边框颜色 + setBorderStyle(style, v_json, "bs_r", "bc_r"); + + + //合并单元格 + //参数1:起始行 参数2:终止行 参数3:起始列 参数4:终止列 + //CellRangeAddress region1 = new CellRangeAddress(rowNumber, rowNumber, (short) 0, (short) 11); + + //mc 合并单元格 + if (v_json.containsKey("mc")) { + //是合并的单元格 + JSONObject mc = v_json.getJSONObject("mc"); + if (mc.containsKey("rs") && mc.containsKey("cs")) { + //合并的第一个单元格 + if (mc.containsKey("r") && mc.containsKey("c")) { + Integer _rs = getIntByDBObject(mc, "rs") - 1; + Integer _cs = getIntByDBObject(mc, "cs") - 1; + Integer _r = getIntByDBObject(mc, "r"); + Integer _c = getIntByDBObject(mc, "c"); + + CellRangeAddress region = new CellRangeAddress(_r.shortValue(), (_r.shortValue() + _rs.shortValue()), _c.shortValue(), (_c.shortValue() + _cs.shortValue())); + sheet.addMergedRegion(region); + } + } else { + //不是合并的第一个单元格 + return; + } + } + + + //取v值 (在数据类型中处理) + //ct 单元格值格式 (fa,t) + setFormatByCt(wb, cell, style, v_json); + + //font设置 + setCellStyleFont(wb, style, v_json); + + //bg 背景颜色 + if (v_json.containsKey("bg")) { + String _v = getByDBObject(v_json, "bg"); + Short _color = ColorUtil.getColorByStr(_v); + if (_color != null) { + style.setFillForegroundColor(_color); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + } + } + + //vt 垂直对齐 垂直对齐方式(0=居中,1=上,2=下) + if (v_json.containsKey("vt")) { + Integer _v = getIntByDBObject(v_json, "vt"); + if (_v != null && _v >= 0 && _v <= 2) { + style.setVerticalAlignment(ConstantUtil.getVerticalType(_v)); + } + } else { + //默认设置居中 + style.setVerticalAlignment(ConstantUtil.getVerticalType(0)); + } + + //ht 水平对齐 水平对齐方式(0=居中,1=左对齐,2=右对齐) + if (v_json.containsKey("ht")) { + Integer _v = getIntByDBObject(v_json, "ht"); + if (_v != null && _v >= 0 && _v <= 2) { + style.setAlignment(ConstantUtil.getHorizontaltype(_v)); + } + } else { + //默认设置左对齐 + style.setAlignment(ConstantUtil.getHorizontaltype(1)); + } + + //tr 文字旋转 文字旋转角度(0=0,1=45,2=-45,3=竖排文字,4=90,5=-90) + if (v_json.containsKey("tr")) { + Integer _v = getIntByDBObject(v_json, "tr"); + if (_v != null) { + style.setRotation(ConstantUtil.getRotation(_v)); + } + } + + //tb 文本换行 0 截断、1溢出、2 自动换行 + // 2:setTextWrapped 0和1:IsTextWrapped = true + if (v_json.containsKey("tb")) { + Integer _v = getIntByDBObject(v_json, "tb"); + if (_v != null) { + if (_v >= 0 && _v <= 1) { + style.setWrapText(false); + } else { + style.setWrapText(true); + } + } + } + + //f 公式 + if (v_json.containsKey("f")) { + String _v = getByDBObject(v_json, "f"); + if (_v.length() > 0) { + try { + if (_v.startsWith("=")) { + cell.setCellFormula(_v.substring(1)); + } else { + cell.setCellFormula(_v); + } + } catch (Exception ex) { + log.error("公式 {};Error:{}", _v, ex.toString()); + } + } + } + + + } + + } + } + } + + /** + * 设置边框 + * + * @param borderInfo + * @param sheet + */ + private static void setCellBoard(Workbook wb, JSONArray borderInfo, Sheet sheet) { + + + //一定要通过 cell.getCellStyle() 不然的话之前设置的样式会丢失 + //设置边框 + for (int i = 0; i < borderInfo.size(); i++) { + JSONObject borderInfoObject = (JSONObject) borderInfo.get(i); + if (borderInfoObject.get("rangeType").equals("cell")) {//单个单元格 + JSONObject borderValueObject = borderInfoObject.getJSONObject("value"); + + JSONObject l = borderValueObject.getJSONObject("l"); + JSONObject r = borderValueObject.getJSONObject("r"); + JSONObject t = borderValueObject.getJSONObject("t"); + JSONObject b = borderValueObject.getJSONObject("b"); + + + int row_ = borderValueObject.getInteger("row_index"); + int col_ = borderValueObject.getInteger("col_index"); + + Row row = sheet.getRow(row_); + if (null == row) { + row = sheet.createRow(row_); + } + Cell cell = row.getCell(col_); + CellStyle style; + if (null == cell) { + style = wb.createCellStyle(); + cell = row.createCell(col_); + cell.setCellStyle(style); + } else { + style = cell.getCellStyle(); + } + + + if (l != null) { + style.setBorderLeft(BorderStyle.valueOf(l.getShort("style"))); //左边框 + Short color = ColorUtil.getColorByStr(l.getString("color")); + if (null != color) { + style.setLeftBorderColor(color);//左边框颜色 + } + + } + if (r != null) { + style.setBorderRight(BorderStyle.valueOf(r.getShort("style"))); //右边框 + Short color = ColorUtil.getColorByStr(r.getString("color")); + if (null != color) { + style.setRightBorderColor(color);//右边框颜色 + } + + } + if (t != null) { + style.setBorderTop(BorderStyle.valueOf(t.getShort("style"))); //顶部边框 + Short _vcolor = ColorUtil.getColorByStr(t.getString("color")); + if (null != _vcolor) { + style.setTopBorderColor(_vcolor);//顶部边框颜色 + } + + } + if (b != null) { + style.setBorderBottom(BorderStyle.valueOf(b.getShort("style"))); //底部边框 + Short _vcolor = ColorUtil.getColorByStr(b.getString("color")); + if (_vcolor != null) { + //底部边框颜色 + style.setBottomBorderColor(_vcolor); + } + } + + } else if (borderInfoObject.get("rangeType").equals("range")) { + //选区 + Short style_ = borderInfoObject.getShort("style"); + String borderType = borderInfoObject.getString("borderType"); + Short color = ColorUtil.getColorByStr(borderInfoObject.getString("color")); + JSONObject rangObject = (JSONObject) ((JSONArray) (borderInfoObject.get("range"))).get(0); + + JSONArray rowList = rangObject.getJSONArray("row"); + JSONArray columnList = rangObject.getJSONArray("column"); + + + for (int row_ = rowList.getInteger(0); row_ < rowList.getInteger(rowList.size() - 1) + 1; row_++) { + for (int col_ = columnList.getInteger(0); col_ < columnList.getInteger(columnList.size() - 1) + 1; col_++) { + Row row = sheet.getRow(row_); + if (null == row) { + row = sheet.createRow(row_); + } + Cell cell = row.getCell(col_); + CellStyle style; + if (null == cell) { + style = wb.createCellStyle(); + cell = row.createCell(col_); + cell.setCellStyle(style); + } else { + style = cell.getCellStyle(); + } + + //"border-left" | "border-right" | "border-top" | "border-bottom" | "border-all" | "border-horizontal" | "border-vertical" + // "border-outside" | "border-inside" | | "border-none" + if ("border-left".equals(borderType) || "border-all".equals(borderType)) { + style.setBorderLeft(BorderStyle.valueOf(style_)); //左边框 + style.setLeftBorderColor(color);//左边框颜色 + } + if ("border-right".equals(borderType) || "border-all".equals(borderType)) { + style.setBorderRight(BorderStyle.valueOf(style_)); //右边框 + style.setRightBorderColor(color);//右边框颜色 + } + + if ("border-top".equals(borderType) || "border-all".equals(borderType)) { + style.setBorderTop(BorderStyle.valueOf(style_)); //顶部边框 + style.setTopBorderColor(color);//顶部边框颜色 + } + + if ("border-bottom".equals(borderType) || "border-all".equals(borderType)) { + style.setBorderBottom(BorderStyle.valueOf(style_)); //底部边框 + style.setBottomBorderColor(color);//底部边框颜色 } + } + + if ("border-outside".equals(borderType)) { + //外圈边框 + if (row_ == rowList.getInteger(0) ) { + style.setBorderTop(BorderStyle.valueOf(style_)); //顶部边框 + style.setTopBorderColor(color);//顶部边框颜色 + } + if (col_ == columnList.getInteger(0)) { + style.setBorderLeft(BorderStyle.valueOf(style_)); //左边框 + style.setLeftBorderColor(color);//左边框颜色 + } + if (row_ == rowList.getInteger(rowList.size() - 1)) { + style.setBorderBottom(BorderStyle.valueOf(style_)); //底部边框 + style.setBottomBorderColor(color);//底部边框颜色 } + } + if (col_ == columnList.getInteger(columnList.size() - 1)) { + style.setBorderRight(BorderStyle.valueOf(style_)); //右边框 + style.setRightBorderColor(color);//右边框颜色 + } + + } + + if ("border-inside".equals(borderType)) { + //所有内边框 + if (row_ >= rowList.getInteger(0) && row_ < rowList.getInteger(rowList.size() - 1)) { + style.setBorderRight(BorderStyle.valueOf(style_)); //右边框 + style.setRightBorderColor(color);//右边框颜色 + style.setBorderBottom(BorderStyle.valueOf(style_)); //底部边框 + style.setBottomBorderColor(color);//底部边框颜色 } + } + + if (col_ >= columnList.getInteger(0) && col_ < columnList.getInteger(columnList.size() - 1)) { + style.setBorderRight(BorderStyle.valueOf(style_)); //右边框 + style.setRightBorderColor(color);//右边框颜色 + style.setBorderBottom(BorderStyle.valueOf(style_)); //底部边框 + style.setBottomBorderColor(color);//底部边框颜色 } + } + + } + + if ("border-horizontal".equals(borderType)) { + //内部横线 + if (row_ >= rowList.getInteger(0) && row_ < rowList.getInteger(rowList.size() - 1)) { + style.setBorderBottom(BorderStyle.valueOf(style_)); //底部边框 + style.setBottomBorderColor(color);//底部边框颜色 } + } + if (col_ >= columnList.getInteger(0) && col_ < columnList.getInteger(columnList.size() - 1)) { + style.setBorderBottom(BorderStyle.valueOf(style_)); //底部边框 + style.setBottomBorderColor(color);//底部边框颜色 } + } + } + + if ("border-vertical".equals(borderType)) { + //内部竖线 + if (row_ >= rowList.getInteger(0) && row_ < rowList.getInteger(rowList.size() - 1)) { + style.setBorderRight(BorderStyle.valueOf(style_)); //右边框 + style.setRightBorderColor(color);//右边框颜色 + } + if (col_ >= columnList.getInteger(0) && col_ < columnList.getInteger(columnList.size() - 1)) { + style.setBorderRight(BorderStyle.valueOf(style_)); //右边框 + style.setRightBorderColor(color);//右边框颜色 + } + } + + + + } + } + + + } + } + + } + + + /** + * 设置单元格,宽、高 + * + * @param dbObject + * @param sheet + */ + private static void setColumAndRow(JSONObject dbObject, Sheet sheet) { + if (dbObject.containsKey("config")) { + JSONObject config = dbObject.getJSONObject("config"); + + if (config.containsKey("columnlen")) { + JSONObject columnlen = config.getJSONObject("columnlen"); + if (columnlen != null) { + for (String k : columnlen.keySet()) { + Integer _i = getStrToInt(k); + Integer _v = getStrToInt(columnlen.get(k).toString()); + if (_i != null && _v != null) { +// sheet.setColumnWidth(_i, MSExcelUtil.heightUnits2Pixel(_v.shortValue())); + // TODO 乘以32,有待商榷 + sheet.setColumnWidth(_i, _v * 32); + } + } + } + } + if (config.containsKey("rowlen")) { + JSONObject rowlen = config.getJSONObject("rowlen"); + if (rowlen != null) { + for (String k : rowlen.keySet()) { + Integer _i = getStrToInt(k); + Integer _v = getStrToInt(rowlen.get(k).toString()); + if (_i != null && _v != null) { + Row row = sheet.getRow(_i); + if (row != null) { +// row.setHeightInPoints(MSExcelUtil.pixel2WidthUnits(_v.shortValue())); + row.setHeightInPoints(_v.shortValue()); + } + } + } + } + } + } + } + + /** + * 单元格字体相关样式 + * + * @param wb + * @param style + * @param dbObject + */ + private static void setCellStyleFont(Workbook wb, CellStyle style, JSONObject dbObject) { + Font font = wb.createFont(); + style.setFont(font); + + //ff 字体 + if (dbObject.containsKey("ff")) { + if (dbObject.get("ff") instanceof Integer) { + Integer _v = getIntByDBObject(dbObject, "ff"); + if (_v != null && ConstantUtil.ff_IntegerToName.containsKey(_v)) { + font.setFontName(ConstantUtil.ff_IntegerToName.get(_v)); + } + } else if (dbObject.get("ff") instanceof String) { + font.setFontName(getByDBObject(dbObject, "ff")); + } + } + //fc 字体颜色 + if (dbObject.containsKey("fc")) { + String _v = getByDBObject(dbObject, "fc"); + Short _color = ColorUtil.getColorByStr(_v); + if (_color != null) { + font.setColor(_color); + } + } + //bl 粗体 + if (dbObject.containsKey("bl")) { + Integer _v = getIntByDBObject(dbObject, "bl"); + if (_v != null) { + if (_v.equals(1)) { + //是否粗体显示 + font.setBold(true); + } else { + font.setBold(false); + } + } + } + //it 斜体 + if (dbObject.containsKey("it")) { + Integer _v = getIntByDBObject(dbObject, "it"); + if (_v != null) { + if (_v.equals(1)) { + font.setItalic(true); + } else { + font.setItalic(false); + } + } + } + //fs 字体大小 + if (dbObject.containsKey("fs")) { + Integer _v = getStrToInt(getObjectByDBObject(dbObject, "fs")); + if (_v != null) { + font.setFontHeightInPoints(_v.shortValue()); + } + } + //cl 删除线 (导入没有) 0 常规 、 1 删除线 + if (dbObject.containsKey("cl")) { + Integer _v = getIntByDBObject(dbObject, "cl"); + if (_v != null) { + if (_v.equals(1)) { + font.setStrikeout(true); + } + } + } + //ul 下划线 + if (dbObject.containsKey("ul")) { + Integer _v = getIntByDBObject(dbObject, "ul"); + if (_v != null) { + if (_v.equals(1)) { + font.setUnderline(Font.U_SINGLE); + } else { + font.setUnderline(Font.U_NONE); + } + } + } + + } + + /** + * 设置cell边框颜色样式 + * + * @param style 样式 + * @param dbObject json对象 + * @param bs 样式 + * @param bc 样式 + */ + private static void setBorderStyle(CellStyle style, JSONObject dbObject, String bs, String bc) { + //bs 边框样式 + if (dbObject.containsKey(bs)) { + Integer _v = getStrToInt(getByDBObject(dbObject, bs)); + if (_v != null) { + //边框没有,不作改变 + if (bs.equals("bs") || bs.equals("bs_t")) { + style.setBorderTop(BorderStyle.valueOf(_v.shortValue())); + } + if (bs.equals("bs") || bs.equals("bs_b")) { + style.setBorderBottom(BorderStyle.valueOf(_v.shortValue())); + } + if (bs.equals("bs") || bs.equals("bs_l")) { + style.setBorderLeft(BorderStyle.valueOf(_v.shortValue())); + } + if (bs.equals("bs") || bs.equals("bs_r")) { + style.setBorderRight(BorderStyle.valueOf(_v.shortValue())); + } + + //bc 边框颜色 + String _vcolor = getByDBObject(dbObject, bc); + if (_vcolor != null) { + Short _color = ColorUtil.getColorByStr(_vcolor); + if (_color != null) { + if (bc.equals("bc") || bc.equals("bc_t")) { + style.setTopBorderColor(_color); + } + if (bc.equals("bc") || bc.equals("bc_b")) { + style.setBottomBorderColor(_color); + } + if (bc.equals("bc") || bc.equals("bc_l")) { + style.setLeftBorderColor(_color); + } + if (bc.equals("bc") || bc.equals("bc_r")) { + style.setRightBorderColor(_color); + } + } + } + } + } + } + + + /** + * 设置单元格格式 ct 单元格值格式 (fa,t) + * + * @param cell + * @param style + * @param dbObject + */ + private static void setFormatByCt(Workbook wb, Cell cell, CellStyle style, JSONObject dbObject) { + + if (!dbObject.containsKey("v") && dbObject.containsKey("ct")) { + /* 处理以下数据结构 + { + "celldata": [{ + "c": 0, + "r": 8, + "v": { + "ct": { + "s": [{ + "v": "sdsdgdf\r\ndfgdfg\r\ndsfgdfgdf\r\ndsfgdfg" + }], + "t": "inlineStr", + "fa": "General" + } + } + }] + } + */ + JSONObject ct = dbObject.getJSONObject("ct"); + if (ct.containsKey("s")) { + Object s = ct.get("s"); + if (s instanceof List && ((List) s).size() > 0) { + JSONObject _s1 = (JSONObject) ((List) s).get(0); + if (_s1.containsKey("v") && _s1.get("v") instanceof String) { + dbObject.put("v", _s1.get("v")); + style.setWrapText(true); + } + } + + } + } + + //String v = ""; //初始化 + if (dbObject.containsKey("v")) { + //v = v_json.get("v").toString(); + //取到v后,存到poi单元格对象 + //设置该单元格值 + //cell.setValue(v); + + //String v=getByDBObject(v_json,"v"); + //cell.setValue(v); + Object obj = getObjectByDBObject(dbObject, "v"); + if (obj instanceof Number) { + cell.setCellValue(Double.valueOf(obj.toString())); + } else if (obj instanceof Double) { + cell.setCellValue((Double) obj); + } else if (obj instanceof Date) { + cell.setCellValue((Date) obj); + } else if (obj instanceof Calendar) { + cell.setCellValue((Calendar) obj); + } else if (obj instanceof RichTextString) { + cell.setCellValue((RichTextString) obj); + } else if (obj instanceof String) { + cell.setCellValue((String) obj); + } else { + cell.setCellValue(obj.toString()); + } + + } + + if (dbObject.containsKey("ct")) { + JSONObject ct = dbObject.getJSONObject("ct"); + if (ct.containsKey("fa") && ct.containsKey("t")) { + //t 0=bool,1=datetime,2=error,3=null,4=numeric,5=string,6=unknown + String fa = getByDBObject(ct, "fa"); //单元格格式format定义串 + String t = getByDBObject(ct, "t"); //单元格格式type类型 + + Integer _i = ConstantUtil.getNumberFormatMap(fa); + switch (t) { + case "s": { + //字符串 + if (_i >= 0) { + style.setDataFormat(_i.shortValue()); + } else { + style.setDataFormat((short) 0); + } + cell.setCellType(CellType.STRING); + break; + } + case "d": { + //日期 + Date _d = null; + String v = getByDBObject(dbObject, "m"); + if (v.length() == 0) { + v = getByDBObject(dbObject, "v"); + } + if (v.length() > 0) { + if (v.indexOf("-") > -1) { + if (v.indexOf(":") > -1) { + _d = ConstantUtil.stringToDateTime(v); + } else { + _d = ConstantUtil.stringToDate(v); + } + } else { + _d = ConstantUtil.toDate(v); + } + } + if (_d != null) { + //能转换为日期 + cell.setCellValue(_d); + DataFormat format = wb.createDataFormat(); + style.setDataFormat(format.getFormat(fa)); + + } else { + //不能转换为日期 + if (_i >= 0) { + style.setDataFormat(_i.shortValue()); + } else { + style.setDataFormat((short) 0); + } + } + break; + } + case "b": { + //逻辑 + cell.setCellType(CellType.BOOLEAN); + if (_i >= 0) { + style.setDataFormat(_i.shortValue()); + } else { + DataFormat format = wb.createDataFormat(); + style.setDataFormat(format.getFormat(fa)); + } + break; + } + case "n": { + //数值 +// cell.setCellType(CellType.NUMERIC); + //数字转字符串 + cell.setCellType(CellType.STRING); + if (_i >= 0) { + style.setDataFormat(_i.shortValue()); + } else { + DataFormat format = wb.createDataFormat(); + style.setDataFormat(format.getFormat(fa)); + } + break; + } + case "u": + case "g": { + //general 自动类型 + //cell.setCellType(CellType._NONE); + if (_i >= 0) { + style.setDataFormat(_i.shortValue()); + } else { + DataFormat format = wb.createDataFormat(); + style.setDataFormat(format.getFormat(fa)); + } + break; + } + case "e": { + //错误 + cell.setCellType(CellType.ERROR); + if (_i >= 0) { + style.setDataFormat(_i.shortValue()); + } else { + DataFormat format = wb.createDataFormat(); + style.setDataFormat(format.getFormat(fa)); + } + break; + } + + } + + } + + } + } + + /** + * 内容按行分组 + * + * @param cells + * @return + */ + private static Map> cellGroup(List cells) { + Map> cellMap = new HashMap<>(100); + for (JSONObject dbObject : cells) { + //行号 + if (dbObject.containsKey("r")) { + Integer r = getStrToInt(dbObject.get("r")); + if (r != null) { + if (cellMap.containsKey(r)) { + cellMap.get(r).add(dbObject); + } else { + List list = new ArrayList<>(10); + list.add(dbObject); + cellMap.put(r, list); + } + } + } + + } + return cellMap; + } + + + /** + * 获取一个k的值 + * + * @param b + * @param k + * @return + */ + public static String getByDBObject(JSONObject b, String k) { + if (b.containsKey(k)) { + if (b.get(k) != null && b.get(k) instanceof String) { + return b.getString(k); + } + } + return null; + } + + /** + * 获取一个k的值 + * + * @param b + * @param k + * @return + */ + public static Object getObjectByDBObject(JSONObject b, String k) { + if (b.containsKey(k)) { + if (b.get(k) != null) { + return b.get(k); + } + } + return ""; + } + + /** + * 没有/无法转换 返回null + * + * @param b + * @param k + * @return + */ + public static Integer getIntByDBObject(JSONObject b, String k) { + if (b.containsKey(k)) { + if (b.get(k) != null) { + try { + String _s = b.getString(k).replace("px", ""); + Double _d = Double.parseDouble(_s); + return _d.intValue(); + } catch (Exception ex) { + log.error(ex.getMessage()); + return null; + } + } + } + return null; + } + + /** + * 转int + * + * @param str + * @return + */ + private static Integer getStrToInt(Object str) { + try { + if (str != null) { + return Integer.parseInt(str.toString()); + } + return null; + } catch (Exception ex) { + log.error("String:{};Error:{}", str, ex.getMessage()); + return null; + } + } + + private static Short getStrToShort(Object str) { + try { + if (str != null) { + return Short.parseShort(str.toString()); + } + return null; + } catch (Exception ex) { + log.error("String:{};Error:{}", str, ex.getMessage()); + return null; + } + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/XlsUtil.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/XlsUtil.java new file mode 100644 index 00000000..51ea0d3e --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/XlsUtil.java @@ -0,0 +1,453 @@ +package com.anjiplus.template.gaea.business.modules.reportexcel.util; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.anjiplus.template.gaea.business.enums.ExcelCenterStyleEnum; +import com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto.GridRecordDataModel; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.poi.hssf.usermodel.HSSFCellStyle; +import org.apache.poi.hssf.usermodel.HSSFFont; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.hssf.util.HSSFColor; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.usermodel.XSSFCellStyle; +import org.apache.poi.xssf.usermodel.XSSFColor; +import org.apache.poi.xssf.usermodel.XSSFFont; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +import javax.validation.constraints.NotNull; +import java.io.IOException; +import java.io.OutputStream; +import java.util.*; + +/** + * 来自:https://github.com/mengshukeji/LuckysheetServer + * 使用poi导出xls + * + * @author Administrator + */ +public class XlsUtil { + + private final static String MODEL = "{\"c\":0,\"r\":0,\"v\":{\"m\":\"模板\",\"v\":\"模板\",\"bl\":1,\"ct\":{\"t\":\"g\",\"fa\":\"General\"}}}"; + private final static String BORDER_MODEL = "{\"rangeType\":\"cell\",\"value\":{\"b\":{\"color\":\"rgb(0, 0, 0)\",\"style\":1},\"r\":{\"color\":\"rgb(0, 0, 0)\",\"style\":1},\"col_index\":5,\"t\":{\"color\":\"rgb(0, 0, 0)\",\"style\":1},\"row_index\":7,\"l\":{\"color\":\"rgb(0, 0, 0)\",\"style\":1}}}"; + /** + * 默认行数 + */ + private static final int DEFAULT_ROW_INDEX = 84; + /** + * 默认列数 + */ + private static final int DEFAULT_COLUMN_INDEX = 64; + + /** + * 输出文件流 + * + * @param outputStream 流 + * @param isXlsx 是否是xlsx + * @param dbObjectList 数据 + */ + public static void exportXlsFile(OutputStream outputStream, Boolean isXlsx, List dbObjectList) throws IOException { + Workbook wb = null; + if (isXlsx) { + wb = new XSSFWorkbook(); + } else { + wb = new HSSFWorkbook(); + } + if (dbObjectList != null && dbObjectList.size() > 0) { + for (int x = 0; x < dbObjectList.size(); x++) { + XlsSheetUtil.exportSheet(wb, x, dbObjectList.get(x)); + } + } + wb.write(outputStream); + } + + /** + * @param workbook 工作簿 + * @return Map + * @description 读取excel + * @author zhouhang + * @date 2021/4/20 + */ + public static List readExcel(Workbook workbook) { + List list = new ArrayList<>(); + Iterator sheetIterator = workbook.sheetIterator(); + int sheetIndex = 0; + while (sheetIterator.hasNext()) { + Sheet sheet = sheetIterator.next(); + //生成默认MODEL + GridRecordDataModel model; + if (Objects.equals(0, sheetIndex)) { + model = strToModel("", (sheetIndex + 1) + "", 1, sheetIndex); + } else { + model = strToModel("", (sheetIndex + 1) + "", 0, sheetIndex); + } + sheetIndex++; + //读取sheet页 + readSheet(sheet, model, workbook); + //设置sheet页名称 + model.getJson_data().put("name", sheet.getSheetName()); + list.add(model); + } + return list; + } + + public static GridRecordDataModel strToModel(String list_id, String index, int status, int order) { + String strSheet = "{\"row\":84,\"name\":\"reSheetName\",\"chart\":[],\"color\":\"\",\"index\":\"reIndex\",\"order\":reOrder,\"column\":60,\"config\":{},\"status\":reStatus,\"celldata\":[],\"ch_width\":4748,\"rowsplit\":[],\"rh_height\":1790,\"scrollTop\":0,\"scrollLeft\":0,\"visibledatarow\":[],\"visibledatacolumn\":[],\"jfgird_select_save\":[],\"jfgrid_selection_range\":{}}"; + strSheet = strSheet.replace("reSheetName", "Sheet" + index).replace("reIndex", index).replace("reOrder", order + "").replace("reStatus", status + ""); + + JSONObject bson = JSONObject.parseObject(strSheet); + GridRecordDataModel model = new GridRecordDataModel(); + model.setBlock_id("fblock"); + model.setRow_col("5_5"); + model.setIndex(index); + model.setIs_delete(0); + model.setJson_data(bson); + model.setStatus(status); + model.setOrder(order); + model.setList_id(list_id); + return model; + } + + /** + * @param sheet sheet页 + * @param model 数据存储 + * @param workbook excel + * @description 读取单个sheet页 + * @author zhouhang + * @date 2021/4/20 + */ + private static void readSheet(Sheet sheet, GridRecordDataModel model, Workbook workbook) { + //excel数据集合 + List dataList = new ArrayList<>(); + model.setDataList(dataList); + //获取行迭代器 + Iterator rowIterator = sheet.rowIterator(); + //获取合并单元格信息 + Map rangeMap = getRangeMap(sheet); + //记录最大列 + int maxCellNumber = 0; + int maxRowNumber = 0; + //列宽 + JSONObject columnLenObj = new JSONObject(); + //行高 + JSONObject rowLenObj = new JSONObject(); + //读取文档 + while (rowIterator.hasNext()) { + Row row = rowIterator.next(); + int rowLen = ((int) row.getHeight()) / 20; + if (rowLen == 0) { + rowLen = 30; + } + rowLenObj.put(row.getRowNum() + "", rowLen); + Iterator cellIterator = row.cellIterator(); + maxRowNumber = row.getRowNum(); + while (cellIterator.hasNext()) { + //"{\"c\":0,\"r\":0,\"v\":{\"m\":\"模板\",\"v\":\"模板\",\"bl\":1,\"ct\":{\"t\":\"g\",\"fa\":\"General\"}}}"; + JSONObject dataModel = JSONObject.parseObject(MODEL); + //初始化默认单元格内容 + Cell cell = cellIterator.next(); + int columnLen = sheet.getColumnWidth(cell.getColumnIndex()) / 25; + if (columnLen == 0) { + columnLen = 73; + } + columnLenObj.put(cell.getColumnIndex() + "", columnLen); + //修改最大列 + maxCellNumber = Math.max(cell.getColumnIndex(), maxCellNumber); + //设置行列 + dataModel.put("c", cell.getColumnIndex()); + dataModel.put("r", row.getRowNum()); + //获取单元格内容 + switch (cell.getCellType()) { + case STRING: + dataModel.getJSONObject("v").put("m", cell.getStringCellValue()); + dataModel.getJSONObject("v").put("v", cell.getStringCellValue()); + break; + case NUMERIC: + dataModel.getJSONObject("v").put("m", cell.getNumericCellValue()); + dataModel.getJSONObject("v").put("v", cell.getNumericCellValue()); + break; + case BLANK: + dataModel.getJSONObject("v").put("m", ""); + dataModel.getJSONObject("v").put("v", ""); + break; + case BOOLEAN: + dataModel.getJSONObject("v").put("m", cell.getBooleanCellValue()); + dataModel.getJSONObject("v").put("v", cell.getBooleanCellValue()); + break; + case ERROR: + dataModel.getJSONObject("v").put("m", cell.getErrorCellValue()); + dataModel.getJSONObject("v").put("v", cell.getErrorCellValue()); + break; + default: + dataModel.getJSONObject("v").put("m", ""); + dataModel.getJSONObject("v").put("v", ""); + } + //设置单元格合并标记 + dealWithCellMarge(rangeMap, row, cell, dataModel); + //设置单元格样式、合并单元格信息 + dealWithExcelStyle(model, dataModel, cell, sheet, workbook); + dataList.add(dataModel); + } + } + //设置最大行、列 + model.getJson_data().put("column", Math.max(maxCellNumber, DEFAULT_COLUMN_INDEX)); + model.getJson_data().put("row", Math.max(maxRowNumber, DEFAULT_ROW_INDEX)); + //设置行高、列宽 + model.getJson_data().getJSONObject("config").put("columnlen", columnLenObj); + model.getJson_data().getJSONObject("config").put("rowlen", rowLenObj); + } + + /** + * @param sheet sheet页信息 + * @return Map 单元格合并信息 + * @description 获取合并单元格信息 所有合并单元的MAP + * @author zhouhang + * @date 2021/4/21 + */ + @NotNull + private static Map getRangeMap(Sheet sheet) { + List rangeAddressList = sheet.getMergedRegions(); + Map rangeMap = new HashMap<>(rangeAddressList.size() * 5); + for (CellRangeAddress cellAddresses : rangeAddressList) { + for (int i = cellAddresses.getFirstRow(); i <= cellAddresses.getLastRow(); i++) { + for (int j = cellAddresses.getFirstColumn(); j <= cellAddresses.getLastColumn(); j++) { + if (i == cellAddresses.getFirstRow() && j == cellAddresses.getFirstColumn()) { + //单元格合并初始值特殊标记 + rangeMap.put(i + "_" + j, cellAddresses.getFirstRow() + "_" + cellAddresses.getFirstColumn() + "_" + cellAddresses.getLastRow() + "_" + cellAddresses.getLastColumn()); + } else { + rangeMap.put(i + "_" + j, cellAddresses.getFirstRow() + "_" + cellAddresses.getFirstColumn()); + } + } + } + } + return rangeMap; + } + + /** + * @param rangeMap 合并信息 + * @param row 行信息 + * @param cell 单元格 + * @param dataModel 单元格数据存储信息 + * @description 设置单元格合并标记 + * @author zhouhang + * @date 2021/4/21 + */ + private static void dealWithCellMarge(Map rangeMap, Row row, Cell cell, JSONObject dataModel) { + if (rangeMap.containsKey(row.getRowNum() + "_" + cell.getColumnIndex())) { + String margeValue = rangeMap.get(row.getRowNum() + "_" + cell.getColumnIndex()); + JSONObject mcData = new JSONObject(); + String[] s = margeValue.split("_"); + mcData.put("r", Integer.parseInt(s[0])); + mcData.put("c", Integer.parseInt(s[1])); + if (s.length == 4) { + mcData.put("rs", Integer.parseInt(s[2]) - Integer.parseInt(s[0]) + 1); + mcData.put("cs", Integer.parseInt(s[3]) - Integer.parseInt(s[1]) + 1); + } + dataModel.getJSONObject("v").put("mc", mcData); + } + } + + /** + * @param model sheet页信息 + * @param dataModel 单元格信息 + * @param cell 单元格 + * @param sheet sheet页数据 + * @param workbook excel + * @description 获取单元格样式,设置单元格样式 + * @author zhouhang + * @date 2021/4/21 + */ + private static void dealWithExcelStyle(GridRecordDataModel model, JSONObject dataModel, Cell cell, Sheet sheet, Workbook workbook) { + //设置单元格合并信息 + dealWithExcelMerge(model, sheet); + //设置字体样式 + setFontStyle(dataModel, workbook, cell); + //设置单元格样式 + dealWithBorderStyle(model, cell, workbook); + } + + /** + * @param model 在线表格存储单元 + * @param cell cell + * @param workbook workbook + * @description 设置单元格样式 + * @author zhouhang + * @date 2021/4/22 + */ + private static void dealWithBorderStyle(GridRecordDataModel model, Cell cell, Workbook workbook) { + CellStyle cellStyle = cell.getCellStyle(); + //判断是否存在边框 + if (cellStyle.getBorderTop().getCode() > 0 || cellStyle.getBorderBottom().getCode() > 0 || + cellStyle.getBorderLeft().getCode() > 0 || cellStyle.getBorderRight().getCode() > 0) { + JSONObject border = JSONObject.parseObject(BORDER_MODEL); + border.getJSONObject("value").put("row_index", cell.getRowIndex()); + border.getJSONObject("value").put("col_index", cell.getColumnIndex()); + //xlsx + if (cellStyle instanceof XSSFCellStyle) { + XSSFCellStyle xssfCellStyle = (XSSFCellStyle) cellStyle; + if (Objects.equals((short) 0, cellStyle.getBorderTop().getCode())) { + border.getJSONObject("value").remove("t"); + } else { + border.getJSONObject("value").getJSONObject("t").put("color", dealWithRbg(xssfCellStyle.getTopBorderXSSFColor().getRGB())); + } + if (Objects.equals((short) 0, cellStyle.getBorderRight().getCode())) { + border.getJSONObject("value").remove("r"); + } else { + border.getJSONObject("value").getJSONObject("r").put("color", dealWithRbg(xssfCellStyle.getRightBorderXSSFColor().getRGB())); + } + if (Objects.equals((short) 0, cellStyle.getBorderLeft().getCode())) { + border.getJSONObject("value").remove("l"); + } else { + border.getJSONObject("value").getJSONObject("l").put("color", dealWithRbg(xssfCellStyle.getLeftBorderXSSFColor().getRGB())); + } + if (Objects.equals((short) 0, cellStyle.getBorderBottom().getCode())) { + border.getJSONObject("value").remove("b"); + } else { + border.getJSONObject("value").getJSONObject("b").put("color", dealWithRbg(xssfCellStyle.getBottomBorderXSSFColor().getRGB())); + } + } else if (cellStyle instanceof HSSFCellStyle) { + //xls + HSSFWorkbook hssfWorkbook = (HSSFWorkbook) workbook; + HSSFCellStyle hssfCellStyle = (HSSFCellStyle) cellStyle; + if (Objects.equals((short) 0, cellStyle.getBorderTop().getCode())) { + border.getJSONObject("value").remove("t"); + } else { + HSSFColor color = hssfWorkbook.getCustomPalette().getColor(hssfCellStyle.getTopBorderColor()); + border.getJSONObject("value").getJSONObject("t").put("color", dealWithRbgShort(color.getTriplet())); + } + if (Objects.equals((short) 0, cellStyle.getBorderRight().getCode())) { + border.getJSONObject("value").remove("r"); + } else { + HSSFColor color = hssfWorkbook.getCustomPalette().getColor(hssfCellStyle.getRightBorderColor()); + border.getJSONObject("value").getJSONObject("r").put("color", dealWithRbgShort(color.getTriplet())); + } + if (Objects.equals((short) 0, cellStyle.getBorderLeft().getCode())) { + border.getJSONObject("value").remove("l"); + } else { + HSSFColor color = hssfWorkbook.getCustomPalette().getColor(hssfCellStyle.getLeftBorderColor()); + border.getJSONObject("value").getJSONObject("l").put("color", dealWithRbgShort(color.getTriplet())); + } + if (Objects.equals((short) 0, cellStyle.getBorderBottom().getCode())) { + border.getJSONObject("value").remove("b"); + } else { + HSSFColor color = hssfWorkbook.getCustomPalette().getColor(hssfCellStyle.getBottomBorderColor()); + border.getJSONObject("value").getJSONObject("b").put("color", dealWithRbgShort(color.getTriplet())); + } + } + JSONArray borderInfo = model.getJson_data().getJSONObject("config").getJSONArray("borderInfo"); + if (Objects.isNull(borderInfo)) { + borderInfo = new JSONArray(); + model.getJson_data().getJSONObject("config").put("borderInfo", borderInfo); + } + borderInfo.add(border); + } + } + + /** + * @param rgb RBG short + * @return rbg(0, 0, 0) + * @description 转换RBG rbg(0,0,0) + * @author zhouhang + * @date 2021/4/26 + */ + private static String dealWithRbgShort(short[] rgb) { + return getRbg(Objects.nonNull(rgb), rgb[0], rgb[1], rgb[2]); + } + + @NotNull + private static String getRbg(boolean b2, short r, short b, short g) { + if (b2) { + return "rgb(" + (r & 0xFF) + ", " + (b & 0xFF) + ", " + (g & 0xFF) + ")"; + } else { + return "rgb(0, 0, 0)"; + } + } + + /** + * @param rgb RBG byte + * @return rbg(0, 0, 0) + * @description 转换RBG rbg(0,0,0) + * @author zhouhang + * @date 2021/4/26 + */ + private static String dealWithRbg(byte[] rgb) { + if (Objects.isNull(rgb)) { + return "rgb(0, 0, 0)"; + } + short[] shorts = new short[]{rgb[0], rgb[1], rgb[2]}; + return getRbg(true, shorts[0], shorts[1], shorts[2]); + } + + /** + * @param dataModel 单元格内容 + * @param workbook workbook + * @param cell cell + * @description s设置字体样式 + * @author zhouhang + * @date 2021/4/21 + */ + private static void setFontStyle(JSONObject dataModel, Workbook workbook, Cell cell) { + CellStyle cellStyle = cell.getCellStyle(); + Font font = workbook.getFontAt(cellStyle.getFontIndexAsInt()); + JSONObject v = dataModel.getJSONObject("v"); + //ht 水平对齐 水平对齐方式(0=居中,1=左对齐,2=右对齐) excel:左:1 中:2 右:3 未设置:0 + v.put("ht", ExcelCenterStyleEnum.getExcelCenterStyleByExcelCenterCode(cellStyle.getAlignment().getCode()).getOnlineExcelCode()); + //bl 字体加粗设置 + v.put("bl", font.getBold() ? 1 : 0); + //lt 斜体 + v.put("it", font.getItalic() ? 1 : 0); + //ff 字体 + v.put("ff", font.getFontName()); + //fc 字体颜色 + if (font instanceof HSSFFont) { + HSSFFont hssfFont = (HSSFFont) font; + HSSFColor hssfColor = hssfFont.getHSSFColor((HSSFWorkbook) workbook); + if (Objects.nonNull(hssfColor)) { + v.put("fc", ColorUtil.convertRGBToHex(hssfColor.getTriplet()[0], hssfColor.getTriplet()[1], hssfColor.getTriplet()[2])); + } + } else { + XSSFFont xssfFont = (XSSFFont) font; + XSSFColor xssfColor = xssfFont.getXSSFColor(); + if (Objects.nonNull(xssfColor)) { + v.put("fc", "#" + xssfColor.getARGBHex().substring(2)); + } + } + //fs 字体大小 + v.put("fs", font.getFontHeightInPoints()); + //cl 删除线 + v.put("cl", font.getStrikeout() ? 1 : 0); + //ul 下划线 + v.put("un", font.getUnderline()); + //背景色 + String fillColorHex = ColorUtil.getFillColorHex(cell); + if (Objects.nonNull(fillColorHex)) { + v.put("bg", fillColorHex); + } + } + + /** + * @param model sheet页信息 + * @param sheet sheet页 + * @description 设置单元格合并信息 + * @author zhouhang + * @date 2021/4/21 + */ + private static void dealWithExcelMerge(GridRecordDataModel model, Sheet sheet) { + if (CollectionUtils.isNotEmpty(sheet.getMergedRegions())) { + //{"color":"","list_id":"","column":60,"index":"1","jfgird_select_save":[],"rh_height":1790,"visibledatacolumn":[],"scrollTop":0,"block_id":"fblock","rowsplit":[],"visibledatarow":[],"jfgrid_selection_range":{},"name":"Sheet1","celldata":[],"ch_width":4748,"row":84,"scrollLeft":0,"id":364598,"chart":[],"config":{},"order":0,"status":1} + JSONObject jsonObject = model.getJson_data(); + JSONObject config = jsonObject.getJSONObject("config"); + JSONObject merge = new JSONObject(); + for (CellRangeAddress mergedRegion : sheet.getMergedRegions()) { + JSONObject mergeBase = new JSONObject(); + mergeBase.put("r", mergedRegion.getFirstRow()); + mergeBase.put("c", mergedRegion.getFirstColumn()); + mergeBase.put("rs", mergedRegion.getLastRow() - mergedRegion.getFirstRow() + 1); + mergeBase.put("cs", mergedRegion.getLastColumn() - mergedRegion.getFirstColumn() + 1); + merge.put(mergedRegion.getFirstRow() + "_" + mergedRegion.getFirstColumn(), mergeBase); + } + config.put("merge", merge); + } + } +}