From c843434720db64c4e7609bd9d5d73ae7365ed403 Mon Sep 17 00:00:00 2001
From: jiang4yu <5122922+jiang4yu@user.noreply.gitee.com>
Date: Tue, 10 Jun 2025 03:48:26 +0000
Subject: [PATCH] =?UTF-8?q?feat(file/poi):=20=E6=96=B0=E5=A2=9E=20continew?=
=?UTF-8?q?-starter-file-poi=20=E6=A8=A1=E5=9D=97=EF=BC=88=E6=B7=BB?=
=?UTF-8?q?=E5=8A=A0=20ExcelImport=20=E4=B8=8E=20ExcelExport=20=E6=B3=A8?=
=?UTF-8?q?=E8=A7=A3=EF=BC=89=201.=E5=B0=86EasyExcel=E5=8D=87=E7=BA=A7?=
=?UTF-8?q?=E4=B8=BAFastExcel=202.=E6=96=B0=E5=A2=9E=20continew-starter-fi?=
=?UTF-8?q?le-poi=20=E6=A8=A1=E5=9D=97=EF=BC=88=E6=B7=BB=E5=8A=A0=20ExcelI?=
=?UTF-8?q?mport=20=E4=B8=8E=20ExcelExport=20=E6=B3=A8=E8=A7=A3=EF=BC=8Cht?=
=?UTF-8?q?tps://zyqok.blog.csdn.net/article/details/121994504=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
continew-starter-dependencies/pom.xml | 8 +-
.../continew-starter-file-excel/pom.xml | 4 +-
.../converter/ExcelBaseEnumConverter.java | 12 +-
.../converter/ExcelBigNumberConverter.java | 12 +-
.../excel/converter/ExcelListConverter.java | 12 +-
.../starter/file/excel/util/ExcelUtils.java | 6 +-
.../continew-starter-file-poi/pom.xml | 39 +
.../file/poi/annotation/ExcelExport.java | 35 +
.../file/poi/annotation/ExcelImport.java | 40 +
.../file/poi/model/ExcelClassField.java | 88 ++
.../starter/file/poi/util/ExcelUtils.java | 1005 +++++++++++++++++
continew-starter-file/pom.xml | 1 +
12 files changed, 1235 insertions(+), 27 deletions(-)
create mode 100644 continew-starter-file/continew-starter-file-poi/pom.xml
create mode 100644 continew-starter-file/continew-starter-file-poi/src/main/java/top/continew/starter/file/poi/annotation/ExcelExport.java
create mode 100644 continew-starter-file/continew-starter-file-poi/src/main/java/top/continew/starter/file/poi/annotation/ExcelImport.java
create mode 100644 continew-starter-file/continew-starter-file-poi/src/main/java/top/continew/starter/file/poi/model/ExcelClassField.java
create mode 100644 continew-starter-file/continew-starter-file-poi/src/main/java/top/continew/starter/file/poi/util/ExcelUtils.java
diff --git a/continew-starter-dependencies/pom.xml b/continew-starter-dependencies/pom.xml
index 728618b3..efa15435 100644
--- a/continew-starter-dependencies/pom.xml
+++ b/continew-starter-dependencies/pom.xml
@@ -31,7 +31,7 @@
1.4.0
1.6.2
15.6
- 3.3.4
+ 1.2.0
2.2.1
1.12.783
2.31.35
@@ -228,9 +228,9 @@
- com.alibaba
- easyexcel
- ${easy-excel.version}
+ cn.idev.excel
+ fastexcel
+ ${fastexcel.version}
diff --git a/continew-starter-file/continew-starter-file-excel/pom.xml b/continew-starter-file/continew-starter-file-excel/pom.xml
index 04b19db8..567c8b04 100644
--- a/continew-starter-file/continew-starter-file-excel/pom.xml
+++ b/continew-starter-file/continew-starter-file-excel/pom.xml
@@ -18,8 +18,8 @@
- com.alibaba
- easyexcel
+ cn.idev.excel
+ fastexcel
\ No newline at end of file
diff --git a/continew-starter-file/continew-starter-file-excel/src/main/java/top/continew/starter/file/excel/converter/ExcelBaseEnumConverter.java b/continew-starter-file/continew-starter-file-excel/src/main/java/top/continew/starter/file/excel/converter/ExcelBaseEnumConverter.java
index 240c7091..c4dadc65 100644
--- a/continew-starter-file/continew-starter-file-excel/src/main/java/top/continew/starter/file/excel/converter/ExcelBaseEnumConverter.java
+++ b/continew-starter-file/continew-starter-file-excel/src/main/java/top/continew/starter/file/excel/converter/ExcelBaseEnumConverter.java
@@ -16,12 +16,12 @@
package top.continew.starter.file.excel.converter;
-import com.alibaba.excel.converters.Converter;
-import com.alibaba.excel.enums.CellDataTypeEnum;
-import com.alibaba.excel.metadata.GlobalConfiguration;
-import com.alibaba.excel.metadata.data.ReadCellData;
-import com.alibaba.excel.metadata.data.WriteCellData;
-import com.alibaba.excel.metadata.property.ExcelContentProperty;
+import cn.idev.excel.converters.Converter;
+import cn.idev.excel.enums.CellDataTypeEnum;
+import cn.idev.excel.metadata.GlobalConfiguration;
+import cn.idev.excel.metadata.data.ReadCellData;
+import cn.idev.excel.metadata.data.WriteCellData;
+import cn.idev.excel.metadata.property.ExcelContentProperty;
import top.continew.starter.core.constant.StringConstants;
import top.continew.starter.core.enums.BaseEnum;
diff --git a/continew-starter-file/continew-starter-file-excel/src/main/java/top/continew/starter/file/excel/converter/ExcelBigNumberConverter.java b/continew-starter-file/continew-starter-file-excel/src/main/java/top/continew/starter/file/excel/converter/ExcelBigNumberConverter.java
index 0c8b943a..855ecbf9 100644
--- a/continew-starter-file/continew-starter-file-excel/src/main/java/top/continew/starter/file/excel/converter/ExcelBigNumberConverter.java
+++ b/continew-starter-file/continew-starter-file-excel/src/main/java/top/continew/starter/file/excel/converter/ExcelBigNumberConverter.java
@@ -18,12 +18,12 @@ package top.continew.starter.file.excel.converter;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.NumberUtil;
-import com.alibaba.excel.converters.Converter;
-import com.alibaba.excel.enums.CellDataTypeEnum;
-import com.alibaba.excel.metadata.GlobalConfiguration;
-import com.alibaba.excel.metadata.data.ReadCellData;
-import com.alibaba.excel.metadata.data.WriteCellData;
-import com.alibaba.excel.metadata.property.ExcelContentProperty;
+import cn.idev.excel.converters.Converter;
+import cn.idev.excel.enums.CellDataTypeEnum;
+import cn.idev.excel.metadata.GlobalConfiguration;
+import cn.idev.excel.metadata.data.ReadCellData;
+import cn.idev.excel.metadata.data.WriteCellData;
+import cn.idev.excel.metadata.property.ExcelContentProperty;
/**
* Easy Excel 大数值转换器
diff --git a/continew-starter-file/continew-starter-file-excel/src/main/java/top/continew/starter/file/excel/converter/ExcelListConverter.java b/continew-starter-file/continew-starter-file-excel/src/main/java/top/continew/starter/file/excel/converter/ExcelListConverter.java
index 786f00be..f86e2e8c 100644
--- a/continew-starter-file/continew-starter-file-excel/src/main/java/top/continew/starter/file/excel/converter/ExcelListConverter.java
+++ b/continew-starter-file/continew-starter-file-excel/src/main/java/top/continew/starter/file/excel/converter/ExcelListConverter.java
@@ -18,12 +18,12 @@ package top.continew.starter.file.excel.converter;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
-import com.alibaba.excel.converters.Converter;
-import com.alibaba.excel.enums.CellDataTypeEnum;
-import com.alibaba.excel.metadata.GlobalConfiguration;
-import com.alibaba.excel.metadata.data.ReadCellData;
-import com.alibaba.excel.metadata.data.WriteCellData;
-import com.alibaba.excel.metadata.property.ExcelContentProperty;
+import cn.idev.excel.converters.Converter;
+import cn.idev.excel.enums.CellDataTypeEnum;
+import cn.idev.excel.metadata.GlobalConfiguration;
+import cn.idev.excel.metadata.data.ReadCellData;
+import cn.idev.excel.metadata.data.WriteCellData;
+import cn.idev.excel.metadata.property.ExcelContentProperty;
import org.springframework.stereotype.Component;
import top.continew.starter.core.constant.StringConstants;
diff --git a/continew-starter-file/continew-starter-file-excel/src/main/java/top/continew/starter/file/excel/util/ExcelUtils.java b/continew-starter-file/continew-starter-file-excel/src/main/java/top/continew/starter/file/excel/util/ExcelUtils.java
index bc3a844c..7937cd09 100644
--- a/continew-starter-file/continew-starter-file-excel/src/main/java/top/continew/starter/file/excel/util/ExcelUtils.java
+++ b/continew-starter-file/continew-starter-file-excel/src/main/java/top/continew/starter/file/excel/util/ExcelUtils.java
@@ -19,8 +19,8 @@ package top.continew.starter.file.excel.util;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.URLUtil;
-import com.alibaba.excel.EasyExcelFactory;
-import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
+import cn.idev.excel.FastExcelFactory;
+import cn.idev.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -78,7 +78,7 @@ public class ExcelUtils {
.format(new Date(), DatePattern.PURE_DATETIME_PATTERN)));
response.setHeader("Content-disposition", "attachment;filename=" + exportFileName);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
- EasyExcelFactory.write(response.getOutputStream(), clazz)
+ FastExcelFactory.write(response.getOutputStream(), clazz)
.autoCloseStream(false)
// 自动适配宽度
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
diff --git a/continew-starter-file/continew-starter-file-poi/pom.xml b/continew-starter-file/continew-starter-file-poi/pom.xml
new file mode 100644
index 00000000..fad6c450
--- /dev/null
+++ b/continew-starter-file/continew-starter-file-poi/pom.xml
@@ -0,0 +1,39 @@
+
+ 4.0.0
+
+ top.continew
+ continew-starter-file
+ ${revision}
+
+
+ continew-starter-file-poi
+ ContiNew Starter 文件处理模块 - POI
+
+
+
+
+ org.apache.httpcomponents.client5
+ httpclient5
+
+
+
+ com.alibaba
+ fastjson
+
+
+ org.springframework
+ spring-webmvc
+
+
+ jakarta.servlet
+ jakarta.servlet-api
+
+
+
+ org.apache.poi
+ poi-ooxml
+ 5.4.1
+
+
+
diff --git a/continew-starter-file/continew-starter-file-poi/src/main/java/top/continew/starter/file/poi/annotation/ExcelExport.java b/continew-starter-file/continew-starter-file-poi/src/main/java/top/continew/starter/file/poi/annotation/ExcelExport.java
new file mode 100644
index 00000000..ede420f9
--- /dev/null
+++ b/continew-starter-file/continew-starter-file-poi/src/main/java/top/continew/starter/file/poi/annotation/ExcelExport.java
@@ -0,0 +1,35 @@
+package top.continew.starter.file.poi.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author jiang4yu
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExcelExport {
+
+ /**
+ * 字段名称
+ */
+ String value();
+
+ /**
+ * 导出排序先后: 数字越小越靠前(默认按Java类字段顺序导出)
+ */
+ int sort() default 0;
+
+ /**
+ * 导出映射,格式如:0-未知;1-男;2-女
+ */
+ String kv() default "";
+
+ /**
+ * 导出模板示例值(有值的话,直接取该值,不做映射)
+ */
+ String example() default "";
+
+}
\ No newline at end of file
diff --git a/continew-starter-file/continew-starter-file-poi/src/main/java/top/continew/starter/file/poi/annotation/ExcelImport.java b/continew-starter-file/continew-starter-file-poi/src/main/java/top/continew/starter/file/poi/annotation/ExcelImport.java
new file mode 100644
index 00000000..6f137c18
--- /dev/null
+++ b/continew-starter-file/continew-starter-file-poi/src/main/java/top/continew/starter/file/poi/annotation/ExcelImport.java
@@ -0,0 +1,40 @@
+package top.continew.starter.file.poi.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author jiang4yu
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExcelImport {
+
+ /**
+ * 字段名称
+ */
+ String value();
+
+ /**
+ * 导出映射,格式如:0-未知;1-男;2-女
+ */
+ String kv() default "";
+
+ /**
+ * 是否为必填字段(默认为非必填)
+ */
+ boolean required() default false;
+
+ /**
+ * 最大长度(默认255)
+ */
+ int maxLength() default 255;
+
+ /**
+ * 导入唯一性验证(多个字段则取联合验证)
+ */
+ boolean unique() default false;
+
+}
\ No newline at end of file
diff --git a/continew-starter-file/continew-starter-file-poi/src/main/java/top/continew/starter/file/poi/model/ExcelClassField.java b/continew-starter-file/continew-starter-file-poi/src/main/java/top/continew/starter/file/poi/model/ExcelClassField.java
new file mode 100644
index 00000000..59dc0651
--- /dev/null
+++ b/continew-starter-file/continew-starter-file-poi/src/main/java/top/continew/starter/file/poi/model/ExcelClassField.java
@@ -0,0 +1,88 @@
+package top.continew.starter.file.poi.model;
+
+import java.util.LinkedHashMap;
+
+/**
+ * @author jiang4yu
+ */
+public class ExcelClassField {
+
+ /**
+ * 字段名称
+ */
+ private String fieldName;
+
+ /**
+ * 表头名称
+ */
+ private String name;
+
+ /**
+ * 映射关系
+ */
+ private LinkedHashMap kvMap;
+
+ /**
+ * 示例值
+ */
+ private Object example;
+
+ /**
+ * 排序
+ */
+ private int sort;
+
+ /**
+ * 是否为注解字段:0-否,1-是
+ */
+ private int hasAnnotation;
+
+ public String getFieldName() {
+ return fieldName;
+ }
+
+ public void setFieldName(String fieldName) {
+ this.fieldName = fieldName;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public LinkedHashMap getKvMap() {
+ return kvMap;
+ }
+
+ public void setKvMap(LinkedHashMap kvMap) {
+ this.kvMap = kvMap;
+ }
+
+ public Object getExample() {
+ return example;
+ }
+
+ public void setExample(Object example) {
+ this.example = example;
+ }
+
+ public int getSort() {
+ return sort;
+ }
+
+ public void setSort(int sort) {
+ this.sort = sort;
+ }
+
+ public int getHasAnnotation() {
+ return hasAnnotation;
+ }
+
+ public void setHasAnnotation(int hasAnnotation) {
+ this.hasAnnotation = hasAnnotation;
+ }
+
+}
\ No newline at end of file
diff --git a/continew-starter-file/continew-starter-file-poi/src/main/java/top/continew/starter/file/poi/util/ExcelUtils.java b/continew-starter-file/continew-starter-file-poi/src/main/java/top/continew/starter/file/poi/util/ExcelUtils.java
new file mode 100644
index 00000000..0a7592f7
--- /dev/null
+++ b/continew-starter-file/continew-starter-file-poi/src/main/java/top/continew/starter/file/poi/util/ExcelUtils.java
@@ -0,0 +1,1005 @@
+package top.continew.starter.file.poi.util;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import jakarta.servlet.ServletOutputStream;
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.poi.hssf.usermodel.HSSFDataValidation;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.usermodel.ClientAnchor.AnchorType;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellRangeAddressList;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.springframework.web.multipart.MultipartFile;
+import top.continew.starter.file.poi.annotation.ExcelExport;
+import top.continew.starter.file.poi.annotation.ExcelImport;
+import top.continew.starter.file.poi.model.ExcelClassField;
+
+import java.io.*;
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.net.URL;
+import java.text.NumberFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
+
+
+/**
+ * Excel导入导出工具类
+ *
+ * @author jiang4yu
+ */
+@SuppressWarnings("unused")
+public class ExcelUtils {
+
+ public static final String ROW_MERGE = "row_merge";
+ public static final String COLUMN_MERGE = "column_merge";
+ private static final String XLSX = ".xlsx";
+ private static final String XLS = ".xls";
+ private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
+ private static final String ROW_NUM = "rowNum";
+ private static final String ROW_DATA = "rowData";
+ private static final String ROW_TIPS = "rowTips";
+ private static final int CELL_OTHER = 0;
+ private static final int CELL_ROW_MERGE = 1;
+ private static final int CELL_COLUMN_MERGE = 2;
+ private static final int IMG_HEIGHT = 30;
+ private static final int IMG_WIDTH = 30;
+ private static final char LEAN_LINE = '/';
+ private static final int BYTES_DEFAULT_LENGTH = 10240;
+ private static final NumberFormat NUMBER_FORMAT = NumberFormat.getNumberInstance();
+
+
+ public static List readFile(File file, Class clazz) throws Exception {
+ JSONArray array = readFile(file);
+ return getBeanList(array, clazz);
+ }
+
+ public static List readMultipartFile(MultipartFile mFile, Class clazz) throws Exception {
+ JSONArray array = readMultipartFile(mFile);
+ return getBeanList(array, clazz);
+ }
+
+ public static JSONArray readFile(File file) throws Exception {
+ return readExcel(null, file);
+ }
+
+ public static JSONArray readMultipartFile(MultipartFile mFile) throws Exception {
+ return readExcel(mFile, null);
+ }
+
+ public static Map readFileManySheet(File file) throws Exception {
+ return readExcelManySheet(null, file);
+ }
+
+ public static Map readFileManySheet(MultipartFile file) throws Exception {
+ return readExcelManySheet(file, null);
+ }
+
+ private static List getBeanList(JSONArray array, Class clazz) throws Exception {
+ List list = new ArrayList<>();
+ Map uniqueMap = new HashMap<>(16);
+ for (int i = 0; i < array.size(); i++) {
+ list.add(getBean(clazz, array.getJSONObject(i), uniqueMap));
+ }
+ return list;
+ }
+
+ /**
+ * 获取每个对象的数据
+ */
+ private static T getBean(Class c, JSONObject obj, Map uniqueMap) throws Exception {
+ T t = c.newInstance();
+ Field[] fields = c.getDeclaredFields();
+ List errMsgList = new ArrayList<>();
+ boolean hasRowTipsField = false;
+ StringBuilder uniqueBuilder = new StringBuilder();
+ int rowNum = 0;
+ for (Field field : fields) {
+ // 行号
+ if (field.getName().equals(ROW_NUM)) {
+ rowNum = obj.getInteger(ROW_NUM);
+ field.setAccessible(true);
+ field.set(t, rowNum);
+ continue;
+ }
+ // 是否需要设置异常信息
+ if (field.getName().equals(ROW_TIPS)) {
+ hasRowTipsField = true;
+ continue;
+ }
+ // 原始数据
+ if (field.getName().equals(ROW_DATA)) {
+ field.setAccessible(true);
+ field.set(t, obj.toString());
+ continue;
+ }
+ // 设置对应属性值
+ setFieldValue(t, field, obj, uniqueBuilder, errMsgList);
+ }
+ // 数据唯一性校验
+ if (uniqueBuilder.length() > 0) {
+ if (uniqueMap.containsValue(uniqueBuilder.toString())) {
+ Set rowNumKeys = uniqueMap.keySet();
+ for (Integer num : rowNumKeys) {
+ if (uniqueMap.get(num).equals(uniqueBuilder.toString())) {
+ errMsgList.add(String.format("数据唯一性校验失败,(%s)与第%s行重复)", uniqueBuilder, num));
+ }
+ }
+ } else {
+ uniqueMap.put(rowNum, uniqueBuilder.toString());
+ }
+ }
+ // 失败处理
+ if (errMsgList.isEmpty() && !hasRowTipsField) {
+ return t;
+ }
+ StringBuilder sb = new StringBuilder();
+ int size = errMsgList.size();
+ for (int i = 0; i < size; i++) {
+ if (i == size - 1) {
+ sb.append(errMsgList.get(i));
+ } else {
+ sb.append(errMsgList.get(i)).append(";");
+ }
+ }
+ // 设置错误信息
+ for (Field field : fields) {
+ if (field.getName().equals(ROW_TIPS)) {
+ field.setAccessible(true);
+ field.set(t, sb.toString());
+ }
+ }
+ return t;
+ }
+
+ private static void setFieldValue(T t, Field field, JSONObject obj, StringBuilder uniqueBuilder, List errMsgList) {
+ // 获取 ExcelImport 注解属性
+ ExcelImport annotation = field.getAnnotation(ExcelImport.class);
+ if (annotation == null) {
+ return;
+ }
+ String cname = annotation.value();
+ if (cname.trim().length() == 0) {
+ return;
+ }
+ // 获取具体值
+ String val = null;
+ if (obj.containsKey(cname)) {
+ val = getString(obj.getString(cname));
+ }
+ if (val == null) {
+ return;
+ }
+ field.setAccessible(true);
+ // 判断是否必填
+ boolean require = annotation.required();
+ if (require && val.isEmpty()) {
+ errMsgList.add(String.format("[%s]不能为空", cname));
+ return;
+ }
+ // 数据唯一性获取
+ boolean unique = annotation.unique();
+ if (unique) {
+ if (uniqueBuilder.length() > 0) {
+ uniqueBuilder.append("--").append(val);
+ } else {
+ uniqueBuilder.append(val);
+ }
+ }
+ // 判断是否超过最大长度
+ int maxLength = annotation.maxLength();
+ if (maxLength > 0 && val.length() > maxLength) {
+ errMsgList.add(String.format("[%s]长度不能超过%s个字符(当前%s个字符)", cname, maxLength, val.length()));
+ }
+ // 判断当前属性是否有映射关系
+ LinkedHashMap kvMap = getKvMap(annotation.kv());
+ if (!kvMap.isEmpty()) {
+ boolean isMatch = false;
+ for (String key : kvMap.keySet()) {
+ if (kvMap.get(key).equals(val)) {
+ val = key;
+ isMatch = true;
+ break;
+ }
+ }
+ if (!isMatch) {
+ errMsgList.add(String.format("[%s]的值不正确(当前值为%s)", cname, val));
+ return;
+ }
+ }
+ // 其余情况根据类型赋值
+ String fieldClassName = field.getType().getSimpleName();
+ try {
+ if ("String".equalsIgnoreCase(fieldClassName)) {
+ field.set(t, val);
+ } else if ("boolean".equalsIgnoreCase(fieldClassName)) {
+ field.set(t, Boolean.valueOf(val));
+ } else if ("int".equalsIgnoreCase(fieldClassName) || "Integer".equals(fieldClassName)) {
+ try {
+ field.set(t, Integer.valueOf(val));
+ } catch (NumberFormatException e) {
+ errMsgList.add(String.format("[%s]的值格式不正确(当前值为%s)", cname, val));
+ }
+ } else if ("double".equalsIgnoreCase(fieldClassName)) {
+ field.set(t, Double.valueOf(val));
+ } else if ("long".equalsIgnoreCase(fieldClassName)) {
+ field.set(t, Long.valueOf(val));
+ } else if ("BigDecimal".equalsIgnoreCase(fieldClassName)) {
+ field.set(t, new BigDecimal(val));
+ } else if ("Date".equalsIgnoreCase(fieldClassName)) {
+ try {
+ field.set(t, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(val));
+ } catch (Exception e) {
+ field.set(t, new SimpleDateFormat("yyyy-MM-dd").parse(val));
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static Map readExcelManySheet(MultipartFile mFile, File file) throws IOException {
+ Workbook book = getWorkbook(mFile, file);
+ if (book == null) {
+ return Collections.emptyMap();
+ }
+ Map map = new LinkedHashMap<>();
+ for (int i = 0; i < book.getNumberOfSheets(); i++) {
+ Sheet sheet = book.getSheetAt(i);
+ JSONArray arr = readSheet(sheet);
+ map.put(sheet.getSheetName(), arr);
+ }
+ book.close();
+ return map;
+ }
+
+ private static JSONArray readExcel(MultipartFile mFile, File file) throws IOException {
+ Workbook book = getWorkbook(mFile, file);
+ if (book == null) {
+ return new JSONArray();
+ }
+ JSONArray array = readSheet(book.getSheetAt(0));
+ book.close();
+ return array;
+ }
+
+ private static Workbook getWorkbook(MultipartFile mFile, File file) throws IOException {
+ boolean fileNotExist = (file == null || !file.exists());
+ if (mFile == null && fileNotExist) {
+ return null;
+ }
+ // 解析表格数据
+ InputStream in;
+ String fileName;
+ if (mFile != null) {
+ // 上传文件解析
+ in = mFile.getInputStream();
+ fileName = getString(mFile.getOriginalFilename()).toLowerCase();
+ } else {
+ // 本地文件解析
+ in = new FileInputStream(file);
+ fileName = file.getName().toLowerCase();
+ }
+ Workbook book;
+ if (fileName.endsWith(XLSX)) {
+ book = new XSSFWorkbook(in);
+ } else if (fileName.endsWith(XLS)) {
+ POIFSFileSystem poifsFileSystem = new POIFSFileSystem(in);
+ book = new HSSFWorkbook(poifsFileSystem);
+ } else {
+ return null;
+ }
+ in.close();
+ return book;
+ }
+
+ private static JSONArray readSheet(Sheet sheet) {
+ // 首行下标
+ int rowStart = sheet.getFirstRowNum();
+ // 尾行下标
+ int rowEnd = sheet.getLastRowNum();
+ // 获取表头行
+ Row headRow = sheet.getRow(rowStart);
+ if (headRow == null) {
+ return new JSONArray();
+ }
+ int cellStart = headRow.getFirstCellNum();
+ int cellEnd = headRow.getLastCellNum();
+ Map keyMap = new HashMap<>();
+ for (int j = cellStart; j < cellEnd; j++) {
+ // 获取表头数据
+ String val = getCellValue(headRow.getCell(j));
+ if (val != null && !val.trim().isEmpty()) {
+ keyMap.put(j, val);
+ }
+ }
+ // 如果表头没有数据则不进行解析
+ if (keyMap.isEmpty()) {
+ return (JSONArray) Collections.emptyList();
+ }
+ // 获取每行JSON对象的值
+ JSONArray array = new JSONArray();
+ // 如果首行与尾行相同,表明只有一行,返回表头数据
+ if (rowStart == rowEnd) {
+ JSONObject obj = new JSONObject();
+ // 添加行号
+ obj.put(ROW_NUM, 1);
+ for (int i : keyMap.keySet()) {
+ obj.put(keyMap.get(i), "");
+ }
+ array.add(obj);
+ return array;
+ }
+ for (int i = rowStart + 1; i <= rowEnd; i++) {
+ Row eachRow = sheet.getRow(i);
+ JSONObject obj = new JSONObject();
+ // 添加行号
+ obj.put(ROW_NUM, i + 1);
+ StringBuilder sb = new StringBuilder();
+ for (int k = cellStart; k < cellEnd; k++) {
+ if (eachRow != null) {
+ String val = getCellValue(eachRow.getCell(k));
+ // 所有数据添加到里面,用于判断该行是否为空
+ sb.append(val);
+ obj.put(keyMap.get(k), val);
+ }
+ }
+ if (!sb.isEmpty()) {
+ array.add(obj);
+ }
+ }
+ return array;
+ }
+
+ private static String getCellValue(Cell cell) {
+ // 空白或空
+ if (cell == null || cell.getCellType() == CellType.BLANK) {
+ return "";
+ }
+ // String类型
+ if (cell.getCellType() == CellType.STRING) {
+ String val = cell.getStringCellValue();
+ if (val == null || val.trim().isEmpty()) {
+ return "";
+ }
+ return val.trim();
+ }
+ // 数字类型
+ if (cell.getCellType() == CellType.NUMERIC) {
+ String s = cell.getNumericCellValue() + "";
+ // 去掉尾巴上的小数点0
+ if (Pattern.matches(".*\\.0*", s)) {
+ return s.split("\\.")[0];
+ } else {
+ return s;
+ }
+ }
+ // 布尔值类型
+ if (cell.getCellType() == CellType.BOOLEAN) {
+ return cell.getBooleanCellValue() + "";
+ }
+ // 错误类型
+ return cell.getCellFormula();
+ }
+
+ public static void exportTemplate(HttpServletResponse response, String fileName, Class clazz) {
+ exportTemplate(response, fileName, fileName, clazz, false);
+ }
+
+ public static void exportTemplate(HttpServletResponse response, String fileName, String sheetName,
+ Class clazz) {
+ exportTemplate(response, fileName, sheetName, clazz, false);
+ }
+
+ public static void exportTemplate(HttpServletResponse response, String fileName, Class clazz,
+ boolean isContainExample) {
+ exportTemplate(response, fileName, fileName, clazz, isContainExample);
+ }
+
+ public static void exportTemplate(HttpServletResponse response, String fileName, String sheetName,
+ Class clazz, boolean isContainExample) {
+ // 获取表头字段
+ List headFieldList = getExcelClassFieldList(clazz);
+ // 获取表头数据和示例数据
+ List> sheetDataList = new ArrayList<>();
+ List