ソースを参照

导入专利任务框架代码

chendayu 1 年間 前
コミット
a60ea01ea0
31 ファイル変更2019 行追加0 行削除
  1. 53 0
      src/main/java/cn/cslg/pas/common/core/CreateTaskThread.java
  2. 81 0
      src/main/java/cn/cslg/pas/common/dto/ExcelImportDTO.java
  3. 24 0
      src/main/java/cn/cslg/pas/common/dto/FMSDeleteFileDTO.java
  4. 12 0
      src/main/java/cn/cslg/pas/common/dto/PatentStarImportDTO.java
  5. 12 0
      src/main/java/cn/cslg/pas/common/dto/UploadFileDTO.java
  6. 144 0
      src/main/java/cn/cslg/pas/common/utils/BackupUtils.java
  7. 183 0
      src/main/java/cn/cslg/pas/common/utils/ExcelUtils.java
  8. 242 0
      src/main/java/cn/cslg/pas/common/utils/FileUtils.java
  9. 38 0
      src/main/java/cn/cslg/pas/common/utils/LoginUtils.java
  10. 222 0
      src/main/java/cn/cslg/pas/common/utils/ReadExcelUtils.java
  11. 18 0
      src/main/java/cn/cslg/pas/common/utils/ThrowException.java
  12. 43 0
      src/main/java/cn/cslg/pas/controller/ProjectImportController.java
  13. 50 0
      src/main/java/cn/cslg/pas/entity/AssoTaskField.java
  14. 88 0
      src/main/java/cn/cslg/pas/entity/ImportTask.java
  15. 95 0
      src/main/java/cn/cslg/pas/entity/ImportTaskCondition.java
  16. 25 0
      src/main/java/cn/cslg/pas/entity/PatentData.java
  17. 64 0
      src/main/java/cn/cslg/pas/entity/SystemFile.java
  18. 15 0
      src/main/java/cn/cslg/pas/exception/XiaoShiException.java
  19. 16 0
      src/main/java/cn/cslg/pas/mapper/AssoTaskFieldMapper.java
  20. 15 0
      src/main/java/cn/cslg/pas/mapper/ImportTaskConditionMapper.java
  21. 15 0
      src/main/java/cn/cslg/pas/mapper/ImportTaskMapper.java
  22. 14 0
      src/main/java/cn/cslg/pas/service/AssoTaskFieldService.java
  23. 139 0
      src/main/java/cn/cslg/pas/service/FileManagerService.java
  24. 18 0
      src/main/java/cn/cslg/pas/service/ImportTaskConditionService.java
  25. 21 0
      src/main/java/cn/cslg/pas/service/ImportTaskService.java
  26. 19 0
      src/main/java/cn/cslg/pas/service/importPatent/IImportPatentFactory.java
  27. 63 0
      src/main/java/cn/cslg/pas/service/importPatent/ImportPatentExcel.java
  28. 22 0
      src/main/java/cn/cslg/pas/service/importPatent/ImportPatentPatentNo.java
  29. 54 0
      src/main/java/cn/cslg/pas/service/importPatent/ImportPatentPatentStar.java
  30. 113 0
      src/main/java/cn/cslg/pas/service/importPatent/PatentQueueService.java
  31. 101 0
      src/main/java/cn/cslg/pas/service/importPatent/ProjectImportService.java

+ 53 - 0
src/main/java/cn/cslg/pas/common/core/CreateTaskThread.java

@@ -0,0 +1,53 @@
+package cn.cslg.pas.common.core;
+
+import cn.cslg.pas.entity.ImportTask;
+import cn.cslg.pas.service.ImportTaskService;
+import cn.cslg.pas.service.importPatent.PatentQueueService;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 项目启动时初始化任务列表队列
+ *
+ * @author chenyu
+ * @date 2023/10/20
+ */
+@Component
+@RequiredArgsConstructor(onConstructor_ = {@Lazy})
+public class CreateTaskThread implements InitializingBean {
+    private final ImportTaskService importTaskService;
+    private final PatentQueueService patentQueueService;
+
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        //查找任务状态为0(等待中)和1(进行中)的任务
+        ArrayList<Integer> stateList = new ArrayList<>();
+        stateList.add(0);
+        stateList.add(1);
+        List<ImportTask> importTasks = importTaskService.list(new LambdaQueryWrapper<ImportTask>().in(ImportTask::getState, stateList));
+        if (importTasks.size() > 0) {
+            //先把0(进行中)的任务存入队列
+            List<Integer> doingTaskIds = importTasks.stream().filter(importTask -> importTask.getState() == 1).map(ImportTask::getId).collect(Collectors.toList());
+            if (doingTaskIds.size() > 0) {
+                patentQueueService.addImportTasksToQueue(doingTaskIds);
+            }
+            //再把1(等待中)的任务存入队列
+            List<Integer> waitingTaskIds = importTasks.stream().filter(importTask -> importTask.getState() == 0).map(ImportTask::getId).collect(Collectors.toList());
+            if (waitingTaskIds.size() > 0) {
+                patentQueueService.addImportTasksToQueue(waitingTaskIds);
+            }
+        }
+
+        //唤醒所有线程...
+
+    }
+
+}

+ 81 - 0
src/main/java/cn/cslg/pas/common/dto/ExcelImportDTO.java

@@ -0,0 +1,81 @@
+package cn.cslg.pas.common.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.List;
+
+/**
+ * Excel导入专利DTO类
+ */
+@Accessors(chain = true)
+@Data
+public class ExcelImportDTO {
+    /**
+     * 项目id
+     */
+    private Integer projectId;
+    /**
+     * 项目类型(0.专题库 1.报告 2.产品)
+     */
+    private Integer projectType;
+
+    private Integer asCompare;
+
+    /**
+     * 数据来源(1.智慧芽 2.合享 3.Patentics)
+     */
+    private String sourceId;
+    /**
+     * 自定义字段ids
+     */
+    private List<Field> fieldList;
+    /**
+     * 文件夹ids
+     */
+    private List<Integer> folderIds;
+
+    /**
+     * 自定义字段信息
+     */
+    @Data
+    public static class Field {
+        /**
+         * 自定义字段id
+         */
+        private Integer fieldId;
+        /**
+         * 自定义字段类型(6为树)
+         */
+        private Integer type;
+        /**
+         * 选项id
+         */
+        private Integer optionId;
+        private String text;
+    }
+
+    /**
+     * 文件夹信息
+     */
+    @Data
+    public static class Folder {
+        /**
+         * 文件夹id
+         */
+        private Integer id;
+        /**
+         * 上级文件夹id
+         */
+        private Integer parentId;
+        /**
+         * 文件夹名称
+         */
+        private String name;
+        private Boolean selected;
+        /**
+         * 子级文件夹们
+         */
+        private List<Folder> children;
+    }
+}

+ 24 - 0
src/main/java/cn/cslg/pas/common/dto/FMSDeleteFileDTO.java

@@ -0,0 +1,24 @@
+package cn.cslg.pas.common.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 调用FMS系统删除文件接口
+ *
+ * @Author xiexiang
+ * @Date 2023/8/14
+ */
+@Data
+public class FMSDeleteFileDTO {
+    /**
+     * 文件ids
+     */
+    private List<Integer> ids;
+
+    /**
+     * 删除类型(2物理删除 1逻辑删除)
+     */
+    private Integer type;
+}

+ 12 - 0
src/main/java/cn/cslg/pas/common/dto/PatentStarImportDTO.java

@@ -0,0 +1,12 @@
+package cn.cslg.pas.common.dto;
+
+/**
+ * 检索导入专利DTO类
+ *
+ * @author chenyu
+ * @date 2023/10/23
+ */
+public class PatentStarImportDTO {
+    private
+
+}

+ 12 - 0
src/main/java/cn/cslg/pas/common/dto/UploadFileDTO.java

@@ -0,0 +1,12 @@
+package cn.cslg.pas.common.dto;
+
+import lombok.Data;
+
+@Data
+public class UploadFileDTO {
+    private String name;
+    private String fileName;
+    private String path;
+    private String extName;
+    private Long fileSize;
+}

+ 144 - 0
src/main/java/cn/cslg/pas/common/utils/BackupUtils.java

@@ -0,0 +1,144 @@
+package cn.cslg.pas.common.utils;
+
+import cn.hutool.core.io.FileUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.system.ApplicationHome;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.File;
+import java.io.InputStream;
+
+@Slf4j
+public class BackupUtils {
+
+    private final static String BACKUP_CONFIG = "backup-config.yml";
+
+    private static Backup getBackupConfig() {
+        try {
+            ApplicationHome ah = new ApplicationHome(BackupUtils.class);
+            File file = ah.getSource();
+            String rootPath = file.getParentFile().toString() + FileUtils.FILE_SEPARATOR + BACKUP_CONFIG;
+            Yaml yaml = new Yaml();
+            InputStream in = FileUtil.getInputStream(rootPath);
+            Backup backup = yaml.loadAs(in, Backup.class);
+            if (in != null) {
+                in.close();
+            }
+            return backup;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    public static void main(String[] args) {
+        System.out.println(getBackupConfig());
+    }
+
+    public void run() {
+        Backup backup = getBackupConfig();
+        if (backup == null) {
+            log.info("数据库备份配置文件不存在");
+            return;
+        }
+        log.info("数据库备份配置文件:{}", backup);
+        if (backup.isEnable()) {
+            String path = FileUtils.getStaticPath(FileUtils.BACKUP_FILE);
+            String fileName = DateUtils.getNowTimeFormat(DateUtils.YYYYMMDDHHMMSS) + ".sql";
+            try {
+                String cmd = String.format("mysqldump --skip-opt -h%s -P%s -u%s -p%s %s > %s", backup.getHost(), backup.getPort(), backup.getUsername(), backup.getPassword(), backup.getDb(), path + FileUtils.FILE_SEPARATOR + fileName);
+                String[] command;
+                if (backup.getOs() == 0) {
+                    command = new String[]{"cmd", "/c", String.valueOf(cmd)};
+                } else {
+                    command = new String[]{"/bin/sh", "-c", String.valueOf(cmd)};
+                }
+                Runtime.getRuntime().exec(command);
+                log.info("备份数据库成功");
+            } catch (Exception e) {
+                e.printStackTrace();
+                log.error("备份数据库失败");
+            }
+        }
+    }
+
+    public static class Backup {
+        private String host;
+        private String port;
+        private String db;
+        private String username;
+        private String password;
+        private int os;
+        private boolean enable;
+
+        @Override
+        public String toString() {
+            return "Backup{" +
+                    "host='" + host + '\'' +
+                    ", port='" + port + '\'' +
+                    ", db='" + db + '\'' +
+                    ", username='" + username + '\'' +
+                    ", password='" + password + '\'' +
+                    ", os=" + os +
+                    ", enable=" + enable +
+                    '}';
+        }
+
+        public boolean isEnable() {
+            return enable;
+        }
+
+        public void setEnable(boolean enable) {
+            this.enable = enable;
+        }
+
+        public String getHost() {
+            return host;
+        }
+
+        public void setHost(String host) {
+            this.host = host;
+        }
+
+        public String getPort() {
+            return port;
+        }
+
+        public void setPort(String port) {
+            this.port = port;
+        }
+
+        public String getDb() {
+            return db;
+        }
+
+        public void setDb(String db) {
+            this.db = db;
+        }
+
+        public String getUsername() {
+            return username;
+        }
+
+        public void setUsername(String username) {
+            this.username = username;
+        }
+
+        public String getPassword() {
+            return password;
+        }
+
+        public void setPassword(String password) {
+            this.password = password;
+        }
+
+        public int getOs() {
+            return os;
+        }
+
+        public void setOs(int os) {
+            this.os = os;
+        }
+    }
+
+}

+ 183 - 0
src/main/java/cn/cslg/pas/common/utils/ExcelUtils.java

@@ -0,0 +1,183 @@
+package cn.cslg.pas.common.utils;
+
+import cn.hutool.core.util.IdUtil;
+import org.apache.poi.hssf.usermodel.*;
+import org.apache.poi.ooxml.POIXMLDocumentPart;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.*;
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
+
+import java.awt.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ExcelUtils {
+
+    public static Map<String, PictureData> getDataFromExcel(String filePath) throws IOException {
+        //判断是否为excel类型文件
+        if (!filePath.endsWith(".xls") && !filePath.endsWith(".xlsx") && !filePath.endsWith(".XLS") && !filePath.endsWith(".XLSX")) {
+            System.out.println("文件不是excel类型");
+        }
+
+        FileInputStream fis = null;
+        Workbook wookbook = null;
+        Sheet sheet = null;
+        try {
+            //获取一个绝对地址的流
+            fis = new FileInputStream(filePath);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        try {
+            //2003版本的excel,用.xls结尾
+            wookbook = new HSSFWorkbook(fis);//得到工作簿
+        } catch (Exception ex) {
+            //ex.printStackTrace();
+            try {
+                //2007版本的excel,用.xlsx结尾
+                fis = new FileInputStream(filePath);
+                wookbook = new XSSFWorkbook(fis);//得到工作簿
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+        Map<String, PictureData> maplist = null;
+        //拿到excel表格的第一个sheet工作簿
+        sheet = wookbook.getSheetAt(0);
+        // 判断用07还是03的方法获取图片
+        if (filePath.endsWith(".xls") || filePath.endsWith(".XLS")) {
+            maplist = getPictures1((HSSFSheet) sheet);
+        } else if (filePath.endsWith(".xlsx") || filePath.endsWith(".XLSX")) {
+            maplist = getPictures2((XSSFSheet) sheet);
+        }
+        wookbook.close();
+        return maplist;
+    }
+
+    /**
+     * 获取图片和位置 (xls)
+     *
+     * @param sheet
+     * @return
+     * @throws IOException
+     */
+    public static Map<String, PictureData> getPictures1(HSSFSheet sheet) throws IOException {
+        Map<String, PictureData> map = new HashMap();
+        if (sheet.getDrawingPatriarch() != null) {
+            List<HSSFShape> list = sheet.getDrawingPatriarch().getChildren();
+            for (HSSFShape shape : list) {
+                if (shape instanceof HSSFPicture) {
+                    HSSFPicture picture = (HSSFPicture) shape;
+                    HSSFClientAnchor cAnchor = (HSSFClientAnchor) picture.getAnchor();
+                    PictureData pdata = picture.getPictureData();
+                    String key = String.valueOf(cAnchor.getRow1());
+                    map.put(key, pdata);
+                }
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 获取图片和位置 (xlsx)
+     *
+     * @param sheet
+     * @return
+     * @throws IOException
+     */
+    public static Map<String, PictureData> getPictures2(XSSFSheet sheet) throws IOException {
+        Map<String, PictureData> map = new HashMap();
+        List<POIXMLDocumentPart> list = sheet.getRelations();
+        for (POIXMLDocumentPart part : list) {
+            if (part instanceof XSSFDrawing) {
+                XSSFDrawing drawing = (XSSFDrawing) part;
+                List<XSSFShape> shapes = drawing.getShapes();
+                for (XSSFShape shape : shapes) {
+                    XSSFPicture picture = (XSSFPicture) shape;
+                    Dimension d = picture.getImageDimension();
+                    //解决图片空指针报错问题 lig  2021-06-03
+                    XSSFClientAnchor anchor = (XSSFClientAnchor) shape.getAnchor();
+                    //XSSFClientAnchor anchor = picture.getPreferredSize();
+                    CTMarker marker = anchor.getFrom();
+                    String key = String.valueOf(marker.getRow());
+                    map.put(key, picture.getPictureData());
+                }
+            }
+        }
+        return map;
+    }
+
+    /**
+     * @param pictureData 图片
+     * @return 返回图片的文件路径和文件名称
+     */
+    public static Map<String, String> savePicture(PictureData pictureData) throws IOException {
+        FileUtils fileUtils = SpringUtils.getBean(FileUtils.class);
+        Map<String, String> result = new HashMap<>();
+        String ext = pictureData.suggestFileExtension();
+        byte[] data = pictureData.getData();
+        String picName = IdUtil.simpleUUID() + "." + ext;
+        String date = DateUtils.getNowTimeFormat("yyyyMMdd");
+        String folderPath = fileUtils.getSavePath(date);
+        String filePath = FileUtils.FILE_SEPARATOR + date + FileUtils.FILE_SEPARATOR + picName;
+        File directory = new File(folderPath);
+        if (!directory.exists()) {
+            directory.mkdir();
+        }
+        FileOutputStream out = new FileOutputStream(folderPath + picName);
+        out.write(data);
+        out.close();
+        result.put("path", filePath);
+        result.put("name", picName);
+        return result;
+    }
+
+    /**
+     * @param
+     * @param x           单元格x轴坐标
+     * @param y           单元格y轴坐标
+     * @param pictureData 图片二进制数据
+     * @param picType     图片格式
+     */
+    public static void writePicture(Sheet sheet, int x, int y, byte[] pictureData, int picType) {
+        Drawing drawingPatriarch = sheet.createDrawingPatriarch();
+        //设置图片单元格位置
+        ClientAnchor anchor = drawingPatriarch.createAnchor(0, 0, 0, 0, x, y, x + 1, y + 1);
+        //随单元格改变位置和大小
+        anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);
+        //添加图片
+        int pictureIndex = sheet.getWorkbook().addPicture(pictureData, picType);
+        drawingPatriarch.createPicture(anchor, pictureIndex);
+    }
+
+    public static void setExcelCellStyle(HSSFCellStyle cellStyle) {
+        cellStyle.setBorderBottom(BorderStyle.THIN);
+        cellStyle.setBorderLeft(BorderStyle.THIN);
+        cellStyle.setBorderRight(BorderStyle.THIN);
+        cellStyle.setBorderTop(BorderStyle.THIN);
+    }
+
+    public static String getValue(Cell cell) {
+        if (cell != null) {
+            if (cell.getCellType() == CellType.NUMERIC && HSSFDateUtil.isCellDateFormatted(cell)) {
+                Date date = cell.getDateCellValue();
+                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+                String dateString = dateFormat.format(date);
+                return dateString;
+            } else {
+                return cell.toString();
+            }
+        }
+        return "";
+    }
+
+
+}

+ 242 - 0
src/main/java/cn/cslg/pas/common/utils/FileUtils.java

@@ -0,0 +1,242 @@
+package cn.cslg.pas.common.utils;
+
+import cn.cslg.pas.common.dto.UploadFileDTO;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.IdUtil;
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
+import org.springframework.boot.system.ApplicationHome;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.commons.CommonsMultipartFile;
+
+import java.io.*;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+
+@Service
+public class FileUtils {
+
+    public static final String FILE_SEPARATOR = System.getProperty("file.separator");
+    public static final String COMMON_FILE = "file";
+    public static final String BACKUP_FILE = "backup";
+
+    public static String getStaticPath(String fileName) {
+        //ApplicationHome类 返回target目录层级
+        ApplicationHome ah = new ApplicationHome(FileUtils.class);
+        //获取 applicationHome 内的路径 ...\target\classes 到这一层级下
+        File file = ah.getSource();
+        //获取 file的parentFile 即最后一级之前的所有层级路径(包括盘符) 这里能获得到的最终层级为  ...\target 后续用FILE_SEPARATOR(系统路径分割通配符 即 "\") 以及fileName拼接生成存放文件的目录层级 即为根目录 root
+        String rootPath = file.getParentFile().toString() + FILE_SEPARATOR + fileName;
+        //根据上方生成的根目录路径 生成对应文件夹 没有就新建
+        File root = new File(rootPath);
+        if (!root.exists()) {
+            root.mkdir();
+        }
+        //返回的最终形式为 盘符:\项目层级\target\file
+        return rootPath;
+    }
+
+    public UploadFileDTO uploadFile(MultipartFile file) {
+        UploadFileDTO fileDTO = new UploadFileDTO();
+        //以下操作为 先取得传入文件的完整文件名 (文件名 + 后缀) 然后用FileUtil分别取出 文件名 和 不带 "." 的后缀 然后将这些内容装配进 实体中
+        //file.getOriginFilename 获取源文件
+        //FileUtil.getPrefix 返回主文件名
+        fileDTO.setName(FileUtil.getPrefix(file.getOriginalFilename()));
+        //FileUtil.extName 获取文件的扩展名(后缀名),扩展名不带 "."
+        fileDTO.setExtName(FileUtil.extName(file.getOriginalFilename()));
+        //获取目录名 用时间作为目录名称
+        String directoryName = this.getDirectoryName();
+        //用IdUtil生成的UUID 与实体中的 extName(后缀名) 拼接后作为文件名 simpleUUID与randomUUID的区别是 simpleUUID 没有 "-"
+        String fileName = IdUtil.simpleUUID() + "." + fileDTO.getExtName();
+        //将完整文件名进行装配
+        fileDTO.setFileName(fileName);
+        //生成存储文件的路径
+        String savePath = this.getSavePath(directoryName);
+        //根据生成存储文件的路径 生成对应文件夹 没有就新建
+        File directory = new File(savePath);
+        if (!directory.exists()) {
+            directory.mkdir();
+        }
+        this.saveFile(file, savePath + fileName);
+        fileDTO.setPath(FILE_SEPARATOR + directoryName + FILE_SEPARATOR + fileName);
+        fileDTO.setFileSize(file.getSize());
+        return fileDTO;
+    }
+
+    public String createDirectory() {
+        String directoryName = this.getDirectoryName();
+        String savePath = this.getSavePath(directoryName);
+        File directory = new File(savePath);
+        if (!directory.exists()) {
+            directory.mkdir();
+        }
+        return directoryName;
+    }
+
+    public void saveFile(MultipartFile file, String path) {
+        try {
+            file.transferTo(new File(path));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public String getTempPath(String fileName) {
+        String tempPath = getStaticPath(COMMON_FILE) + FILE_SEPARATOR + "temp";
+        File file = new File(tempPath);
+        if (!file.exists()) {
+            file.mkdir();
+        }
+        return tempPath + FILE_SEPARATOR + fileName;
+    }
+
+    public String getSavePath(String directoryName) {
+        return getStaticPath(COMMON_FILE) + FILE_SEPARATOR + directoryName + FILE_SEPARATOR;
+    }
+
+    public String getDirectory(String fileName) {
+        return FILE_SEPARATOR + this.createDirectory() + FILE_SEPARATOR + fileName;
+    }
+
+    public String getDirectory2(String directoryName) {
+        return FILE_SEPARATOR + directoryName + FILE_SEPARATOR;
+    }
+
+    public String getSystemPath(String url) {
+        return getStaticPath(COMMON_FILE) + FILE_SEPARATOR + url;
+    }
+
+    public String getSystemPath() {
+        return getStaticPath(COMMON_FILE);
+    }
+
+    public String getDirectoryName() {
+        return DateUtils.getNowTimeFormat("yyyyMMdd");
+    }
+
+    public String getPath(String url) {
+        return getStaticPath(COMMON_FILE) + url;
+    }
+
+    public String analysisJsonFile() {
+        ApplicationHome ah = new ApplicationHome(BackupUtils.class);
+        File file = ah.getSource();
+        String settingFilePath = file.getParentFile().toString() + FileUtils.FILE_SEPARATOR + "uploadSetting.json";
+        BufferedReader reader = null;
+        StringBuilder last = new StringBuilder();
+        InputStreamReader inputStreamReader;
+        try (FileInputStream fileInputStream = new FileInputStream(settingFilePath)) {
+            inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
+
+            reader = new BufferedReader(inputStreamReader);
+            String tempString;
+            while ((tempString = reader.readLine()) != null) {
+                last.append(tempString);
+            }
+            reader.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return last.toString();
+    }
+    public String analysisJsonFile(String fileName) {
+        ApplicationHome ah = new ApplicationHome(BackupUtils.class);
+        File file = ah.getSource();
+        String settingFilePath = file.getParentFile().toString() + FileUtils.FILE_SEPARATOR + "uploadSetting.json";
+        BufferedReader reader = null;
+        StringBuilder last = new StringBuilder();
+        InputStreamReader inputStreamReader;
+        try (FileInputStream fileInputStream = new FileInputStream(settingFilePath)) {
+            inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
+
+            reader = new BufferedReader(inputStreamReader);
+            String tempString;
+            while ((tempString = reader.readLine()) != null) {
+                last.append(tempString);
+            }
+            reader.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return last.toString();
+    }
+
+    public static MultipartFile fileToMultipartFile(File file) {
+        DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory(16, null);
+        FileItem item = diskFileItemFactory.createItem(file.getName(), "text/plain", true, file.getName());
+        int bytesRead = 0;
+        byte[] buffer = new byte[8192];
+        try {
+            FileInputStream fis = new FileInputStream(file);
+            OutputStream os = item.getOutputStream();
+            int len = 8192;
+            while ((bytesRead = fis.read(buffer, 0, len)) != -1) {
+                os.write(buffer, 0, bytesRead);
+            }
+            os.close();
+            fis.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return (MultipartFile) new CommonsMultipartFile(item);
+    }
+
+    public static File getFile(String url) throws Exception {
+        //读取图片类型
+        String fileName = url.substring(url.lastIndexOf("."), url.length());
+        File file = null;
+
+        URL urlfile;
+        InputStream inStream = null;
+        OutputStream os = null;
+        try {
+            file = File.createTempFile("new_url", ".jpg");
+            //获取文件
+            urlfile = new URL(url);
+            inStream = urlfile.openStream();
+            os = new FileOutputStream(file);
+
+            int bytesRead = 0;
+            byte[] buffer = new byte[8192];
+            while ((bytesRead = inStream.read(buffer, 0, 8192)) != -1) {
+                os.write(buffer, 0, bytesRead);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (null != os) {
+                    os.close();
+                }
+                if (null != inStream) {
+                    inStream.close();
+                }
+
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+        return file;
+    }
+
+
+}
+

+ 38 - 0
src/main/java/cn/cslg/pas/common/utils/LoginUtils.java

@@ -0,0 +1,38 @@
+package cn.cslg.pas.common.utils;
+
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+
+@Component
+public class LoginUtils {
+    @Resource
+    private RedisUtil redisUtil;
+
+    public static String getToken() {
+        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
+        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
+        HttpServletRequest httpRequest = sra.getRequest();
+        String tem = httpRequest.getHeader("Cookie");
+        List<String> lst = StringUtils.changeStringToString(tem, ";");
+        final String[] token = {null};
+        lst.forEach(item -> {
+            if (item.contains("token")) {
+                token[0] = item;
+            }
+        });
+        return token[0].replaceAll(" ", "");
+    }
+
+    public Integer getId() {
+        String oriToken = LoginUtils.getToken();
+        String q = "token:login:" + oriToken.replace("=", ":");
+        String IdS = redisUtil.get(q);
+        return Integer.parseInt(IdS);
+    }
+}

+ 222 - 0
src/main/java/cn/cslg/pas/common/utils/ReadExcelUtils.java

@@ -0,0 +1,222 @@
+package cn.cslg.pas.common.utils;
+
+import cn.cslg.pas.entity.PatentData;
+import org.apache.poi.hssf.usermodel.*;
+import org.apache.poi.ooxml.POIXMLDocumentPart;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.*;
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Author xiexiang
+ * @Date 2023/5/30
+ */
+@Service
+public class ReadExcelUtils {
+    /**
+     * 检测Excel文件合法性
+     *
+     * @param tempFile 临时文件
+     * @return 返回文件总行数
+     */
+    public static Integer textExcel(File tempFile, String sourceId) throws IOException {
+        //判断文件是否存在
+        if (!tempFile.exists() || tempFile.getPath().trim().equals("")) {
+            ThrowException.throwXiaoShiException("文件上传失败,服务器忙请稍后再试!");
+        }
+
+        // 检测是否为excel文件
+        String suffix = tempFile.getPath().substring(tempFile.getPath().lastIndexOf("."));
+        if (!suffix.equals(".xls") && !suffix.equals(".xlsx") && !suffix.equals(".XLS") && !suffix.equals(".XLSX")) {
+            //删除临时文件tempFile
+            new File(tempFile.getPath()).delete();
+            ThrowException.throwXiaoShiException("文件格式错误,请上传Excel文件!");
+        }
+
+        InputStream fis = new FileInputStream(tempFile);
+        //使用poi框架解析处理Excel文件
+        Workbook workbook = null;
+        //区分不同版本Excel,使用各自对应的工具类
+        if (suffix.equals(".xls") || suffix.equals(".XLS")) {
+            workbook = new HSSFWorkbook(fis);
+        } else if (suffix.equals(".xlsx") || suffix.equals(".XLSX")) {
+            workbook = new XSSFWorkbook(fis);
+        }
+        //读取第几个sheet
+        Sheet sheet = workbook.getSheetAt(0);
+        //读取总行数
+        int rows = sheet.getPhysicalNumberOfRows();
+        if (rows <= 1) {
+            //删除临时文件tempFile
+            fis.close();
+            new File(tempFile.getPath()).delete();
+            ThrowException.throwXiaoShiException("文件内容格式不正确,请检查总行数是否有专利内容");
+        }
+
+        //获取第一行抬头
+        Row firstRow = sheet.getRow(0);
+        boolean flag1 = false;  //是否有 "公开(公告)号"
+        boolean flag2 = false;  //是否有 "申请号"
+        //遍历第一行单元格抬头,检查合法性
+        String title = "", source = "";
+        if (sourceId.equals("1")) {
+            source = "智慧芽";
+            title = "公开(公告)号";
+        } else if (sourceId.equals("2")) {
+            source = "合享";
+            title = "公开(公告)号";
+        } else {
+            source = "Patentics";
+            title = "公开号";
+        }
+        for (Cell cell : firstRow) {
+            if (cell.getStringCellValue().equals(title)) {
+                flag1 = true;
+            }
+            if (cell.getStringCellValue().equals("申请号")) {
+                flag2 = true;
+            }
+        }
+        if (!flag1 || !flag2) {
+            //删除临时文件tempFile
+            fis.close();
+            new File(tempFile.getPath()).delete();
+            ThrowException.throwXiaoShiException("文件内容格式不正确,您选择【" + source + "】来源,Excel第一行抬头必须有【" + title + "】和【申请号】");
+        }
+
+        //关闭流
+        fis.close();
+
+        //返回文件总行数-1(即专利总数量)
+        return rows - 1;
+    }
+
+    /**
+     * 获取一行专利的全部数据(专利内容数据 + 摘要附图)
+     *
+     * @param tempFile Excel临时文件
+     * @param row      行数
+     * @return 返回装载专利数据(专利内容数据 + 摘要附图)的对象
+     */
+    public static PatentData readExcelOneRow(File tempFile, Sheet sheet, int row) throws IOException {
+        //创建返回最终结果的对象 patentData
+        PatentData patentData = new PatentData();
+        //装载专利数据(除了摘要附图)的map:(key:表头如 "公开(公告)号"  value:表头对应内容如 "CN1307082B")
+        Map<Object, Object> map = new HashMap<>();
+        //装载摘要附图的对象
+        PictureData pictureData = null;
+
+        //开始装载专利数据
+        Row firstRow = sheet.getRow(0);
+        Row needRow = sheet.getRow(row);
+        //获得总列数
+        int columns = firstRow.getLastCellNum();
+        for (int i = 0; i < columns; i++) {
+            map.put(firstRow.getCell(i) + "", ExcelUtils.getValue(needRow.getCell(i)) + "");
+        }
+
+        //开始装载专利摘要附图(判断用07还是03的方法获取图片)
+        String suffix = tempFile.getName().substring(tempFile.getName().lastIndexOf("."));
+        if (suffix.equals(".xls") || suffix.equals(".XLS")) {
+            pictureData = getPictures1((HSSFSheet) sheet, row);
+        } else if (suffix.equals(".xlsx") || suffix.equals(".XLSX")) {
+            pictureData = getPictures2((XSSFSheet) sheet, row);
+        }
+
+        //返回结果对象装载结果
+        patentData.setMap(map);
+        patentData.setPictureData(pictureData);
+
+        return patentData;
+    }
+
+    public static Sheet readExcel(File tempFile) {
+        Sheet sheet = null;
+
+        try {
+            InputStream inputStream = new FileInputStream(tempFile);
+            //POI可以处理Excel文件
+            Workbook workbook = null;
+            //当文件以.xls结尾时
+            String suffix = tempFile.getName().substring(tempFile.getName().lastIndexOf("."));
+            if (suffix.equals(".xls") || suffix.equals(".XLS")) {
+                workbook = new HSSFWorkbook(inputStream);
+            } else if (suffix.equals(".xlsx") || suffix.equals(".XLSX")) {
+                workbook = new XSSFWorkbook(inputStream);
+            }
+
+            //读取第几个sheet
+            sheet = workbook.getSheetAt(0);
+
+            //关闭流
+            inputStream.close();
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        return sheet;
+    }
+
+    /**
+     * 03版本Excel取附图
+     *
+     * @param sheet Excel工作簿
+     * @return 返回附图map
+     */
+    public static PictureData getPictures1(HSSFSheet sheet, Integer row) throws IOException {
+        if (sheet.getDrawingPatriarch() != null) {
+            List<HSSFShape> list = sheet.getDrawingPatriarch().getChildren();
+            for (HSSFShape shape : list) {
+                if (shape instanceof HSSFPicture) {
+                    HSSFPicture picture = (HSSFPicture) shape;
+                    HSSFClientAnchor cAnchor = (HSSFClientAnchor) picture.getAnchor();
+                    int row1 = cAnchor.getRow1();
+                    if (row1 == row) {
+                        return picture.getPictureData();
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 07版本Excel取附图
+     *
+     * @param sheet Excel工作簿
+     * @return 返回附图map
+     */
+    public static PictureData getPictures2(XSSFSheet sheet, Integer row) throws IOException {
+        List<POIXMLDocumentPart> list = sheet.getRelations();
+        for (POIXMLDocumentPart part : list) {
+            if (part instanceof XSSFDrawing) {
+                XSSFDrawing drawing = (XSSFDrawing) part;
+                List<XSSFShape> shapes = drawing.getShapes();
+                for (XSSFShape shape : shapes) {
+                    //解决图片空指针报错问题 lig  2021-06-03
+                    XSSFClientAnchor anchor = (XSSFClientAnchor) shape.getAnchor();
+                    //XSSFClientAnchor anchor = picture.getPreferredSize();
+                    CTMarker marker = anchor.getFrom();
+                    int excelRow = marker.getRow();
+                    if (excelRow == row) {
+                        XSSFPicture picture = (XSSFPicture) shape;
+                        return picture.getPictureData();
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+
+}

+ 18 - 0
src/main/java/cn/cslg/pas/common/utils/ThrowException.java

@@ -0,0 +1,18 @@
+package cn.cslg.pas.common.utils;
+
+import cn.cslg.pas.exception.XiaoShiException;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @Author chenyu
+ * @Date 2023/4/2
+ */
+@Slf4j
+public class ThrowException {
+
+    public static void throwXiaoShiException(String message) {
+        log.info("{}", message);
+        throw new XiaoShiException(message);
+    }
+
+}

+ 43 - 0
src/main/java/cn/cslg/pas/controller/ProjectImportController.java

@@ -0,0 +1,43 @@
+package cn.cslg.pas.controller;
+
+import cn.cslg.pas.common.core.base.Constants;
+import cn.cslg.pas.common.dto.ExcelImportDTO;
+import cn.cslg.pas.common.utils.Response;
+import cn.cslg.pas.service.importPatent.ProjectImportService;
+import io.swagger.v3.oas.annotations.Operation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+
+/**
+ * @author chenyu
+ * @date 2023/10/23
+ */
+@Slf4j
+@RequiredArgsConstructor
+@RequestMapping(Constants.API_XiaoSHI + "/import")
+@RestController
+public class ProjectImportController {
+    private final ProjectImportService projectImportService;
+
+    @Operation(summary = "Excel导入专利任务")
+    @PostMapping("/excelImport")
+    public String excelImport(MultipartFile file, ExcelImportDTO excelImportDTO) throws IOException {
+        projectImportService.addExcelImportTask(file, excelImportDTO);
+        return Response.success();
+    }
+
+    @Operation(summary = "检索导入专利任务")
+    @PostMapping("/patentStarImport")
+    public String patentStarImport(ExcelImportDTO excelImportDTO) throws IOException {
+        projectImportService
+        return Response.success();
+    }
+
+
+}

+ 50 - 0
src/main/java/cn/cslg/pas/entity/AssoTaskField.java

@@ -0,0 +1,50 @@
+package cn.cslg.pas.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @author chenyu
+ * @date 2023/10/23
+ */
+@Accessors(chain = true)
+@TableName("asso_task_field")
+@Data
+public class AssoTaskField {
+    /**
+     * 主键id
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+    /**
+     * 任务id
+     */
+    @TableField("import_task_id")
+    private Integer importTaskId;
+    /**
+     * 项目(专题库/报告/产品)id
+     */
+    @TableField("project_id")
+    private Integer project_id;
+    /**
+     * 栏位类型
+     */
+    @TableField("field_type")
+    private Integer fieldType;
+    /**
+     * 栏位
+     */
+    @TableField("field_id")
+    private Integer fieldId;
+    /**
+     * 栏位值id
+     */
+    @TableField("field_value_id")
+    private Integer fieldValueId;
+
+
+}

+ 88 - 0
src/main/java/cn/cslg/pas/entity/ImportTask.java

@@ -0,0 +1,88 @@
+package cn.cslg.pas.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+
+/**
+ * 导入任务表
+ *
+ * @author chenyu
+ * @date 2023/10/20
+ */
+@Accessors(chain = true)
+@TableName("import_task")
+@Data
+public class ImportTask {
+    /**
+     * 主键id
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+    /**
+     * 条件
+     */
+    @TableField("condition")
+    private String condition;
+    /**
+     * 导入总条数
+     */
+    @TableField("all_num")
+    private Integer allNum;
+    /**
+     * 进度
+     */
+    @TableField("progress")
+    private Double progress;
+    /**
+     * 完成条数
+     */
+    @TableField("success_num")
+    private Integer successNum;
+    /**
+     * 失败条数
+     */
+    @TableField("default_num")
+    private Integer defaultNum;
+    /**
+     * 任务条件id
+     */
+    @TableField("import_task_condition_id")
+    private Integer importTaskConditionId;
+    /**
+     * 任务类型
+     * 1 excel导入
+     * 2 专利号导入
+     * 3 专利号文件导入
+     * 4 检索导入
+     * 5 pdf文档导入
+     */
+    @TableField("type")
+    private Integer type;
+    /**
+     * 状态(0.等待中 1.进行中 2.已完成 4.已暂停 5.已取消 6.PDF首页合并中)
+     */
+    @TableField("state")
+    private Integer state;
+    /**
+     * 完成时间
+     */
+    @TableField("finish_time")
+    private Date finishTime;
+    /**
+     * 创建人id
+     */
+    @TableField("create_id")
+    private Integer createId;
+    /**
+     * 创建时间
+     */
+    @TableField("create_time")
+    private Date createTime;
+
+}

+ 95 - 0
src/main/java/cn/cslg/pas/entity/ImportTaskCondition.java

@@ -0,0 +1,95 @@
+package cn.cslg.pas.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+
+/**
+ * 导入任务条件表
+ *
+ * @author chenyu
+ * @date 2023/10/20
+ */
+@Accessors(chain = true)
+@TableName("import_task_condition")
+@Data
+public class ImportTaskCondition {
+    /**
+     * 主键id
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+    /**
+     * 项目id
+     */
+    @TableField("project_id")
+    private Integer projectId;
+    /**
+     * 项目类型
+     * 0 专题库
+     * 1 报告
+     */
+    @TableField("project_type")
+    private Integer projectType;
+    /**
+     * 周期
+     */
+    @TableField("crons")
+    private String crons;
+    /**
+     * 上次更新时间
+     */
+    @TableField("last_update_date")
+    private Date lastUpdateDate;
+    /**
+     * 若是检索导入/专利号导入则必填五位数字
+     * 1著录项目 2附图 3权利要求 4说明书文本 5pdf文档
+     */
+    @TableField("import_content")
+    private Integer importContent;
+    /**
+     * 是否更新
+     */
+    @TableField("if_update")
+    private Integer ifUpdate;
+    /**
+     * 条件
+     */
+    @TableField("condition")
+    private String condition;
+    /**
+     * 1 excel导入
+     * 2 专利号导入
+     * 3 专利号文件导入
+     * 4 检索导入
+     * 5 pdf文档导入
+     */
+    @TableField("type")
+    private Integer type;
+    /**
+     * 文件guid
+     */
+    @TableField("file_guid")
+    private String fileGuid;
+    /**
+     * 若是excel导入任务,则使用到配置文件source_id
+     */
+    @TableField("source_id")
+    private Integer sourceId;
+    /**
+     * 创建人id
+     */
+    @TableField("create_id")
+    private Integer createId;
+    /**
+     * 创建时间
+     */
+    @TableField("create_time")
+    private Date createTime;
+
+}

+ 25 - 0
src/main/java/cn/cslg/pas/entity/PatentData.java

@@ -0,0 +1,25 @@
+package cn.cslg.pas.entity;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+import org.apache.poi.ss.usermodel.PictureData;
+
+import java.util.Map;
+
+/**
+ * @Author chenyu
+ * @Date 2023/5/31
+ */
+@Accessors(chain = true)
+@Data
+public class PatentData {
+    /**
+     * 专利内容数据(除了摘要附图, key:表头如 "公开(公告)号"  value:表头对应内容如 "CN1307082B")
+     */
+    private Map<Object, Object> map;
+    /**
+     * 专利摘要附图
+     */
+    private PictureData pictureData;
+
+}

+ 64 - 0
src/main/java/cn/cslg/pas/entity/SystemFile.java

@@ -0,0 +1,64 @@
+package cn.cslg.pas.entity;
+
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class SystemFile {
+    private Integer id;
+    /**
+     * 唯一标识id
+     */
+    private String GUID;
+
+    /**
+     * 存储位置
+     */
+    private Integer pType;
+
+    /**
+     * 文件路径
+     */
+    private String filePath;
+
+    /**
+     * 文件名称
+     */
+    private String fileName;
+
+    /**
+     * 文件名称
+     */
+    private String suffix;
+    /**
+     * 原始名称
+     */
+    private String originalName;
+
+    /**
+     * 文件大小
+     */
+    private String fileLength;
+
+    /**
+     * 创建人id
+     */
+    private Integer createId;
+
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 是否删除
+     */
+    private Integer isDelete;
+
+}

+ 15 - 0
src/main/java/cn/cslg/pas/exception/XiaoShiException.java

@@ -0,0 +1,15 @@
+package cn.cslg.pas.exception;
+
+/**
+ * 整个项目通用异常类
+ *
+ * @Author chenyu
+ * @Date 2023/3/7
+ */
+public class XiaoShiException extends RuntimeException {
+
+    public XiaoShiException(String message) {
+        super(message);
+    }
+
+}

+ 16 - 0
src/main/java/cn/cslg/pas/mapper/AssoTaskFieldMapper.java

@@ -0,0 +1,16 @@
+package cn.cslg.pas.mapper;
+
+import cn.cslg.pas.entity.AssoTaskField;
+import cn.cslg.pas.entity.ImportTask;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springframework.stereotype.Repository;
+
+/**
+ * 任务可见栏位表
+ *
+ * @author chenyu
+ * @date 2023/10/20
+ */
+@Repository
+public interface AssoTaskFieldMapper extends BaseMapper<AssoTaskField> {
+}

+ 15 - 0
src/main/java/cn/cslg/pas/mapper/ImportTaskConditionMapper.java

@@ -0,0 +1,15 @@
+package cn.cslg.pas.mapper;
+
+import cn.cslg.pas.entity.ImportTaskCondition;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springframework.stereotype.Repository;
+
+/**
+ * 导入任务条件表
+ *
+ * @author chenyu
+ * @date 2023/10/20
+ */
+@Repository
+public interface ImportTaskConditionMapper extends BaseMapper<ImportTaskCondition> {
+}

+ 15 - 0
src/main/java/cn/cslg/pas/mapper/ImportTaskMapper.java

@@ -0,0 +1,15 @@
+package cn.cslg.pas.mapper;
+
+import cn.cslg.pas.entity.ImportTask;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springframework.stereotype.Repository;
+
+/**
+ * 导入任务表
+ *
+ * @author chenyu
+ * @date 2023/10/20
+ */
+@Repository
+public interface ImportTaskMapper extends BaseMapper<ImportTask> {
+}

+ 14 - 0
src/main/java/cn/cslg/pas/service/AssoTaskFieldService.java

@@ -0,0 +1,14 @@
+package cn.cslg.pas.service;
+
+import cn.cslg.pas.entity.AssoTaskField;
+import cn.cslg.pas.mapper.AssoTaskFieldMapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+/**
+ * 任务可见栏位表业务层
+ *
+ * @author chenyu
+ * @date 2023/10/23
+ */
+public class AssoTaskFieldService extends ServiceImpl<AssoTaskFieldMapper, AssoTaskField> {
+}

+ 139 - 0
src/main/java/cn/cslg/pas/service/FileManagerService.java

@@ -0,0 +1,139 @@
+package cn.cslg.pas.service;
+
+import cn.cslg.pas.common.dto.FMSDeleteFileDTO;
+import com.google.gson.Gson;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
+import org.apache.commons.io.FileUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.util.FileCopyUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import static cn.hutool.core.io.FileUtil.getMimeType;
+
+/**
+ * Okhttp调用FMS上传文件接口
+ *
+ * @Author xiexiang
+ * @Date 2023/8/10
+ */
+@RequiredArgsConstructor
+@Slf4j
+@Service
+public class FileManagerService {
+    @Value("${FMSUrl}")
+    private String FMSUrl;
+    @Value("${FileSource}")
+    private Integer FileSource;
+
+    /**
+     * 调用文件系统上传文件接口
+     *
+     * @param multipartFiles 文件
+     */
+    public String uploadFile(List<MultipartFile> multipartFiles) throws IOException {
+        List<File> files = new ArrayList<>();
+        for (MultipartFile multipartFile : multipartFiles) {
+            File file = new File(multipartFile.getOriginalFilename());
+            FileCopyUtils.copy(multipartFile.getBytes(), file);
+            files.add(file);
+        }
+        MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder()
+                .setType(MultipartBody.FORM);
+        for (File file : files) {
+            //根据文件名获取文件的MIME类型
+            String mimeType = getMimeType(file.getPath());
+            multipartBodyBuilder.addFormDataPart("files", file.getName(), RequestBody.create(MediaType.parse(mimeType), file));
+        }
+        RequestBody requestBody = multipartBodyBuilder
+                .addFormDataPart("sourceId", String.valueOf(FileSource))
+                .build();
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(FMSUrl + "/fileManager/uploadSystemFile")
+                .post(requestBody)
+                .build();
+        Response response = null;
+        response = okHttpClient.newCall(request).execute();
+        // 最后记得删除临时文件
+        for (File file : files) {
+            FileUtils.deleteQuietly(file);
+        }
+        return Objects.requireNonNull(response.body()).string();
+    }
+
+    /**
+     * 调用文件系统取出文件接口(获得文件流)
+     *
+     * @param fieldId 文件id
+     */
+    public byte[] downloadSystemFileFromFMS(Integer fieldId) throws IOException {
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(FMSUrl + "/fileManager/downloadSystemFile?fileId=" + fieldId)
+                .get()
+                .build();
+        return Objects.requireNonNull(okHttpClient.newCall(request).execute().body()).bytes();
+    }
+
+    /**
+     * 调用文件系统获取文件信息接口
+     *
+     * @param fileIds 文件ids
+     */
+    public String getSystemFileFromFMS(List<Integer> fileIds) throws IOException {
+        String param = new Gson().toJson(fileIds);
+        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), param);
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(FMSUrl + "/fileManager/getFileData")
+                .post(requestBody)
+                .build();
+        return Objects.requireNonNull(okHttpClient.newCall(request).execute().body()).string();
+    }
+
+    /**
+     * 调用文件系统删除文件接口
+     *
+     * @param ids 需要删除的文件ids
+     */
+    public String deleteFileFromFMS(List<Integer> ids) throws IOException {
+        FMSDeleteFileDTO fmsDeleteFileDTO = new FMSDeleteFileDTO();
+        fmsDeleteFileDTO.setIds(ids);
+        fmsDeleteFileDTO.setType(2);
+        String param = new Gson().toJson(fmsDeleteFileDTO);
+        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), param);
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(FMSUrl + "/fileManager/deleteSystemFile")
+                .post(requestBody)
+                .build();
+        return Objects.requireNonNull(okHttpClient.newCall(request).execute().body()).string();
+    }
+
+}

+ 18 - 0
src/main/java/cn/cslg/pas/service/ImportTaskConditionService.java

@@ -0,0 +1,18 @@
+package cn.cslg.pas.service;
+
+import cn.cslg.pas.entity.ImportTaskCondition;
+import cn.cslg.pas.mapper.ImportTaskConditionMapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+/**
+ * 导入任务条件表业务层
+ *
+ * @author chenyu
+ * @date 2023/10/20
+ */
+@Service
+@RequiredArgsConstructor
+public class ImportTaskConditionService extends ServiceImpl<ImportTaskConditionMapper, ImportTaskCondition> {
+}

+ 21 - 0
src/main/java/cn/cslg/pas/service/ImportTaskService.java

@@ -0,0 +1,21 @@
+package cn.cslg.pas.service;
+
+import cn.cslg.pas.entity.ImportTask;
+import cn.cslg.pas.mapper.ImportTaskMapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+/**
+ * 导入任务表业务层
+ *
+ * @author chenyu
+ * @date 2023/10/20
+ */
+@Service
+@RequiredArgsConstructor
+public class ImportTaskService extends ServiceImpl<ImportTaskMapper, ImportTask> {
+
+
+
+}

+ 19 - 0
src/main/java/cn/cslg/pas/service/importPatent/IImportPatentFactory.java

@@ -0,0 +1,19 @@
+package cn.cslg.pas.service.importPatent;
+
+import cn.cslg.pas.entity.ImportTask;
+
+/**
+ * 导入专利工厂类方法接口
+ *
+ * @author chenyu
+ * @date 2023/10/20
+ */
+public interface IImportPatentFactory {
+    /**
+     * 执行导入专利数据入库方法
+     *
+     * @param importTask 导入任务对象
+     */
+    void startImport(ImportTask importTask);
+
+}

+ 63 - 0
src/main/java/cn/cslg/pas/service/importPatent/ImportPatentExcel.java

@@ -0,0 +1,63 @@
+package cn.cslg.pas.service.importPatent;
+
+import cn.cslg.pas.entity.ImportTask;
+import cn.cslg.pas.entity.ImportTaskCondition;
+import cn.cslg.pas.service.ImportTaskConditionService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+/**
+ * Excel导入专利工厂类
+ *
+ * @author chenyu
+ * @date 2023/10/20
+ */
+@Service
+@RequiredArgsConstructor
+public class ImportPatentExcel implements IImportPatentFactory {
+    private final ImportTaskConditionService importTaskConditionService;
+    private Integer pauseTaskId = 0;
+    private Integer pauseTaskState = 0;
+
+    @Override
+    public void startImport(ImportTask importTask) {
+        //从任务中获取文件guid
+        Integer importTaskConditionId = importTask.getImportTaskConditionId();
+        ImportTaskCondition importTaskCondition = importTaskConditionService.getById(importTaskConditionId);
+        String fileGuid = importTaskCondition.getFileGuid();
+        //根据文件guid,调用文件系统获得文件流
+        //创建临时文件tempFile,并将文件流写入该临时文件
+
+
+    }
+
+    /**
+     * 设置当前Excel导入任务的状态
+     *
+     * @param taskId    任务id
+     * @param taskState 任务状态
+     */
+    public void setTaskStatus(Integer taskId, Integer taskState) {
+        this.pauseTaskId = taskId;
+        this.pauseTaskState = taskState;
+    }
+
+    /**
+     * 获得当前导入任务的id
+     *
+     * @return 返回当前导入任务的id
+     */
+    public Integer getPauseTaskId() {
+        return pauseTaskId;
+    }
+
+    /**
+     * 获得当前导入任务的状态
+     *
+     * @return 返回当前导入任务的状态
+     */
+    public Integer getPauseTaskState() {
+        return pauseTaskState;
+    }
+
+}

+ 22 - 0
src/main/java/cn/cslg/pas/service/importPatent/ImportPatentPatentNo.java

@@ -0,0 +1,22 @@
+package cn.cslg.pas.service.importPatent;
+
+import cn.cslg.pas.entity.ImportTask;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+/**
+ * 专利号导入专利工厂类
+ *
+ * @author chenyu
+ * @date 2023/10/20
+ */
+@Service
+@RequiredArgsConstructor
+public class ImportPatentPatentNo implements IImportPatentFactory {
+
+    @Override
+    public void startImport(ImportTask importTask) {
+
+    }
+
+}

+ 54 - 0
src/main/java/cn/cslg/pas/service/importPatent/ImportPatentPatentStar.java

@@ -0,0 +1,54 @@
+package cn.cslg.pas.service.importPatent;
+
+import cn.cslg.pas.entity.ImportTask;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 检索导入专利工厂类
+ *
+ * @author chenyu
+ * @date 2023/10/20
+ */
+@Service
+@RequiredArgsConstructor
+public class ImportPatentPatentStar implements IImportPatentFactory {
+
+    @Override
+    public void startImport(ImportTask importTask) {
+        //若本次下载任务是超过一万条专利的全部下载任务
+        Integer allNum = importTask.getAllNum();
+        if (allNum <= 10000) {  //导入不超过一万件专利
+            importLessThan10000(importTask);
+        } else {  //导入超过一万件专利
+            //importMoreThan10000(importTask);
+        }
+
+    }
+
+    private void importLessThan10000(ImportTask importTask) {
+        try {
+            Integer successNum = importTask.getSuccessNum();
+
+            //下载 isAdd中的专利
+            if (isAddPatentNos != null && isAddPatentNos.size() > 0) {
+                String patentNoCondition = StringUtils.join(isAddPatentNos, " OR ");
+                conditions = "AN=(" + patentNoCondition + ")";
+                downLoadIsAddPatentNos(isAddPatentNos, task, orderBy, orderByType, dbType, cells, conditions);
+            }
+
+        } catch (IOException e) {
+            e.printStackTrace();
+            //生产消费到一半时,发生错误异常,将任务状态置为完成
+            task = taskService.getById(task.getId());
+            task.setStatus(2);
+            taskService.updateById(task);
+        }
+    }
+
+}

+ 113 - 0
src/main/java/cn/cslg/pas/service/importPatent/PatentQueueService.java

@@ -0,0 +1,113 @@
+package cn.cslg.pas.service.importPatent;
+
+import cn.cslg.pas.entity.ImportTask;
+import cn.cslg.pas.service.ImportTaskConditionService;
+import cn.cslg.pas.service.ImportTaskService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * 导入专利所需的各队列和线程
+ *
+ * @author chenyu
+ * @date 2023/10/20
+ */
+@Service
+@RequiredArgsConstructor
+public class PatentQueueService {
+    private final ImportTaskService importTaskService;
+    private final ImportPatentExcel importPatentExcel;
+    private final ImportPatentPatentNo importPatentPatentNo;
+    private final ImportPatentPatentStar importPatentPatentStar;
+    private final List<Integer> importTaskQueue = new ArrayList<>();
+    private final Lock importTaskLock = new ReentrantLock();
+    private final Condition importTaskCondition = importTaskLock.newCondition();
+
+    /**
+     * 从任务队列取出并执行任务
+     */
+    public void excuteTask() {
+        while (true) {
+            ImportTask importTask = new ImportTask();
+            try {
+                //判断任务队列是否有任务,若没有则线程等待唤醒
+                if (importTaskQueue.size() == 0) {
+                    importTaskLock.lock();
+                    importTaskCondition.await();
+                }
+
+                //线程被唤醒后 ↓
+                if (importTaskQueue.size() > 0) {
+                    //从任务队列中取出第一个任务,同时将其从任务队列中剔除
+                    importTask = importTaskService.getById(importTaskQueue.remove(0));
+                    //判断任务状态,若不存在/已完成/已暂停/已取消,则跳过继续取下一个任务
+                    if (importTask == null || importTask.getState().equals(2) || importTask.getState().equals(4) || importTask.getState().equals(5)) {
+                        continue;
+                    }
+
+                    //TODO 调用工厂方法
+                    IImportPatentFactory object = createObject(importTask);
+                    //执行导入专利方法
+                    object.startImport(importTask);
+
+                }
+
+            } catch (Exception e) {
+                e.printStackTrace();
+                //导入任务表更新数据(导入状态完成、完成时间)
+                importTask.setState(2);
+                importTask.setFinishTime(new Date());
+                importTaskService.updateById(importTask);
+            }
+
+        }
+    }
+
+    /**
+     * 工厂方法,根据导入任务的类型type返回对应的导入任务工厂类对象
+     *
+     * @param importTask 导入任务对象
+     * @return 返回对应的导入任务工厂类对象
+     */
+    public IImportPatentFactory createObject(ImportTask importTask) {
+        switch (importTask.getType()) {
+            case 1:
+                return importPatentExcel;
+            case 2:
+                return importPatentPatentNo;
+            case 4:
+                return importPatentPatentStar;
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * 唤醒生产者线程
+     */
+    public void awakeTasktch() {
+        if (importTaskLock.tryLock()) {
+            //taskLock.lock();
+            importTaskCondition.signalAll();
+            importTaskLock.unlock();
+        }
+    }
+
+    /**
+     * 添加导入专利任务到任务队列
+     *
+     * @param importTaskIds 任务ids
+     */
+    public void addImportTasksToQueue(List<Integer> importTaskIds) {
+        importTaskQueue.addAll(importTaskIds);
+    }
+
+
+}

+ 101 - 0
src/main/java/cn/cslg/pas/service/importPatent/ProjectImportService.java

@@ -0,0 +1,101 @@
+package cn.cslg.pas.service.importPatent;
+
+import cn.cslg.pas.common.dto.ExcelImportDTO;
+import cn.cslg.pas.common.utils.LoginUtils;
+import cn.cslg.pas.common.utils.ReadExcelUtils;
+import cn.cslg.pas.entity.AssoTaskField;
+import cn.cslg.pas.entity.ImportTask;
+import cn.cslg.pas.entity.ImportTaskCondition;
+import cn.cslg.pas.service.AssoTaskFieldService;
+import cn.cslg.pas.service.FileManagerService;
+import cn.cslg.pas.service.ImportTaskConditionService;
+import cn.cslg.pas.service.ImportTaskService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.compress.utils.IOUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 导入专利业务层
+ *
+ * @author chenyu
+ * @date 2023/10/23
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class ProjectImportService {
+    private final FileManagerService fileManagerService;
+    private final PatentQueueService patentQueueService;
+    private final ImportTaskService importTaskService;
+    private final ImportTaskConditionService importTaskConditionService;
+    private final AssoTaskFieldService assoTaskFieldService;
+    private final LoginUtils loginUtils;
+
+    /**
+     * 新增Excel导入任务
+     *
+     * @param file           Excel文件
+     * @param excelImportDTO Excel导入专利DTO类对象
+     */
+    public void addExcelImportTask(MultipartFile file, ExcelImportDTO excelImportDTO) throws IOException {
+        //获得文件类型后缀
+        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
+
+        //创建临时文件 tempFile,并将 file读取到 tempFile
+        File tempFile = File.createTempFile("temp", suffix);
+        try (
+                InputStream inputStream = file.getInputStream();
+                FileOutputStream outputStream = new FileOutputStream(tempFile)
+        ) {
+            IOUtils.copy(inputStream, outputStream);
+        }
+
+        //检查临时文件 tempFile合法性并获取专利总数量 total
+        Integer total = ReadExcelUtils.textExcel(tempFile, excelImportDTO.getSourceId());
+
+        //删除临时文件tempFile
+        new File(tempFile.getPath()).delete();
+
+        //TODO 将文件file上传至服务器,并返回文件guid
+
+
+        //导入任务条件表新增数据
+        ImportTaskCondition importTaskCondition = new ImportTaskCondition()
+                .setProjectId(excelImportDTO.getProjectId())
+                .setProjectType(excelImportDTO.getProjectType())
+                .setType(1)
+                //.setFileGuid() 等谢翔文件系统
+                .setSourceId(Integer.valueOf(excelImportDTO.getSourceId()))
+                .setCreateId(loginUtils.getId());
+        log.info("导入任务条件表新增数据");
+        importTaskConditionService.save(importTaskCondition);
+
+        //导入任务表新增数据
+        ImportTask importTask = new ImportTask()
+                .setAllNum(total)
+                .setProgress(0D)
+                .setSuccessNum(0)
+                .setDefaultNum(0)
+                .setImportTaskConditionId(importTaskCondition.getId())
+                .setType(1)
+                .setState(0)
+                .setCreateId(loginUtils.getId());
+        log.info("导入任务表新增数据");
+        importTaskService.save(importTask);
+
+        //任务存入生产者任务队列并唤醒生产者线程
+        patentQueueService.addImportTasksToQueue(Arrays.asList(importTask.getId()));
+        patentQueueService.awakeTasktch();
+    }
+
+}