|
@@ -1,6 +1,7 @@
|
|
|
package com.boman.common.core.utils.poi;
|
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.alibaba.fastjson.util.TypeUtils;
|
|
|
import com.boman.common.core.annotation.Excel;
|
|
|
import com.boman.common.core.annotation.Excel.ColumnType;
|
|
|
import com.boman.common.core.annotation.Excel.Type;
|
|
@@ -8,13 +9,16 @@ import com.boman.common.core.annotation.Excels;
|
|
|
import com.boman.common.core.text.Convert;
|
|
|
import com.boman.common.core.utils.DateUtils;
|
|
|
import com.boman.common.core.utils.StringUtils;
|
|
|
+import com.boman.common.core.utils.array.ArrayUtils;
|
|
|
import com.boman.common.core.utils.file.FileTypeUtils;
|
|
|
import com.boman.common.core.utils.file.ImageUtils;
|
|
|
import com.boman.common.core.utils.obj.ObjectUtils;
|
|
|
import com.boman.common.core.utils.reflect.ReflectUtils;
|
|
|
import com.boman.domain.GenTableColumn;
|
|
|
import com.boman.domain.SysDictData;
|
|
|
-import com.boman.domain.SysUser;
|
|
|
+import com.boman.domain.constant.FormDataConstant;
|
|
|
+import com.boman.domain.constant.MaskConstant;
|
|
|
+import org.apache.commons.lang3.BooleanUtils;
|
|
|
import org.apache.poi.ss.usermodel.*;
|
|
|
import org.apache.poi.ss.util.CellRangeAddressList;
|
|
|
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
|
|
@@ -29,10 +33,15 @@ import java.io.InputStream;
|
|
|
import java.io.OutputStream;
|
|
|
import java.lang.reflect.Field;
|
|
|
import java.math.BigDecimal;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
import java.text.DecimalFormat;
|
|
|
import java.util.*;
|
|
|
+import java.util.function.Predicate;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
+import static com.boman.common.core.utils.obj.ObjectUtils.*;
|
|
|
+import static com.boman.domain.constant.FormDataConstant.*;
|
|
|
+
|
|
|
/**
|
|
|
* Excel相关处理
|
|
|
*
|
|
@@ -77,6 +86,11 @@ public class ExcelUtil<T>
|
|
|
*/
|
|
|
private List<T> list;
|
|
|
|
|
|
+ /**
|
|
|
+ * 导入导出数据列表
|
|
|
+ */
|
|
|
+ private List<Map<String, Object>> jsonObjectList;
|
|
|
+
|
|
|
/**
|
|
|
* 注解列表
|
|
|
*/
|
|
@@ -120,6 +134,19 @@ public class ExcelUtil<T>
|
|
|
createWorkbook();
|
|
|
}
|
|
|
|
|
|
+ public void initJSONObject(List<Map<String, Object>> list, String sheetName, Type type)
|
|
|
+ {
|
|
|
+ if (list == null)
|
|
|
+ {
|
|
|
+ list = new ArrayList<>();
|
|
|
+ }
|
|
|
+ this.jsonObjectList = list;
|
|
|
+ this.sheetName = sheetName;
|
|
|
+ this.type = type;
|
|
|
+ createExcelField();
|
|
|
+ createWorkbook();
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 对excel表单默认第一个索引名转换成list
|
|
|
*
|
|
@@ -355,52 +382,6 @@ public class ExcelUtil<T>
|
|
|
return cellMap;
|
|
|
}
|
|
|
|
|
|
- private Object getValueByFieldType(Object val, Field field, Class<?> fieldType) {
|
|
|
- if (String.class == fieldType) {
|
|
|
- String s = Convert.toStr(val);
|
|
|
- if (StringUtils.endsWith(s, ".0")) {
|
|
|
- val = StringUtils.substringBefore(s, ".0");
|
|
|
- } else {
|
|
|
- String dateFormat = field.getAnnotation(Excel.class).dateFormat();
|
|
|
- if (StringUtils.isNotEmpty(dateFormat)) {
|
|
|
- val = DateUtils.parseDateToStr(dateFormat, (Date) val);
|
|
|
- } else {
|
|
|
- val = Convert.toStr(val);
|
|
|
- }
|
|
|
- }
|
|
|
- } else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) {
|
|
|
- val = Convert.toInt(val);
|
|
|
- } else if (Long.TYPE == fieldType || Long.class == fieldType) {
|
|
|
- val = Convert.toLong(val);
|
|
|
- } else if (Double.TYPE == fieldType || Double.class == fieldType) {
|
|
|
- val = Convert.toDouble(val);
|
|
|
- } else if (Float.TYPE == fieldType || Float.class == fieldType) {
|
|
|
- val = Convert.toFloat(val);
|
|
|
- } else if (BigDecimal.class == fieldType) {
|
|
|
- val = Convert.toBigDecimal(val);
|
|
|
- } else if (Date.class == fieldType) {
|
|
|
- if (val instanceof String) {
|
|
|
- val = DateUtils.parseDate(val);
|
|
|
- } else if (val instanceof Double) {
|
|
|
- val = DateUtil.getJavaDate((Double) val);
|
|
|
- }
|
|
|
- } else if (Boolean.TYPE == fieldType || Boolean.class == fieldType) {
|
|
|
- val = Convert.toBool(val, false);
|
|
|
- }
|
|
|
- return val;
|
|
|
- }
|
|
|
-
|
|
|
- private String getColumnNameByFieldName(String columnComment, Object value, List<GenTableColumn> columns) {
|
|
|
- for (GenTableColumn column : columns) {
|
|
|
- if (columnComment.equals(column.getColumnComment())) {
|
|
|
- return column.getColumnName();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- throw new IllegalArgumentException(String.format("表格中的 [%s] 列, 不在数据库表中, 检查是否出现错误", columnComment));
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
private Object handleFK(String columnName, Object value, List<GenTableColumn> columns) {
|
|
|
for (GenTableColumn column : columns) {
|
|
|
if (columnName.equals(column.getColumnName())) {
|
|
@@ -417,6 +398,25 @@ public class ExcelUtil<T>
|
|
|
return value;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 功能描述: 通用的导出
|
|
|
+ *
|
|
|
+ * @param response 返回数据
|
|
|
+ * @param list 导出数据集合
|
|
|
+ * @param sheetName 工作表的名称
|
|
|
+ * @param columns 所有的列
|
|
|
+ * @param empty 所有的列
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public void exportExcelCommon(HttpServletResponse response, List<Map<String, Object>> list
|
|
|
+ , String sheetName, List<GenTableColumn> columns, Boolean empty) throws IOException {
|
|
|
+ response.setContentType("application/vnd.ms-excel");
|
|
|
+ response.setCharacterEncoding("utf-8");
|
|
|
+ this.initJSONObject(list, sheetName, Type.EXPORT);
|
|
|
+ exportExcelCommon(response.getOutputStream(), list, columns, empty);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* 对list数据源将其里面的数据导入到excel表单
|
|
|
*
|
|
@@ -434,6 +434,60 @@ public class ExcelUtil<T>
|
|
|
exportExcel(response.getOutputStream());
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 功能描述: 通用导出
|
|
|
+ *
|
|
|
+ * @param outputStream outputStream
|
|
|
+ * @param columns columns
|
|
|
+ * @param empty true=>只带表头的excel,不含数据, false=>带数据的excel
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public void exportExcelCommon(OutputStream outputStream, List<Map<String, Object>> list, List<GenTableColumn> columns, Boolean empty) {
|
|
|
+ try {
|
|
|
+ // 写入各个字段的列头名称 列表可见
|
|
|
+ List<GenTableColumn> listVisibleColumns = filterData(columns, 4, MaskConstant.LIST_VISIBLE::equals);
|
|
|
+
|
|
|
+ // 取出一共有多少个sheet.
|
|
|
+ double sheetNo = Math.ceil(list.size() / sheetSize);
|
|
|
+ for (int index = 0; index <= sheetNo; index++) {
|
|
|
+ createSheet(sheetNo, index);
|
|
|
+
|
|
|
+ // 产生一行
|
|
|
+ Row row = sheet.createRow(0);
|
|
|
+ int columnIndex = 0;
|
|
|
+ for (GenTableColumn column : listVisibleColumns) {
|
|
|
+ createCellByColumn(column, row, columnIndex++);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (BooleanUtils.isFalse(empty)) {
|
|
|
+ if (Type.EXPORT.equals(type)) {
|
|
|
+ fillExcelDataByJSONObject(index, row, listVisibleColumns);
|
|
|
+// addStatisticsRow();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ wb.write(outputStream);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("导出Excel异常{}", e.getMessage());
|
|
|
+ } finally {
|
|
|
+ if (wb != null) {
|
|
|
+ try {
|
|
|
+ wb.close();
|
|
|
+ } catch (IOException e1) {
|
|
|
+ e1.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (outputStream != null) {
|
|
|
+ try {
|
|
|
+ outputStream.close();
|
|
|
+ } catch (IOException e1) {
|
|
|
+ e1.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 对list数据源将其里面的数据导入到excel表单
|
|
|
*
|
|
@@ -538,6 +592,24 @@ public class ExcelUtil<T>
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 填充excel数据
|
|
|
+ *
|
|
|
+ * @param index 序号
|
|
|
+ * @param row 单元格行
|
|
|
+ */
|
|
|
+ public void fillExcelDataByJSONObject(int index, Row row, List<GenTableColumn> listVisibleColumns) {
|
|
|
+ int startNo = index * sheetSize;
|
|
|
+ int endNo = Math.min(startNo + sheetSize, jsonObjectList.size());
|
|
|
+ for (int i = startNo; i < endNo; i++) {
|
|
|
+ row = sheet.createRow(i + 1 - startNo);
|
|
|
+ Map<String, Object> jsonObject = jsonObjectList.get(i);
|
|
|
+
|
|
|
+ addCellByJSONObject(row, jsonObject, listVisibleColumns);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 创建表格样式
|
|
|
*
|
|
@@ -620,6 +692,33 @@ public class ExcelUtil<T>
|
|
|
return cell;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建单元格
|
|
|
+ */
|
|
|
+ public void createCellByColumn(GenTableColumn column, Row row, int columnIndex) {
|
|
|
+ // 创建列
|
|
|
+ Cell cell = row.createCell(columnIndex);
|
|
|
+ // 写入列信息
|
|
|
+ cell.setCellValue(column.getColumnComment());
|
|
|
+ setDataValidationByColumn(column, row, columnIndex);
|
|
|
+ if (GenTableColumn.IS_REQUIRED.equals(column.getIsRequired())) {
|
|
|
+ CellStyle style = wb.createCellStyle();
|
|
|
+ style.cloneStyleFrom(styles.get("data"));
|
|
|
+ style.setAlignment(HorizontalAlignment.CENTER);
|
|
|
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
+// style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
|
|
|
+// style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
|
|
+ Font headerFont = wb.createFont();
|
|
|
+ headerFont.setFontName("Arial");
|
|
|
+ headerFont.setFontHeightInPoints((short) 10);
|
|
|
+// headerFont.setBold(true);
|
|
|
+ headerFont.setColor(IndexedColors.RED.getIndex());
|
|
|
+ style.setFont(headerFont);
|
|
|
+ cell.setCellStyle(style);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 设置单元格信息
|
|
|
*
|
|
@@ -708,6 +807,100 @@ public class ExcelUtil<T>
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 创建表格样式
|
|
|
+ */
|
|
|
+ public void setDataValidationByColumn(GenTableColumn column, Row row, int columnIndex) {
|
|
|
+ if (column.getColumnComment().contains("注:")) {
|
|
|
+ sheet.setColumnWidth(columnIndex, 6000);
|
|
|
+ } else {
|
|
|
+ // 设置列宽
|
|
|
+ sheet.setColumnWidth(columnIndex, (int) ((16 + 0.72) * 256));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 如果设置了提示信息则鼠标放上去提示.
|
|
|
+// if (StringUtils.isNotEmpty(attr.prompt())) {
|
|
|
+// // 这里默认设了2-101列提示.
|
|
|
+// setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, columnIndex, columnIndex);
|
|
|
+// }
|
|
|
+ // 如果设置了combo属性则本列只能选择不能输入
|
|
|
+// if (attr.combo().length > 0) {
|
|
|
+// // 这里默认设了2-101列只能选择不能输入.
|
|
|
+// setXSSFValidation(sheet, attr.combo(), 1, 100, columnIndex, columnIndex);
|
|
|
+// }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加单元格
|
|
|
+ */
|
|
|
+ public void addCellByJSONObject(Row row, Map<String, Object> jsonObject, List<GenTableColumn> listVisibleColumns) {
|
|
|
+ Cell cell;
|
|
|
+ try {
|
|
|
+ int columnIndex = 0;
|
|
|
+ for (GenTableColumn column : listVisibleColumns) {
|
|
|
+ for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
|
|
|
+ String columnName = entry.getKey();
|
|
|
+ Object value = entry.getValue();
|
|
|
+ if (!column.getColumnName().equals(columnName)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置行高
|
|
|
+ row.setHeight((short) 600);
|
|
|
+ // 创建cell
|
|
|
+ cell = row.createCell(columnIndex++);
|
|
|
+ cell.setCellStyle(styles.get("data"));
|
|
|
+
|
|
|
+ if (isNotEmpty(value) && FormDataConstant.BYTE_ARRAY.equals(value.getClass().getSimpleName())) {
|
|
|
+ // blob
|
|
|
+ cell.setCellValue(byteToString(((byte[]) value)));
|
|
|
+ } else if (isNotEmpty(column.getDictType())) {
|
|
|
+ // 字典
|
|
|
+ cell.setCellValue(handleDictForExport(jsonObject, column));
|
|
|
+ } else if (NEED_CONVERT_DATE_LIST.contains(column.getColumnType())) {
|
|
|
+ // time
|
|
|
+ if (isNotEmpty(value)) {
|
|
|
+ cell.setCellValue(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, TypeUtils.castToTimestamp(value)));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 设置列类型
|
|
|
+ cell.setCellValue(String.valueOf(value));
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 用于读取对象中的属性
|
|
|
+// Object value = getTargetValueByJSONObject(vo, field, attr);
|
|
|
+// String dateFormat = attr.dateFormat();
|
|
|
+// String readConverterExp = attr.readConverterExp();
|
|
|
+// String separator = attr.separator();
|
|
|
+//
|
|
|
+//
|
|
|
+//
|
|
|
+//
|
|
|
+// if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) {
|
|
|
+// cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value));
|
|
|
+// } else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) {
|
|
|
+// cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator));
|
|
|
+// } else if (value instanceof BigDecimal && -1 != attr.scale()) {
|
|
|
+// cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).toString());
|
|
|
+// } else {
|
|
|
+// // 设置列类型
|
|
|
+// setCellVo(value, attr, cell);
|
|
|
+// }
|
|
|
+//
|
|
|
+// addStatisticsData(columnIndex, Convert.toStr(value), attr);
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("导出Excel失败: {}", e);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 添加单元格
|
|
|
*/
|
|
@@ -936,6 +1129,31 @@ public class ExcelUtil<T>
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 获取bean中的属性值
|
|
|
+ *
|
|
|
+ * @param vo 实体对象
|
|
|
+ * @param field 字段
|
|
|
+ * @param excel 注解
|
|
|
+ * @return 最终的属性值
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ private Object getTargetValueByJSONObject(T vo, Field field, Excel excel) throws Exception {
|
|
|
+ Object o = field.get(vo);
|
|
|
+ if (StringUtils.isNotEmpty(excel.targetAttr())) {
|
|
|
+ String target = excel.targetAttr();
|
|
|
+ if (target.contains(".")) {
|
|
|
+ String[] targets = target.split("[.]");
|
|
|
+ for (String name : targets) {
|
|
|
+ o = getValue(o, name);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ o = getValue(o, target);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return o;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 获取bean中的属性值
|
|
|
*
|
|
@@ -1132,4 +1350,81 @@ public class ExcelUtil<T>
|
|
|
}
|
|
|
return val;
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 功能描述: 把新增可见或者修改可见或者.....的列过滤出来
|
|
|
+ *
|
|
|
+ * @param allColumns 所有的列
|
|
|
+ * @param maskIndex 那六个1的顺序 [1,1,1,1,1,1]
|
|
|
+ * sort=0 => 新增可见
|
|
|
+ * sort=1 => 新增可修改
|
|
|
+ * sort=2 => 修改可见
|
|
|
+ * sort=3 => 修改可修改
|
|
|
+ * sort=4 => 列表可见
|
|
|
+ * sort=5 => 列表可修改
|
|
|
+ * @return List<GenTableColumn>
|
|
|
+ */
|
|
|
+ public static List<GenTableColumn> filterData(List<GenTableColumn> allColumns, int maskIndex, Predicate<String> predicate) {
|
|
|
+ assert maskIndex < 6;
|
|
|
+ List<GenTableColumn> returnData = new ArrayList<>(16);
|
|
|
+ for (GenTableColumn allColumn : allColumns) {
|
|
|
+ if (HR.equals(allColumn.getHtmlType())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (checkMask(maskIndex, allColumn, predicate)) {
|
|
|
+ returnData.add(allColumn);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return returnData;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 功能描述: 判断mask == 0 返回true
|
|
|
+ *
|
|
|
+ * @param maskIndex mask的索引
|
|
|
+ * @param column column
|
|
|
+ * @param predicate predicate 注意传的是1还是0
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
+ public static boolean checkMask(int maskIndex, GenTableColumn column, Predicate<String> predicate) {
|
|
|
+ String mask = column.getMask();
|
|
|
+ String columnName = column.getColumnName();
|
|
|
+ String tableName = column.getTableName();
|
|
|
+ String errorMsg = String.format("mask is empty, tableName = [ %s ], columnName = [ %s ]", tableName, columnName);
|
|
|
+ String[] maskArray = requireNonNull(mask, errorMsg).split("");
|
|
|
+ assert maskArray.length == 6;
|
|
|
+ String maskMark = maskArray[maskIndex];
|
|
|
+ return predicate.test(maskMark);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static String byteToString(byte[] bytes) {
|
|
|
+ String result = "";
|
|
|
+ if (ArrayUtils.isNotEmpty(bytes)) {
|
|
|
+ result = new String(bytes, StandardCharsets.UTF_8);
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 功能描述: 处理字典值,不查询所有的字典值, 不放入sysDictData,只根据dictValue查询dictLabel
|
|
|
+ *
|
|
|
+ * @param jsonObject db中查出的结果
|
|
|
+ * @param column 所有的列
|
|
|
+ */
|
|
|
+ public static String handleDictForExport(Map<String, Object> jsonObject, GenTableColumn column) {
|
|
|
+ if (isEmpty(jsonObject)) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ String columnName = column.getColumnName();
|
|
|
+ // 列表需要字典值的dictLabel, 不放入sysDictData
|
|
|
+ List<SysDictData> dictDataList = column.getSysDictData();
|
|
|
+ SysDictData sysDictData = filterOne(dictDataList, dict -> dict.getDictValue().equals(jsonObject.get(columnName)));
|
|
|
+
|
|
|
+ return sysDictData.getDictLabel();
|
|
|
+ }
|
|
|
+
|
|
|
}
|