|
@@ -0,0 +1,206 @@
|
|
|
+package com.fjhx.service.excel.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.io.IoUtil;
|
|
|
+import cn.hutool.core.util.ObjectUtil;
|
|
|
+import com.alibaba.excel.EasyExcel;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.fjhx.base.BaseEntity;
|
|
|
+import com.fjhx.config.TaskPoolConfig;
|
|
|
+import com.fjhx.entity.excel.ExcelImportLog;
|
|
|
+import com.fjhx.listener.EasyExcelListener;
|
|
|
+import com.fjhx.mapper.excel.ExcelImportLogMapper;
|
|
|
+import com.fjhx.params.excel.ExcelProcessingProgress;
|
|
|
+import com.fjhx.service.excel.ExcelImportLogService;
|
|
|
+import org.springblade.core.excel.support.ExcelException;
|
|
|
+import org.springblade.core.redis.cache.BladeRedis;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Qualifier;
|
|
|
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.util.ObjectUtils;
|
|
|
+import org.springframework.util.StringUtils;
|
|
|
+import org.springframework.web.multipart.MultipartFile;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.io.BufferedInputStream;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+import java.util.function.Consumer;
|
|
|
+
|
|
|
+/**
|
|
|
+ * <p>
|
|
|
+ * 服务实现类
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @author ${author}
|
|
|
+ * @since 2022-12-07
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class ExcelImportLogServiceImpl extends ServiceImpl<ExcelImportLogMapper, ExcelImportLog> implements ExcelImportLogService {
|
|
|
+
|
|
|
+ @Qualifier(TaskPoolConfig.excelExecutor)
|
|
|
+ @Autowired
|
|
|
+ private ThreadPoolTaskExecutor executor;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private BladeRedis bladeRedis;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public <T> void asyncRead(String flag, MultipartFile file, Class<T> cls, Integer businessType,
|
|
|
+ Consumer<List<T>> handleFun, Runnable errorFun) {
|
|
|
+
|
|
|
+ String filename = file.getOriginalFilename();
|
|
|
+ if (ObjectUtils.isEmpty(filename)) {
|
|
|
+ throw new ExcelException("请上传文件!");
|
|
|
+ }
|
|
|
+ if ((!StringUtils.endsWithIgnoreCase(filename, ".xls") && !StringUtils.endsWithIgnoreCase(filename, ".xlsx"))) {
|
|
|
+ throw new ExcelException("请上传正确的excel文件!");
|
|
|
+ }
|
|
|
+
|
|
|
+ InputStream inputStream;
|
|
|
+ try {
|
|
|
+ inputStream = new BufferedInputStream(file.getInputStream());
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new ExcelException("文件读取失败!");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 导入信息放入redis缓存
|
|
|
+ ExcelProcessingProgress excelProcessingProgress = new ExcelProcessingProgress();
|
|
|
+ excelProcessingProgress.setStatus(1); // 预处理阶段
|
|
|
+ excelProcessingProgress.setPercentage(5); // 进度 5%
|
|
|
+ setProgress(flag, excelProcessingProgress); // 保存
|
|
|
+
|
|
|
+ executor.execute(() -> {
|
|
|
+ try {
|
|
|
+ // 开始时间
|
|
|
+ long start = System.currentTimeMillis();
|
|
|
+
|
|
|
+ // 信息保存到数据库
|
|
|
+ saveLog(flag, businessType, file);
|
|
|
+
|
|
|
+ // 开始处理 进度 10%
|
|
|
+ verificationAndUpdateProgress(flag, 2, 10);
|
|
|
+
|
|
|
+ EasyExcel.read(inputStream, cls, new EasyExcelListener<T>(
|
|
|
+ 500,
|
|
|
+ (list, totalLine, readLine) -> {
|
|
|
+ handleFun.accept(list);
|
|
|
+ if (totalLine == readLine) {
|
|
|
+ editLog(start, flag, 1);
|
|
|
+ // 已完成
|
|
|
+ verificationAndUpdateProgress(flag, 5, 100);
|
|
|
+ } else {
|
|
|
+ // 处理中
|
|
|
+ verificationAndUpdateProgress(flag, 3, 10 + readLine * 90 / totalLine);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ (exception) -> {
|
|
|
+ exception.printStackTrace();
|
|
|
+ errorFun.run();
|
|
|
+ // 用户取消
|
|
|
+ if (exception instanceof ExcelException) {
|
|
|
+ editLog(start, flag, 3);
|
|
|
+ verificationAndUpdateProgress(flag, 6, 0);
|
|
|
+ }
|
|
|
+ // 发生异常
|
|
|
+ else {
|
|
|
+ editLog(start, flag, 2);
|
|
|
+ verificationAndUpdateProgress(flag, 4, 0);
|
|
|
+ }
|
|
|
+ })).doReadAll();
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error(e.getMessage());
|
|
|
+ } finally {
|
|
|
+ IoUtil.close(inputStream);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ExcelProcessingProgress getReadRate(String flag) {
|
|
|
+ ExcelProcessingProgress excelProcessingProgress = bladeRedis.get(flag);
|
|
|
+
|
|
|
+ // 如果处理完成、用户取消、发生异常,删除缓存
|
|
|
+ if (excelProcessingProgress != null && excelProcessingProgress.getStatus() > 3) {
|
|
|
+ bladeRedis.del(flag);
|
|
|
+ }
|
|
|
+
|
|
|
+ return excelProcessingProgress;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void stopRead(String flag) {
|
|
|
+ // 导入信息放入redis缓存
|
|
|
+ ExcelProcessingProgress excelProcessingProgress = new ExcelProcessingProgress();
|
|
|
+ excelProcessingProgress.setStatus(6); // 预处理阶段
|
|
|
+ excelProcessingProgress.setPercentage(0); // 进度 0%
|
|
|
+ setProgress(flag, excelProcessingProgress);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 插入缓存信息
|
|
|
+ *
|
|
|
+ * @param flag 缓存标记
|
|
|
+ * @param excelProcessingProgress 缓存对象
|
|
|
+ */
|
|
|
+ private synchronized void setProgress(String flag, ExcelProcessingProgress excelProcessingProgress) {
|
|
|
+ bladeRedis.setEx(flag, excelProcessingProgress, 60L * 60 * 12);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 验证并更新缓存信息
|
|
|
+ *
|
|
|
+ * @param flag 缓存标记
|
|
|
+ * @param status 状态
|
|
|
+ * @param percentage 进度
|
|
|
+ */
|
|
|
+ private synchronized void verificationAndUpdateProgress(String flag, Integer status, Integer percentage) {
|
|
|
+ ExcelProcessingProgress excelProcessingProgress = bladeRedis.get(flag);
|
|
|
+ if (ObjectUtil.isNull(excelProcessingProgress) || excelProcessingProgress.getStatus().equals(6)) {
|
|
|
+ throw new ExcelException("取消导入");
|
|
|
+ }
|
|
|
+
|
|
|
+ excelProcessingProgress.setStatus(status);
|
|
|
+ excelProcessingProgress.setPercentage(percentage);
|
|
|
+ bladeRedis.setEx(flag, excelProcessingProgress, 60L * 60 * 12);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存导入记录
|
|
|
+ *
|
|
|
+ * @param flag 导入标记
|
|
|
+ * @param businessType 业务类型
|
|
|
+ * @param file 文件
|
|
|
+ */
|
|
|
+ private void saveLog(String flag, Integer businessType, MultipartFile file) {
|
|
|
+ // 上传记录记录数据库
|
|
|
+ ExcelImportLog excelImportLog = new ExcelImportLog();
|
|
|
+ excelImportLog.setFlag(flag);
|
|
|
+ excelImportLog.setBusinessType(businessType);
|
|
|
+ excelImportLog.setStatus(0);
|
|
|
+ excelImportLog.setFileName(file.getOriginalFilename());
|
|
|
+ save(excelImportLog);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新导入记录
|
|
|
+ *
|
|
|
+ * @param start 开始导入时间戳
|
|
|
+ * @param flag 标记
|
|
|
+ * @param status 状态
|
|
|
+ */
|
|
|
+ private void editLog(Long start, String flag, Integer status) {
|
|
|
+ long end = System.currentTimeMillis();
|
|
|
+
|
|
|
+ update(q -> q
|
|
|
+ .eq(ExcelImportLog::getFlag, flag)
|
|
|
+ .set(ExcelImportLog::getStatus, status)
|
|
|
+ .set(ExcelImportLog::getExecuteTime, (end - start) / 1000)
|
|
|
+ .set(BaseEntity::getUpdateTime, new Date())
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|