business/src/main/java/com/ycl/controller/ProjectInfoController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
business/src/main/java/com/ycl/domain/entity/File.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
business/src/main/java/com/ycl/listener/excel/ProjectImportListener.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
business/src/main/java/com/ycl/service/ProjectInfoService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
business/src/main/java/com/ycl/service/impl/ProjectInfoServiceImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
common/src/main/java/com/ycl/common/utils/file/FileUploadUtils.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
common/src/main/java/com/ycl/common/utils/poi/ExcelUtil.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
business/src/main/java/com/ycl/controller/ProjectInfoController.java
@@ -1,6 +1,7 @@ package com.ycl.controller; import com.ycl.common.base.Result; import com.ycl.common.exception.base.BaseException; import com.ycl.common.group.Add; import com.ycl.common.group.Update; import com.ycl.common.utils.ProjectCodeGenerator; @@ -16,6 +17,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import javax.validation.constraints.NotEmpty; @@ -147,4 +149,18 @@ public Result updateUsedStatus(@PathVariable Integer id, @PathVariable Integer usedStatus) { return projectInfoService.updateUsedStatus(id, usedStatus); } /** * 项目导入 * @param file * @return */ @PostMapping("/import") public Result importProject(@RequestPart("file") MultipartFile file) { if (file.getSize() > 100 * 1024 * 1024) { throw new BaseException("文件过大,文件不得超过100MB"); } projectInfoService.importProject(file); return Result.ok(); } } business/src/main/java/com/ycl/domain/entity/File.java
@@ -4,6 +4,7 @@ import com.ycl.common.enums.business.FileTypeEnum; import com.ycl.system.domain.base.AbsEntity; import lombok.Data; import lombok.experimental.Accessors; import java.math.BigDecimal; import java.time.LocalDateTime; @@ -16,6 +17,7 @@ */ @Data @TableName("t_file") @Accessors(chain = true) public class File extends AbsEntity { private static final long serialVersionUID = 1L; business/src/main/java/com/ycl/listener/excel/ProjectImportListener.java
New file @@ -0,0 +1,142 @@ package com.ycl.listener.excel; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.ycl.common.exception.ServiceException; import com.ycl.common.exception.base.BaseException; import com.ycl.common.utils.excel.core.ExcelListener; import com.ycl.common.utils.excel.core.ExcelResult; import com.ycl.common.utils.spring.SpringUtils; import com.ycl.domain.entity.*; import com.ycl.domain.excel.ProjectExcelTemplate; import com.ycl.service.ProjectInvestmentFundingService; import com.ycl.service.ProjectInvestmentInfoService; import com.ycl.service.ProjectInvestmentPolicyComplianceService; import com.ycl.service.ProjectUnitRegistrationInfoService; import com.ycl.service.impl.ProjectInfoServiceImpl; import lombok.Data; import java.util.HashMap; import java.util.List; import java.util.Map; @Data //@NoArgsConstructor public class ProjectImportListener extends AnalysisEventListener<ProjectExcelTemplate> implements ExcelListener<ProjectExcelTemplate> { private final ProjectInfoServiceImpl projectInfoService; private final ProjectInvestmentInfoService projectInvestmentInfoService; private final ProjectInvestmentFundingService projectInvestmentFundingService; private final ProjectUnitRegistrationInfoService projectUnitRegistrationInfoService; private final ProjectInvestmentPolicyComplianceService projectPolicyComplianceService; private int successNum = 0; private int failureNum = 0; private final StringBuilder successMsg = new StringBuilder(); private final StringBuilder failureMsg = new StringBuilder(); private boolean hasData = false; private Map<String, Long> projectInfoMap = new HashMap<>(); private Map<String, Long> investmentProjectPolicyComplianceMap = new HashMap<>(); private Map<String, Long> documentsMap = new HashMap<>(); public ProjectImportListener() { this.projectInfoService = SpringUtils.getBean(ProjectInfoServiceImpl.class); this.projectInvestmentInfoService = SpringUtils.getBean(ProjectInvestmentInfoService.class); this.projectInvestmentFundingService = SpringUtils.getBean(ProjectInvestmentFundingService.class); this.projectUnitRegistrationInfoService = SpringUtils.getBean(ProjectUnitRegistrationInfoService.class); this.projectPolicyComplianceService = SpringUtils.getBean(ProjectInvestmentPolicyComplianceService.class); } @Override public ExcelResult<ProjectExcelTemplate> getExcelResult() { return new ExcelResult<>() { @Override public String getAnalysis() { if (failureNum > 0) { failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); throw new ServiceException(failureMsg.toString()); } else { successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); } return successMsg.toString(); } @Override public List<ProjectExcelTemplate> getList() { return null; } @Override public List<String> getErrorList() { return null; } }; } @Override public void invoke(ProjectExcelTemplate projectExcelTemplate, AnalysisContext analysisContext) { hasData = true; //处理项目基础信息 ProjectInfo projectInfo = BeanUtil.toBean(projectExcelTemplate, ProjectInfo.class); projectInfoService.checkProjectNameUnique(projectInfo); projectInfoService.save(projectInfo); //审批计划书 if (StrUtil.isNotBlank(projectExcelTemplate.getApprovalPlan())) { String[] names = projectExcelTemplate.getApprovalPlan().split(","); for (String name : names) { projectInfoMap.put(name, projectInfo.getId()); } } //处理投资管理信息 ProjectInvestmentInfo projectInvestmentInfo = BeanUtil.toBean(projectExcelTemplate, ProjectInvestmentInfo.class); projectInvestmentInfo.setProjectId(projectInfo.getId()); projectInvestmentInfoService.save(projectInvestmentInfo); //处理项目投资及资金来源 ProjectInvestmentFunding projectInvestmentFunding = BeanUtil.toBean(projectExcelTemplate, ProjectInvestmentFunding.class); projectInvestmentFunding.setProjectId(projectInfo.getId()); projectInvestmentFundingService.save(projectInvestmentFunding); // 处理项目法人单位信息 ProjectUnitRegistrationInfo projectUnitRegistrationInfo = BeanUtil.toBean(projectExcelTemplate, ProjectUnitRegistrationInfo.class); projectUnitRegistrationInfo.setProjectId(projectInfo.getId()); projectUnitRegistrationInfoService.save(projectUnitRegistrationInfo); //处理投资产业政策符合情况 ProjectInvestmentPolicyCompliance investmentProjectPolicyCompliance = BeanUtil.toBean(projectExcelTemplate, ProjectInvestmentPolicyCompliance.class); investmentProjectPolicyCompliance.setProjectId(projectInfo.getId()); projectPolicyComplianceService.save(investmentProjectPolicyCompliance); //符合政策附件 if (StrUtil.isNotBlank(projectExcelTemplate.getPolicyComplianceAttachment())) { String[] names2 = projectExcelTemplate.getPolicyComplianceAttachment().split(","); for (String name : names2) { investmentProjectPolicyComplianceMap.put(name, investmentProjectPolicyCompliance.getId()); } } // 相关文书 if (StrUtil.isNotBlank(projectExcelTemplate.getDocuments())) { String[] documentNames = projectExcelTemplate.getDocuments().split(","); for (String name : documentNames) { documentsMap.put(name, projectInfo.getId()); } } } @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { if (!hasData) { throw new BaseException("excel为空,请填入数据后导入"); } } } business/src/main/java/com/ycl/service/ProjectInfoService.java
@@ -9,6 +9,7 @@ import com.ycl.domain.query.ProjectInfoQuery; import com.ycl.domain.vo.IndexCountVO; import com.ycl.domain.vo.IndexDTO; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @@ -84,4 +85,6 @@ void export(HttpServletResponse response, ProjectExportQuery query) throws IOException; Result updateUsedStatus(Integer id, Integer usedStatus); void importProject(MultipartFile file); } business/src/main/java/com/ycl/service/impl/ProjectInfoServiceImpl.java
@@ -2,11 +2,13 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.ZipUtil; 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.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ycl.common.base.Result; import com.ycl.common.config.SysConfig; @@ -21,6 +23,9 @@ import com.ycl.common.utils.StringUtils; import com.ycl.common.utils.bean.BeanUtils; import com.ycl.common.utils.excel.OutputExcelUtils; import com.ycl.common.utils.file.FileUploadUtils; import com.ycl.common.utils.file.FileUtils; import com.ycl.common.utils.poi.ExcelUtil; import com.ycl.domain.entity.*; import com.ycl.domain.excel.ProjectExcelTemplate; import com.ycl.domain.form.DocumentInfoForm; @@ -30,6 +35,7 @@ import com.ycl.domain.query.ProjectInfoQuery; import com.ycl.domain.vo.*; import com.ycl.framework.utils.PageUtil; import com.ycl.listener.excel.ProjectImportListener; import com.ycl.mapper.*; import com.ycl.service.FileService; import com.ycl.service.ProjectInfoService; @@ -38,20 +44,25 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.math.RoundingMode; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.text.SimpleDateFormat; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.zip.ZipOutputStream; /** @@ -546,4 +557,123 @@ baseMapper.updateById(entity); return Result.ok("删除成功"); } @Transactional @Override public void importProject(MultipartFile file) { java.io.File tempZip = null; java.io.File tempDir = null; try { tempZip = java.io.File.createTempFile("temp", ".zip"); try(InputStream inputStream = file.getInputStream()) { Files.copy(inputStream, tempZip.toPath(), StandardCopyOption.REPLACE_EXISTING); } tempDir = Files.createTempDirectory("temp-dir").toFile(); ZipUtil.unzip(tempZip, tempDir, StandardCharsets.ISO_8859_1); Path path = tempDir.toPath(); ProjectImportListener projectImportListener = new ProjectImportListener(); //需要存入数据库 ArrayList<File> attachments = new ArrayList<>(); //实际的文件 List<java.io.File> files = new ArrayList<>(); try (Stream<Path> pathStream = Files.walk(path)) { pathStream.forEach(filePath -> { if (Files.isDirectory(filePath) && filePath.getFileName().toString().equals("attachment")) { //附件处理 try (Stream<Path> stream = Files.walk(filePath)) { stream.forEach(attachmentPath -> { if (Files.isRegularFile(attachmentPath)) { files.add(attachmentPath.toFile()); } }); } catch (IOException e) { log.error(e.getMessage()); throw new RuntimeException(e); } } else if (Files.isRegularFile(filePath) && filePath.getFileName().toString().equals("excel.xlsx")) { //导入数据处理 try (FileInputStream fileInputStream = new FileInputStream(filePath.toFile())) { ExcelUtil.importExcel(fileInputStream, ProjectExcelTemplate.class, projectImportListener); } catch (IOException e) { log.error(e.getMessage()); throw new RuntimeException(e); } } }); } /* 把附件存入上传路径 */ //上传文件路径 String filePath = SysConfig.getUploadPath(); files.forEach(attachmentFile -> { try { //上传 String url = FileUploadUtils.upload(filePath, file); //存放的文件名会加上_时间戳的后缀 String newName = FileUtils.getName(url); attachments.add(new File() .setUrl(url) .setName(newName) .setOriginalName(attachmentFile.getName())); } catch (IOException e) { e.printStackTrace(); } }); Map<String, Long> projectInfoMap = projectImportListener.getProjectInfoMap(); Map<String, Long> investmentProjectPolicyComplianceMap = projectImportListener.getInvestmentProjectPolicyComplianceMap(); Map<String, Long> documentsMap = projectImportListener.getDocumentsMap(); //补充type和busId字段 attachments.forEach(attachment -> { String fileName = attachment.getOriginalName(); if (ObjectUtil.isNotNull(projectInfoMap.get(fileName))) { attachment.setBusId(projectInfoMap.get(fileName)); attachment.setType(FileTypeEnum.PROJECT_INFO); } else if (ObjectUtil.isNotNull(investmentProjectPolicyComplianceMap.get(fileName))) { attachment.setBusId(investmentProjectPolicyComplianceMap.get(fileName)); attachment.setType(FileTypeEnum.INVEST_POLICY); } else if (ObjectUtil.isNotNull(documentsMap.get(fileName))) { attachment.setBusId(documentsMap.get(fileName)); attachment.setType(FileTypeEnum.DOCUMENT_INFO); } }); // 添加项目附件关联表 fileService.saveBatch(attachments); } catch (IOException e) { log.error(e.getMessage()); throw new RuntimeException(e); } finally { deleteDirectoryOrFile(tempZip); deleteDirectoryOrFile(tempDir); } } private static void deleteDirectoryOrFile(java.io.File file) { if (ObjectUtil.isNull(file)) { return; } if (file.isDirectory()) { java.io.File[] files = file.listFiles(); if (files != null) { for (java.io.File f : files) { deleteDirectoryOrFile(f); } } } file.delete(); } /** * 项目名称校验重复 * @return */ public void checkProjectNameUnique(ProjectInfo projectInfo) { if (StrUtil.isBlank(projectInfo.getProjectName())) { throw new BaseException("项目名称不能为空"); } Assert.isTrue(baseMapper.selectCount(Wrappers.<ProjectInfo>lambdaQuery().eq(ProjectInfo::getProjectName, projectInfo.getProjectName())) == 0, "项目名称重复"); } } common/src/main/java/com/ycl/common/utils/file/FileUploadUtils.java
@@ -2,7 +2,9 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.Objects; import org.apache.commons.io.FilenameUtils; import org.springframework.web.multipart.MultipartFile; @@ -85,7 +87,44 @@ throw new IOException(e.getMessage(), e); } } /** * 文件上传 * * @param baseDir 相对应用的基目录 * @param file 上传的文件 * @return 返回上传成功的文件名 * @throws FileSizeLimitExceededException 如果超出最大大小 * @throws FileNameLengthLimitExceededException 文件名太长 * @throws IOException 比如读写文件出错时 * @throws InvalidExtensionException 文件校验异常 */ public static final String uploadIOFile(String baseDir, java.io.File file) throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException { int fileNamelength = Objects.requireNonNull(file.getName()).length(); if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) { throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); } //上传IOFile文件逻辑 String fileName = file.getName(); //带日期前缀的文件名 String formatName = StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(), FilenameUtils.getBaseName(fileName), Seq.getId(Seq.uploadSeqType), fileName.substring(fileName.lastIndexOf(".") + 1)); // /home/projectManagement/uploadPath/upload/2024/11/11/xxxx String url = baseDir + File.separator + formatName; File newFile = new File(url); if (!newFile.exists()) { if (!newFile.getParentFile().exists()) { newFile.getParentFile().mkdirs(); } } //复制文件到上传路径 Files.copy(file.toPath(), newFile.toPath(), StandardCopyOption.REPLACE_EXISTING); return getPathFileName(baseDir, formatName); } /** * 文件上传 * common/src/main/java/com/ycl/common/utils/poi/ExcelUtil.java
@@ -24,6 +24,10 @@ import java.util.UUID; import java.util.stream.Collectors; import javax.servlet.http.HttpServletResponse; import com.alibaba.excel.EasyExcel; import com.ycl.common.utils.excel.core.ExcelListener; import com.ycl.common.utils.excel.core.ExcelResult; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.RegExUtils; import org.apache.commons.lang3.reflect.FieldUtils; @@ -500,6 +504,20 @@ } /** * 使用自定义监听器 异步导入 自定义返回 * * @param is 输入流 * @param clazz 对象类型 * @param listener 自定义监听器 * @return 转换后集合 */ public static <T> ExcelResult<T> importExcel(InputStream is, Class<T> clazz, ExcelListener<T> listener) { EasyExcel.read(is, clazz, listener).sheet().doRead(); return listener.getExcelResult(); } /** * 对list数据源将其里面的数据导入到excel表单 * * @param list 导出数据集合