fuliqi
2024-12-12 23e187554324e1bdff896d7d18634711a7372755
项目库上传后端逻辑
6个文件已修改
1个文件已添加
352 ■■■■■ 已修改文件
business/src/main/java/com/ycl/controller/ProjectInfoController.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
business/src/main/java/com/ycl/domain/entity/File.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
business/src/main/java/com/ycl/listener/excel/ProjectImportListener.java 142 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
business/src/main/java/com/ycl/service/ProjectInfoService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
business/src/main/java/com/ycl/service/impl/ProjectInfoServiceImpl.java 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
common/src/main/java/com/ycl/common/utils/file/FileUploadUtils.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
common/src/main/java/com/ycl/common/utils/poi/ExcelUtil.java 18 ●●●●● 补丁 | 查看 | 原始文档 | 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 导出数据集合