diff --git a/epmet-module/epmet-common-service/common-service-client/src/main/java/com/epmet/constants/ImportTaskConstants.java b/epmet-module/epmet-common-service/common-service-client/src/main/java/com/epmet/constants/ImportTaskConstants.java index 46b99ffea4..e15f7f5057 100644 --- a/epmet-module/epmet-common-service/common-service-client/src/main/java/com/epmet/constants/ImportTaskConstants.java +++ b/epmet-module/epmet-common-service/common-service-client/src/main/java/com/epmet/constants/ImportTaskConstants.java @@ -22,6 +22,10 @@ public interface ImportTaskConstants { * 核酸检测 */ String BIZ_TYPE_IC_NAT = "ic_nat"; + /** + * 行程上报 + */ + String BIZ_TYPE_IC_TRIP_REPORT = "ic_trip_report"; /** * 处理状态:处理中 diff --git a/epmet-user/epmet-user-client/src/main/java/com/epmet/dto/form/IcTripReportFormDTO.java b/epmet-user/epmet-user-client/src/main/java/com/epmet/dto/form/IcTripReportFormDTO.java index 3de314d424..d9a7f4d565 100644 --- a/epmet-user/epmet-user-client/src/main/java/com/epmet/dto/form/IcTripReportFormDTO.java +++ b/epmet-user/epmet-user-client/src/main/java/com/epmet/dto/form/IcTripReportFormDTO.java @@ -74,7 +74,7 @@ public class IcTripReportFormDTO implements Serializable { /** * 现居地编码路径:"presentAddressPathCode":"37,3702,370203,370203026,370203026002" */ - @NotBlank(message = "现居地编码不能为空", groups = {ResiUserRequired.class}) + @NotBlank(message = "现居地编码路径不能为空", groups = {ResiUserRequired.class}) private String presentAddressPathCode; /** @@ -98,7 +98,7 @@ public class IcTripReportFormDTO implements Serializable { /** * 来源地编码路径: "sourceAddressPathCode": "37,3702,370203,370203026,370203026002" */ - @NotBlank(message = "来自地区编码不能为空", groups = {ResiUserRequired.class}) + @NotBlank(message = "来自地编码路径不能为空", groups = {ResiUserRequired.class}) private String sourceAddressPathCode; /** diff --git a/epmet-user/epmet-user-server/src/main/java/com/epmet/controller/IcTripReportRecordController.java b/epmet-user/epmet-user-server/src/main/java/com/epmet/controller/IcTripReportRecordController.java index 4b4fff68f8..4c06646ee1 100644 --- a/epmet-user/epmet-user-server/src/main/java/com/epmet/controller/IcTripReportRecordController.java +++ b/epmet-user/epmet-user-server/src/main/java/com/epmet/controller/IcTripReportRecordController.java @@ -5,18 +5,30 @@ import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.write.metadata.WriteSheet; import com.epmet.commons.tools.annotation.LoginUser; import com.epmet.commons.tools.aop.NoRepeatSubmit; +import com.epmet.commons.tools.constant.AppClientConstant; import com.epmet.commons.tools.constant.NumConstant; +import com.epmet.commons.tools.constant.ServiceConstant; import com.epmet.commons.tools.dto.form.PageFormDTO; +import com.epmet.commons.tools.exception.EpmetErrorCode; +import com.epmet.commons.tools.exception.EpmetException; +import com.epmet.commons.tools.exception.ExceptionUtils; +import com.epmet.commons.tools.feign.ResultDataResolver; import com.epmet.commons.tools.page.PageData; import com.epmet.commons.tools.security.dto.TokenDto; +import com.epmet.commons.tools.utils.EpmetRequestHolder; import com.epmet.commons.tools.utils.ExcelUtils; +import com.epmet.commons.tools.utils.FileUtils; import com.epmet.commons.tools.utils.Result; import com.epmet.commons.tools.validator.ValidatorUtils; import com.epmet.constant.IcResiUserConstant; +import com.epmet.constants.ImportTaskConstants; import com.epmet.dto.IcTripReportRecordDTO; import com.epmet.dto.form.IcTripReportFormDTO; +import com.epmet.dto.form.ImportTaskCommonFormDTO; import com.epmet.dto.form.MyReportedTripFormDTO; import com.epmet.dto.form.PageTripReportFormDTO; +import com.epmet.dto.result.ImportTaskCommonResultDTO; +import com.epmet.feign.EpmetCommonServiceOpenFeignClient; import com.epmet.service.IcTripReportRecordService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; @@ -25,28 +37,34 @@ import org.apache.commons.lang3.ArrayUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URLEncoder; +import java.nio.file.Path; import java.util.List; +import java.util.UUID; /** * 行程上报信息 * * @author generator generator@elink-cn.com - * @since v1.0.0 2022-03-25 + * @since v10.0 2022-03-25 */ @Slf4j @RestController @RequestMapping("tripreport") -public class IcTripReportRecordController { +public class IcTripReportRecordController implements ResultDataResolver { @Autowired private IcTripReportRecordService icTripReportRecordService; + @Autowired + private EpmetCommonServiceOpenFeignClient commonServiceOpenFeignClient; /** * pc: 行程上报-列表 @@ -203,4 +221,58 @@ public class IcTripReportRecordController { } } } + + + /** + * 导入excel + * @return + */ + @PostMapping("import") + public Result importExcel(MultipartFile file) { + String userId = EpmetRequestHolder.getHeader(AppClientConstant.USER_ID); + + // 1.暂存文件 + String originalFilename = file.getOriginalFilename(); + String extName = originalFilename.substring(originalFilename.lastIndexOf(".")); + + Path fileSavePath; + try { + Path importPath = FileUtils.getAndCreateDirUnderEpmetFilesDir("ic_trip_preport", "import"); + fileSavePath = importPath.resolve(UUID.randomUUID().toString().concat(extName)); + } catch (IOException e) { + String errorMsg = ExceptionUtils.getErrorStackTrace(e); + log.error("【行程上报导入】创建临时存储文件失败:{}", errorMsg); + throw new EpmetException(EpmetErrorCode.EPMET_COMMON_OPERATION_FAIL.getCode(), "文件上传失败", "文件上传失败"); + } + + InputStream is = null; + FileOutputStream os = null; + + try { + is = file.getInputStream(); + os = new FileOutputStream(fileSavePath.toString()); + IOUtils.copy(is, os); + } catch (Exception e) { + e.printStackTrace(); + } finally { + org.apache.poi.util.IOUtils.closeQuietly(is); + org.apache.poi.util.IOUtils.closeQuietly(os); + } + + // 2.生成导入任务记录 + ImportTaskCommonFormDTO importTaskForm = new ImportTaskCommonFormDTO(); + importTaskForm.setOperatorId(userId); + importTaskForm.setBizType(ImportTaskConstants.BIZ_TYPE_IC_TRIP_REPORT); + importTaskForm.setOriginFileName(originalFilename); + + ImportTaskCommonResultDTO rstData = getResultDataOrThrowsException(commonServiceOpenFeignClient.createImportTask(importTaskForm), + ServiceConstant.EPMET_COMMON_SERVICE, + EpmetErrorCode.EPMET_COMMON_OPERATION_FAIL.getCode(), + "excel行程上报导入错误", + "行程上报导入失败"); + + // 3.执行导入 + icTripReportRecordService.execAsyncExcelImport(fileSavePath, rstData.getTaskId()); + return new Result(); + } } diff --git a/epmet-user/epmet-user-server/src/main/java/com/epmet/excel/data/IcTripReportExcelData.java b/epmet-user/epmet-user-server/src/main/java/com/epmet/excel/data/IcTripReportExcelData.java new file mode 100644 index 0000000000..f6f2a86e42 --- /dev/null +++ b/epmet-user/epmet-user-server/src/main/java/com/epmet/excel/data/IcTripReportExcelData.java @@ -0,0 +1,75 @@ +package com.epmet.excel.data; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.Date; + + +/** + * 行程上报excel数据 + */ +@Data +public class IcTripReportExcelData { + @NotBlank(message = "姓名为必填项") + @ExcelProperty("姓名") + private String name; + + @NotBlank(message = "身份证号为必填项") + @ExcelProperty("身份证号") + private String idCard; + + @NotBlank(message = "手机号为必填项") + @ExcelProperty("手机号") + private String mobile; + + @NotBlank(message = "现居地为必填项") + @ExcelProperty("现居地(格式:省-市-区-街道-社区)") + private String presentAddress; + + @NotBlank(message = "详细地址为必填项") + @ExcelProperty("详细地址") + private String detailAddress; + + @NotBlank(message = "来自地区为必填项") + @ExcelProperty("来自地区(格式:省-市-区-街道-社区)") + private String sourceAddress; + + @NotNull(message = "来到本地时间为必填项") + @ExcelProperty("来到本地时间(格式:2022-01-01)") + private Date arriveDate; + + @ExcelProperty("离开本地时间(格式:2022-01-01)") + private Date leaveDate; + + /** + * 备注信息 + */ + @Length(max = 500,message = "备注不能超过500字") + @ExcelProperty("备注(500字以内)") + private String remark; + + @Data + public static class ErrorRow { + + @ExcelProperty("姓名") + @ColumnWidth(20) + private String name; + + @ColumnWidth(20) + @ExcelProperty("身份证号") + private String idCard; + + @ExcelProperty("手机号") + @ColumnWidth(20) + private String mobile; + + @ColumnWidth(60) + @ExcelProperty("错误信息") + private String errorInfo; + } +} diff --git a/epmet-user/epmet-user-server/src/main/java/com/epmet/excel/handler/IcTripReportExcelImportListener.java b/epmet-user/epmet-user-server/src/main/java/com/epmet/excel/handler/IcTripReportExcelImportListener.java new file mode 100644 index 0000000000..e0531d7303 --- /dev/null +++ b/epmet-user/epmet-user-server/src/main/java/com/epmet/excel/handler/IcTripReportExcelImportListener.java @@ -0,0 +1,113 @@ +package com.epmet.excel.handler; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.epmet.commons.tools.dto.result.CustomerStaffInfoCacheResult; +import com.epmet.commons.tools.exception.ExceptionUtils; +import com.epmet.commons.tools.exception.ValidateException; +import com.epmet.commons.tools.utils.ConvertUtils; +import com.epmet.commons.tools.validator.ValidatorUtils; +import com.epmet.constant.IcResiUserConstant; +import com.epmet.entity.IcTripReportRecordEntity; +import com.epmet.excel.data.IcTripReportExcelData; +import com.epmet.service.impl.IcTripReportRecordServiceImpl; +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.List; + + +/** + * 行程上报excel导入监听器 + */ +@Slf4j +public class IcTripReportExcelImportListener implements ReadListener { + + + /** + * 最大条数阈值 + */ + public static final int MAX_THRESHOLD = 2; + /** + * 当前操作用户 + */ + private CustomerStaffInfoCacheResult staffInfo; + + /** + * 数据 + */ + private List datas = new ArrayList<>(); + + /** + * 错误项列表 + */ + private List errorRows = new ArrayList<>(); + + private IcTripReportRecordServiceImpl tripReportRecordService; + + public IcTripReportExcelImportListener(CustomerStaffInfoCacheResult staffInfo, IcTripReportRecordServiceImpl tripReportRecordService) { + this.staffInfo = staffInfo; + this.tripReportRecordService = tripReportRecordService; + } + + @Override + public void invoke(IcTripReportExcelData data, AnalysisContext context) { + + try { + // 先校验数据 + ValidatorUtils.validateEntity(data); + + IcTripReportRecordEntity tripReportRecordEntity = ConvertUtils.sourceToTarget(data, IcTripReportRecordEntity.class); + tripReportRecordEntity.setAgencyId(staffInfo.getAgencyId()); + tripReportRecordEntity.setPids(staffInfo.getAgencyPIds()); + tripReportRecordEntity.setUserType(IcResiUserConstant.USER_TYPE_IMPORT); + datas.add(tripReportRecordEntity); + + if (datas.size() == MAX_THRESHOLD) { + execPersist(); + } + } catch (Exception e) { + String errorMsg = null; + if (e instanceof ValidateException) { + errorMsg = ((ValidateException) e).getMsg(); + } else { + errorMsg = "未知错误"; + log.error("【行程上报导入】出错:{}", ExceptionUtils.getErrorStackTrace(e)); + } + + IcTripReportExcelData.ErrorRow errorRow = new IcTripReportExcelData.ErrorRow(); + errorRow.setName(data.getName()); + errorRow.setMobile(data.getMobile()); + errorRow.setIdCard(data.getIdCard()); + errorRow.setErrorInfo(errorMsg); + errorRows.add(errorRow); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + // 最后几条达不到阈值,这里必须再调用一次 + execPersist(); + } + + /** + * 执行持久化 + */ + private void execPersist() { + try { + if (datas != null && datas.size() > 0) { + tripReportRecordService.batchPersist(datas); + } + } finally { + datas.clear(); + } + } + + /** + * 获取错误行 + * @return + */ + public List getErrorRows() { + return errorRows; + } +} diff --git a/epmet-user/epmet-user-server/src/main/java/com/epmet/service/IcTripReportRecordService.java b/epmet-user/epmet-user-server/src/main/java/com/epmet/service/IcTripReportRecordService.java index a7f961542d..66ec0d9f9e 100644 --- a/epmet-user/epmet-user-server/src/main/java/com/epmet/service/IcTripReportRecordService.java +++ b/epmet-user/epmet-user-server/src/main/java/com/epmet/service/IcTripReportRecordService.java @@ -9,6 +9,7 @@ import com.epmet.dto.form.PageTripReportFormDTO; import com.epmet.dto.result.TripListDTO; import com.epmet.entity.IcTripReportRecordEntity; +import java.nio.file.Path; import java.util.List; import java.util.Map; @@ -93,4 +94,10 @@ public interface IcTripReportRecordService extends BaseService tripList(String customerId, String idCard); + + /** + * 执行Excel导入 + * @param filePath + */ + void execAsyncExcelImport(Path filePath, String importTaskId); } \ No newline at end of file diff --git a/epmet-user/epmet-user-server/src/main/java/com/epmet/service/impl/IcTripReportRecordServiceImpl.java b/epmet-user/epmet-user-server/src/main/java/com/epmet/service/impl/IcTripReportRecordServiceImpl.java index 5c42a0d00e..e8597fed16 100644 --- a/epmet-user/epmet-user-server/src/main/java/com/epmet/service/impl/IcTripReportRecordServiceImpl.java +++ b/epmet-user/epmet-user-server/src/main/java/com/epmet/service/impl/IcTripReportRecordServiceImpl.java @@ -1,28 +1,38 @@ package com.epmet.service.impl; +import com.alibaba.excel.EasyExcel; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.epmet.commons.mybatis.service.impl.BaseServiceImpl; +import com.epmet.commons.tools.constant.AppClientConstant; import com.epmet.commons.tools.constant.FieldConstant; import com.epmet.commons.tools.constant.NumConstant; import com.epmet.commons.tools.dto.result.CustomerStaffInfoCacheResult; import com.epmet.commons.tools.exception.EpmetErrorCode; import com.epmet.commons.tools.exception.EpmetException; +import com.epmet.commons.tools.exception.ExceptionUtils; +import com.epmet.commons.tools.feign.ResultDataResolver; import com.epmet.commons.tools.page.PageData; import com.epmet.commons.tools.redis.common.CustomerOrgRedis; import com.epmet.commons.tools.redis.common.CustomerStaffRedis; import com.epmet.commons.tools.redis.common.bean.AgencyInfoCache; import com.epmet.commons.tools.redis.common.bean.GridInfoCache; -import com.epmet.commons.tools.utils.ConvertUtils; -import com.epmet.commons.tools.utils.DateUtils; +import com.epmet.commons.tools.utils.*; import com.epmet.constant.IcResiUserConstant; +import com.epmet.constants.ImportTaskConstants; import com.epmet.dao.IcTripReportRecordDao; import com.epmet.dao.UserBaseInfoDao; import com.epmet.dto.IcEpidemicSpecialAttentionDTO; import com.epmet.dto.IcTripReportRecordDTO; import com.epmet.dto.form.*; import com.epmet.dto.result.TripListDTO; +import com.epmet.dto.result.UploadImgResultDTO; import com.epmet.entity.IcTripReportRecordEntity; +import com.epmet.excel.data.IcTripReportExcelData; +import com.epmet.excel.handler.IcTripReportExcelImportListener; +import com.epmet.feign.EpmetCommonServiceOpenFeignClient; +import com.epmet.feign.OssFeignClient; import com.epmet.service.IcEpidemicSpecialAttentionService; import com.epmet.service.IcNoticeService; import com.epmet.service.IcTripReportRecordService; @@ -32,11 +42,21 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.ListUtils; import org.apache.commons.collections4.MapUtils; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileItemFactory; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.lang3.StringUtils; +import org.apache.http.entity.ContentType; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.commons.CommonsMultipartFile; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.*; import java.util.stream.Collectors; @@ -48,7 +68,7 @@ import java.util.stream.Collectors; */ @Slf4j @Service -public class IcTripReportRecordServiceImpl extends BaseServiceImpl implements IcTripReportRecordService { +public class IcTripReportRecordServiceImpl extends BaseServiceImpl implements IcTripReportRecordService, ResultDataResolver { @Autowired private UserBaseInfoDao userBaseInfoDao; //关注 @@ -57,6 +77,11 @@ public class IcTripReportRecordServiceImpl extends BaseServiceImpl errorRows = listener.getErrorRows(); + + // 生成并上传错误文件 + try { + // 文件生成 + Path errorDescDir = FileUtils.getAndCreateDirUnderEpmetFilesDir("ic_trip_preport", "import", "error_des"); + String fileName = UUID.randomUUID().toString().concat(".xlsx"); + errorDescFile = errorDescDir.resolve(fileName); + + FileItemFactory factory = new DiskFileItemFactory(16, errorDescDir.toFile()); + FileItem fileItem = factory.createItem("file", ContentType.APPLICATION_OCTET_STREAM.toString(), true, fileName); + OutputStream os = fileItem.getOutputStream(); + + EasyExcel.write(os, IcTripReportExcelData.ErrorRow.class).sheet("导入失败列表").doWrite(errorRows); + + // 文件上传oss + Result errorDesFileUploadResult = ossFeignClient.uploadImportTaskDescFile(new CommonsMultipartFile(fileItem)); + if (errorDesFileUploadResult.success()) { + errorDesFileUrl = errorDesFileUploadResult.getData().getUrl(); + } + } finally { + if (Files.exists(errorDescFile)) { + Files.delete(errorDescFile); + } + } + ImportTaskCommonFormDTO importFinishTaskForm = new ImportTaskCommonFormDTO(); + importFinishTaskForm.setTaskId(importTaskId); + importFinishTaskForm.setProcessStatus(errorRows.size() <= 0 ? ImportTaskConstants.PROCESS_STATUS_FINISHED_SUCCESS : ImportTaskConstants.PROCESS_STATUS_FINISHED_FAIL); + importFinishTaskForm.setOperatorId(userId); + importFinishTaskForm.setResultDesc(""); + importFinishTaskForm.setResultDescFilePath(errorDesFileUrl); + + Result result = commonServiceOpenFeignClient.finishImportTask(importFinishTaskForm); + if (!result.success()) { + log.error("【行程上报导入】finishImportTask失败"); + } + } catch (Exception e) { + String errorMsg = ExceptionUtils.getErrorStackTrace(e); + log.error("【行程上报导入】出错:{}", errorMsg); + + ImportTaskCommonFormDTO importFinishTaskForm = new ImportTaskCommonFormDTO(); + importFinishTaskForm.setTaskId(importTaskId); + importFinishTaskForm.setProcessStatus(ImportTaskConstants.PROCESS_STATUS_FINISHED_FAIL); + importFinishTaskForm.setOperatorId(userId); + importFinishTaskForm.setResultDesc("导入失败"); + + Result result = commonServiceOpenFeignClient.finishImportTask(importFinishTaskForm); + if (!result.success()) { + log.error("【行程上报导入】导入记录状态修改为'完成'失败"); + } + } finally { + // 删除临时文件 + if (Files.exists(filePath)) { + try { + Files.delete(filePath); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + } + + /** + * 批量持久化 + * @param entities + */ + public void batchPersist(List entities) { + String currentUserId = EpmetRequestHolder.getHeader(AppClientConstant.USER_ID); + entities.forEach(e -> { + String id = IdWorker.getIdStr(e); + e.setId(id); + e.setUpdatedBy(currentUserId); + baseDao.insert(e); + }); + } } \ No newline at end of file