需求分析
Excel导入去做一些前置检查,包括非空检查和根据前面的字段生成对应的值、唯一索引等检查。
以及导入的数据失败的原因,成功的条数日志记录。
Excel的标题名和字段名数据库映射。
思路
数据映射
之前其实是有一个版本,是按照getCell(0) 列数来获取的,并没有做数据映射。这个有一个问题,就是模板一旦出现一点改动,随之而来的就是代码的大量改动。
并且硬编码代码过多,当然他也有优点,效率高。
为了完成数据映射,那么就必须引入反射,自定义注解来帮助我们完成数据映射,自定义注解引入的话,就会出现一个bean需要单独的维护。
字典
并且之前的字典写法,static {
// 加载map
}
创建了n个map,然后put进去。
这样子,会影响性能。
下个一版本,改为enum枚举类。
有效行数
还有一个成功条数和失败条数,本人使用了Atomic原子类,总觉得i++,i—不放心,所以我就使用了原子类。 POI的API没有计算有效行数,故而需要我们写代码实现。比如:getLastRowNum()方法获取也不是正确的行数。
什么是有效行数?
每一行有真正的数据,而不是空行数据。
这个逻辑就是有三个原子类。
我认为当连续空行数大于100行,那么没必要继续遍历查询。
计算有内容行核心逻辑
难点与问题
第一个难点
list.add()内容覆盖问题
参照我的博客解决方案。
https://blog.csdn.net/qq_41520636/article/details/124493078
第二个难点
比如:
class A {
private B b;
}
class B {
}
此时应该怎么处理这个B,相当于标题栏里面正好有两个Bean,还好这个情况只有一个,不然我心态崩了。
这个解决方案只有看代码了。
第三个难点
比如:
class A{
private String name;
}
class B {
private String name;
}
这两个其实一对一关系,并且在标题映射时,我用怎么让B获取到A的值。
实现
因为是公司代码就不贴全部代码,只贴核心代码。
/**
* <p>
* excel导入注解
* </p>
*
* @author lisonglin
* @version 1.0
* @since 2022/4/25 16:19
*/
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelImport {
/**
* 与excel标题头对应
*/
String exportName();
/**
* 转换格式, 如时间类型 yyyy-MM-dd HH:mm:ss
*/
String pattern() default "";
/**
* 在excel中位置
*/
int order() default 0;
/**
* 长度
**/
int width() default 0;
/**
* 检查非空
**/
boolean checkNotNull() default false;
/**
* 唯一性
*/
boolean uniqueness() default false;
/**
* 可根据其他属性生成的Code(如果没有设置,则根据其他属性生成)
*/
String rule() default "";
}
/**
* <p>
* 字典
* </p>
*
* @author lisonglin
* @version 1.0
* @since 2022/4/25 19:42
*/
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Dict {
/**
* 对应字典名称
**/
Class dictClass();
}
/**
* <p>
* 字段映射
* </p>
*
* @author lisonglin
* @version 1.0
* @since 2022/5/6 19:27
*/
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelMapping {
/**
* 映射名
*/
String mappingName() default "";
/**
* 是否必填
*/
boolean isRequired() default false;
}
/**
* <p>
* 默认值注解
* </p>
*
* @author lisonglin
* @version 1.0
* @since 2022/4/25 18:28
*/
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelToValue {
String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TableName {
String value() default "";
}
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Column {
String value() default "";
}
@TableName("ZJDSP_ZJDZD")
public class ZjdspZjdzd implements Serializable {
/**
*
*/
@JSONField(name = "iid")
@Column("IID")
private String iid;
/**
*
*/
@ExcelToValue(value = Constants.INPUT_INDEX)
@JSONField(name = "input_index")
@Column("INPUT_INDEX")
private String inputIndex;
/**
* 要素代码
*/
@ExcelToValue(value = YsdmConstans.YSDM_ZRZ)
@JSONField(name = "ysdm")
@Column("YSDM")
private String ysdm;
/**
* 所有权人代码
*/
@ExcelImport(exportName = "所有权人代码", checkNotNull = true, uniqueness = true)
@JSONField(name = "suyqrdm")
@Column("SUYQRDM")
private String suyqrdm;
/**
* 宅基地代码(所有权人代码+6位顺序号)
*/
@ExcelMapping(mappingName = "ZjdspZjdzd")
@ExcelImport(exportName = "宅基地代码", checkNotNull = true, uniqueness = true, rule = "SUYQRDM")
@JSONField(name = "zjddm")
@Column("ZJDDM")
private String zjddm;
@ExcelToValue
private ZjdspZjdzdxx zjdspZjdzdxx;
}
@TableName("ZJDSP_ZJDZDXX")
public class ZjdspZjdzdxx implements Serializable {
/**
*
*/
@JSONField(name = "iid")
@Column("IID")
private String iid;
/**
*
*/
@ExcelToValue(value = Constants.INPUT_INDEX)
@JSONField(name = "input_index")
@Column("INPUT_INDEX")
private String inputIndex;
/**
* 要素代码
*/
@ExcelToValue(value = YsdmConstans.YSDM_ZJDZDXX)
@JSONField(name = "ysdm")
@Column("YSDM")
private String ysdm;
/**
* 宅基地代码
*/
@ExcelMapping(mappingName = "ZjdspZjdzdxx", isRequired = true)
@JSONField(name = "zjddm")
@Column("ZJDDM")
private String zjddm;
}
package antu.zjdsjjg.tool;
import antu.com.Database;
import antu.com.annotations.Column;
import antu.com.annotations.TableName;
import antu.com.tools.LogUtils;
import antu.zjdsjjg.action.AppConfig;
import antu.zjdsjjg.domian.*;
import antu.zjdsjjg.domian.constants.Constants;
import antu.zjdsjjg.domian.constants.ExcelConstants;
import antu.zjdsjjg.model.ZjdspDrlsLog;
import antu.zjdsjjg.model.port.ObjectLocal;
import antu.zjdsjjg.model.vo.ContentVo;
import antu.zjdsjjg.provider.wh.GetWhAdapterProvider;
import antu.zjdsjjg.provider.wh.GetWhAdapterProviderImpl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.util.StopWatch;
import org.springframework.web.multipart.MultipartFile;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.*;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
/**
* <p>
* excel工具类
* </p>
*
* @author lisonglin
* @version 1.0
* @since 2022/3/9 14:10
*/
public class ExcelTool {
/**
* 导入excel
*
* @param multipartFile 文件
* @param sheet 工作表
* @param jsonData json
* @return 导入的数据
*/
public static List<Object> importExcel(MultipartFile multipartFile, String jsonData, String token,
String... sheet) {
JSONObject jsonObject = JSONObject.parseObject(jsonData);
String xzqdm = jsonObject.getString("xzqdm");
String userid = jsonObject.getString("userid");
String cjzzdm = jsonObject.getString("cjzzdm");
String zjzzdm = jsonObject.getString("zjzzdm");
StopWatch watch = new StopWatch();
watch.start();
// 获取用户名
String userSql = "select name from st_employee where employee_id = ?";
Database atpDb = new Database(AppConfig.atp_db);
String userName = atpDb.firstOrDefault(String.class, userSql, userid);
// 日志记录初始值
ZjdspDrlsLog zjdspDrlsLog = new ZjdspDrlsLog();
// 设置行政区代码
zjdspDrlsLog.setXzqdm(xzqdm);
// 设置操作系统名
zjdspDrlsLog.setMis(AppConfig.zjdsjjg_db);
// 设置导入时间为系统时间
zjdspDrlsLog.setImportDate(new java.sql.Timestamp(System.currentTimeMillis()));
// 设置导入人
zjdspDrlsLog.setCreateUser(userName);
zjdspDrlsLog.setCjzzdm(cjzzdm);
zjdspDrlsLog.setZjzzdm(zjzzdm);
if (!checkFile(multipartFile)) {
LogUtils.warn("上传的文件类型出错!");
// 设置导入状态为失败
zjdspDrlsLog.setHandleType(ExcelConstants.EXCEL_TYPE_ERROR);
// 设置导入类型
zjdspDrlsLog.setGrade(ExcelConstants.EXCEL_GRADE_ERROR);
// 设置失败原因
zjdspDrlsLog.setContent("上传的文件类型出错!");
return null;
}
Workbook workBook = getWorkBook(multipartFile);
return parseExcel(workBook, zjdspDrlsLog, xzqdm, token, watch, sheet);
}
/**
* 日期类型转换
*
* @param cell 单元格
* @return 字符串的时间
*/
public static String stringDateProcess(Cell cell) {
String result;
// 处理日期格式、时间格式
short dataFormat = cell.getCellStyle().getDataFormat();
if (HSSFDateUtil.isCellDateFormatted(cell)) {
SimpleDateFormat sdf = null;
if (cell.getCellStyle().getDataFormat() == HSSFDataFormat.getBuiltinFormat("h:mm")) {
sdf = new SimpleDateFormat("HH:mm");
} else {
// 日期
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
Date date = cell.getDateCellValue();
result = sdf.format(date);
} else if (dataFormat == ExcelConstants.EXCEL_DATE_MD) {
// 处理自定义日期格式:m月d日(通过判断单元格的格式id解决,id的值是58)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
double value = cell.getNumericCellValue();
Date date = DateUtil.getJavaDate(value);
result = sdf.format(date);
} else {
double value = cell.getNumericCellValue();
// int类型
if (String.valueOf(value).indexOf(".0") > 0) {
result = String.valueOf(value).substring(0, String.valueOf(value).indexOf(".0"));
} else {
// double类型
DecimalFormat format = new DecimalFormat();
int len = (value + "").length() - (value + "").indexOf(".") - 1;
if (len > 0) {
format.applyPattern("#." + StringUtils.repeat("0", len));
} else {
format.applyPattern("#");
}
result = format.format(value);
}
}
return result;
}
/**
* 转换excel数据类型
*
* @param cell 单元格
* @return 转换后的数据
*/
private static String convertCellValueToString(Cell cell) {
if (cell == null || cell.toString().trim().equals(Constants.EMPTY)) {
return null;
}
String cellValue;
switch (cell.getCellTypeEnum()) {
case BOOLEAN:
// 读取布尔
cellValue = String.valueOf(cell.getBooleanCellValue());
break;
case NUMERIC:
// 读取日期格式
cellValue = stringDateProcess(cell);
break;
case FORMULA:
// 读取公式
cellValue = String.valueOf(cell.getCellFormula());
break;
case STRING:
// 读取String
cellValue = String.valueOf(cell.getStringCellValue());
break;
case ERROR:
// 读取故障
cellValue = "非法字符";
break;
case _NONE:
case BLANK:
cellValue = "";
break;
default:
cellValue = "未知类型";
}
return cellValue;
}
/**
* 获取字段键值对 如:{所有权人代码=["setSuyqrdm", "yyyy-MM-dd", “”, “91360421MA35XB656Y”]}
* 键值对关系:
* Excel表头的字段名称 = [字段set方法名, 时间格式, 需要匹配的字典, 默认值]
*
* @param clazz 实体类
* @return 字段键值对
*/
public static List<Object> getFieldMap(Class<?> clazz, Object catObj) {
Field[] fields = clazz.getDeclaredFields();
List<Object> objectList = new ArrayList<>();
// 将所有标有Annotation的字段,也就是允许导入数据的字段,放入到一个map中
Map<String, ObjectLocal> fieldMap = new HashMap<>(10);
Map<String, Object[]> childrenSetMap = new HashMap<>(2);
try {
// 循环读取所有字段
for (Field field : fields) {
putMap(clazz, fieldMap, field, catObj, childrenSetMap);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
objectList.add(fieldMap);
objectList.add(childrenSetMap);
return objectList;
}
/**
* 将对象实例添加进Map中(处理一些默认值)
*
* @param clazz bean
* @param fieldMap 字段Map
* @param field 字段属性
* @param newInstance 实例化对象
* @throws Exception 异常
*/
private static void putMap(Class<?> clazz, Map<String, ObjectLocal> fieldMap, Field field, Object newInstance,
Map<String, Object[]> childrenSetMap) throws Exception {
ExcelImport exa = field.getAnnotation(ExcelImport.class);
ExcelToValue eValue = field.getAnnotation(ExcelToValue.class);
boolean isExist = field.isAnnotationPresent(ExcelToValue.class);
Dict dict = field.getAnnotation(Dict.class);
Column column = field.getAnnotation(Column.class);
ExcelMapping excelMapping = field.getAnnotation(ExcelMapping.class);
Enum[] enumConstants = null;
if (null != excelMapping){
String fieldName = field.getName();
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(fieldName, clazz);
Method writeMethod = propertyDescriptor.getWriteMethod();
Method readMethod = propertyDescriptor.getReadMethod();
boolean required = excelMapping.isRequired();
String mappingName = excelMapping.mappingName();
if (required) {
// zjdxx
childrenSetMap.put(mappingName, new Object[]{writeMethod});
} else {
// zjdzd
childrenSetMap.put(mappingName, new Object[]{readMethod});
}
}
if (exa != null) {
String fieldName = field.getName();
// 数据库映射值
String value = column.value();
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(fieldName, clazz);
Method writeMethod = propertyDescriptor.getWriteMethod();
Method readMethod = propertyDescriptor.getReadMethod();
// 非空检查
boolean checkNotNull = exa.checkNotNull();
// 唯一性检查
boolean uniqueness = exa.uniqueness();
// 可生成性检查
String generativeCode = exa.rule();
Method dictMethod = null;
if (dict != null) {
Class<Enum> aClass = dict.dictClass();
// 获取所有枚举实例
enumConstants = aClass.getEnumConstants();
dictMethod = aClass.getDeclaredMethod("getNameByRole", String.class);
}
ObjectLocal objectLocal = new ObjectLocal();
objectLocal.setWriteMethod(writeMethod);
objectLocal.setReadMethod(readMethod);
objectLocal.setCheckNotNull(checkNotNull);
objectLocal.setUniqueness(uniqueness);
objectLocal.setGenerativeCode(generativeCode);
objectLocal.setDictMethod(dictMethod);
objectLocal.setEnumConstants(enumConstants);
objectLocal.setValue(value);
objectLocal.setNewInstance(newInstance);
fieldMap.put(exa.exportName(), objectLocal);
}
if (isExist) {
// 默认值
String value = eValue.value();
String fieldName2 = field.getName();
PropertyDescriptor propertyDescriptor2 = new PropertyDescriptor(fieldName2, clazz);
Method writeMethod2 = propertyDescriptor2.getWriteMethod();
if (!StringUtil.isNullOrEmpty(value)) {
writeMethod2.invoke(newInstance, value);
} else {
// 内部对象
Class<?> type = field.getType();
// 内部对象
Object instance = type.newInstance();
for (Field declaredField : type.getDeclaredFields()) {
putMap(type, fieldMap, declaredField, instance, childrenSetMap);
}
// 内部对象set进包裹对象
childrenSetMap.put("children", new Object[]{writeMethod2, newInstance, instance});
}
}
}
/**
* 解析excel
*
* @param workbook 工作簿
* @param zjdspDrlsLog 日志
* @param sheets 工作表
* @return 解析的数据
*/
public static List<Object> parseExcel(Workbook workbook, ZjdspDrlsLog zjdspDrlsLog, String xzqdm, String token,
StopWatch watch, String... sheets) {
List<Object> resultList = new CopyOnWriteArrayList<>();
List<Object> resultList2 = new CopyOnWriteArrayList<>();
// 返回的真实行数
AtomicInteger realRow = new AtomicInteger(0);
// 连续空行数
AtomicInteger emptyRow = new AtomicInteger(0);
// 失败行数
AtomicInteger failureRow = new AtomicInteger(0);
// 主体内容,包括成功条数和失败条数,失败原因,以及失败的数据
List<ContentVo> contentVoList = new ArrayList<>();
Database zjdsjjgDb = new Database(AppConfig.zjdsjjg_db);
// 解析sheet
for (String sheet : sheets) {
try {
String clazzName = ExcelEnum.getNameByRole(sheet);
Class<?> classType = Class.forName(clazzName);
Object catObj = classType.newInstance();
TableName tableName = catObj.getClass().getAnnotation(TableName.class);
String table = tableName.value();
// 获取自定义注解的信息
List<Object> list = getFieldMap(classType, catObj);
Map<String, ObjectLocal> fieldMap = (Map<String, ObjectLocal>) list.get(0);
SimpleObject simpleObject = new SimpleObject();
Map<String, String> ruleMap = new HashMap<>(10);
Sheet wbSheet = workbook.getSheet(sheet);
// 校验sheet是否合法
if (sheet == null) {
// 设置导入状态为失败
zjdspDrlsLog.setHandleType(ExcelConstants.EXCEL_TYPE_ERROR);
// 设置导入类型
zjdspDrlsLog.setGrade(ExcelConstants.EXCEL_GRADE_ERROR);
// 设置失败原因
zjdspDrlsLog.setContent("解析Excel失败,该sheet不存在!");
continue;
}
// 获取第一行数据
int firstRowNum = wbSheet.getFirstRowNum();
Row firstRow = wbSheet.getRow(firstRowNum);
if (null == firstRow) {
LogUtils.warn("解析Excel失败,在第一行没有读取到任何数据!");
// 设置导入状态为失败
zjdspDrlsLog.setHandleType(ExcelConstants.EXCEL_TYPE_ERROR);
// 设置导入类型
zjdspDrlsLog.setGrade(ExcelConstants.EXCEL_GRADE_ERROR);
// 设置失败原因
zjdspDrlsLog.setContent("解析Excel失败,在第一行没有读取到任何数据!");
continue;
}
// 第二行数据
int startRow = firstRowNum + 2;
// 获取物理行数,不包括空行或隔行
int lastRowNum = wbSheet.getLastRowNum();
if (lastRowNum > 1000) {
lastRowNum = 1000;
}
// 取得标题头行
Row titleRow = wbSheet.getRow(1);
// 得到第一行的所有列
Iterator<Cell> cellTitle = titleRow.cellIterator();
// 将标题的文字内容放入到一个map中。
Map<Integer, String> titleMap = new HashMap<>(16);
// 循环标题所有的列
for (int i = 0; cellTitle.hasNext(); i++) {
Cell cell = cellTitle.next();
if (cell == null) {
continue;
}
String value = cell.getStringCellValue().trim();
titleMap.put(i, value);
}
int titleSize = titleMap.size();
// 计算有内容行
for (int i = startRow; i <= lastRowNum; i++) {
Row row = wbSheet.getRow(i);
// 连续空行数超过一百行,跳过后续内容
int emptyRowToInt = emptyRow.get();
if (emptyRowToInt >= 100) {
break;
}
if (null == row) {
emptyRow.getAndIncrement();
continue;
}
// 连续空行列数
AtomicInteger emptyColumn = new AtomicInteger(0);
// 遍历一行的列
for (int rowNum = 0; rowNum < titleSize; rowNum++) {
Cell cell = row.getCell(rowNum);
if (cell == null || CellType.BLANK == cell.getCellTypeEnum()) {
emptyColumn.incrementAndGet();
int i2 = emptyColumn.get();
// 连续空行列数大于标题数,空行数加一
if (i2 >= titleSize) {
emptyRow.getAndIncrement();
}
}
}
if (emptyRow.get() <= 0) {
realRow.getAndIncrement();
}
}
// 解析内容行
for (int i = 0; i < realRow.get(); i++) {
int traverse = startRow + i;
Row row = wbSheet.getRow(traverse);
boolean checkAndConvert = true;
// 解析内容列
for (int rowNum = 0; rowNum < titleSize; rowNum++) {
Cell cell = row.getCell(rowNum);
// 对应的标题
String title = titleMap.get(rowNum);
// 拥有的字段mao和Excel的标题匹配
if (fieldMap.containsKey(title)) {
ObjectLocal obj = fieldMap.get(title);
ObjectLocal objectLocal = obj;
// 不为空检查
boolean checkNotNull = obj.isCheckNotNull();
if (cell == null || CellType.BLANK == cell.getCellTypeEnum()) {
// 检验数据是否合法
if (checkNotNull) {
// 日志记录(失败的导入)
checkContent(failureRow, contentVoList, title, "", ExcelConstants.CHECK_NOT_NULL);
realRow.incrementAndGet();
continue;
}
}
// 父类实例化对象
checkAndConvert = checkAndConvert(cell, objectLocal, zjdsjjgDb, failureRow, contentVoList, title
, ruleMap, xzqdm, token, table);
}
}
if (checkAndConvert){
// 子类set进父类
Map<String, Object[]> childrenSetMap = (Map<String, Object[]>) list.get(1);
Object[] children = childrenSetMap.get("children");
//Method writeMethod = (Method) children[0];
Object newInstance = children[1];
Object instance = children[2];
Object[] newInstanceObjects = childrenSetMap.get(newInstance.getClass().getSimpleName());
Object[] instanceObjects = childrenSetMap.get(instance.getClass().getSimpleName());
Method instanceReadMethod = (Method) newInstanceObjects[0];
Method newInstanceWriteMethod = (Method) instanceObjects[0];
// zjdxx.setZjddm(zjdzd.getZjddm)
newInstanceWriteMethod.invoke(instance, instanceReadMethod.invoke(newInstance));
//writeMethod.invoke(newInstance, instance);
simpleObject.setInstance(instance);
simpleObject.setNewInstance(newInstance);
SimpleObject simpleObject2 = SerializationUtils.clone(simpleObject);
if (simpleObject2.getInstance() != null) {
resultList2.add(simpleObject2.getInstance());
}
resultList.add(simpleObject2.getNewInstance());
}
}
try {
zjdsjjgDb.BeginTransaction();
String newInstanceSql = SqlTool.genSqlInsert(simpleObject.getNewInstance(),
resultList.size());
if (resultList2.size() > 0) {
String instanceSql = SqlTool.genSqlInsert(simpleObject.getInstance(), resultList2.size());
Object[] resultColumn = SqlTool.genColumn(resultList2);
zjdsjjgDb.executeUpdate(instanceSql, resultColumn);
}
zjdsjjgDb.executeUpdate(newInstanceSql, SqlTool.genColumn(resultList));
zjdsjjgDb.CompleteTransaction();
} catch (Exception e) {
zjdsjjgDb.AbortTransaction();
e.printStackTrace();
}
// 日志记录 (导入总数)
LogUtils.info("》》》》" + sheet + ",共有:" + realRow + "行");
zjdspDrlsLog.setGrade(ExcelConstants.EXCEL_GRADE_INFO);
zjdspDrlsLog.setHandleType(ExcelConstants.EXCEL_TYPE_INFO);
String dataCount = String.format("》》》》 %s工作簿,总共有{ %s }条数据", sheet, realRow);
zjdspDrlsLog.setDataCount(dataCount);
int failureRowToInt = failureRow.get();
int realRowToInt = realRow.get();
int result = realRowToInt - failureRowToInt;
String contentStr = JSON.toJSON(contentVoList).toString();
String content = String.format("入库成功{ %s }条,导入失败{ %s }条。导入失败原因:%s", result, failureRowToInt,
contentStr);
zjdspDrlsLog.setContent(content);
} catch (Exception e) {
// 设置导入状态为失败
zjdspDrlsLog.setHandleType(ExcelConstants.EXCEL_TYPE_ERROR);
// 设置导入类型
zjdspDrlsLog.setGrade(ExcelConstants.EXCEL_GRADE_ERROR);
// 设置失败原因
zjdspDrlsLog.setContent(e.getMessage());
throw new RuntimeException(e);
} finally {
try {
watch.stop();
zjdspDrlsLog.setTotalTime("总共耗时:" + watch.getTotalTimeSeconds() + "秒");
zjdsjjgDb.BeginTransaction();
zjdsjjgDb.insert(zjdspDrlsLog);
zjdsjjgDb.CompleteTransaction();
} catch (Exception e) {
zjdsjjgDb.AbortTransaction();
e.printStackTrace();
}
try {
workbook.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
return resultList;
}
private static void checkContent(AtomicInteger failureRow, List<ContentVo> contentVoList, String titleString,
String cellValue, String reason) {
ContentVo contentVo = new ContentVo();
failureRow.getAndIncrement();
// 失败的数据关键字
contentVo.setKey(titleString + ":" + cellValue);
// 失败原因
contentVo.setReason(reason);
contentVoList.add(contentVo);
}
private static boolean checkAndConvert(Cell cell, ObjectLocal obj, Database zjdsjjgDb, AtomicInteger failureRow,
List<ContentVo> contentVoList, String titleString,
Map<String, String> ruleMap, String xzqdm, String token, String table) throws IllegalAccessException, InvocationTargetException {
// set方法
Method setMethod = obj.getWriteMethod();
// 字典
Method dictMethod = obj.getDictMethod();
// 父类实例化对象
Object clazz = obj.getNewInstance();
// 枚举类实例化对象
Enum[] anEnum = obj.getEnumConstants();
// 唯一性检查
boolean uniqueness = obj.isUniqueness();
// 可生成性检查
String rule = obj.getGenerativeCode();
// 数据库映射值
String column = obj.getValue();
// 检验数据是否合法
if (uniqueness) {
// 检查唯一性
String cellValue = cell.getStringCellValue();
String sqlFormat = "select %s from %s where %s = ?";
String sql = String.format(sqlFormat, column.toLowerCase(), table, column.toLowerCase());
// 查询数据库
String index = zjdsjjgDb.firstOrDefault(String.class, sql, cellValue);
if (!StringUtil.isNullOrEmpty(index)) {
// 唯一性检查失败
// 日志记录
LogUtils.info("》》》》" + cellValue + "已存在,请检查");
// 失败内容
checkContent(failureRow, contentVoList, titleString, cellValue, ExcelConstants.CHECK_NOT_UNIQUENESS);
return false;
} else {
// 唯一性检查成功
// 将有唯一性的数据放入Map集合
// map存放 <数据库映射值, 单元格值>
ruleMap.put(column, cellValue);
if (StringUtil.isNullOrEmpty(cellValue)) {
if (!StringUtil.isNullOrEmpty(rule)) {
// 检查可生成性
if (ruleMap.containsKey(rule)) {
// 根据集合中的唯一性数据生成对应的数据
// 那么生成规则是什么呢?
String genRule = ruleMap.get(rule);
GetWhAdapterProvider whAdapterProvider = new GetWhAdapterProviderImpl();
String wh = whAdapterProvider.getWh(column, xzqdm, genRule, token);
setMethod.invoke(clazz, wh);
}
} else {
// 不检查可生成性
convert(cell, setMethod, dictMethod, clazz, anEnum);
}
} else {
// 不检查可生成性
convert(cell, setMethod, dictMethod, clazz, anEnum);
}
}
} else {
convert(cell, setMethod, dictMethod, clazz, anEnum);
}
return true;
}
private static void convert(Cell cell, Method setMethod, Method dictMethod, Object clazz, Enum[] anEnum) throws IllegalAccessException, InvocationTargetException {
// 得到setter方法的参数
Type[] ts = setMethod.getGenericParameterTypes();
String xclass = ts[0].toString();
// 判断参数类型
if ("class java.lang.String".equals(xclass)) {
// 拥有字典的场合
if (null != dictMethod) {
// 字典映射后的value enum实例化对象
Object dictValue = dictMethod.invoke(anEnum, convertCellValueToString(cell));
setMethod.invoke(clazz, dictValue);
} else {
setMethod.invoke(clazz, convertCellValueToString(cell));
}
} else if ("class java.util.Date".equals(xclass)) {
setMethod.invoke(clazz, !StringUtil.isNullOrEmpty(convertCellValueToString(cell)) ?
DataTimeTool.StrToDate(convertCellValueToString(cell)) : null);
} else if ("class java.lang.Boolean".equals(xclass)) {
setMethod.invoke(clazz, convertCellValueToString(cell));
} else if ("class java.lang.Integer".equals(xclass)) {
setMethod.invoke(clazz, !StringUtils.isBlank(convertCellValueToString(cell)) ?
Integer.parseInt(convertCellValueToString(cell)) : 0);
} else if ("class java.lang.Long".equals(xclass)) {
setMethod.invoke(clazz, convertCellValueToString(cell));
} else if ("class java.lang.Double".equals(xclass)) {
setMethod.invoke(clazz, !StringUtils.isBlank(convertCellValueToString(cell)) ?
Double.parseDouble(convertCellValueToString(cell)) : 0D);
} else if ("class java.lang.Object".equals(xclass)) {
setMethod.invoke(clazz, convertCellValueToString(cell));
}
}
/**
* 根据文件后缀名类型获取对应的工作簿对象
*
* @param multipartFile 导入的文件
* @return 包含文件数据的工作簿对象
*/
public static Workbook getWorkBook(MultipartFile multipartFile) {
//获得文件名
String fileName = multipartFile.getOriginalFilename();
Workbook workbook = null;
try {
InputStream ips = multipartFile.getInputStream();
if (Objects.requireNonNull(fileName).endsWith(ExcelConstants.EXCEL_XLSX_TYPE)) {
//2007 及2007以上
workbook = new XSSFWorkbook(ips);
} else if (fileName.endsWith(ExcelConstants.EXCEL_XLS_TYPE)) {
//2003
workbook = new HSSFWorkbook(ips);
} else {
throw new NoSuchMethodError("没有能够处理此文件的方法");
}
} catch (IOException e) {
e.getMessage();
}
return workbook;
}
/**
* 检查文件类型
*
* @param file 导入的文件
* @return 是否是XLS或XLSX文件
*/
public static boolean checkFile(MultipartFile file) {
//判断文件是否存在
if (null == file) {
return false;
}
//获得文件名
String fileName = file.getOriginalFilename();
//判断文件是否是excel文件
return Objects.requireNonNull(fileName).endsWith(ExcelConstants.EXCEL_XLSX_TYPE) || fileName.endsWith(ExcelConstants.EXCEL_XLS_TYPE);
}
}
class SimpleObject implements Serializable {
private Object newInstance;
private Object instance;
public Object getInstance() {
return instance;
}
public void setInstance(Object instance) {
this.instance = instance;
}
public Object getNewInstance() {
return newInstance;
}
public void setNewInstance(Object newInstance) {
this.newInstance = newInstance;
}
}
public class ObjectLocal implements Serializable {
private Method writeMethod;
private Method readMethod;
private boolean checkNotNull;
private boolean uniqueness;
private String generativeCode;
private Method dictMethod;
private Enum[] enumConstants;
private String value;
private Object newInstance;
public Method getWriteMethod() {
return writeMethod;
}
public void setWriteMethod(Method writeMethod) {
this.writeMethod = writeMethod;
}
public Method getReadMethod() {
return readMethod;
}
public void setReadMethod(Method readMethod) {
this.readMethod = readMethod;
}
public boolean isCheckNotNull() {
return checkNotNull;
}
public void setCheckNotNull(boolean checkNotNull) {
this.checkNotNull = checkNotNull;
}
public boolean isUniqueness() {
return uniqueness;
}
public void setUniqueness(boolean uniqueness) {
this.uniqueness = uniqueness;
}
public String getGenerativeCode() {
return generativeCode;
}
public void setGenerativeCode(String generativeCode) {
this.generativeCode = generativeCode;
}
public Method getDictMethod() {
return dictMethod;
}
public void setDictMethod(Method dictMethod) {
this.dictMethod = dictMethod;
}
public Enum[] getEnumConstants() {
return enumConstants;
}
public void setEnumConstants(Enum[] enumConstants) {
this.enumConstants = enumConstants;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Object getNewInstance() {
return newInstance;
}
public void setNewInstance(Object newInstance) {
this.newInstance = newInstance;
}
}
参照连接:https://blog.csdn.net/fangchao2011/article/details/105534252
https://blog.csdn.net/lbq15735104044/article/details/108980532