初始提交

This commit is contained in:
panbaolin 2024-08-08 19:02:01 +08:00
commit 5caf20ef40
415 changed files with 121812 additions and 0 deletions

117
.gitignore vendored Normal file
View File

@ -0,0 +1,117 @@
# ---> Java
*.eclipse.*
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
# ---> JetBrains
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
.idea
*.iml
/classes/META-INF/
target/classes/application-dev.properties
target/classes/application-prod.properties
target/classes/com/platform/attendance/mapper/CheckInRecordMapper.xml
target/classes/com/platform/projects/mapper/ProjectInfoMapper.xml
target/classes/com/platform/projects/mapper/ProjectTaskMapper.xml
target/classes/com/platform/projects/mapper/ProjectUserMapper.xml
target/classes/com/platform/system/mapper/SysOperationLogMapper.xml
target/classes/com/platform/system/mapper/SysRoleMapper.xml
target/classes/com/platform/system/mapper/SysUserMapper.xml
target/generated-sources/target
/.classpath
/.factorypath
/.project
/target/
/log/

21
Dockerfile Normal file
View File

@ -0,0 +1,21 @@
#基于jdk8镜像进行构建创建的镜像已经配置好java环境
FROM openjdk:8
#上述的pom中配置的JAR_FILE将会传入到该参数
#也可以在这里直接配置 ARG JAR_FILE=/target/web-1.0.jar
#用于配置spingboot应用maven打包生成的jar文件
ARG JAR_FILE
#在镜像中创建一个工作目录
RUN mkdir /worker
#将jar文件复制到工作目录中
add ${JAR_FILE} /worker
#暴露镜像的端口8452其他端口不开放
expose 8089
#镜像启动时执行的命令,配置多条仅执行最后一条
#这里配置启动jar文件: java -jar /worker/web-1.0.jar
entrypoint ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/springbootmybatis-1.0.jar"]
# entrypoint ["java","-jar","/worker/springbootmybatis-1.0.jar"]

85
README.md Normal file
View File

@ -0,0 +1,85 @@
# platform Boot是一款基于Springboot的基础开发平台
## 功能包括行政区域管理、用户管理、部门管理、角色权限控制、Redis缓存管理、操作日志管理、数据字典管理、菜单管理等功能
### 适用项目
#### 可以应用在任何J2EE项目的开发中适合企业信息管理系统、内部办公系统、客户管理系统等。
####
#### <font color=red>该程序代码会自动创建更新数据库表接口,不要手动更改数据库表结构信息。</font>
###执行步骤
####1、初始化pom文件
####2、修改配置文件主要修改数据库连接串、数据库账户、数据库密码、redis配置、服务端口号。
####3、手动创建数据库字符集选择"utf-8",排序规则选择”utf8_general_ci“
####4、编译代码
####5、手动执行目录 resources/sql/base_sys_menu.sql 数据库脚本,初始化菜单;
####6、启动项目<font color=red>自动生成管理员账户、角色信息;</font>
####7、打开浏览器http://localhost:port/swagger-ui/index.html<font color=red>swagger接口调试工具</font>
### 模型数据注解参考网站:
https://www.yuque.com/sunchenbin/actable/olgtiz
#### 开发环境使用application-dev.properties 配置文件
#### 测试环境使用application-prod.properties 配置文件
#### 第一次从git拉取下的代码需要手动切换到开发环境配置修改文件application.properties
#spring.profiles.active=prod
spring.profiles.active=dev
### 添加Swagger
#### 打开 common->config->SwaggerConfig 文件,参考增加
@Bean
public Docket createSystemRestApi() {
return createRestApi("com.platform.system.controller", "系统管理");
}
### 权限控制
#### 打开Controller 文件,在接口上增加 @PreAuthorize
“pro:sys:menu:add“ 为菜单权限码
@PostMapping("/add")
@PreAuthorize("@Permission.hasPermi('pro:sys:menu:add')")
@AutoLog(value = "新增菜单", operationType = OperationTypeEnum.INSERT, module = "系统管理/菜单管理")
public boolean add(@RequestBody SysMenuCreateInputVo inputVo) {
return menuService.create(inputVo);
}
### 操作日志
#### 打开Controller 文件,在接口上增加 @AutoLog
@DeleteMapping("/remove")
@PreAuthorize("@Permission.hasPermi('pro:sys:dic:remove')")
@AutoLog(value = "删除字典数据", level = 9, operationType = OperationTypeEnum.DELETE, module = "系统管理/字典管理")
public boolean remove(String key) {
return dataService.remove(key);
}
### 分页
#### Vo 继承 SearchInputVo
####
### 缓存数据转化,支持用户信息、角色信息、部门信息、字典信息转化
@CacheFormat(key = "createUserId", cacheType = CacheFormatEnum.USER)
### 数据权限,支持所有、按所属部门、按自定义部门、按自定义人员查询;
@CustomDataPermission(operation = OperationTypeEnum.SELECT, perm = "sys:base:user")
### 数据权限,需要升级
<dependency>
<groupId>com.gitee.sunchenbin.mybatis.actable</groupId>
<artifactId>mybatis-enhance-actable</artifactId>
<version>1.5.0.RELEASE</version>
</dependency>
#### TODO 待续

View File

@ -0,0 +1,5 @@
支持添加注解方式实现数据权限查询目前支持查询所有、按所属部门查询、按自定义部门查询、按自定义人员查询、按自己数据查询5种数据查询权限。
自定义数据权限实现代码位置

37
docker.SH Normal file
View File

@ -0,0 +1,37 @@
#操作/项目路径(Dockerfile存放的路劲)
BASE_PATH=/usr/ms_backend
# 源jar路径 即jenkins构建后存放的路径
SOURCE_PATH=/var/jenkins_home/workspace/test
#docker 镜像/容器名字或者jar名字 这里都命名为这个
SERVER_NAME=springbootmybatis-1.0
#容器id
CID=$(docker ps | grep "$SERVER_NAME" | awk '{print $1}')
#镜像id
IID=$(docker images | grep "$SERVER_NAME" | awk '{print $3}')
echo "最新构建代码 $SOURCE_PATH/target/springbootmybatis-1.0.jar 迁移至 $BASE_PATH ...."
#把项目从jenkins构建后的目录移动到我们的项目目录下同时重命名下
sudo docker cp 50af4cde876e:$SOURCE_PATH/target/springbootmybatis-1.0.jar $BASE_PATH
#修改文件的权限
chmod 777 /usr/ms_backend/springbootmybatis-1.0.jar
echo "迁移完成"
# 构建docker镜像
if [ -n "$IID" ]; then
echo "存在$SERVER_NAME镜像IID=$IID"
else
echo "不存在$SERVER_NAME镜像开始构建镜像"
cd $BASE_PATH
sudo docker build -t $SERVER_NAME .
fi
# 运行docker容器
docker rm $SERVER_NAME //删除原来的容器
# --name docker-test 容器的名字为docker-test
# -d 容器后台运行
# -p 3636:3636 指定容器映射的端口和主机对应的端口都为3636
# -v /usr/ms_backend/:/usr/ms_backend/ 将主机的/usr/ms_backend/目录挂载到容器的/usr/ms_backend/ 目录中不可少每次本地更新jar包重启容器即可不用重新构建镜像
sudo docker run --name $SERVER_NAME -v $BASE_PATH:$BASE_PATH -d -p 8089:8089 $SERVER_NAME
echo "$SERVER_NAME容器创建完成"

401
pom.xml Normal file
View File

@ -0,0 +1,401 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.platform</groupId>
<artifactId>springbootmybatis</artifactId>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/>
</parent>
<repositories>
<repository>
<id>com.e-iceblue</id>
<name>e-iceblue</name>
<url>http://repo.e-iceblue.cn/repository/maven-public/</url>
</repository>
<repository>
<id>mvn-repo</id>
<url>http://maven.ansj.org/</url>
</repository>
<repository>
<id>XINCHECK</id>
<name>XINCHECK Public Repository</name>
<url>https://maven.xincheck.com/repository/pro/</url>
</repository>
<!-- 阿里云仓库 -->
<repository>
<id>aliyun</id>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</repository>
</repositories>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<jdk.version>1.8</jdk.version>
<JAVA_HOME>C:\Program Files\Java\jdk1.8.0_351</JAVA_HOME>
<!--编译时的编码-->
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<itextpdf.version>7.1.13</itextpdf.version>
<html2pdf.version>3.0.2</html2pdf.version>
<pdfbox.version>2.0.27</pdfbox.version>
<jai-imageio.version>1.4.0</jai-imageio.version>
<jai-imageio-jpeg2000.version>1.3.0</jai-imageio-jpeg2000.version>
<okhttp3.version>3.14.9</okhttp3.version>
<elasticsearch.version>7.15.2</elasticsearch.version>
</properties>
<dependencies>
<!-- xincheck -->
<dependency>
<groupId>com.xincheck</groupId>
<artifactId>duplicate-check-pro</artifactId>
<version>0.5.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 模版 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>ognl</groupId>
<artifactId>ognl</artifactId>
<version>3.3.3</version>
</dependency>
<!-- redis组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- elasticsearch -->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
<!-- 数据库组件 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>com.gitee.sunchenbin.mybatis.actable</groupId>
<artifactId>mybatis-enhance-actable</artifactId>
<version>1.5.0.RELEASE</version>
</dependency>
<!-- json -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.19</version>
</dependency>
<!-- api文档 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-core</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-metadata</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<version>2.4.3</version>
</dependency>
<!-- commons -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.belerweb</groupId>
<artifactId>pinyin4j</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!--验证码kaptcha-->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
<!--hutool工具-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.6</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- 新增依赖-->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.13.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.5</version>
<exclusions>
<exclusion>
<artifactId>commons-codec</artifactId>
<groupId>commons-codec</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/info.debatty/java-string-similarity -->
<dependency>
<groupId>info.debatty</groupId>
<artifactId>java-string-similarity</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.1</version>
</dependency>
<!-- itext全局引入 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>kernel</artifactId>
<version>${itextpdf.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>io</artifactId>
<version>${itextpdf.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>layout</artifactId>
<version>${itextpdf.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>forms</artifactId>
<version>${itextpdf.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>pdfa</artifactId>
<version>${itextpdf.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>sign</artifactId>
<version>${itextpdf.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>barcodes</artifactId>
<version>${itextpdf.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>font-asian</artifactId>
<version>${itextpdf.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>hyph</artifactId>
<version>${itextpdf.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
<version>${html2pdf.version}</version>
</dependency>
<!-- pdfbox -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>${pdfbox.version}</version>
</dependency>
<dependency>
<groupId>com.github.jai-imageio</groupId>
<artifactId>jai-imageio-core</artifactId>
<version>${jai-imageio.version}</version>
</dependency>
<dependency>
<groupId>com.github.jai-imageio</groupId>
<artifactId>jai-imageio-jpeg2000</artifactId>
<version>${jai-imageio-jpeg2000.version}</version>
</dependency>
<!-- okhttp3 -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp3.version}</version>
</dependency>
<!-- poi -->
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<exclusions>
<exclusion>
<artifactId>commons-io</artifactId>
<groupId>commons-io</groupId>
</exclusion>
</exclusions>
<version>1.12.0</version>
</dependency>
<!-- 获取文档属性 -->
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.doc</artifactId>
<version>5.4.2</version>
</dependency>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.pdf</artifactId>
<version>5.4.2</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!--fork : 如果没有该项配置devtools不会起作用即应用不会restart -->
<fork>true</fork>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
<encoding>UTF-8</encoding>
<compilerArguments>
<verbose />
<bootclasspath>${JAVA_HOME}/jre/lib/rt.jar${path.separator}${JAVA_HOME}/jre/lib/jce.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,64 @@
package com.platform;
import cn.textcheck.CheckManager;
import cn.textcheck.engine.config.Config;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.env.Environment;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* @author admin
*/
@SpringBootApplication
@MapperScan({"com.platform.*.mapper", "com.gitee.sunchenbin.mybatis.actable.dao"})
@ComponentScan(basePackages = {"com.gitee.sunchenbin.mybatis.actable.manager.*", "com.platform.*"})
@Slf4j
public class DemoApplication extends SpringBootServletInitializer {
public static void main(String[] args) throws UnknownHostException {
ConfigurableApplicationContext application= SpringApplication.run(DemoApplication.class, args);
Environment env = application.getEnvironment();
log.info("此主机机器码为:"+CheckManager.INSTANCE.getMachineCode());
//设置授权码
CheckManager.INSTANCE.setRegCode(env.getProperty("system.regCode"));
//设置查重段落划分字数
Config.ITEM.put("segmentSize",env.getProperty("system.segmentSize"));
//查重时是否忽略参考文献部分不忽略
Config.ITEM.put("checkIgnoreReferences",env.getProperty("false"));
log.info("SDK授权状态"+CheckManager.INSTANCE.regState());
log.info("\n----------------------------------------------------------\n\t" +
"Application '{}' is running! Access URLs:\n\t" +
"Local: \t\thttp://localhost:{}\n\t" +
"External: \thttp://{}:{}\n\t"+
"Doc: \thttp://{}:{}/swagger-ui/index.html\n"+
"----------------------------------------------------------",
env.getProperty("spring.application.name"),
env.getProperty("server.port"),
InetAddress.getLocalHost().getHostAddress(),
env.getProperty("server.port"),
InetAddress.getLocalHost().getHostAddress(),
env.getProperty("server.port"));
}
/**
* /为了打包springboot项目
*
* @param builder builder
* @return 打包
*/
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(this.getClass());
}
}

View File

@ -0,0 +1,21 @@
package com.platform.check.actuator;
import com.platform.project.domain.CheckProject;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class CustomTaskUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{
protected CheckProject project;
public void init(CheckProject project) {
this.project = project;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
log.error("捕获到任务{}解析异常,任务将停止",project.getProcurementContent());
}
}

View File

@ -0,0 +1,120 @@
package com.platform.check.actuator.china;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;
import com.platform.check.actuator.parsing.BaseActurtor;
import com.platform.check.actuator.task.TaskCounter;
import com.platform.check.actuator.task.TaskThreadMonitor;
import com.platform.check.domain.CheckDocTask;
import com.platform.check.domain.CheckFile;
import com.platform.check.service.CheckDocTaskService;
import com.platform.check.service.CheckDocumentService;
import com.platform.check.service.CheckPaperLibraryService;
import com.platform.check.service.CheckRepeatedDocumentService;
import com.platform.check.service.CheckReportService;
import com.platform.check.service.CheckReportSimilarFileService;
import com.platform.common.elastic.ElasticsearchService;
import com.platform.common.properties.SystemProperties;
import com.platform.common.redis.RedisUtil;
import com.platform.project.domain.CheckProject;
import lombok.Getter;
import lombok.Setter;
public abstract class Handler {
protected CheckDocumentService checkDocumentService;
protected CheckRepeatedDocumentService checkRepeatedDocumentService;
protected CheckReportSimilarFileService checkReportSimilarFileService;
protected CheckReportService checkReportService;
protected CheckDocTaskService checkDocTaskService;
protected CheckDocTask checkDocTask;
protected SystemProperties properties;
protected List<CheckFile> checkFiles;
protected ThreadPoolExecutor poolExecutor;
protected RedisUtil redisUtil;
protected CheckProject project;
protected CheckPaperLibraryService checkPaperLibraryService;
protected TaskCounter taskCounter;
protected ElasticsearchService elasticsearchService;
protected String parsingType;
/**
* 匹配标记
*/
@Getter
protected boolean matchFlag = false;
/**
* 上一任处理链
*/
@Setter
protected Handler previous;
/**
* 下一任处理链
*/
@Setter
protected Handler next;
/**
* 设置是否匹配成功标记
* @param matchFlag
*/
protected void setMatchFlag(boolean matchFlag) {
this.previous.setMatchFlag(matchFlag);
}
/**
* 处理上传的文件列表
* @param files
*/
public abstract void handlerFiles(List<CheckFile> files);
/**
* 设置过滤链路
*/
protected abstract void setChina();
/**
* 初始化服务
*/
public void initService(
CheckDocumentService checkDocumentService,
CheckRepeatedDocumentService checkRepeatedDocumentService,
CheckReportSimilarFileService checkReportSimilarFileService,
CheckReportService checkReportService,
CheckDocTaskService checkDocTaskService,
CheckDocTask checkDocTask,
SystemProperties properties,
List<CheckFile> checkFiles,
CheckProject project,
CheckPaperLibraryService checkPaperLibraryService,
RedisUtil redisUtil,
TaskCounter taskCounter,
ElasticsearchService elasticsearchService) {
this.checkDocumentService = checkDocumentService;
this.checkRepeatedDocumentService = checkRepeatedDocumentService;
this.checkReportSimilarFileService = checkReportSimilarFileService;
this.checkReportService = checkReportService;
this.checkDocTaskService = checkDocTaskService;
this.checkDocTask = checkDocTask;
this.properties = properties;
this.checkFiles = checkFiles;
this.project = project;
this.checkPaperLibraryService = checkPaperLibraryService;
this.redisUtil = redisUtil;
this.taskCounter = taskCounter;
this.elasticsearchService = elasticsearchService;
//设置过滤链路
this.setChina();
}
/**
* 缓存文件解析执行器
* @param acturtor
*/
protected void cacheActurtor(BaseActurtor acturtor) {
TaskThreadMonitor.getInstance().offer(this.checkDocTask.getId(),acturtor);
}
}

View File

@ -0,0 +1,71 @@
package com.platform.check.actuator.china;
import java.util.List;
import com.platform.check.actuator.parsing.BaseActurtor;
import com.platform.check.actuator.parsing.ImgParsingActurtor;
import com.platform.check.domain.CheckFile;
import com.platform.check.enums.FileSuffix;
/**
* img处理链
* @author 86187
*
*/
public class ImgHandler extends Handler {
public void setChina() {
WordHandler wordHandler = new WordHandler();
wordHandler.initService(
checkDocumentService,
checkRepeatedDocumentService,
checkReportSimilarFileService,
checkReportService,
checkDocTaskService,
checkDocTask,
properties,
checkFiles,
project,
checkPaperLibraryService,
redisUtil,
taskCounter,
elasticsearchService);
wordHandler.setPrevious(this);
super.setNext(wordHandler);
}
@Override
public void handlerFiles(List<CheckFile> files) {
boolean flag = true;
for(CheckFile checkFile : files) {
if(!checkFile.getFileExt().equalsIgnoreCase(FileSuffix.JPEG.getValue()) &&
!checkFile.getFileExt().equalsIgnoreCase(FileSuffix.JPG.getValue()) &&
!checkFile.getFileExt().equalsIgnoreCase(FileSuffix.PNG.getValue())) {
flag = false;
}
}
if(flag) {
String poolName = "img-parsing-Pool";
BaseActurtor imgParsingActurtor = new ImgParsingActurtor();
imgParsingActurtor.init(
super.checkDocumentService,
super.checkRepeatedDocumentService,
super.checkReportSimilarFileService,
super.checkReportService,
super.checkDocTaskService,
super.checkDocTask,
super.properties,
super.checkFiles,
super.project,
super.checkPaperLibraryService,
poolName,
taskCounter,
elasticsearchService);
imgParsingActurtor.setName("img-parsing-thread");
imgParsingActurtor.start();
super.cacheActurtor(imgParsingActurtor);
}else {
super.next.handlerFiles(files);
}
}
}

View File

@ -0,0 +1,72 @@
package com.platform.check.actuator.china;
import java.util.List;
import com.platform.check.actuator.parsing.BaseActurtor;
import com.platform.check.actuator.parsing.PDFParsingGroupActurtor;
import com.platform.check.domain.CheckFile;
import com.platform.check.enums.FileSuffix;
/**
* pdf处理链
* @author 86187
*
*/
public class PDFHandler extends Handler {
public void setChina() {
ImgHandler imgHandler = new ImgHandler();
imgHandler.initService(
checkDocumentService,
checkRepeatedDocumentService,
checkReportSimilarFileService,
checkReportService,
checkDocTaskService,
checkDocTask,
properties,
checkFiles,
project,
checkPaperLibraryService,
redisUtil,
taskCounter,
elasticsearchService);
imgHandler.setPrevious(this);
super.setNext(imgHandler);
//pdf链路是第一个所以上一个链路也是自己
super.setPrevious(this);
}
@Override
public void handlerFiles(List<CheckFile> files) {
boolean flag = true;
for(CheckFile checkFile : files) {
if(!checkFile.getFileExt().equals(FileSuffix.PDF.getValue())) {
flag = false;
}
}
if(flag) {
String poolName = "pdf-parsing-Pool";
BaseActurtor pdfGroupActurtor = new PDFParsingGroupActurtor();
pdfGroupActurtor.init(
super.checkDocumentService,
super.checkRepeatedDocumentService,
super.checkReportSimilarFileService,
super.checkReportService,
super.checkDocTaskService,
super.checkDocTask,
super.properties,
super.checkFiles,
super.redisUtil,
super.project,
super.checkPaperLibraryService,
poolName,
taskCounter,
elasticsearchService);
pdfGroupActurtor.setName("pdf-parsing-thread");
pdfGroupActurtor.start();
super.cacheActurtor(pdfGroupActurtor);
}else {
super.next.handlerFiles(files);
}
}
}

View File

@ -0,0 +1,57 @@
package com.platform.check.actuator.china;
import java.util.List;
import com.platform.check.actuator.parsing.BaseActurtor;
import com.platform.check.actuator.parsing.WordParsingActurtor;
import com.platform.check.domain.CheckFile;
import com.platform.check.enums.FileSuffix;
import com.platform.common.exception.BusinessException;
/**
* word处理链
* @author 86187
*
*/
public class WordHandler extends Handler{
@Override
protected void setChina() {
}
@Override
public void handlerFiles(List<CheckFile> files) {
boolean flag = true;
for(CheckFile checkFile : files) {
if(!checkFile.getFileExt().equals(FileSuffix.WORD_DOC.getValue()) &&
!checkFile.getFileExt().equals(FileSuffix.WORD_DOCX.getValue()) &&
!checkFile.getFileExt().equals(FileSuffix.TXT.getValue())) {
flag = false;
}
}
if(flag) {
//如果此次任务是word解析
BaseActurtor wordParsingThread = new WordParsingActurtor();
wordParsingThread.init(
super.checkDocTask,
super.checkDocumentService,
super.checkRepeatedDocumentService,
super.checkReportService,
super.checkDocTaskService,
super.checkReportSimilarFileService,
super.checkFiles,
super.properties,
super.checkPaperLibraryService,
super.project,
super.taskCounter,
super.elasticsearchService);
wordParsingThread.setName("word-txt-parsing-thread");
wordParsingThread.start();
super.cacheActurtor(wordParsingThread);
}else {
throw new BusinessException("上传文件类型不符合需求,解析失败!");
}
}
}

View File

@ -0,0 +1,69 @@
package com.platform.check.actuator.model;
import java.io.IOException;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
/**
* 任务解析文档索引相关设置
* @author 86187
*
*/
public class DocIndexSetting {
/**
* 获取索引分片及备份设置
* @return
* @throws IOException
*/
public static XContentBuilder getSetting() throws IOException{
XContentBuilder settingsBuilder = XContentFactory.jsonBuilder();
settingsBuilder.startObject();
{
settingsBuilder.startObject("index");
{
settingsBuilder.field("number_of_shards",2);
settingsBuilder.field("number_of_replicas",1);
}
settingsBuilder.endObject();
}
settingsBuilder.endObject();
return settingsBuilder;
}
/**
* 获取索引文档映射设置
* @return
* @throws IOException
*/
public static XContentBuilder getMapping() throws IOException{
XContentBuilder mappingBuilder = XContentFactory.jsonBuilder();
mappingBuilder.startObject();
{
mappingBuilder.startObject("properties");
{
mappingBuilder.startObject("pageNum");
{
mappingBuilder.field("type","integer");
mappingBuilder.field("index",true);
}
mappingBuilder.endObject();
mappingBuilder.startObject("content");
{
mappingBuilder.field("type","text");
mappingBuilder.field("index",true);
}
mappingBuilder.endObject();
mappingBuilder.startObject("localDate");
{
mappingBuilder.field("type","keyword");
mappingBuilder.field("index",true);
}
mappingBuilder.endObject();
}
mappingBuilder.endObject();
}
mappingBuilder.endObject();
return mappingBuilder;
}
}

View File

@ -0,0 +1,22 @@
package com.platform.check.actuator.model;
import java.io.Serializable;
import java.time.LocalDateTime;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
@Data
public class DocPageInfo implements Serializable{
private static final long serialVersionUID = 1L;
private Integer pageNum;
private String content;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime localDate;
}

View File

@ -0,0 +1,28 @@
package com.platform.check.actuator.model;
import java.io.Serializable;
import lombok.Data;
/**
* pdf文件图片解析状态数据
* @author 86187
*
*/
@Data
public class PDFPageParsingStatus implements Serializable{
private static final long serialVersionUID = 1L;
/**
* 页码
*/
private Integer pageNum;
/**
* 文件存储路径
*/
private String filePath;
/**
* 当前解析状态
* -1解析失败1图片已解析2图片已识别
*/
private Integer status;
}

View File

@ -0,0 +1,400 @@
package com.platform.check.actuator.parsing;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.IBodyElement;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.platform.check.actuator.model.DocIndexSetting;
import com.platform.check.actuator.model.DocPageInfo;
import com.platform.check.actuator.task.TaskCounter;
import com.platform.check.domain.CheckDocTask;
import com.platform.check.domain.CheckFile;
import com.platform.check.enums.FileSuffix;
import com.platform.check.enums.PDFParsingSectionPath;
import com.platform.check.service.CheckDocTaskService;
import com.platform.check.service.CheckDocumentService;
import com.platform.check.service.CheckPaperLibraryService;
import com.platform.check.service.CheckRepeatedDocumentService;
import com.platform.check.service.CheckReportService;
import com.platform.check.service.CheckReportSimilarFileService;
import com.platform.common.elastic.ElasticsearchService;
import com.platform.common.properties.SystemProperties;
import com.platform.common.redis.RedisUtil;
import com.platform.project.domain.CheckProject;
import lombok.Getter;
import lombok.Setter;
/**
* 基础执行器
* @author 86187
*
*/
public abstract class BaseActurtor extends Thread{
@Getter @Setter
protected volatile boolean isStop = false;
/** 文字识别服务要求图片最大宽度为800 */
protected final static int IMG_WIDTH = 800;
/** 线程计数器 */
CountDownLatch taskLatch = null;
protected CheckDocumentService checkDocumentService;
protected CheckRepeatedDocumentService checkRepeatedDocumentService;
protected CheckReportSimilarFileService checkReportSimilarFileService;
protected CheckReportService checkReportService;
protected CheckDocTaskService checkDocTaskService;
protected CheckDocTask checkDocTask;
protected SystemProperties properties;
protected List<CheckFile> checkFiles;
protected ThreadPoolExecutor poolExecutor;
protected RedisUtil redisUtil;
protected CheckProject project;
protected CheckPaperLibraryService checkPaperLibraryService;
protected TaskCounter taskCounter;
protected ElasticsearchService elasticsearchService;
protected String poolName;
/**
* 初始化
*/
public void init(
CheckDocumentService checkDocumentService,
CheckRepeatedDocumentService checkRepeatedDocumentService,
CheckReportSimilarFileService checkReportSimilarFileService,
CheckReportService checkReportService,
CheckDocTaskService checkDocTaskService,
CheckDocTask checkDocTask,
SystemProperties properties,
List<CheckFile> checkFiles,
CheckProject project,
CheckPaperLibraryService checkPaperLibraryService,
String poolName,
TaskCounter taskCounter,
ElasticsearchService elasticsearchService) {
this.checkDocumentService = checkDocumentService;
this.checkRepeatedDocumentService = checkRepeatedDocumentService;
this.checkReportSimilarFileService = checkReportSimilarFileService;
this.checkReportService = checkReportService;
this.checkDocTaskService = checkDocTaskService;
this.checkDocTask = checkDocTask;
this.properties = properties;
this.checkFiles = checkFiles;
this.project = project;
this.checkPaperLibraryService = checkPaperLibraryService;
this.taskCounter = taskCounter;
this.elasticsearchService = elasticsearchService;
this.poolName = poolName;
}
/**
* 初始化
*/
public void init(
CheckDocumentService checkDocumentService,
CheckRepeatedDocumentService checkRepeatedDocumentService,
CheckReportSimilarFileService checkReportSimilarFileService,
CheckReportService checkReportService,
CheckDocTaskService checkDocTaskService,
CheckDocTask checkDocTask,
SystemProperties properties,
List<CheckFile> checkFiles,
RedisUtil redisUtil,
CheckProject project,
CheckPaperLibraryService checkPaperLibraryService,
String poolName,
TaskCounter taskCounter,
ElasticsearchService elasticsearchService) {
this.checkDocumentService = checkDocumentService;
this.checkRepeatedDocumentService = checkRepeatedDocumentService;
this.checkReportSimilarFileService = checkReportSimilarFileService;
this.checkReportService = checkReportService;
this.checkDocTaskService = checkDocTaskService;
this.checkDocTask = checkDocTask;
this.properties = properties;
this.checkFiles = checkFiles;
this.redisUtil = redisUtil;
this.project = project;
this.checkPaperLibraryService = checkPaperLibraryService;
this.taskCounter = taskCounter;
this.elasticsearchService = elasticsearchService;
this.poolName = poolName;
}
/**
* 初始化
*/
public void init(
CheckDocTask checkDocTask,
CheckDocumentService checkDocumentService,
CheckRepeatedDocumentService checkRepeatedDocumentService,
CheckReportService checkReportService,
CheckDocTaskService checkDocTaskService,
CheckReportSimilarFileService checkReportSimilarFileService,
List<CheckFile> checkFiles,
SystemProperties properties,
CheckPaperLibraryService checkPaperLibraryService,
CheckProject project,
TaskCounter taskCounter,
ElasticsearchService elasticsearchService) {
this.checkDocTask = checkDocTask;
this.checkDocumentService = checkDocumentService;
this.checkRepeatedDocumentService = checkRepeatedDocumentService;
this.checkReportService = checkReportService;
this.checkDocTaskService = checkDocTaskService;
this.checkReportSimilarFileService = checkReportSimilarFileService;
this.checkFiles = checkFiles;
this.properties = properties;
this.checkPaperLibraryService = checkPaperLibraryService;
this.project = project;
this.taskCounter = taskCounter;
this.elasticsearchService = elasticsearchService;
}
/**
* 初始化
*/
public void init(
CheckDocTask checkDocTask,
CheckDocumentService checkDocumentService,
CheckRepeatedDocumentService checkRepeatedDocumentService,
CheckReportService checkReportService,
CheckDocTaskService checkDocTaskService,
CheckReportSimilarFileService checkReportSimilarFileService,
List<CheckFile> checkFiles,
SystemProperties properties,
CheckPaperLibraryService checkPaperLibraryService,
CheckProject project,
ElasticsearchService elasticsearchService) {
this.checkDocTask = checkDocTask;
this.checkDocumentService = checkDocumentService;
this.checkRepeatedDocumentService = checkRepeatedDocumentService;
this.checkReportService = checkReportService;
this.checkDocTaskService = checkDocTaskService;
this.checkReportSimilarFileService = checkReportSimilarFileService;
this.checkFiles = checkFiles;
this.properties = properties;
this.checkPaperLibraryService = checkPaperLibraryService;
this.project = project;
this.elasticsearchService = elasticsearchService;
}
/**
* 初始化
*/
public void init(
CheckDocTask checkDocTask,
CheckDocTaskService checkDocTaskService,
SystemProperties properties,
RedisUtil redisUtil,
CheckProject project,
ElasticsearchService elasticsearchService) {
this.checkDocTask = checkDocTask;
this.checkDocTaskService = checkDocTaskService;
this.properties = properties;
this.redisUtil = redisUtil;
this.project = project;
this.elasticsearchService = elasticsearchService;
}
/**
* 初始化线程池
*/
protected void initThreadPool(String poolName,Integer corePoolSize,UncaughtExceptionHandler handler) {
//获取机器可用核心数
int maximumPoolSize = Runtime.getRuntime().availableProcessors();
//初始化线程池
ThreadFactory threadFactory = new CustomThreadFactory(handler,poolName);
poolExecutor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,5, TimeUnit.SECONDS, new LinkedBlockingQueue<>(),threadFactory);
}
/**
* 计算任务步骤占比
*/
protected abstract void computationStepProportion();
/**
* 创建文档索引
* @throws IOException
*/
protected void createIndex() throws IOException {
for(CheckFile checkFile : this.checkFiles) {
if(checkFile.getFileName().endsWith(FileSuffix.PDF.getValue()) ||
checkFile.getFileName().endsWith(FileSuffix.WORD_DOC.getValue()) ||
checkFile.getFileName().endsWith(FileSuffix.WORD_DOCX.getValue())) {
boolean exists = elasticsearchService.indexExists(checkFile.getId());
if(exists) {
elasticsearchService.deleteIndex(checkFile.getId());
}
elasticsearchService.createIndex(checkFile.getId(),DocIndexSetting.getSetting(),DocIndexSetting.getMapping());
}
}
}
/**
* 把解析后的word内容存储到ES
* @param fileId
* @param pageNum
* @param filePath
*/
protected void saveWordContentToES(String fileId,Integer pageNum,String filePath) {
FileInputStream fis = null;
XWPFDocument document = null;
File file = new File(filePath);
StringBuilder content = new StringBuilder();
try {
if(!file.exists() || file.length()==0) {
content.append(StringUtils.EMPTY);
}else {
fis = new FileInputStream(file);
document = new XWPFDocument(fis);
for(IBodyElement element : document.getBodyElements()) {
if(element instanceof XWPFParagraph) {
XWPFParagraph paragraph = (XWPFParagraph) element;
content.append(paragraph.getText());
}else if(element instanceof XWPFTable) {
XWPFTable table = (XWPFTable) element;
for (XWPFTableRow row : table.getRows()) {
for (XWPFTableCell cell : row.getTableCells()) {
content.append(cell.getText());
}
}
}
}
}
} catch (IOException e) {
content.append(StringUtils.EMPTY);
e.printStackTrace();
}finally {
if(null != fis) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(null != document) {
try {
document.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//读取文档进行截图时pdfbox获取页面索引是从0开始的这里根据用户看文档习惯应是从1开始所以往ES里存储页码从1开始
pageNum = pageNum +1;
DocPageInfo info = new DocPageInfo();
info.setPageNum(pageNum);
info.setLocalDate(LocalDateTime.now());
info.setContent(StringUtils.lowerCase(content.toString()));
elasticsearchService.createDoc(fileId,pageNum.toString(),JSON.toJSONString(info));
}
}
/**
* 获取文件路径
* @return
*/
protected String getFilePath(CheckFile checkFile) {
StringBuilder filePath = new StringBuilder();
filePath.append(properties.getTaskFilePath());
filePath.append(File.separator);
filePath.append(checkDocTask.getId());
filePath.append(File.separator);
filePath.append(checkFile.getMd5Value());
filePath.append(File.separator);
filePath.append(checkFile.getFileName());
return filePath.toString();
}
/**
* 处理图片文件解析后的word存储路径
* @return
*/
protected String handleWordPath(CheckFile checkFile) {
StringBuilder sectionPath = new StringBuilder();
sectionPath.append(properties.getTaskFilePath());
sectionPath.append(File.separator);
sectionPath.append(checkDocTask.getId());
sectionPath.append(File.separator);
sectionPath.append(checkFile.getMd5Value());
sectionPath.append(File.separator);
sectionPath.append(PDFParsingSectionPath.WORD.getValue());
File sectionFolder = new File(sectionPath.toString());
if(!sectionFolder.exists()) {
sectionFolder.mkdirs();
}
return sectionFolder.getAbsolutePath();
}
/**
* 处理文件解析过程的图片存储路径
* @return
*/
protected String handleSectionPath(CheckFile checkFile) {
StringBuilder sectionPath = new StringBuilder();
sectionPath.append(properties.getTaskFilePath());
sectionPath.append(File.separator);
sectionPath.append(checkDocTask.getId());
sectionPath.append(File.separator);
sectionPath.append(checkFile.getMd5Value());
sectionPath.append(File.separator);
sectionPath.append(PDFParsingSectionPath.SECTION.getValue());
File sectionFolder = new File(sectionPath.toString());
if(!sectionFolder.exists()) {
sectionFolder.mkdirs();
}
return sectionFolder.getAbsolutePath();
}
/**
* 获取图片存储的绝对路径
* @return
*/
protected String getImagePath(int index,CheckFile checkFile,String sectionPath) {
StringBuilder imagePath = new StringBuilder();
imagePath.append(sectionPath);
imagePath.append(File.separator);
imagePath.append(checkFile.getId());
imagePath.append(StringPool.DASH);
imagePath.append(index);
imagePath.append(FileSuffix.JPG.getValue());
return imagePath.toString();
}
protected void clearCountDownLatch() {
long count = taskLatch.getCount();
for(long i=0;i < count;i++) {
taskLatch.countDown();
}
}
protected void closeThreadPool() {
if(Objects.nonNull(poolExecutor)) {
poolExecutor.shutdownNow();
}
}
public void stopTask() {
this.setStop(true);
this.interrupt();
this.closeThreadPool();
}
}

View File

@ -0,0 +1,36 @@
package com.platform.check.actuator.parsing;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.concurrent.ThreadFactory;
import org.springframework.util.CustomizableThreadCreator;
/**
* 自定义线程工厂
* @author 86187
*
*/
public class CustomThreadFactory extends CustomizableThreadCreator implements ThreadFactory{
private static final long serialVersionUID = 1L;
private String threadNamePrefix;
private UncaughtExceptionHandler handler;
public CustomThreadFactory(UncaughtExceptionHandler handler,String threadNamePrefix) {
this.handler = handler;
this.threadNamePrefix = threadNamePrefix;
}
public void setThreadNamePrefix() {
super.setThreadNamePrefix(threadNamePrefix);
}
@Override
public Thread newThread(Runnable runnable) {
Thread thread = new Thread(runnable);
thread.setUncaughtExceptionHandler(handler);
return thread;
}
}

View File

@ -0,0 +1,391 @@
package com.platform.check.actuator.parsing;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
import com.platform.check.enums.*;
import com.platform.common.exception.BusinessException;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.platform.check.actuator.progress.ProgressEvent;
import com.platform.check.actuator.progress.ProgressQueue;
import com.platform.check.domain.CheckDocument;
import com.platform.check.domain.CheckPaperLibrary;
import com.platform.check.domain.CheckRepeatedDocument;
import com.platform.check.domain.CheckReport;
import com.platform.check.domain.CheckReportSimilarFile;
import cn.textcheck.CheckManager;
import cn.textcheck.engine.checker.CheckTask;
import cn.textcheck.engine.pojo.CheckResult;
import cn.textcheck.engine.pojo.LocalPaperLibrary;
import cn.textcheck.engine.pojo.Pair;
import cn.textcheck.engine.pojo.Paper;
import cn.textcheck.engine.pojo.PaperSeg;
import cn.textcheck.engine.report.Reporter;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
/**
* WORD解析执行器
* @author 86187
*
*/
public abstract class DocParsingActurtor extends BaseActurtor{
/** 单步骤占比 */
protected Double stepProportion;
/** XINCHECK查重任务 */
protected CheckTask checkTask;
/** 查重待对比文件 */
private List<Paper> papers;
/** 查重待对比文件库 */
private LocalPaperLibrary paperLibrary;
/**
* 存储文件id文件名称
*/
protected Map<String,String> fileIdAndNameMap = Maps.newHashMap();
/**
* 计算任务步骤占比
*/
@Override
protected abstract void computationStepProportion();
/**
* 处理对比库及待对比文件
* @throws IOException
* @throws Exception
*/
protected void handleCheckFile() throws IOException{
if(CheckTaskType.BATCH_CHECK.getValue().equals(this.checkDocTask.getCheckType())) {
//处理批次查重文档
this.batchCheck();
}else{
//处理历史查重文档
this.historyCheck();
}
//保存文档到历史库
this.saveHistoryLibrary();
}
/**
* 保存本次任务报告信息
* @param reporters
*/
protected void saveReporters(List<Reporter> reporters) throws Exception{
for(Reporter reporter : reporters) {
//保存报告信息
String reporterId = this.createCheckReport(reporter);
//保存相似文件列表
this.createSimilarFile(reporter,reporterId);
//以Parper id为key文档id为value
Map<String, String> copyPaperIdMap = getCopyPaperIdMap(reporter);
List<CheckResult> checkResults = reporter.getCheckResults();
checkResults.forEach(result->{
result.getCopySegMap().forEach((paperSeg,paperSegs)->{
//保存原文档涉及重复内容文本
String sourceFileId = reporter.getPaper().getId();
String checkDocumentId = this.createCheckDocument(paperSeg,reporterId,sourceFileId);
paperSegs.forEach(t->{
//保存对比库文档涉及重复内容文本
String copyFileId = copyPaperIdMap.get(t.getPaperId());
this.createCheckRepeatedDocument(checkDocumentId, t,reporterId,copyFileId);
});
});
});
ProgressEvent middleEvent = new ProgressEvent(this.checkDocTask.getId(),this.project.getId(),this.stepProportion,false);
ProgressQueue.getInstance().offer(middleEvent);
}
}
/**
* 历史查重
* @throws IOException
* @throws Exception
*/
private void historyCheck() throws IOException {
List<Paper> papers = getPapers();
List<Paper> historyPapers = getHistoryLibrary();
if(CollectionUtils.isNotEmpty(papers) && CollectionUtils.isNotEmpty(historyPapers)) {
this.papers = papers;
this.paperLibrary = LocalPaperLibrary.load(historyPapers);
}
}
/**
* 批量查重
* @throws IOException
* @throws Exception
*/
private void batchCheck() throws IOException{
List<Paper> papers = getPapers();
if(CollectionUtils.isNotEmpty(papers)) {
this.papers = papers;
this.paperLibrary = LocalPaperLibrary.load(papers);
}
}
/**
* 获取待查文件
* @return
* @throws IOException
*/
protected abstract List<Paper> getPapers() throws IOException;
/**
* 获取历史库
* @return
* @throws IOException
* @throws Exception
*/
private List<Paper> getHistoryLibrary() throws IOException{
List<Paper> papers = Lists.newArrayList();
List<CheckPaperLibrary> hietoryLribrary = this.checkPaperLibraryService.list();
for(CheckPaperLibrary checkPaperLibrary: hietoryLribrary) {
File file = new File(checkPaperLibrary.getFilePath());
if(file.exists() && file.isFile() && file.length() > 0) {
Paper paper = Paper.load(file);
paper.setId(checkPaperLibrary.getFileId());
papers.add(paper);
//把文件id和文件名称存入map供后续使用03
this.fileIdAndNameMap.put(checkPaperLibrary.getFileId(),file.getName());
}
}
return papers;
}
/**
* 保存文档到历史库
*/
protected abstract void saveHistoryLibrary();
/**
* 启动对比任务
* @throws InterruptedException
* @throws IOException
*/
protected List<Reporter> startCheckTask() throws InterruptedException, IOException{
if(CollectionUtils.isNotEmpty(papers) && Objects.nonNull(paperLibrary)) {
CheckTask.Builder builder = CheckManager.INSTANCE.getCheckTaskBuilder();
builder.setUid(checkDocTask.getId());
builder.addCheckPaper(papers);
builder.addLibrary(paperLibrary);
//添加过滤词
if(FilterWordType.TEXT_FILTER.getValue().equals(checkDocTask.getFilterWordType())) {
if (StringUtils.isNotBlank(checkDocTask.getFilterWordText())){
List<String> words = Arrays.asList(checkDocTask.getFilterWordText().split("\r\n"));
builder.addWhiteWord(words);
}
}else if(FilterWordType.FILE_FILTER.getValue().equals(checkDocTask.getFilterWordType())) {
String filePath = checkDocTask.getFilterWordFilePath();
File file = new File(filePath);
if (!file.exists()){
throw new BusinessException("所选过滤词文件不存在,请重新上传!");
}
List<String> words = new ArrayList<>();
if (filePath.endsWith(FileSuffix.WORD_DOC.getValue())){
words = this.readDOCParagraphs(filePath);
}else if(filePath.endsWith(FileSuffix.WORD_DOCX.getValue())){
words = this.readDOCXParagraphs(filePath);
}
builder.addWhiteWord(words);
}
this.checkTask = builder.build();
checkTask.start();
checkTask.join();
List<Reporter> reporters = checkTask.getReporters();
if(CollectionUtils.isNotEmpty(reporters)) {
return reporters;
}
}
return Collections.emptyList();
}
public List<String> readDOCParagraphs(String filePath) throws IOException{
List<String> result = new ArrayList<>();
try (FileInputStream fis = new FileInputStream(new File(filePath));
HWPFDocument doc = new HWPFDocument(fis);){
// 段落
Range range = doc.getRange();
for (int i=0;i<range.numParagraphs();i++){
result.add(range.getParagraph(i).text());
}
} catch (IOException e) {
throw e;
}
return result;
}
public List<String> readDOCXParagraphs(String filePath) throws IOException{
List<String> result = new ArrayList<>();
try (FileInputStream fis = new FileInputStream(new File(filePath));
XWPFDocument doc = new XWPFDocument(fis);){
// 段落
List<XWPFParagraph> paragraphs = doc.getParagraphs();
for (XWPFParagraph paragraph:paragraphs) {
result.add(paragraph.getText());
}
} catch (IOException e) {
throw e;
}
return result;
}
@Override
public void destroy() {
if(null != this.checkTask && this.checkTask.isAlive()) {
this.checkTask.interrupt();
}
}
/**
* 创建报告信息
* @param reporter
* @return
*/
private String createCheckReport(Reporter reporter) {
CheckReport checkReport = new CheckReport();
checkReport.setCheckTaskId(this.checkDocTask.getId());
checkReport.setCheckFileId(reporter.getPaper().getId());
checkReport.setSimilarity(reporter.getCopyRate());
checkReport.setRepeatWords(reporter.getCopyWords());
checkReport.setTotalWords(reporter.getPaper().length());
checkReport.setSuspectedMaxRepeatLength(reporter.getMaxSectionCopyWords());
checkReport.setSuspectedMinRepeatLength(reporter.getMinSectionCopyWords());
checkReport.setTotalStructNumber(reporter.getSectionNum());
checkReport.setSuspectedStructNumber(reporter.getMaxSinglePaperCopyRate());
checkReport.setForeRepeatNumber(reporter.getFrontCopyWords());
checkReport.setBackRepeatNumber(reporter.getEndCopyWords());
checkReportService.create(checkReport);
return checkReport.getId();
}
/**
* 创建原文档涉及重复内容数据
* @param paperSeg
* @param reporterId
* @return
*/
private String createCheckDocument(PaperSeg paperSeg,String reporterId,String fileId) {
//查询此文本在查重文档所属页码,此方法内部会判断只有word文档才可查询txtimg单文件不查询
String pageNum = this.matchPhraseQueryForIds(fileId,paperSeg.getText());
//保存待查文档内容信息
CheckDocument doc = new CheckDocument();
doc.setCheckTaskId(this.checkDocTask.getId());
doc.setCheckReportId(reporterId);
doc.setFrontContent(paperSeg.getFrontContext());
doc.setDocContent("\n"+paperSeg.getText()+"\n");
doc.setBackContent(paperSeg.getBackContext());
doc.setRepeatedWords(StringUtils.replace(paperSeg.getText(),"","").length());
doc.setPageNum(pageNum);
doc.setSort(paperSeg.getStartIndex());
checkDocumentService.create(doc);
return doc.getId();
}
/**
* 创建对比库文档涉及重复内容数据
* @param checkDocumentId
* @param paperSeg
* @param reporterId
*/
private void createCheckRepeatedDocument(String checkDocumentId,PaperSeg paperSeg,String reporterId,String fileId) {
//查询此文本在查重文档所属页码,此方法内部会判断只有word文档才可查询txtimg单文件不查询
String pageNum = this.matchPhraseQueryForIds(fileId,paperSeg.getText());
//保存文档库重复内容信息
CheckRepeatedDocument repeatedDoc = new CheckRepeatedDocument();
repeatedDoc.setCheckDocumentId(checkDocumentId);
repeatedDoc.setCheckReportId(reporterId);
repeatedDoc.setCheckFileId(fileId);
repeatedDoc.setFrontContent(paperSeg.getFrontContext());
repeatedDoc.setDocContent(paperSeg.getText());
repeatedDoc.setBackContent(paperSeg.getBackContext());
repeatedDoc.setPageNum(pageNum);
repeatedDoc.setSort(paperSeg.getStartIndex());
checkRepeatedDocumentService.create(repeatedDoc);
}
/**
* 查询此文本在查重文档所属页码,此方法内部会判断只有word文档才可查询txtimg单文件不查询
* @param indexName
* @param content
* @return
*/
private String matchPhraseQueryForIds(String fileId,String content) {
String pageNum = "";
if(this.fileIdAndNameMap.containsKey(fileId)) {
String fileName = this.fileIdAndNameMap.get(fileId);
if(fileName.endsWith(FileSuffix.WORD_DOCX.getValue()) ||
fileName.endsWith(FileSuffix.WORD_DOC.getValue())) {
List<String> pageNums = elasticsearchService.matchPhraseQueryForIds(fileId,"content",content);
if(CollectionUtils.isNotEmpty(pageNums)) {
List<Integer> pageNumsToIntList = pageNums.stream().map(pn->Integer.parseInt(pn)).collect(Collectors.toList());
Collections.sort(pageNumsToIntList,new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
});
pageNum = pageNumsToIntList.stream().map(Object::toString).collect(Collectors.joining(","));
}
}
}
return pageNum;
}
/**
* 保存相似文献列表
* @param reporter
* @param reporterId
*/
private void createSimilarFile(Reporter reporter,String reporterId) {
List<CheckReportSimilarFile> similarFileList = Lists.newArrayList();
List<Pair<Paper, Integer>> paperCopyWordsList = reporter.getMaxSinglePaperCopyWordsList();
if(CollectionUtils.isNotEmpty(paperCopyWordsList)) {
paperCopyWordsList.forEach(copyPaper->{
CheckReportSimilarFile similarFile = new CheckReportSimilarFile();
similarFile.setCheckReportId(reporterId);
similarFile.setCheckFileId(copyPaper.getKey().getId());
BigDecimal cardinalNumber = new BigDecimal("100");
BigDecimal totalWords = new BigDecimal(reporter.getPaper().length());
BigDecimal cpoyWords = new BigDecimal(copyPaper.getValue());
BigDecimal similarProportion = cpoyWords.divide(totalWords,3,RoundingMode.HALF_UP);
BigDecimal execResult = similarProportion.multiply(cardinalNumber).setScale(1);
similarFile.setSimilarProportion(execResult.doubleValue());
similarFile.setCopyWords(copyPaper.getValue());
similarFileList.add(similarFile);
});
}
if(CollectionUtils.isNotEmpty(similarFileList)) {
checkReportSimilarFileService.saveBatch(similarFileList);
}
}
/**
* 获取比对库中Paper的key->paperid,value->文档id文件id
* @param reporter
* @return
*/
private Map<String,String> getCopyPaperIdMap(Reporter reporter){
Map<String,String> copyPaperIdMap = new HashMap<>();
reporter.getCheckResults().forEach(result->{
result.getCopyDetailMap().forEach((key,val)->{
if(!copyPaperIdMap.containsKey(key)) {
copyPaperIdMap.put(key,val.getKey().getId());
}
});
});
return copyPaperIdMap;
}
}

View File

@ -0,0 +1,185 @@
package com.platform.check.actuator.parsing;
import java.awt.image.BufferedImage;
import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import javax.imageio.ImageIO;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.util.StopWatch;
import com.platform.check.actuator.progress.ProgressEvent;
import com.platform.check.actuator.progress.ProgressQueue;
import com.platform.check.domain.CheckFile;
import com.platform.check.enums.CheckStatus;
import com.platform.common.util.ImageUtil;
import com.platform.common.util.OkHttpClientUtil;
import com.platform.common.util.OkHttpFormDataBodyForFile;
import lombok.extern.slf4j.Slf4j;
/**
* Image文件解析执行器解析本次任务所以文件
* @author 86187
*
*/
@Slf4j
public class ImgParsingActurtor extends BaseActurtor implements Thread.UncaughtExceptionHandler{
/** 图片校验单步骤占比 */
private Double checkStepProportion;
/** 图片解析单步骤占比 */
private Double parseingStepProportion;
@Override
protected void computationStepProportion() {
BigDecimal totalStepBg = new BigDecimal(checkFiles.size());
//计算校验图片步骤单步占比
BigDecimal checkTotalProportion = new BigDecimal("10");
BigDecimal checkStepProportion = checkTotalProportion.divide(totalStepBg,2,RoundingMode.HALF_UP);
this.checkStepProportion = checkStepProportion.doubleValue();
//计算图片识别步骤单步占比
BigDecimal parseingTotalProportion = new BigDecimal("90");
BigDecimal parseingStepProportion = parseingTotalProportion.divide(totalStepBg,2,RoundingMode.HALF_UP);
this.parseingStepProportion = parseingStepProportion.doubleValue();
}
@Override
public void run() {
try {
//初始化线程池
super.initThreadPool(super.poolName,properties.getThreadPoolProp().getDocExecCorePoolSize(),this);
//计算任务步骤占比
this.computationStepProportion();
//检查图片
this.checkImgs();
//解析图片
this.parseImgs();
//解析识别后的word
this.parsingWord();
} catch (Exception e) {
//任务执行失败修改任务状态
checkDocTaskService.updateProgressStatus(checkDocTask.getId(),project.getId(),CheckStatus.FAIL.getCode(),null);
log.error("{}任务查重失败,原因:{}",super.project.getProcurementContent(),e.getMessage());
super.stopTask();
taskCounter.decrementAndGet();
taskCounter.notifyLock();
e.printStackTrace();
}
}
/**
* 解析PDF图片
* @throws Exception
*/
private void checkImgs() throws Exception {
if(CollectionUtils.isNotEmpty(checkFiles)) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
for(CheckFile checkFile : checkFiles) {
if(super.isStop) {
return;
}
String imgPath = getFilePath(checkFile);
File imgFile = new File(imgPath);
BufferedImage bufferedImage = ImageIO.read(imgFile);
//如果图片宽度大于800需要压缩否则图片识别服务会识别不出来报错
if(bufferedImage.getWidth()>IMG_WIDTH) {
ImageUtil.resize(bufferedImage,imgFile,800, 1F);
}
//修改进度
ProgressEvent event = new ProgressEvent(checkDocTask.getId(),project.getId(),(checkStepProportion),false);
ProgressQueue.getInstance().offer(event);
}
stopWatch.stop();
log.info("{}查重任务图片校验完成,时间为:{}秒",project.getProcurementContent(),stopWatch.getTotalTimeSeconds());
}
}
/**
* 解析图片
* @param fileList
* @throws InterruptedException
*/
private void parseImgs() throws Exception{
if(CollectionUtils.isNotEmpty(checkFiles) && !super.isStop) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
String url = "http://"+properties.getDockerServer().getIp()+":"+properties.getDockerServer().getPort()+"/"+properties.getDockerServer().getRequestAddress();
taskLatch = new CountDownLatch(checkFiles.size());
for (CheckFile checkFile : checkFiles) {
poolExecutor.execute(()-> {
//获取图片路径
String filePath = getFilePath(checkFile);
File file = new File(filePath);
try {
//构建请求体
OkHttpFormDataBodyForFile param = new OkHttpFormDataBodyForFile();
param.setParamName("files");
param.setFileName(UUID.randomUUID().toString()+checkFile.getFileName());
param.setMediaType("image/jpg");
param.setFile(file);
//设置解析后的word文件保存路径
String wordFilePath = handleWordPath(checkFile);
//上传图片并下载
OkHttpClientUtil.doPostForFileFormData(url, param,file,wordFilePath);
} catch (Exception e) {
e.printStackTrace();
} finally {
//修改进度
ProgressEvent event = new ProgressEvent(checkDocTask.getId(),project.getId(),(parseingStepProportion),false);
ProgressQueue.getInstance().offer(event);
taskLatch.countDown();
}
});
}
try {
taskLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
stopWatch.stop();
log.info("{}查重任务图片识别完成,时间为:{}秒",project.getProcurementContent(),stopWatch.getTotalTimeSeconds());
}
}
/**
* 对比识别后的word
*/
private void parsingWord() throws Exception{
if(super.isStop) {
return;
}
BaseActurtor wordParsingThread = new ImgWordParsingActurtor();
wordParsingThread.init(
checkDocTask,
checkDocumentService,
checkRepeatedDocumentService,
checkReportService,
checkDocTaskService,
checkReportSimilarFileService,
checkFiles,
properties,
checkPaperLibraryService,
project,
elasticsearchService);
wordParsingThread.setName("word-parsing-thread");
wordParsingThread.setUncaughtExceptionHandler(this);
wordParsingThread.start();
}
@Override
public void uncaughtException(Thread t, Throwable e) {
//任务执行失败修改任务状态
log.error("{}任务查重失败,原因:{}",super.project.getProcurementContent(),e.getMessage());
checkDocTaskService.updateProgressStatus(checkDocTask.getId(),project.getId(),CheckStatus.FAIL.getCode(),null);
super.stopTask();
taskCounter.decrementAndGet();
taskCounter.notifyLock();
e.printStackTrace();
}
}

View File

@ -0,0 +1,110 @@
package com.platform.check.actuator.parsing;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import com.google.common.collect.Lists;
import com.platform.check.actuator.progress.ProgressEvent;
import com.platform.check.actuator.progress.ProgressQueue;
import com.platform.check.domain.CheckFile;
import com.platform.check.enums.FileSuffix;
import com.platform.check.enums.PDFParsingSectionPath;
import cn.textcheck.engine.pojo.Paper;
import cn.textcheck.engine.report.Reporter;
/**
* img识别后所属word文档解析
* @author 86187
*
*/
public class ImgWordParsingActurtor extends DocParsingActurtor{
/**
* 计算任务步骤占比
*/
@Override
protected void computationStepProportion() {
//计算word对比步骤单步占比
BigDecimal totalProportionBg = new BigDecimal("10");
BigDecimal totalStepBg = new BigDecimal(checkFiles.size()+2);
BigDecimal result = totalProportionBg.divide(totalStepBg,2,RoundingMode.HALF_UP);
super.stepProportion = result.doubleValue();
}
@Override
public void run(){
try {
//计算任务步骤占比
computationStepProportion();
//更新任务进度
ProgressEvent fontEvent = new ProgressEvent(this.checkDocTask.getId(),this.project.getId(),stepProportion,false);
ProgressQueue.getInstance().offer(fontEvent);
//处理待对比文件及对比库
super.handleCheckFile();
//启动任务返回报告
List<Reporter> reporters = super.startCheckTask();
super.saveReporters(reporters);
//修改最终进度
ProgressEvent backEvent = new ProgressEvent(this.checkDocTask.getId(),this.project.getId(),this.stepProportion,true);
ProgressQueue.getInstance().offer(backEvent);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取待查文件
* @return
* @throws IOException
*/
@Override
protected List<Paper> getPapers() throws IOException{
List<Paper> papers = Lists.newArrayList();
for(CheckFile checkFile : super.checkFiles) {
StringBuilder filePath = new StringBuilder();
filePath.append(properties.getTaskFilePath());
filePath.append(File.separator);
filePath.append(checkDocTask.getId());
filePath.append(File.separator);
filePath.append(checkFile.getMd5Value());
filePath.append(File.separator);
filePath.append(PDFParsingSectionPath.WORD.getValue());
filePath.append(File.separator);
String imgName = checkFile.getFileName().substring(0, checkFile.getFileName().indexOf("."))+FileSuffix.WORD_DOCX.getValue();
filePath.append(imgName);
File file = new File(filePath.toString());
if(file.exists() && file.isFile() && file.length() > 0) {
Paper paper = Paper.load(file);
paper.setId(checkFile.getId());
papers.add(paper);
}
}
return papers;
}
/**
* 保存文档到历史库
*/
@Override
protected void saveHistoryLibrary() {
for(CheckFile checkFile : this.checkFiles) {
StringBuilder filePath = new StringBuilder();
filePath.append(properties.getTaskFilePath());
filePath.append(File.separator);
filePath.append(checkDocTask.getId());
filePath.append(File.separator);
filePath.append(checkFile.getMd5Value());
filePath.append(File.separator);
filePath.append(PDFParsingSectionPath.WORD.getValue());
filePath.append(File.separator);
String imgName = checkFile.getFileName().substring(0, checkFile.getFileName().indexOf("."))+FileSuffix.WORD_DOCX.getValue();
filePath.append(imgName);
File file = new File(filePath.toString());
if(file.exists() && file.isFile() && file.length() > 0) {
this.checkPaperLibraryService.create(this.checkDocTask.getId(),checkFile.getId(),filePath.toString());
}
}
}
}

View File

@ -0,0 +1,459 @@
package com.platform.check.actuator.parsing;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.platform.common.elastic.ElasticsearchService;
import com.platform.common.enums.RedisKeyEnum;
import com.platform.common.redis.RedisUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.openxml4j.util.ZipSecureFile;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.util.StopWatch;
import com.deepoove.poi.xwpf.NiceXWPFDocument;
import com.platform.check.actuator.model.PDFPageParsingStatus;
import com.platform.check.actuator.progress.ProgressEvent;
import com.platform.check.actuator.progress.ProgressQueue;
import com.platform.check.domain.CheckDocTask;
import com.platform.check.domain.CheckFile;
import com.platform.check.enums.FileSuffix;
import com.platform.check.enums.PDFImageParsingFlag;
import com.platform.check.service.CheckDocTaskService;
import com.platform.common.properties.SystemProperties;
import com.platform.common.util.FileUtils;
import com.platform.common.util.OkHttpClientUtil;
import com.platform.common.util.OkHttpFormDataBodyForFile;
import com.platform.project.domain.CheckProject;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class PDFParsingActurtor extends BaseActurtor{
/** 存储解析过程中图片和文档路径 */
private String sectionPath;
/** 存储解析完成后的完整文档路径 */
private String wordPath;
/** 中间部分单步骤占比 */
private Double stepProportion;
private CheckFile checkFile;
private CountDownLatch taskLatch;
private int totalImgs;
private String redisKey;
private final static int BATCH_MERGE_WORD_NUM = 40;
private final static String ELEMENT_WORD_PREFIX = "ElementWord";
public void init(
CheckDocTask checkDocTask,
CheckFile checkFile,
CheckDocTaskService checkDocTaskService,
SystemProperties properties,
CountDownLatch taskLatch,
RedisUtil redisUtil,
int totalImgs,
CheckProject project,
ElasticsearchService elasticsearchService) {
super.init(
checkDocTask,
checkDocTaskService,
properties,
redisUtil,
project,
elasticsearchService);
this.checkFile = checkFile;
this.totalImgs = totalImgs;
this.taskLatch = taskLatch;
this.redisKey = RedisKeyEnum.PARSING_PDF_CACHE.getCode(checkDocTask.getId(),checkFile.getId());
//初始化pdf文件图片和合并word存放路径
this.sectionPath = handleSectionPath(checkFile);
this.wordPath = handleWordPath(checkFile);
//获取机器可用核心数
int maximumPoolSize = Runtime.getRuntime().availableProcessors();
//初始化线程池
ThreadFactory threadFactory = new CustomizableThreadFactory("pdf-img-parsing-pool");
super.poolExecutor = new ThreadPoolExecutor(properties.getThreadPoolProp().getImgExecCorePoolSize(),maximumPoolSize,5, TimeUnit.SECONDS, new LinkedBlockingQueue<>(),threadFactory);
}
@Override
protected void computationStepProportion() {
// 表示该阶段占比多少
BigDecimal totalProportion = new BigDecimal("80");
// 计算文字解析步骤单步占比
BigDecimal totalStepBg = new BigDecimal(totalImgs);
BigDecimal result = totalProportion.divide(totalStepBg,2,RoundingMode.HALF_UP);
this.stepProportion = result.doubleValue();
}
@Override
public void run() {
try {
//计算任务步骤占比
this.computationStepProportion();
//封装图片请求docker服务生成word,并返回路径
StopWatch imgStopWatch = new StopWatch();
imgStopWatch.start();
this.uploadPDFImages();
imgStopWatch.stop();
log.info("{}文字识别完毕,耗时:{}秒",checkFile.getFileName(),imgStopWatch.getTotalTimeSeconds());
//合并word文件
StopWatch wordStopWatch = new StopWatch();
wordStopWatch.start();
this.mergeWord();
wordStopWatch.stop();
log.info("{}合并封装word文件完毕耗时{}秒",checkFile.getFileName(),wordStopWatch.getTotalTimeSeconds());
} catch (Exception e) {
throw new RuntimeException(e);
}finally {
//关闭线程池
closeThreadPool();
taskLatch.countDown();
}
}
/**
* 梳理需解析后的图片文件集合并上传到docker文字识别服务
* 此服务解析完成后返回文件流
* @throws Exception
*/
private void uploadPDFImages() throws Exception {
String url = "http://"+properties.getDockerServer().getIp()+":"+properties.getDockerServer().getPort()+"/"+properties.getDockerServer().getRequestAddress();
//处理该文件图片处理的缓存信息如果此图片已解析完成则删除缓存后续不重复解析
List<String> imgStatusJsonCacheList = redisUtil.lRange(redisKey,0,-1);
List<PDFPageParsingStatus> imgStatusCacheList = imgStatusJsonCacheList.stream()
.map(m->JSON.parseObject(m,PDFPageParsingStatus.class)).collect(Collectors.toList());
for(int i=imgStatusCacheList.size()-1;i>=0;i--) {
if (PDFImageParsingFlag.IMG_OCR.getValue().equals(imgStatusCacheList.get(i).getStatus())) {
imgStatusCacheList.remove(i);
}
}
CountDownLatch taskLatch = new CountDownLatch(imgStatusCacheList.size());
for (int i=imgStatusCacheList.size()-1;i>=0;i--) {
PDFPageParsingStatus parsingStatus = imgStatusCacheList.get(i);
// 此状态标记为解析成功跳出本次循环
if (PDFImageParsingFlag.IMG_OCR.getValue().equals(parsingStatus.getStatus())) {
taskLatch.countDown();
log.info("{}图片已完成识别,已存在相应文档",parsingStatus.getFilePath());
continue;
}
final int currPage = i;
//识别图片并把识别结果保存到ES
ImgOCR imgocr = new ImgOCR();
imgocr.init(parsingStatus,url,currPage,taskLatch);
poolExecutor.execute(imgocr);
}
taskLatch.await();
}
/**
* 合并word
* @throws Exception
*/
private void mergeWord() throws Exception {
//收集下载后的word文件
File wordFilePath = new File(this.sectionPath);
File[] wordFiles = wordFilePath.listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
//本判断只有上次查重失败会涉及若上次查重失败则删除此文件历史合并的word重新合并
if(file.getName().startsWith(ELEMENT_WORD_PREFIX)) {
file.delete();
}else {
if(file.getName().endsWith(FileSuffix.WORD_DOCX.getValue())) {
return true;
}
}
return false;
}
});
if(ArrayUtil.isNotEmpty(wordFiles)) {
//把word数组转为集合
List<File> wordFileList = CollUtil.toList(wordFiles);
//对文件进行排序
Collections.sort(wordFileList,new Comparator<File>() {
@Override
public int compare(File file1, File file2) {
int fileName1Index = Integer.parseInt(file1.getName().substring(file1.getName().indexOf(StringPool.DASH)+1,file1.getName().indexOf(StringPool.DOT)));
int fileName2Index = Integer.parseInt(file2.getName().substring(file2.getName().indexOf(StringPool.DASH)+1,file2.getName().indexOf(StringPool.DOT)));
return Integer.compare(fileName1Index, fileName2Index);
}
});
//存储节点word文件
List<File> elementFiles = new ArrayList<>();
//计算合并word批次数
int num;
if(wordFileList.size() <= BATCH_MERGE_WORD_NUM) {
num = 1;//如果word数量小于40则一次合并
}else {
num = wordFileList.size()%BATCH_MERGE_WORD_NUM==0?wordFileList.size()/BATCH_MERGE_WORD_NUM:wordFileList.size()/BATCH_MERGE_WORD_NUM+1;
}
CountDownLatch taskLatch = new CountDownLatch(num);
for(int i=1;i<=num;i++) {
int start = (i-1)*BATCH_MERGE_WORD_NUM;
int end;
if(i==num) {
end = wordFileList.size();
}else {
//因为subList包含头部不包含尾部所以这里其实end值是i*40-1
end = i*BATCH_MERGE_WORD_NUM;
}
StringBuilder elementFilePath = new StringBuilder();
elementFilePath.append(this.sectionPath);
elementFilePath.append(File.separator);
elementFilePath.append(ELEMENT_WORD_PREFIX);
elementFilePath.append(StringPool.DASH);
elementFilePath.append(start);
elementFilePath.append(StringPool.DASH);
elementFilePath.append(end);
elementFilePath.append(FileSuffix.WORD_DOCX.getValue());
File elementFile = new File(elementFilePath.toString());
if(!elementFile.exists()) {
elementFile.createNewFile();
}
elementFiles.add(elementFile);
try {
poolExecutor.execute(new MergeWord(elementFile,start,end,wordFileList,taskLatch));
} catch (Exception e2) {
continue;
}
}
//等待所有批次word合并线程执行完毕
taskLatch.await();
Resource resource = new ClassPathResource("/templates/template.docx");
//执行最后合并
ZipSecureFile.setMinInflateRatio(-1.0d);
NiceXWPFDocument mainDoc = new NiceXWPFDocument(resource.getInputStream());
List<NiceXWPFDocument> docs = new ArrayList<>(elementFiles.size());
NiceXWPFDocument mergeResult = null;
try {
for(File docFile : elementFiles) {
if(docFile.exists() && docFile.isFile() && docFile.length()>0) {
docs.add(new NiceXWPFDocument(Files.newInputStream(docFile.toPath())));
}
}
XWPFParagraph paragraph = mainDoc.createParagraph();
XWPFRun xwpfRun = paragraph.createRun();
mergeResult = mainDoc.merge(docs,xwpfRun);
this.transferResultWordToLocal(mergeResult);
} finally {
if(null != mainDoc) {
mainDoc.close();
}
if(CollectionUtils.isNotEmpty(docs)) {
docs.forEach(doc->{
try {
doc.close();
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
}else {
Resource resource = new ClassPathResource("/templates/template.docx");
NiceXWPFDocument mainDoc = new NiceXWPFDocument(resource.getInputStream());
this.transferResultWordToLocal(mainDoc);
}
}
/**
* 保存word到本地
* @param mergeResult
* @throws Exception
*/
private void transferResultWordToLocal(NiceXWPFDocument mergeResult) throws Exception {
String fileName = this.checkFile.getFileName().replace(FileSuffix.PDF.getValue(),FileSuffix.WORD_DOCX.getValue());
String filePath = this.wordPath+File.separator+fileName;
FileUtils.createFile(filePath);
File wordFile = new File(filePath);
OutputStream out = null;
try{
out = new FileOutputStream(wordFile);
mergeResult.write(out);
}finally {
if(null != mergeResult) {
try {
mergeResult.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(null != out) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 识别图片并把识别结果保存到ES
* @author 86187
*
*/
private class ImgOCR implements Runnable{
private CountDownLatch taskLatch;
private String url;
private PDFPageParsingStatus parsingStatus;
private Integer currPage;
public void init(PDFPageParsingStatus parsingStatus,String url,Integer currPage,CountDownLatch taskLatch) {
this.parsingStatus = parsingStatus;
this.url = url;
this.currPage = currPage;
this.taskLatch = taskLatch;
}
@Override
public void run() {
File file = new File(parsingStatus.getFilePath());
try {
//构建请求体
OkHttpFormDataBodyForFile param = new OkHttpFormDataBodyForFile();
param.setParamName("files");
param.setFileName(file.getName());
param.setMediaType("image/jpg");
param.setFile(file);
//上传图片并下载
OkHttpClientUtil.doPostForFileFormData(url, param,file,sectionPath);
// redis中标记为文件解析成功
parsingStatus.setStatus(PDFImageParsingFlag.IMG_OCR.getValue());
redisUtil.lUpdateIndex(redisKey,currPage,JSON.toJSONString(parsingStatus));
log.info("图片识别成功,地址:{}",file.getAbsolutePath());
} catch (Exception e) {
// redis中标记为文件解析失败
parsingStatus.setStatus(PDFImageParsingFlag.PARSING_FAIL.getValue());
redisUtil.lUpdateIndex(redisKey,currPage,JSON.toJSONString(parsingStatus));
e.printStackTrace();
} finally {
//把解析后的word内容存储到ES
String fileName = file.getName().substring(0,file.getName().lastIndexOf("."))+FileSuffix.WORD_DOCX.getValue();
String filePath = sectionPath+File.separator+fileName;
saveWordContentToES(checkFile.getId(),parsingStatus.getPageNum(),filePath);
//修改进度
ProgressEvent event = new ProgressEvent(checkDocTask.getId(),project.getId(),(stepProportion),false);
ProgressQueue.getInstance().offer(event);
taskLatch.countDown();
}
}
}
/**
* word合并内部类
* @author 86187
*
*/
private class MergeWord implements Runnable{
private CountDownLatch taskLatch;
private List<File> files;
private File elementFile;
private int start;
private int end;
private MergeWord(File elementFile,int start,int end,List<File> files,CountDownLatch taskLatch) {
this.elementFile = elementFile;
this.start = start;
this.end = end;
this.files = files;
this.taskLatch = taskLatch;
}
@Override
public void run() {
OutputStream out = null;
NiceXWPFDocument mergeResult = null;
NiceXWPFDocument mainDoc = null;
List<NiceXWPFDocument> docs = new ArrayList<>();
try {
List<File> docFiles = this.files.subList(start, end);
if(CollUtil.isNotEmpty(docFiles)) {
Resource resource = new ClassPathResource("/templates/template.docx");
ZipSecureFile.setMinInflateRatio(-1.0d);
mainDoc = new NiceXWPFDocument(resource.getInputStream());
for(File docFile : docFiles) {
if(docFile.exists() && docFile.isFile() && docFile.length()>0) {
FileInputStream fileInputStream = new FileInputStream(docFile);
docs.add(new NiceXWPFDocument(fileInputStream));
}
}
out = new FileOutputStream(elementFile);
XWPFParagraph paragraph = mainDoc.createParagraph();
XWPFRun xwpfRun = paragraph.createRun();
mergeResult = mainDoc.merge(docs,xwpfRun);
mergeResult.write(out);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(null != mainDoc) {
try {
mainDoc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(CollectionUtils.isNotEmpty(docs)) {
docs.forEach(doc->{
try {
doc.close();
} catch (IOException e) {
e.printStackTrace();
}
});
}
if(null != mergeResult) {
try {
mergeResult.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(null != out) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
taskLatch.countDown();
}
}
}
}

View File

@ -0,0 +1,289 @@
package com.platform.check.actuator.parsing;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import javax.imageio.ImageIO;
import javax.imageio.stream.FileImageOutputStream;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPageTree;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;
import com.alibaba.fastjson.JSON;
import com.platform.check.actuator.model.PDFPageParsingStatus;
import com.platform.check.actuator.progress.ProgressEvent;
import com.platform.check.actuator.progress.ProgressQueue;
import com.platform.check.domain.CheckDocTask;
import com.platform.check.domain.CheckFile;
import com.platform.check.enums.CheckStatus;
import com.platform.check.enums.PDFImageParsingFlag;
import com.platform.common.enums.RedisKeyEnum;
import com.platform.common.util.ImageUtil;
import com.platform.project.domain.CheckProject;
import lombok.extern.slf4j.Slf4j;
/**
* PDF文件解析执行器解析本次任务所以文件
* @author 86187
*
*/
@Slf4j
public class PDFParsingGroupActurtor extends BaseActurtor implements Thread.UncaughtExceptionHandler{
/** 前部分单步骤占比 */
private Double stepProportion;
/** 文字识别服务要求图片最大宽度为800 */
private final static int IMG_WIDTH = 800;
/** 统计本次任务共多少张图片 */
private int totalImgs=0;
@Override
protected void computationStepProportion() {
//计算图片解析步骤单步占比
BigDecimal totalProportion = new BigDecimal("10");
BigDecimal totalStepBg = new BigDecimal(checkFiles.size());
BigDecimal result = totalProportion.divide(totalStepBg,2,RoundingMode.HALF_UP);
this.stepProportion = result.doubleValue();
}
@Override
public void run() {
try {
//初始化线程池
super.initThreadPool(super.poolName,properties.getThreadPoolProp().getDocExecCorePoolSize(),this);
//计算任务步骤占比
this.computationStepProportion();
//创建文档索引
super.createIndex();
//解析PDF图片
this.parsingPdfImgs();
//解析合并后的word
this.parsingWord();
} catch (Exception e) {
if(super.isStop == false) {
//任务执行失败修改任务状态
checkDocTaskService.updateProgressStatus(this.checkDocTask.getId(),this.project.getId(),CheckStatus.FAIL.getCode(),null);
log.error("{}任务查重失败,原因:{}",super.project.getProcurementContent(),e.getMessage());
super.stopTask();
taskCounter.decrementAndGet();
taskCounter.notifyLock();
}
e.printStackTrace();
}
}
/**
* 解析PDF图片
* @throws ExecutionException
* @throws InterruptedException
*/
private void parsingPdfImgs() throws InterruptedException, ExecutionException {
if(!CollectionUtils.isEmpty(checkFiles) && !super.isStop) {
//解析pdf图片
StopWatch stopWatch = new StopWatch();
stopWatch.start();
CountDownLatch parseImgTaskLatch = new CountDownLatch(checkFiles.size());
for(CheckFile checkFile : checkFiles) {
ParsePDFImages parsePDFImages = new ParsePDFImages(this.checkDocTask,this.project,checkFile,this.stepProportion,parseImgTaskLatch);
poolExecutor.execute(parsePDFImages);
}
parseImgTaskLatch.await();
stopWatch.stop();
log.info("{}查重任务图片解析时间为:{}秒",project.getProcurementContent(),stopWatch.getTotalTimeSeconds());
if(super.isStop) {
return;
}
//执行图片识别和word合并线程
CountDownLatch identifyImgTaskLatch = new CountDownLatch(checkFiles.size());
for(CheckFile checkFile : checkFiles) {
PDFParsingActurtor pdfParsingThread = new PDFParsingActurtor();
pdfParsingThread.init(
checkDocTask,
checkFile,
checkDocTaskService,
properties,
identifyImgTaskLatch,
redisUtil,
totalImgs,
project,
elasticsearchService);
poolExecutor.execute(pdfParsingThread);
}
try {
identifyImgTaskLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 解析合并后的word
*/
private void parsingWord() {
if(super.isStop) {
return;
}
BaseActurtor wordParsingThread = new PDFWordParsingActurtor();
wordParsingThread.init(
checkDocTask,
checkDocumentService,
checkRepeatedDocumentService,
checkReportService,
checkDocTaskService,
checkReportSimilarFileService,
checkFiles,
properties,
checkPaperLibraryService,
project,
elasticsearchService);
wordParsingThread.setName("word-parsing-thread");
wordParsingThread.setUncaughtExceptionHandler(this);
wordParsingThread.start();
}
/** 解析pdf图片线程 */
private class ParsePDFImages implements Runnable{
private CheckDocTask checkDocTask;
private CheckProject project;
private CheckFile checkFile;
private Double stepProportion;
private CountDownLatch taskLatch;
private String sectionPath;
public ParsePDFImages(CheckDocTask checkDocTask, CheckProject project, CheckFile checkFile, Double stepProportion, CountDownLatch taskLatch) {
this.checkDocTask = checkDocTask;
this.project = project;
this.checkFile = checkFile;
this.stepProportion = stepProportion;
this.taskLatch = taskLatch;
//处理图片存储过程中的存储路径
this.sectionPath = handleSectionPath(checkFile);
}
@Override
public void run() {
int pageSize = 0;
int complatePageSize = 0;
FileInputStream fis = null;
PDDocument doc = null;
try {
//处理文件路径
String filePath = getFilePath(checkFile);
fis = new FileInputStream(new File(filePath));
doc = PDDocument.load(fis);
//处理文件图片解析缓存
String redisKey = RedisKeyEnum.PARSING_PDF_CACHE.getCode(checkDocTask.getId(),checkFile.getId());
List<String> imgStatusJsonCacheList = redisUtil.lRange(redisKey,0,-1);
Map<Integer,PDFPageParsingStatus> imgStatusCacheMap = null;
if(!CollectionUtils.isEmpty(imgStatusJsonCacheList)) {
imgStatusCacheMap = imgStatusJsonCacheList.stream()
.map(m->JSON.parseObject(m,PDFPageParsingStatus.class))
.collect(Collectors.toMap(PDFPageParsingStatus::getPageNum,imgStatusCache->imgStatusCache));
}
//开始解析文件图片
PDFRenderer pdfRenderer = new PDFRenderer(doc);
PDPageTree pages = doc.getPages();
pageSize = pages.getCount();
for(int i=0;i < pageSize;i++) {
if(isStop) {
return;
}
//统计本次任务共多少张图片
totalImgs++;
// 如果文件解析状态是以解析或者已识别则跳过这个文件
if (!CollectionUtils.isEmpty(imgStatusCacheMap) && imgStatusCacheMap.containsKey(i)) {
PDFPageParsingStatus imgStatus = imgStatusCacheMap.get(i);
if(PDFImageParsingFlag.IMG_PARSING.getValue().equals(imgStatus.getStatus()) ||
PDFImageParsingFlag.IMG_OCR.getValue().equals(imgStatus.getStatus())) {
complatePageSize++;
log.info("{}文件第{}页图片已存在",checkFile.getFileName(),i);
continue;
}
}
String imagePath = getImagePath(i,checkFile,sectionPath);
File imgFile = new File(imagePath);
BufferedImage bufferedImage = pdfRenderer.renderImageWithDPI(i,96);
if(Objects.nonNull(bufferedImage)) {
//如果图片宽度大于800需要压缩否则图片识别服务会识别不出来报错
if(bufferedImage.getWidth()>IMG_WIDTH) {
ImageUtil.resize(bufferedImage,imgFile,800, 1F);
}else {
FileImageOutputStream fios = new FileImageOutputStream(imgFile);
ImageIO.write(bufferedImage,"jpg", fios);
}
//存储当前pdf页解析状态
PDFPageParsingStatus parsingStatus = new PDFPageParsingStatus();
parsingStatus.setPageNum(i);
parsingStatus.setFilePath(imagePath);
parsingStatus.setStatus(PDFImageParsingFlag.IMG_PARSING.getValue());
redisUtil.lPush(redisKey, JSON.toJSONString(parsingStatus));
log.info("{}文件已解析至第{}页",checkFile.getFileName(),i);
}
}
log.info("{}文件解析完毕",checkFile.getFileName());
} catch (Exception e) {
log.error("{}文档图片解析失败,原因:",this.checkFile.getFileName(),e.getMessage());
throw new RuntimeException(e);
}finally {
//如果已解析页面图片数量不等于此文档总页码则说明上次此文件未解析完成则修改进度
if(complatePageSize != pageSize) {
ProgressEvent event = new ProgressEvent(this.checkDocTask.getId(),project.getId(),(stepProportion),false);
ProgressQueue.getInstance().offer(event);
}
if(null != fis) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(null != doc) {
try {
doc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
this.taskLatch.countDown();
}
}
}
@Override
public void uncaughtException(Thread t, Throwable e) {
//如果isStop为true说明stopTask已被执行过这里如果再捕获异常不在处理否则会导致任务计数器多减1
//此问题只有pdf解析会出现因为多个文件会有多个子线程而此方法是捕获线程未知异常方法
//一个文档解析出错此次任务都会关闭其他文档线程也会强制关闭会多次触发该方法
if(super.isStop == false) {
//任务执行失败修改任务状态
log.error("{}任务查重失败,原因:{}",super.project.getProcurementContent(),e.getMessage());
checkDocTaskService.updateProgressStatus(checkDocTask.getId(),project.getId(),CheckStatus.FAIL.getCode(),null);
super.stopTask();
taskCounter.decrementAndGet();
taskCounter.notifyLock();
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,109 @@
package com.platform.check.actuator.parsing;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import com.google.common.collect.Lists;
import com.platform.check.actuator.progress.ProgressEvent;
import com.platform.check.actuator.progress.ProgressQueue;
import com.platform.check.domain.CheckFile;
import com.platform.check.enums.FileSuffix;
import com.platform.check.enums.PDFParsingSectionPath;
import cn.textcheck.engine.pojo.Paper;
import cn.textcheck.engine.report.Reporter;
/**
* pdf识别后所属word文档解析
* @author 86187
*
*/
public class PDFWordParsingActurtor extends DocParsingActurtor{
/**
* 计算任务步骤占比
*/
@Override
protected void computationStepProportion() {
//计算word对比步骤单步占比
BigDecimal totalProportionBg = new BigDecimal("10");
BigDecimal totalStepBg = new BigDecimal(checkFiles.size()+2);
BigDecimal result = totalProportionBg.divide(totalStepBg,2,RoundingMode.HALF_UP);
super.stepProportion = result.doubleValue();
}
@Override
public void run(){
try {
//计算任务步骤占比
computationStepProportion();
//更新任务进度
ProgressEvent fontEvent = new ProgressEvent(this.checkDocTask.getId(),this.project.getId(),stepProportion,false);
ProgressQueue.getInstance().offer(fontEvent);
//处理待对比文件及对比库
super.handleCheckFile();
//启动任务返回报告
List<Reporter> reporters = super.startCheckTask();
super.saveReporters(reporters);
//修改最终进度
ProgressEvent backEvent = new ProgressEvent(this.checkDocTask.getId(),this.project.getId(),this.stepProportion,true);
ProgressQueue.getInstance().offer(backEvent);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取待查文件
* @return
* @throws IOException
*/
@Override
protected List<Paper> getPapers() throws IOException {
List<Paper> papers = Lists.newArrayList();
for(CheckFile checkFile : super.checkFiles) {
StringBuilder filePath = new StringBuilder();
filePath.append(properties.getTaskFilePath());
filePath.append(File.separator);
filePath.append(checkDocTask.getId());
filePath.append(File.separator);
filePath.append(checkFile.getMd5Value());
filePath.append(File.separator);
filePath.append(PDFParsingSectionPath.WORD.getValue());
filePath.append(File.separator);
filePath.append(checkFile.getFileName().replace(FileSuffix.PDF.getValue(),FileSuffix.WORD_DOCX.getValue()));
File file = new File(filePath.toString());
if(file.exists() && file.isFile() && file.length() > 0) {
Paper paper = Paper.load(file);
paper.setId(checkFile.getId());
papers.add(paper);
//把文件id和文件名称存入map供后续使用
super.fileIdAndNameMap.put(checkFile.getId(),file.getName());
}
}
return papers;
}
/**
* 保存文档到历史库
*/
@Override
protected void saveHistoryLibrary() {
for(CheckFile checkFile : this.checkFiles) {
StringBuilder filePath = new StringBuilder();
filePath.append(properties.getTaskFilePath());
filePath.append(File.separator);
filePath.append(checkDocTask.getId());
filePath.append(File.separator);
filePath.append(checkFile.getMd5Value());
filePath.append(File.separator);
filePath.append(PDFParsingSectionPath.WORD.getValue());
filePath.append(File.separator);
filePath.append(checkFile.getFileName().replace(FileSuffix.PDF.getValue(),FileSuffix.WORD_DOCX.getValue()));
File file = new File(filePath.toString());
if(file.exists() && file.isFile() && file.length() > 0) {
this.checkPaperLibraryService.create(this.checkDocTask.getId(),checkFile.getId(),filePath.toString());
}
}
}
}

View File

@ -0,0 +1,171 @@
package com.platform.check.actuator.parsing;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.platform.check.actuator.model.DocPageInfo;
import com.platform.check.actuator.progress.ProgressEvent;
import com.platform.check.actuator.progress.ProgressQueue;
import com.platform.check.domain.CheckFile;
import com.platform.check.enums.CheckStatus;
import com.platform.check.enums.FileSuffix;
import cn.textcheck.engine.pojo.Paper;
import cn.textcheck.engine.report.Reporter;
import lombok.extern.slf4j.Slf4j;
/**
* 纯word/txt解析
* @author 86187
*
*/
@Slf4j
public class WordParsingActurtor extends DocParsingActurtor{
/**
* 计算任务步骤占比
*/
@Override
protected void computationStepProportion() {
//计算word对比步骤单步占比
BigDecimal totalProportionBg = new BigDecimal("100");
BigDecimal totalStepBg = new BigDecimal(checkFiles.size()+2);
BigDecimal result = totalProportionBg.divide(totalStepBg,2,RoundingMode.HALF_UP);
super.stepProportion = result.doubleValue();
}
@Override
public void run(){
try {
//计算任务步骤占比
this.computationStepProportion();
//创建文档索引
// super.createIndex();
//解析word/txt保存到ES
this.parsingWordOrTxtToES();
//更新任务进度
ProgressEvent fontEvent = new ProgressEvent(this.checkDocTask.getId(),this.project.getId(),stepProportion,false);
ProgressQueue.getInstance().offer(fontEvent);
//处理待对比文件及对比库
super.handleCheckFile();
//启动任务返回报告
List<Reporter> reporters = super.startCheckTask();
super.saveReporters(reporters);
//修改最终进度
ProgressEvent backEvent = new ProgressEvent(this.checkDocTask.getId(),this.project.getId(),this.stepProportion,true);
ProgressQueue.getInstance().offer(backEvent);
} catch (Exception e) {
//任务执行失败修改任务状态
super.checkDocTaskService.updateProgressStatus(this.checkDocTask.getId(),this.project.getId(),CheckStatus.FAIL.getCode(),null);
log.error("{}任务查重失败,原因:{}",super.project.getProcurementContent(),e.getMessage());
taskCounter.decrementAndGet();
taskCounter.notifyLock();
e.printStackTrace();
}
}
/**
* 获取待查文件
* @return
* @throws IOException
*/
@Override
protected List<Paper> getPapers() throws IOException{
List<Paper> papers = Lists.newArrayList();
for(CheckFile checkFile : super.checkFiles) {
String filePath = getFilePath(checkFile);
File file = new File(filePath);
if(file.exists() && file.isFile() && file.length() > 0) {
Paper paper = Paper.load(file);
paper.setId(checkFile.getId());
papers.add(paper);
//把文件id和文件名称存入map供后续使用
// super.fileIdAndNameMap.put(checkFile.getId(),checkFile.getFileName());
}
}
return papers;
}
/**
* 保存文档到历史库
*/
@Override
protected void saveHistoryLibrary() {
for(CheckFile checkFile : this.checkFiles) {
String filePath = getFilePath(checkFile);
File file = new File(filePath.toString());
if(file.exists() && file.isFile() && file.length() > 0) {
this.checkPaperLibraryService.create(this.checkDocTask.getId(),checkFile.getId(),filePath.toString());
}
}
}
/**
* 解析word/txt存储到ES
* @throws IOException
*/
private void parsingWordOrTxtToES() throws IOException {
for(CheckFile checkFile : super.checkFiles) {
if(checkFile.getFileName().endsWith(FileSuffix.TXT.getValue())) {
this.parsingTxtToES(checkFile);
}
if(checkFile.getFileName().endsWith(FileSuffix.WORD_DOC.getValue()) ||
checkFile.getFileName().endsWith(FileSuffix.WORD_DOCX.getValue())) {
this.parsingWordToES(checkFile);
}
}
}
/**
* 解析word把每页内容存储到ES
* @throws IOException
*/
private void parsingWordToES(CheckFile checkFile) throws IOException {
String filePath = getFilePath(checkFile);
StringBuilder content = new StringBuilder();
try (FileInputStream fis = new FileInputStream(filePath);
XWPFDocument document1 = new XWPFDocument(fis);){
} catch (IOException e) {
log.error("{}文件不存在解析文件内容存储到ES失败,原因:{}",checkFile.getFileName(),e.getMessage());
throw e;
}
}
/**
* 解析txt把每页内容存储到ES
* @throws IOException
*/
private void parsingTxtToES(CheckFile checkFile) throws IOException{
String filePath = getFilePath(checkFile);
try (FileReader fis = new FileReader(filePath);
BufferedReader reader = new BufferedReader(fis);){
Stream<String> lines = reader.lines();
StringBuilder content = new StringBuilder();
lines.forEach(t->{
content.append(t);
});
if(StringUtils.isNotBlank(content)) {
DocPageInfo info = new DocPageInfo();
info.setPageNum(1);//单文件页面固定为1
info.setLocalDate(LocalDateTime.now());
info.setContent(StringUtils.lowerCase(content.toString()));
elasticsearchService.createDoc(checkFile.getId(),info.getPageNum().toString(),JSON.toJSONString(info));
}
} catch (IOException e) {
log.error("{}文件不存在解析文件内容存储到ES失败,原因:{}",checkFile.getFileName(),e.getMessage());
throw e;
}
}
}

View File

@ -0,0 +1,36 @@
package com.platform.check.actuator.progress;
import java.io.Serializable;
import lombok.Getter;
import lombok.Setter;
/**
* 进度事件
* @author 86187
*
*/
public class ProgressEvent implements Serializable{
private static final long serialVersionUID = 1L;
@Getter
private String checkTaskId;
@Getter
private String checkProjectId;
@Getter @Setter
private Double currProgress;
@Getter @Setter
private boolean isLastStep;
public ProgressEvent(String checkTaskId,String checkProjectId,Double currProgress,boolean isLastStep) {
super();
this.checkTaskId = checkTaskId;
this.checkProjectId = checkProjectId;
this.currProgress = currProgress;
this.isLastStep = isLastStep;
}
}

View File

@ -0,0 +1,58 @@
package com.platform.check.actuator.progress;
import java.util.Date;
import java.util.Objects;
import org.springframework.stereotype.Component;
import com.platform.check.actuator.task.TaskCounter;
import com.platform.check.enums.CheckStatus;
import com.platform.check.service.CheckDocTaskService;
import com.platform.check.service.CheckReportService;
import lombok.RequiredArgsConstructor;
/**
* 进度监视器线程
* @author 86187
*
*/
@Component
@RequiredArgsConstructor
public class ProgressMonitor{
private final CheckDocTaskService checkDocTaskService;
private final CheckReportService checkReportService;
private final TaskCounter taskCounter;
public void start() {
ProgressMonitorThread monitor = new ProgressMonitorThread();
monitor.setName("任务进度检测线程");
monitor.start();
}
private class ProgressMonitorThread extends Thread{
@Override
public void run() {
for(;;) {
ProgressEvent event = ProgressQueue.getInstance().take();
if(Objects.nonNull(event)) {
if(event.isLastStep()) {
//修改任务所属报告结论
checkReportService.updateThreshold(event.getCheckTaskId());
event.setCurrProgress(100D);
//修改任务结束状态
checkDocTaskService.updateTaskFinish(event.getCheckTaskId(),event.getCheckProjectId(),CheckStatus.COMPLETED.getCode(),new Date(),event.getCurrProgress());
//当前运行任务数减1
//唤醒任务监测线程
taskCounter.decrementAndGet();
taskCounter.notifyLock();
}else {
checkDocTaskService.updateTaskProgress(event.getCheckTaskId(),event.getCurrProgress());
}
}
}
}
}
}

View File

@ -0,0 +1,36 @@
package com.platform.check.actuator.progress;
import java.util.LinkedList;
public class ProgressQueue {
private final LinkedList<ProgressEvent> queue = new LinkedList<>();
private static ProgressQueue progressQueue = new ProgressQueue();
public static ProgressQueue getInstance() {
return progressQueue;
}
public void offer(ProgressEvent event) {
synchronized (queue) {
queue.addLast(event);
queue.notify();
}
}
public ProgressEvent take(){
synchronized (queue) {
if(queue.isEmpty()) {
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
ProgressEvent event = queue.removeFirst();
return event;
}
}
}

View File

@ -0,0 +1,69 @@
package com.platform.check.actuator.task;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.stereotype.Component;
import com.platform.common.properties.SystemProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* 任务计数器
* @author 86187
*
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class TaskCounter {
private final SystemProperties properties;
/**
* 当前运行任务数量
*/
private static AtomicInteger currRunTasks = new AtomicInteger();
/**
* 阻塞锁
*/
private Object lock = new Object();
/**
* 增加任务运行数
*/
public void incrementAndGet() {
currRunTasks.incrementAndGet();
}
/**
* 减少任务运行数
*/
public void decrementAndGet() {
if(currRunTasks.get() > 0) {
currRunTasks.decrementAndGet();
}
}
/**
* 检查任务数等于配置文件配置数则等待
* @throws InterruptedException
*/
public void checkTaskNums() throws InterruptedException {
synchronized (lock) {
if(currRunTasks.get() == properties.getTaskMaxRunNums()) {
log.info("当前任务运行数量已达到最大值{},进入等待期",properties.getTaskMaxRunNums());
lock.wait();
}
}
}
/**
* 唤醒等待线程
*/
public void notifyLock() {
synchronized (lock) {
lock.notify();
}
}
}

View File

@ -0,0 +1,103 @@
package com.platform.check.actuator.task;
import java.util.Date;
import java.util.List;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;
import com.google.common.base.Splitter;
import com.platform.check.actuator.china.Handler;
import com.platform.check.actuator.china.PDFHandler;
import com.platform.check.domain.CheckDocTask;
import com.platform.check.domain.CheckFile;
import com.platform.check.enums.CheckStatus;
import com.platform.check.service.CheckDocTaskService;
import com.platform.check.service.CheckDocumentService;
import com.platform.check.service.CheckFileService;
import com.platform.check.service.CheckPaperLibraryService;
import com.platform.check.service.CheckRepeatedDocumentService;
import com.platform.check.service.CheckReportService;
import com.platform.check.service.CheckReportSimilarFileService;
import com.platform.common.elastic.ElasticsearchService;
import com.platform.common.properties.SystemProperties;
import com.platform.common.redis.RedisUtil;
import com.platform.project.domain.CheckProject;
import com.platform.project.mapper.CheckProjectMapper;
import lombok.RequiredArgsConstructor;
/**
* 任务监视器线程
* 实时监测TaskQueue队列是否有新进数据
* @author 86187
*
*/
@Component
@RequiredArgsConstructor
public class TaskMonitor{
private final RedisUtil redisUtil;
private final TaskQueue taskQueue;
private final CheckFileService checkFileService;
private final CheckProjectMapper projectEntityMapper;
private final CheckDocumentService checkDocumentService;
private final CheckRepeatedDocumentService checkRepeatedDocumentService;
private final CheckReportSimilarFileService checkReportSimilarFileService;
private final CheckReportService checkReportService;
private final SystemProperties properties;
private final CheckPaperLibraryService checkPaperLibraryService;
private final CheckDocTaskService checkDocTaskService;
private final TaskCounter taskCounter;
private final ElasticsearchService elasticsearchService;
public void start() {
TaskMonitorThread monitor = new TaskMonitorThread();
monitor.setName("任务监测线程");
monitor.start();
}
private class TaskMonitorThread extends Thread{
@Override
public void run() {
for(;;) {
try {
//检查任务数等于配置文件配置数则等待
taskCounter.checkTaskNums();
CheckDocTask checkDocTask = taskQueue.take();
String fileIdList = checkDocTask.getFileIdList();
Splitter splitter = Splitter.on(",").omitEmptyStrings().trimResults();
List<String> fileIds = splitter.splitToList(fileIdList);
List<CheckFile> checkFiles = checkFileService.findList(fileIds);
if(CollectionUtils.isNotEmpty(checkFiles)) {
//查询此任务所属项目
CheckProject project = projectEntityMapper.selectById(checkDocTask.getCheckProjectId());
//修改项目任务状态-解析中
checkDocTaskService.updateProgressStatus(checkDocTask.getId(),project.getId(),CheckStatus.PARSING.getCode(),new Date());
//处理上传的文件使用责任链模式匹配成功则执行
Handler handler = new PDFHandler();
handler.initService(
checkDocumentService,
checkRepeatedDocumentService,
checkReportSimilarFileService,
checkReportService,
checkDocTaskService,
checkDocTask,
properties,
checkFiles,
project,
checkPaperLibraryService,
redisUtil,
taskCounter,
elasticsearchService);
handler.handlerFiles(checkFiles);
//+1操作
taskCounter.incrementAndGet();
}
//捕获异常不处理保障出异常后线程不停止
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}

View File

@ -0,0 +1,194 @@
package com.platform.check.actuator.task;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.platform.check.domain.CheckDocTask;
import com.platform.check.enums.CheckStatus;
import com.platform.check.mapper.CheckDocTaskMapper;
import com.platform.common.core.SystemConstant;
import com.platform.common.exception.BusinessException;
import com.platform.common.ip.IpUtils;
import com.platform.common.redis.RedisUtil;
import lombok.RequiredArgsConstructor;
/**
* 任务队列
* @author 86187
*
*/
@Component
@RequiredArgsConstructor
public class TaskQueue {
private final RedisUtil redisUtil;
private final CheckDocTaskMapper checkDocTaskMapper;
/**
* 任务队列
*/
private final LinkedList<CheckDocTask> queue = new LinkedList<>();
/**
* 任务排序
*/
private final Map<String,Integer> elementOrderMap = new LinkedHashMap<>();
private String localIp = null;
public void init() {
this.localIp = IpUtils.getLocalIP();
//启动项目时上次处理失败的任务加入队列重新查重
LambdaQueryWrapper<CheckDocTask> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(CheckDocTask::getTaskStatus,CheckStatus.PARSING.getCode());
queryWrapper.orderByAsc(CheckDocTask::getStartTime);
List<CheckDocTask> queryResult = checkDocTaskMapper.selectList(queryWrapper);
if(CollectionUtils.isNotEmpty(queryResult)) {
List<String> cacheTasks = redisUtil.lRange(SystemConstant.redis_task_data+":"+localIp, 0, -1);
if(CollectionUtils.isNotEmpty(cacheTasks)) {
for (CheckDocTask queryTask:queryResult) {
boolean flag = false;
for(int i=0;i<cacheTasks.size();i++) {
CheckDocTask cacheTask = JSON.parseObject(cacheTasks.get(i),CheckDocTask.class);
if(queryTask.getCheckProjectId().equals(cacheTask.getCheckProjectId())) {
flag = true;
break;
}
}
if(flag == false) {
redisUtil.rPush(SystemConstant.redis_task_data+":"+localIp,JSON.toJSONString(queryTask));
}
}
}else {
for (CheckDocTask task:queryResult) {
redisUtil.rPush(SystemConstant.redis_task_data+":"+localIp,JSON.toJSONString(task));
}
}
}
//启动项目时redis中未处理的任务数据加入队列重新查重
List<String> cacheTasks = redisUtil.lRange(SystemConstant.redis_task_data+":"+localIp, 0, -1);
if(CollectionUtils.isNotEmpty(cacheTasks)) {
for(int i=cacheTasks.size()-1;i>=0;i--) {
CheckDocTask task = JSON.parseObject(cacheTasks.get(i),CheckDocTask.class);
this.queue.addLast(task);
elementOrderMap.put(task.getCheckProjectId(),queue.size());
}
}
}
/**
* 从队列尾部添加元素
* @param task
*/
public void offer(CheckDocTask task) {
synchronized (queue) {
redisUtil.lPush(SystemConstant.redis_task_data+":"+localIp,JSON.toJSONString(task));
queue.addLast(task);
elementOrderMap.put(task.getCheckProjectId(),queue.size());
queue.notify();
}
}
/**
* 获取队列头部元素
* @return
*/
public CheckDocTask take(){
synchronized (queue) {
if(queue.isEmpty()) {
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
CheckDocTask task = queue.removeFirst();
redisUtil.rPop(SystemConstant.redis_task_data+":"+localIp);
elementOrderMap.clear();
for(int i=0;i<queue.size();i++) {
elementOrderMap.put(queue.get(i).getCheckProjectId(),(i+1));
}
return task;
}
}
/**
* 删除队列中的元素
* @param projectId
*/
public void remove(String projectId) {
synchronized (queue) {
if(!queue.isEmpty()) {
Iterator<CheckDocTask> iterator = this.queue.iterator();
while (iterator.hasNext()) {
CheckDocTask next = iterator.next();
if(next.getCheckProjectId().equals(projectId)) {
iterator.remove();
redisUtil.remove(SystemConstant.redis_task_data+":"+localIp,JSON.toJSONString(next));
elementOrderMap.clear();
for(int i=0;i<queue.size();i++) {
elementOrderMap.put(queue.get(i).getCheckProjectId(),(i+1));
}
}
}
}
}
}
/**
* 获取项目排序
* @param projectId
* @return
*/
public Integer getElementOrder(String projectId){
synchronized (queue) {
return elementOrderMap.getOrDefault(projectId,null);
}
}
/**
* 修改任务排名
* @param projectId
* @param taskOrder
* @return
*/
public boolean updateTaskOrder(String projectId,Integer currOrder) {
Boolean result = false;
synchronized (queue) {
if(currOrder > this.queue.size()) {
throw new BusinessException("当前任务排名大于队列任务数量:"+this.queue.size()+",修改失败",result.toString());
}
CheckDocTask checkDocTask = this.queue.get(currOrder-1);
if(!projectId.equals(checkDocTask.getCheckProjectId())) {
throw new BusinessException("当前任务排名已发生变化,请刷新后重试",result.toString());
}
if(1 == currOrder && projectId.equals(checkDocTask.getCheckProjectId())) {
throw new BusinessException("当前任务已排在第一位,无需置顶",result.toString());
}
try {
//修改redis缓存
this.redisUtil.remove(SystemConstant.redis_task_data+":"+localIp,JSON.toJSONString(checkDocTask));
this.redisUtil.rPush(SystemConstant.redis_task_data+":"+localIp,JSON.toJSONString(checkDocTask));
//修改任务队列
this.queue.remove(currOrder.intValue()-1);
this.queue.offerFirst(checkDocTask);
//修改任务排名
elementOrderMap.clear();
for(int i=0;i<this.queue.size();i++) {
elementOrderMap.put(this.queue.get(i).getCheckProjectId(),(i+1));
}
result = true;
} catch (Exception e) {
e.printStackTrace();
throw new BusinessException("任务排名修改失败,请重试",result.toString());
}
}
return result;
}
}

View File

@ -0,0 +1,38 @@
package com.platform.check.actuator.task;
import java.util.HashMap;
import java.util.Map;
import com.platform.check.actuator.parsing.BaseActurtor;
public class TaskThreadMonitor {
private final Map<String,BaseActurtor> taskThreadMap = new HashMap<>();
private static TaskThreadMonitor taskThreadMonitor = new TaskThreadMonitor();
public static TaskThreadMonitor getInstance() {
return taskThreadMonitor;
}
public void offer(String taskId,BaseActurtor baseActurtor) {
synchronized (taskThreadMap) {
taskThreadMap.put(taskId, baseActurtor);
}
}
public BaseActurtor take(String taskId){
synchronized (taskThreadMap) {
if(!taskThreadMap.isEmpty() && taskThreadMap.containsKey(taskId)) {
return taskThreadMap.get(taskId);
}
return null;
}
}
public void remove(String taskId) {
if(!taskThreadMap.isEmpty() && taskThreadMap.containsKey(taskId)) {
taskThreadMap.remove(taskId);
}
}
}

View File

@ -0,0 +1,98 @@
package com.platform.check.controller;
import com.platform.check.actuator.task.TaskQueue;
import com.platform.check.domain.vo.*;
import com.platform.check.service.CheckDocTaskService;
import com.platform.common.annotation.AutoLog;
import com.platform.common.enums.OperationTypeEnum;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
@RestController
@RequestMapping("/task")
@Api(tags = {"查重任务管理"})
@RequiredArgsConstructor
public class CheckDocTaskController {
private final CheckDocTaskService checkDocTaskService;
private final TaskQueue taskQueue;
@PostMapping("/create")
@ApiOperation("创建文档查重任务")
@AutoLog(value = "创建文档查重任务", operationType = OperationTypeEnum.INSERT, module = "文件服务")
public void create(CheckDocTaskVo checkDocTaskVo) {
checkDocTaskService.create(checkDocTaskVo);
}
@ApiOperation("查看文件对应报告信息")
@GetMapping("findCheckReport")
public CheckReportVo findCheckReport(String taskId, String fileId){
CheckReportVo checkReport = checkDocTaskService.findCheckReport(taskId, fileId);
return checkReport;
}
@ApiOperation("获取当前任务总报告信息")
@GetMapping("findAllReport")
public List<CheckReportVo> findAllReport(String taskId){
List<CheckReportVo> result = checkDocTaskService.findAllReport(taskId);
return result;
}
@ApiOperation("下载文件对应报告信息")
@GetMapping("downloadCheckReport")
public void downloadCheckReport(String taskId, String fileId,HttpServletResponse res) throws UnsupportedEncodingException{
res.setContentType("application/pdf");
res.setCharacterEncoding("utf-8");
res.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode("文档查重检测报告.pdf","UTF-8"));
res.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
checkDocTaskService.downloadCheckReport(taskId, fileId,res);
}
@ApiOperation("删除文档查重任务")
@DeleteMapping("deleteTask")
public void deleteTask(String taskId){
checkDocTaskService.deleteTask(taskId);
}
@ApiOperation("提交任务")
@PutMapping("updateSubmitState")
public String updateSubmitState(String taskId,Integer submitState,String description,String analysis){
return checkDocTaskService.updateSubmitState(taskId,submitState,description,analysis);
}
@ApiOperation("重新上传查询文件查重任务详情接口")
@GetMapping("findTaskDetail")
public CheckDocTaskResultVo findTaskDetail(String taskId){
CheckDocTaskResultVo result = checkDocTaskService.findTaskDetail(taskId);
return result;
}
@ApiOperation("停止任务接口")
@GetMapping("stopTask")
public String stopTask(String projectId){
checkDocTaskService.stopTask(projectId);
return "任务停止成功";
}
@ApiOperation("修改任务排名")
@PutMapping("updateTaskOrder")
public boolean updateTaskOrder(String projectId,Integer currOrder){
boolean result = taskQueue.updateTaskOrder(projectId,currOrder);
return result;
}
@ApiOperation("下载过滤文档")
@GetMapping("downloadFilterWord")
public void downloadFilterWord(String filterWordPath, String filterWordName, HttpServletRequest req, HttpServletResponse res){
checkDocTaskService.downloadFilterWord(filterWordPath, filterWordName, req, res);
}
}

View File

@ -0,0 +1,315 @@
package com.platform.check.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.platform.check.domain.CheckFile;
import com.platform.check.domain.CheckFileUnit;
import com.platform.check.domain.vo.*;
import com.platform.check.enums.DownloadType;
import com.platform.check.enums.FileSuffix;
import com.platform.check.enums.PDFParsingSectionPath;
import com.platform.check.mapper.CheckFileUnitMapper;
import com.platform.check.service.CheckFileService;
import com.platform.common.annotation.AutoLog;
import com.platform.common.entity.PagedResultVo;
import com.platform.common.enums.OperationTypeEnum;
import com.platform.common.exception.BusinessException;
import com.platform.common.properties.SystemProperties;
import com.platform.common.util.DownloadUtils;
import com.platform.project.domain.CheckProject;
import com.platform.project.domain.CheckUnit;
import com.platform.project.mapper.CheckProjectMapper;
import com.platform.project.mapper.CheckUnitMapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.apache.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Objects;
@RestController
@RequestMapping("/file")
@Api(tags = {"查重文件管理"})
@RequiredArgsConstructor
public class CheckFileController {
private final CheckFileService checkFileService;
private final CheckFileUnitMapper checkFileUnitMapper;
private final CheckUnitMapper checkUnitMapper;
private final CheckProjectMapper checkProjectMapper;
private final SystemProperties systemProperties;
@GetMapping("/verifyFileExist")
@ApiOperation("验证文件是否存在")
@AutoLog(value = "验证文件是否存在", operationType = OperationTypeEnum.SELECT, module = "文件服务")
public FileExistVo verifyFileExist(String fileMD5Value) {
FileExistVo fileExist = checkFileService.verifyFileExist(fileMD5Value);
return fileExist;
}
@PostMapping("/uploadFile")
@ApiOperation(value = "上传文件")
@AutoLog(value = "上传文件", operationType = OperationTypeEnum.UNKNOWN, module = "文件服务")
public FileUploadResultVo uploadFile(FileVo fileVo){
if (!fileVo.getFileExt().equals(FileSuffix.PDF.getValue()) && !fileVo.getFileExt().equals(FileSuffix.WORD_DOC.getValue()) &&
!fileVo.getFileExt().equals(FileSuffix.WORD_DOCX.getValue()) && !fileVo.getFileExt().equals(FileSuffix.TXT.getValue()) &&
!fileVo.getFileExt().equalsIgnoreCase(FileSuffix.JPG.getValue()) && !fileVo.getFileExt().equalsIgnoreCase(FileSuffix.JPEG.getValue()) &&
!fileVo.getFileExt().equalsIgnoreCase(FileSuffix.PNG.getValue())){
throw new BusinessException(500, "当前上传文件类型不支持!");
}
FileUploadResultVo resultVo = checkFileService.uploadFile(fileVo);
return resultVo;
}
@ApiOperation(value = "查询文件信息")
@GetMapping("findFilePage")
public PagedResultVo<CheckFileResultVo> findFilePage(CheckFileSearchVo checkFileSearchVo){
PagedResultVo<CheckFileResultVo> result = checkFileService.findFilePage(checkFileSearchVo);
return result;
}
@GetMapping("/downloadTask")
@ApiOperation(value = "下载文件")
public void downloadTask(String taskId, String fileId,Integer downloadType,HttpServletRequest req,HttpServletResponse resp) {
//根据任务id和文件id查询中间表关联信息
LambdaQueryWrapper<CheckFileUnit> fileUnitQueryWrapper = new LambdaQueryWrapper<>();
fileUnitQueryWrapper.eq(CheckFileUnit::getTaskId,taskId);
fileUnitQueryWrapper.eq(CheckFileUnit::getFileId,fileId);
CheckFileUnit checkFileUnit = checkFileUnitMapper.selectOne(fileUnitQueryWrapper);
if (Objects.isNull(checkFileUnit)){
throw new BusinessException(500,"当前任务及文件对应的信息不存在!");
}
//查询项目名称
CheckProject projectEntity = checkProjectMapper.selectById(checkFileUnit.getProjectId());
if (Objects.isNull(projectEntity)){
throw new BusinessException(500,"当前文件对应的项目信息不存在!");
}
//查询公司名称
CheckUnit checkUnit = checkUnitMapper.selectById(checkFileUnit.getUnitId());
if (Objects.isNull(checkUnit)){
throw new BusinessException(500,"当前文件对应的部门信息不存在!");
}
//查询文件对应信息
CheckFile checkFile = checkFileService.getById(checkFileUnit.getFileId());
if (Objects.isNull(checkFile)){
throw new BusinessException(500,"当前文件对应的信息不存在!");
}
//得到源文件后缀
String fileSuffix = checkFile.getFileName().substring(checkFile.getFileName().indexOf(StringPool.DOT));
String filePath = null;
String newFileName = null;
if(DownloadType.SOURCE.getValue().equals(downloadType)) {
//拼接项目文件存放路径
newFileName = projectEntity.getProcurementContent()+StringPool.DASH+checkUnit.getUnitName()+fileSuffix;
filePath = systemProperties.getTaskFilePath()+File.separator+checkFileUnit.getTaskId()+File.separator+checkFile.getMd5Value()+File.separator+newFileName;
}else {
if(DownloadType.RESOLVED.getValue().equals(downloadType) &&
(FileSuffix.PDF.getValue().equalsIgnoreCase(fileSuffix) ||
FileSuffix.JPEG.getValue().equalsIgnoreCase(fileSuffix)||
FileSuffix.JPG.getValue().equalsIgnoreCase(fileSuffix) ||
FileSuffix.PNG.getValue().equalsIgnoreCase(fileSuffix)
)){
newFileName = projectEntity.getProcurementContent()+StringPool.DASH+checkUnit.getUnitName()+FileSuffix.WORD_DOCX.getValue();
filePath = systemProperties.getTaskFilePath()+File.separator+checkFileUnit.getTaskId()+File.separator+checkFile.getMd5Value()+File.separator+PDFParsingSectionPath.WORD.getValue()+File.separator+newFileName;
}
}
File newFile = new File(filePath);
if (newFile.exists()) {
DownloadUtils.downloadTask(req,resp,filePath,newFileName);
} else {
throw new BusinessException(500, "该文件不存在");
}
}
@GetMapping("/downloadTaskById")
@ApiOperation(value = "pdf文件在线预览")
public void downloadTaskById(String taskId, String fileId, HttpServletResponse response) {
//根据任务id和文件id查询中间表关联信息
LambdaQueryWrapper<CheckFileUnit> fileUnitQueryWrapper = new LambdaQueryWrapper<>();
fileUnitQueryWrapper.eq(CheckFileUnit::getTaskId,taskId);
fileUnitQueryWrapper.eq(CheckFileUnit::getFileId,fileId);
CheckFileUnit checkFileUnit = checkFileUnitMapper.selectOne(fileUnitQueryWrapper);
if (Objects.isNull(checkFileUnit)){
throw new BusinessException(500,"当前任务及文件对应的信息不存在!");
}
//查询项目名称
CheckProject projectEntity = checkProjectMapper.selectById(checkFileUnit.getProjectId());
if (Objects.isNull(projectEntity)){
throw new BusinessException(500,"当前文件对应的项目信息不存在!");
}
//查询公司名称
CheckUnit checkUnit = checkUnitMapper.selectById(checkFileUnit.getUnitId());
if (Objects.isNull(checkUnit)){
throw new BusinessException(500,"当前文件对应的部门信息不存在!");
}
//查询文件对应信息
CheckFile checkFile = checkFileService.getById(checkFileUnit.getFileId());
if (Objects.isNull(checkFile)){
throw new BusinessException(500,"当前文件对应的信息不存在!");
}
//拼接项目文件存放路径
String fileSuffix = checkFile.getFileName().substring(checkFile.getFileName().indexOf(StringPool.DOT));
String newFileName = projectEntity.getProcurementContent()+StringPool.DASH+checkUnit.getUnitName()+fileSuffix;
String filePath = systemProperties.getTaskFilePath()+File.separator+checkFileUnit.getTaskId()+File.separator+checkFile.getMd5Value()+File.separator+newFileName;
File file = new File(filePath);
if (file.exists()) {
//转换为绝对路径
try {
InputStream ins = new FileInputStream(file);
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
OutputStream os = response.getOutputStream();
byte[] b = new byte[4096];
int len;
while ((len = ins.read(b)) > 0) {
os.write(b, 0, len);
}
os.flush();
os.close();
ins.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
} else {
response.setStatus(org.apache.http.HttpStatus.SC_NOT_FOUND);
}
}
@GetMapping("/downloadTaskConvertFile")
@ApiOperation(value = "doc文件在线预览")
public void downloadTaskConvertFile(String taskId, String fileId, HttpServletResponse response) {
//根据任务id和文件id查询中间表关联信息
LambdaQueryWrapper<CheckFileUnit> fileUnitQueryWrapper = new LambdaQueryWrapper<>();
fileUnitQueryWrapper.eq(CheckFileUnit::getTaskId,taskId);
fileUnitQueryWrapper.eq(CheckFileUnit::getFileId,fileId);
CheckFileUnit checkFileUnit = checkFileUnitMapper.selectOne(fileUnitQueryWrapper);
if (Objects.isNull(checkFileUnit)){
throw new BusinessException(500,"当前任务及文件对应的信息不存在!");
}
//查询项目名称
CheckProject projectEntity = checkProjectMapper.selectById(checkFileUnit.getProjectId());
if (Objects.isNull(projectEntity)){
throw new BusinessException(500,"当前文件对应的项目信息不存在!");
}
//查询公司名称
CheckUnit checkUnit = checkUnitMapper.selectById(checkFileUnit.getUnitId());
if (Objects.isNull(checkUnit)){
throw new BusinessException(500,"当前文件对应的部门信息不存在!");
}
//查询文件对应信息
CheckFile checkFile = checkFileService.getById(checkFileUnit.getFileId());
if (Objects.isNull(checkFile)){
throw new BusinessException(500,"当前文件对应的信息不存在!");
}
//拼接项目文件存放路径
String fileSuffix = checkFile.getFileName().substring(checkFile.getFileName().indexOf(StringPool.DOT));
String newFileName = projectEntity.getProcurementContent()+StringPool.DASH+checkUnit.getUnitName()+fileSuffix;
String filePath = systemProperties.getTaskFilePath()+File.separator+checkFileUnit.getTaskId()+File.separator+checkFile.getMd5Value()+File.separator+newFileName;
File file = new File(filePath);
if (file.exists()) {
//转换为绝对路径
try (InputStream ins = new FileInputStream(file);
OutputStream os = response.getOutputStream();){
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
byte[] b = new byte[4096];
int len;
while ((len = ins.read(b)) > 0) {
os.write(b, 0, len);
}
os.flush();
} catch (IOException ioe) {
ioe.printStackTrace();
}
} else {
response.setStatus(HttpStatus.SC_NOT_FOUND);
}
}
@GetMapping("/download")
@ApiOperation(value = "下载文件")
public void download(String fileId, HttpServletRequest req,HttpServletResponse resp) {
//通过id查询当前对应的文档文件
CheckFile file = checkFileService.getById(fileId);
//获取源文件的文件地址
String filePath = file.getFilePath()+File.separator+file.getFileName();
File newFile = new File(filePath);
if (newFile.exists()) {
DownloadUtils.download(req,resp,file);
} else {
throw new BusinessException(500, "该文件不存在");
}
}
@GetMapping("/downloadById")
@ApiOperation(value = "pdf文件在线预览")
public void downloadById(String fileId, HttpServletResponse response) {
CheckFile fileEntity = checkFileService.getById(fileId);
String filePath = fileEntity.getFilePath()+File.separator+fileEntity.getFileName();
File file = new File(filePath);
if (file.exists()) {
//转换为绝对路径
try {
InputStream ins = new FileInputStream(file);
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
OutputStream os = response.getOutputStream();
byte[] b = new byte[4096];
int len;
while ((len = ins.read(b)) > 0) {
os.write(b, 0, len);
}
os.flush();
os.close();
ins.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
} else {
response.setStatus(org.apache.http.HttpStatus.SC_NOT_FOUND);
}
}
@GetMapping("/downloadConvertFile")
@ApiOperation(value = "doc文件在线预览")
public void downloadConvertFile(String fileId, HttpServletResponse response) {
CheckFile fileEntity = checkFileService.getById(fileId);
if (fileEntity == null) {
response.setStatus(HttpStatus.SC_NOT_FOUND);
return;
}
String filePath = fileEntity.getFilePath()+File.separator+fileEntity.getFileName();
File file = new File(filePath);
if (file.exists()) {
//转换为绝对路径
try (InputStream ins = new FileInputStream(file);
OutputStream os = response.getOutputStream();){
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
byte[] b = new byte[4096];
int len;
while ((len = ins.read(b)) > 0) {
os.write(b, 0, len);
}
os.flush();
} catch (IOException ioe) {
ioe.printStackTrace();
}
} else {
response.setStatus(HttpStatus.SC_NOT_FOUND);
}
}
}

View File

@ -0,0 +1,28 @@
package com.platform.check.controller;
import com.platform.check.domain.CheckTaskDescription;
import com.platform.check.domain.vo.CheckTaskDescriptionViewVo;
import com.platform.check.service.CheckTaskDescriptionService;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("checkTaskDescription")
@Api("任务日志管理")
public class CheckTaskDescriptionController {
@Autowired
private CheckTaskDescriptionService checkTaskDescriptionService;
@GetMapping("findList")
public List<CheckTaskDescriptionViewVo> findList(String taskId){
List<CheckTaskDescriptionViewVo> list = checkTaskDescriptionService.findList(taskId);
return list;
}
}

View File

@ -0,0 +1,78 @@
package com.platform.check.controller;
import com.platform.check.domain.ThresholdEntity;
import com.platform.check.domain.vo.threshold.ThresholdCreateVo;
import com.platform.check.domain.vo.threshold.ThresholdUpdateVo;
import com.platform.check.domain.vo.threshold.ThresholdViewVo;
import com.platform.check.service.IThresholdService;
import com.platform.common.annotation.AutoLog;
import com.platform.common.enums.OperationTypeEnum;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static java.util.Arrays.stream;
/**
* @author fubo
* @date 2022/9/3 15:16
*/
@RestController
@RequestMapping("checkThreshold")
@Api(tags = {"检查结论"})
public class ThresholdController {
@Resource
private IThresholdService thresholdService;
@ApiOperation("新增结论设置")
@PostMapping("add")
@AutoLog(value = "新增结论设置", operationType = OperationTypeEnum.INSERT,module = "检查报告结论设置模块")
public boolean add(@RequestBody ThresholdCreateVo thresholdVo) {
ThresholdEntity threshold = new ThresholdEntity();
BeanUtils.copyProperties(thresholdVo, threshold);
thresholdService.checkThreshold(threshold);
return thresholdService.save(threshold);
}
@ApiOperation("修改结论设置")
@PostMapping("update")
@AutoLog(value = "修改结论设置", operationType = OperationTypeEnum.UPDATE,module = "检查报告结论设置模块")
public boolean update(@RequestBody ThresholdUpdateVo thresholdVo) {
ThresholdEntity threshold = new ThresholdEntity();
BeanUtils.copyProperties(thresholdVo, threshold);
thresholdService.checkThreshold(threshold);
return thresholdService.updateById(threshold);
}
@ApiOperation("查询结论设置")
@GetMapping
@AutoLog(value = "查询结论设置", operationType = OperationTypeEnum.SELECT,module = "检查报告结论设置模块")
public List<ThresholdViewVo> findAll() {
List<ThresholdViewVo> result = new ArrayList<>();
List<ThresholdEntity> list = thresholdService.lambdaQuery().orderByDesc(ThresholdEntity::getUpperLimit).list();
if (CollectionUtils.isNotEmpty(list)){
result = list.stream().map(threshold -> {
ThresholdViewVo vo = new ThresholdViewVo();
BeanUtils.copyProperties(threshold, vo);
return vo;
}).collect(Collectors.toList());
}
return result;
}
@ApiOperation("删除结论设置")
@DeleteMapping
@AutoLog(value = "删除结论设置", operationType = OperationTypeEnum.DELETE,module = "检查报告结论设置模块")
public boolean removeById(String thresholdId) {
return thresholdService.deleteById(thresholdId);
}
}

View File

@ -0,0 +1,109 @@
package com.platform.check.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnComment;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnType;
import com.gitee.sunchenbin.mybatis.actable.annotation.TableComment;
import com.gitee.sunchenbin.mybatis.actable.constants.MySqlTypeConstant;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@TableName("check_task")
@TableComment("查重任务表")
public class CheckDocTask implements Serializable{
private static final long serialVersionUID = 1L;
@TableId
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("主键")
private String id;
@TableField()
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("项目idcheck_project表id")
private String checkProjectId;
@TableField()
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 300)
@ColumnComment("参与单位")
private String participateUnit;
@TableField()
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 350)
@ColumnComment("对比文档ids(check_file表id)")
private String fileIdList;
@TableField()
@ColumnType(value = MySqlTypeConstant.TINYINT)
@ColumnComment("查重类型1-批量导入文档查重2指定文档与历史库所有文档查重")
private Integer checkType;
@TableField()
@ColumnType(value = MySqlTypeConstant.TINYINT)
@ColumnComment("解析进度")
private Double taskProgress;
@TableField(value = "dept_id",fill = FieldFill.INSERT)
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("部门idbase_sys_dept表id")
private String deptId;
@TableField()
@ColumnType(value = MySqlTypeConstant.TINYINT)
@ColumnComment("提交状态0-未提交1-已提交)")
private Integer submitState;
@TableField()
@ColumnType(value = MySqlTypeConstant.TINYINT)
@ColumnComment("白名单过滤词类型0-无过滤1-文本过滤2文档内容过滤")
private Integer filterWordType;
@TableField()
@ColumnType(value = MySqlTypeConstant.TEXT)
@ColumnComment("过滤词文本")
private String filterWordText;
@TableField()
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 200)
@ColumnComment("过滤词文件地址")
private String filterWordFilePath;
@TableField()
@ColumnType(value = MySqlTypeConstant.TINYINT)
@ColumnComment("任务状态(-1-失败,0-未开始1解析中2-已完成)")
private Integer taskStatus;
@TableField()
@ColumnType(value = MySqlTypeConstant.DATETIME)
@ColumnComment("查重开始时间")
private Date startTime;
@TableField()
@ColumnType(value = MySqlTypeConstant.DATETIME)
@ColumnComment("查重结束时间")
private Date endTime;
@TableField()
@ColumnType(value = MySqlTypeConstant.DATETIME)
@ColumnComment("创建时间")
private Date createTime;
@TableField(value = "create_user_id", fill = FieldFill.INSERT)
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("创建用户id")
private String createUserId;
@TableField()
@ColumnType(value = MySqlTypeConstant.VARCHAR,length = 180)
@ColumnComment("备注")
private String remark;
}

View File

@ -0,0 +1,71 @@
package com.platform.check.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnComment;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnType;
import com.gitee.sunchenbin.mybatis.actable.annotation.TableComment;
import com.gitee.sunchenbin.mybatis.actable.constants.MySqlTypeConstant;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@TableName(value = "check_document")
@TableComment("文档对比内容")
public class CheckDocument implements Serializable{
private static final long serialVersionUID = 1L;
@TableId
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("id")
private String id;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("查重任务idcheck_task表id")
private String checkTaskId;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("查重报告idcheck_report表id")
private String checkReportId;
@TableField
@ColumnType(value = MySqlTypeConstant.TEXT)
@ColumnComment("文本重复段的前置内容")
private String frontContent;
@TableField
@ColumnType(value = MySqlTypeConstant.TEXT)
@ColumnComment("文本重复段的原文")
private String docContent;
@TableField
@ColumnType(value = MySqlTypeConstant.TEXT)
@ColumnComment("文本重复段的后置内容")
private String backContent;
@TableField
@ColumnType(value = MySqlTypeConstant.INT)
@ColumnComment("文本重复段的原文重复字数")
private Integer repeatedWords;//page_num
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR)
@ColumnComment("页码")
private String pageNum;
@TableField
@ColumnType(value = MySqlTypeConstant.INT)
@ColumnComment("排序")
private Integer sort;
@TableField
@ColumnType(value = MySqlTypeConstant.DATETIME)
@ColumnComment("创建时间")
private Date createTime;
}

View File

@ -0,0 +1,135 @@
package com.platform.check.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnComment;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnType;
import com.gitee.sunchenbin.mybatis.actable.annotation.TableComment;
import com.gitee.sunchenbin.mybatis.actable.constants.MySqlTypeConstant;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@TableName(value = "check_file")
@TableComment("文件")
public class CheckFile implements Serializable{
private static final long serialVersionUID = 1L;
@TableId
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("id")
private String id;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("文件名称")
private String fileName;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 250)
@ColumnComment("文件存储磁盘路径")
private String filePath;
@TableField
@ColumnType(value = MySqlTypeConstant.DOUBLE, length = 20)
@ColumnComment("文件大小,单位Kb")
private Double fileSize;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("后缀格式")
private String fileExt;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("文件MD5值")
private String md5Value;
@TableField
@ColumnType(value = MySqlTypeConstant.INT)
@ColumnComment("分片总数")
private Integer shareTotal;
@TableField
@ColumnType(value = MySqlTypeConstant.INT)
@ColumnComment("已上传分片索引")
private Integer shareIndex;
@TableField()
@ColumnType(value = MySqlTypeConstant.DATETIME)
@ColumnComment("创建时间")
private Date createTime;
@TableField()
@ColumnType(value = MySqlTypeConstant.VARCHAR)
@ColumnComment("标题")
private String title;
@TableField()
@ColumnType(value = MySqlTypeConstant.VARCHAR)
@ColumnComment("主题")
private String subject;
@TableField()
@ColumnType(value = MySqlTypeConstant.VARCHAR)
@ColumnComment("类别")
private String category;
@TableField()
@ColumnType(value = MySqlTypeConstant.VARCHAR)
@ColumnComment("作者")
private String author;
@TableField()
@ColumnType(value = MySqlTypeConstant.VARCHAR)
@ColumnComment("最后保存者")
private String lastAuthor;
@TableField()
@ColumnType(value = MySqlTypeConstant.VARCHAR)
@ColumnComment("修订号")
private String revisionNumber;
@TableField()
@ColumnType(value = MySqlTypeConstant.VARCHAR)
@ColumnComment("程序名称")
private String applicationName;
@TableField()
@ColumnType(value = MySqlTypeConstant.VARCHAR)
@ColumnComment("公司")
private String company;
@TableField()
@ColumnType(value = MySqlTypeConstant.VARCHAR)
@ColumnComment("管理者")
private String manager;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
@TableField()
@ColumnType(value = MySqlTypeConstant.DATETIME)
@ColumnComment("文档创建时间")
private Date createDate;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
@TableField()
@ColumnType(value = MySqlTypeConstant.DATETIME)
@ColumnComment("文档最后保存时间")
private Date lastSaveDate;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
@TableField()
@ColumnType(value = MySqlTypeConstant.DATETIME)
@ColumnComment("最后打印时间")
private Date lastPrinted;
@TableField()
@ColumnType(value = MySqlTypeConstant.VARCHAR)
@ColumnComment("总编辑时间")
private String totalEditingTime;
}

View File

@ -0,0 +1,49 @@
package com.platform.check.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnComment;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnType;
import com.gitee.sunchenbin.mybatis.actable.annotation.TableComment;
import com.gitee.sunchenbin.mybatis.actable.constants.MySqlTypeConstant;
import lombok.Data;
import java.io.Serializable;
@Data
@TableName("check_file_unit")
@TableComment("查重任务表")
public class CheckFileUnit implements Serializable {
@TableId
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("主键")
private String id;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("查重任务id")
private String taskId;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("文件id")
private String fileId;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("公司id")
private String unitId;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("部门id")
private String deptId;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("项目id")
private String projectId;
}

View File

@ -0,0 +1,47 @@
package com.platform.check.domain;
import java.io.Serializable;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnComment;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnType;
import com.gitee.sunchenbin.mybatis.actable.annotation.TableComment;
import com.gitee.sunchenbin.mybatis.actable.constants.MySqlTypeConstant;
import lombok.Data;
@Data
@TableName(value = "check_paper_library")
@TableComment("查重历史库")
public class CheckPaperLibrary implements Serializable{
private static final long serialVersionUID = 1L;
@TableId
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("id")
private String id;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("任务id")
private String taskId;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("文件id")
private String fileId;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 300)
@ColumnComment("解析后word存储路径")
private String filePath;
@TableField()
@ColumnType(value = MySqlTypeConstant.DATETIME)
@ColumnComment("创建时间")
private Date createTime;
}

View File

@ -0,0 +1,68 @@
package com.platform.check.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnComment;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnType;
import com.gitee.sunchenbin.mybatis.actable.annotation.TableComment;
import com.gitee.sunchenbin.mybatis.actable.constants.MySqlTypeConstant;
import lombok.Data;
import java.util.Date;
@Data
@TableName(value = "check_repeated_document")
@TableComment("对比库文档内容表")
public class CheckRepeatedDocument {
@TableId
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("id")
private String id;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("文档内容表idcheck_document表id")
private String checkDocumentId;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("查重报告idcheck_report表id")
private String checkReportId;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("文件idcheck_file表id")
private String checkFileId;
@TableField
@ColumnType(value = MySqlTypeConstant.TEXT)
@ColumnComment("文本重复段的前置内容")
private String frontContent;
@TableField
@ColumnType(value = MySqlTypeConstant.TEXT)
@ColumnComment("文本重复段的原文")
private String docContent;
@TableField
@ColumnType(value = MySqlTypeConstant.TEXT)
@ColumnComment("文本重复段的后置内容")
private String backContent;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR)
@ColumnComment("页码")
private String pageNum;
@TableField
@ColumnType(value = MySqlTypeConstant.INT)
@ColumnComment("排序")
private Integer sort;
@TableField()
@ColumnType(value = MySqlTypeConstant.DATETIME)
@ColumnComment("创建时间")
private Date createTime;
}

View File

@ -0,0 +1,91 @@
package com.platform.check.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnComment;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnType;
import com.gitee.sunchenbin.mybatis.actable.annotation.TableComment;
import com.gitee.sunchenbin.mybatis.actable.constants.MySqlTypeConstant;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@TableComment("查重报告表")
@TableName("check_report")
@Data
public class CheckReport implements Serializable{
private static final long serialVersionUID = 1L;
@TableId
@ColumnType(value = MySqlTypeConstant.VARCHAR,length = 50)
@ColumnComment("主键")
private String id;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR,length = 50)
@ColumnComment("任务idcheck_task表id")
private String checkTaskId;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR,length = 50)
@ColumnComment("check_file表id")
private String checkFileId;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR,length = 50)
@ColumnComment("总文字复制比")
private String similarity;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR,length = 50)
@ColumnComment("重复字数")
private String repeatWords;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR,length = 50)
@ColumnComment("结论表idcheck_threshold表id")
private String thresholdId;
@ColumnComment("总字数")
@ColumnType(value = MySqlTypeConstant.BIGINT)
@TableField
private Integer totalWords;
@ColumnComment("疑似段落最大重复字数")
@ColumnType(value = MySqlTypeConstant.BIGINT)
@TableField
private String suspectedMaxRepeatLength;
@ColumnComment("疑似段落最小重复字数")
@ColumnType(value = MySqlTypeConstant.BIGINT)
@TableField
private String suspectedMinRepeatLength;
@ColumnComment("总段落数")
@ColumnType(value = MySqlTypeConstant.INT)
@TableField
private String totalStructNumber;
@ColumnComment("疑似段落数")
@ColumnType(value = MySqlTypeConstant.INT)
@TableField
private String suspectedStructNumber;
@ColumnComment("前部重复字数")
@ColumnType(value = MySqlTypeConstant.BIGINT)
@TableField
private String foreRepeatNumber;
@ColumnComment("后部重复字数")
@ColumnType(value = MySqlTypeConstant.BIGINT)
@TableField
private String backRepeatNumber;
@ColumnComment("创建时间")
@TableField
@ColumnType(value = MySqlTypeConstant.DATETIME)
private Date createTime;
}

View File

@ -0,0 +1,51 @@
package com.platform.check.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnComment;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnType;
import com.gitee.sunchenbin.mybatis.actable.annotation.TableComment;
import com.gitee.sunchenbin.mybatis.actable.constants.MySqlTypeConstant;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@TableComment("相似文献列表")
@TableName("check_report_similar_file")
@Data
public class CheckReportSimilarFile implements Serializable{
private static final long serialVersionUID = 1L;
@TableId
@ColumnType(value = MySqlTypeConstant.VARCHAR,length = 50)
@ColumnComment("id")
private String id;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR,length = 50)
@ColumnComment("查重报告id")
private String checkReportId;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR,length = 50)
@ColumnComment("相似文件id")
private String checkFileId;
@TableField
@ColumnType(value = MySqlTypeConstant.DOUBLE)
@ColumnComment("段落相似比")
private Double similarProportion;
@TableField
@ColumnType(value = MySqlTypeConstant.INT)
@ColumnComment("重复字数")
private Integer copyWords;
@TableField
@ColumnType(value = MySqlTypeConstant.DATETIME)
@ColumnComment("创建时间")
private Date createTime;
}

View File

@ -0,0 +1,56 @@
package com.platform.check.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnComment;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnType;
import com.gitee.sunchenbin.mybatis.actable.annotation.TableComment;
import com.gitee.sunchenbin.mybatis.actable.constants.MySqlTypeConstant;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@TableName("check_task_description")
@TableComment("查重任务退回原因表")
public class CheckTaskDescription implements Serializable {
@TableId
@ColumnType(value = MySqlTypeConstant.VARCHAR,length = 50)
@ColumnComment("主键")
private String id;
@TableField(value = "task_id")
@ColumnType(value = MySqlTypeConstant.VARCHAR,length = 50)
@ColumnComment("查重任务id")
private String taskId;
@TableField(value = "analysis")
@ColumnType(value = MySqlTypeConstant.VARCHAR,length = 1500)
@ColumnComment("查重分析")
private String analysis;
@TableField(value = "description")
@ColumnType(value = MySqlTypeConstant.VARCHAR,length = 1500)
@ColumnComment("说明")
private String description;
@TableField(value = "type")
@ColumnType(value = MySqlTypeConstant.INT)
@ColumnComment("提交类型0-退回1-提交)")
private Integer type;
@TableField(value = "create_user_id", fill = FieldFill.INSERT)
@ColumnType(value = MySqlTypeConstant.VARCHAR,length = 50)
@ColumnComment("创建用户id")
private String createUserId;
@TableField(value = "create_time", fill = FieldFill.INSERT)
@ColumnType(value = MySqlTypeConstant.DATETIME)
@ColumnComment("创建时间")
private Date createTime;
}

View File

@ -0,0 +1,42 @@
package com.platform.check.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnComment;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnType;
import com.gitee.sunchenbin.mybatis.actable.annotation.TableComment;
import com.platform.common.entity.BaseEntity;
import lombok.*;
/**
* @author fubo
* @date 2022/9/3 15:07
*/
@Data
@TableName(value = "check_threshold")
@TableComment("检查阈值")
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
@NoArgsConstructor
public class ThresholdEntity extends BaseEntity {
@TableField
@ColumnComment("上限")
@ColumnType(decimalLength = 4)
private Double upperLimit;
@TableField
@ColumnComment("下限")
@ColumnType(decimalLength = 4)
private Double lowerLimit;
@TableField
@ColumnComment("颜色")
private String rgba;
@TableField
@ColumnComment("结论")
private String conclusion;
}

View File

@ -0,0 +1,14 @@
package com.platform.check.domain.dto;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class ImageHandleRequestSuccessResult implements Serializable{
private static final long serialVersionUID = 1L;
private List<String> res;
}

View File

@ -0,0 +1,22 @@
package com.platform.check.domain.vo;
import com.platform.check.domain.CheckDocTask;
import com.platform.check.domain.CheckFile;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
public class CheckDocTaskResultVo extends CheckDocTask {
@ApiModelProperty("项目名称")
private String projectName;
@ApiModelProperty("文件集合")
private List<CheckFile> files;
@ApiModelProperty("文件名称")
private String wordFileName;
}

View File

@ -0,0 +1,25 @@
package com.platform.check.domain.vo;
import com.alibaba.fastjson.annotation.JSONField;
import com.platform.check.domain.CheckDocTask;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
public class CheckDocTaskVo extends CheckDocTask{
private static final long serialVersionUID = 1L;
/**
* 上传文件
*/
@JSONField(serialize = false)
private MultipartFile file;
private String fileUnits;
}

View File

@ -0,0 +1,22 @@
package com.platform.check.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
@Data
public class CheckFileListVo implements Serializable {
private String taskId;
private String description;
private Integer taskStatus;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createDate;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endDate;
private String timeDifference;
List<CheckFileVo> checkFileVos;
}

View File

@ -0,0 +1,32 @@
package com.platform.check.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
@Data
public class CheckFileResultVo {
@ApiModelProperty("文件id")
private String id;
@ApiModelProperty("文件名称")
private String fileName;
@ApiModelProperty("文件路径")
private String filePath;
@ApiModelProperty("文件类型")
private String fileType;
@ApiModelProperty("文件大小")
private Double fileSize;
@ApiModelProperty("开始时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
}

View File

@ -0,0 +1,33 @@
package com.platform.check.domain.vo;
import com.platform.common.entity.SearchInputVo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
public class CheckFileSearchVo extends SearchInputVo {
@ApiModelProperty("文件名称")
private String fileName;
@ApiModelProperty("采购内容")
private String procurementContent;
@ApiModelProperty("开始时间")
private String startTime;
@ApiModelProperty("结束时间")
private String endTime;
@ApiModelProperty("部门id")
private String deptId;
@ApiModelProperty("公司名称")
private String unitName;
@ApiModelProperty("公司id")
private List<String> unitIds;
}

View File

@ -0,0 +1,28 @@
package com.platform.check.domain.vo;
import com.platform.check.domain.CheckFile;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
public class CheckFileVo extends CheckFile {
private static final long serialVersionUID = 1L;
@Getter @Setter
@ApiModelProperty("初步结论")
private String conclusion;
@Getter @Setter
@ApiModelProperty("结论颜色")
private String rgba;
@Getter @Setter
@ApiModelProperty("总文字复制比")
private String similarity;
@Getter @Setter
@ApiModelProperty("文件查重任务id")
private String taskId;
}

View File

@ -0,0 +1,56 @@
package com.platform.check.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.platform.check.domain.CheckDocument;
import com.platform.check.domain.CheckFile;
import com.platform.check.domain.CheckReport;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
import java.util.List;
public class CheckReportVo extends CheckReport {
private static final long serialVersionUID = 1L;
@Getter @Setter
@ApiModelProperty("采购内容")
private String procurementContent;
@Getter @Setter
@ApiModelProperty("初步结论")
private String conclusion;
@Getter @Setter
@ApiModelProperty("相似文件信息集合")
List<SimilarFileVo> reportSimilarFiles;
@Getter @Setter
@ApiModelProperty("文件信息")
private CheckFile checkFile;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Getter @Setter
@ApiModelProperty("检测时间")
private Date checkTime;
@Getter @Setter
@ApiModelProperty("检测人")
private String checkUser;
@Getter @Setter
@ApiModelProperty("存储原文内容及对比内容")
private List<DocContentContrastVo> docContentList;
public class DocContentContrastVo{
@Getter @Setter
private CheckDocument originalDoc;
@Getter @Setter
private List<SimilarContentVo> repeatDocList;
}
}

View File

@ -0,0 +1,21 @@
package com.platform.check.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
@Data
public class CheckTaskDescriptionViewVo {
private Integer type;
private String description;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date createTime;
private String createUserName;
}

View File

@ -0,0 +1,20 @@
package com.platform.check.domain.vo;
import lombok.Data;
import java.io.Serializable;
@Data
public class FileExistVo implements Serializable{
private static final long serialVersionUID = 1L;
private boolean exist;
private String fileId;
private Integer shareTotal;
private Integer shareIndex;
}

View File

@ -0,0 +1,14 @@
package com.platform.check.domain.vo;
import lombok.Data;
import java.io.Serializable;
@Data
public class FileUnit implements Serializable {
private String fileId;
private String unitName;
}

View File

@ -0,0 +1,24 @@
package com.platform.check.domain.vo;
import lombok.Data;
import java.io.Serializable;
/**
* 上传文件结果VO
*/
@Data
public class FileUploadResultVo implements Serializable{
private static final long serialVersionUID = 1L;
/**
* 是否上传完毕
*/
private boolean completed;
/**
* 记录id
*/
private String id;
}

View File

@ -0,0 +1,28 @@
package com.platform.check.domain.vo;
import com.alibaba.fastjson.annotation.JSONField;
import com.platform.check.domain.CheckFile;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.web.multipart.MultipartFile;
/**
* 上传文件VO
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class FileVo extends CheckFile{
private static final long serialVersionUID = 1L;
/**
* 是否进行分片
*/
private boolean fileShare;
/**
* 上传文件
*/
@JSONField(serialize = false)
private MultipartFile file;
}

View File

@ -0,0 +1,41 @@
package com.platform.check.domain.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
@Data
public class ReportResultVo {
@ApiModelProperty("文档查重任务id")
private String totalTaskId;
@ApiModelProperty("项目id")
private String projectId;
@ApiModelProperty("检测结论")
private String conclusion;
@ApiModelProperty("状态(0未开始,1解析中,2已完成,-1失败)")
private Integer status;
@ApiModelProperty("进度")
private Double schedule;
@ApiModelProperty("查重开始时间")
private Date startTime;
@ApiModelProperty("查重结束时间")
private Date endTime;
@ApiModelProperty("排序用创建时间时间")
private Date createTime;
@ApiModelProperty("检查类型")
private Integer checkType;
@ApiModelProperty("项目名称")
private String projectName;
@ApiModelProperty("供应商名称")
private String supplierName;
@ApiModelProperty("提交状态0未提交/1已提交")
private Integer submitState;
@ApiModelProperty("部门id")
private String deptId;
}

View File

@ -0,0 +1,18 @@
package com.platform.check.domain.vo;
import com.platform.common.entity.SearchInputVo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
public class ReportSearchVo extends SearchInputVo {
private static final long serialVersionUID = 1L;
@Getter @Setter
@ApiModelProperty("项目名称")
private String projectName;
}

View File

@ -0,0 +1,14 @@
package com.platform.check.domain.vo;
import com.platform.check.domain.CheckRepeatedDocument;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
public class SimilarContentVo extends CheckRepeatedDocument{
@Getter @Setter
@ApiModelProperty("重复内容来源文件")
private String fileName;
}

View File

@ -0,0 +1,17 @@
package com.platform.check.domain.vo;
import com.platform.check.domain.CheckReportSimilarFile;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
public class SimilarFileVo extends CheckReportSimilarFile{
private static final long serialVersionUID = 1L;
@Getter @Setter
@ApiModelProperty("文件名称")
private String fileName;
}

View File

@ -0,0 +1,14 @@
package com.platform.check.domain.vo;
import java.io.Serializable;
import lombok.Data;
@Data
public class TaskFileVo implements Serializable{
private static final long serialVersionUID = 1L;
private String taskId;
private String fileId;
}

View File

@ -0,0 +1,48 @@
package com.platform.check.domain.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
@Data
public class TaskResultVo {
@ApiModelProperty("任务监控id")
private String id;
@ApiModelProperty("文件查重任务id")
private String totalTaskId;
@ApiModelProperty("创建时间")
private Date createTime;
@ApiModelProperty("结束时间")
private Date startTime;
@ApiModelProperty("结束时间")
private Date endTime;
@ApiModelProperty("创建人")
private String createUserName;
@ApiModelProperty("进度")
private Double schedule;
@ApiModelProperty("对比方式(1.批量导入文件查重 2.指定文档与历史库所有文档查重)")
private Integer checkType;
@ApiModelProperty("状态(0未开始,1解析中,2已完成,-1失败)")
private Integer status;
@ApiModelProperty("项目名称")
private String projectName;
@ApiModelProperty("项目id")
private String projectId;
@ApiModelProperty("备注")
private String remark;
// @ApiModelProperty("对比文档状态")
// private List<DocumentViewVo> documentList;
// @ApiModelProperty("相关pdf文件状态")
// private List<PdfFileViewVo> pdfList;
}

View File

@ -0,0 +1,33 @@
package com.platform.check.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.platform.common.entity.SearchInputVo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
@Data
public class TaskSearchVo extends SearchInputVo {
@ApiModelProperty("开始时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
@ApiModelProperty("结束时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
@ApiModelProperty("对比方式(1.批量导入文件查重 2.指定文档与历史库所有文档查重)")
private Integer checkType;
@ApiModelProperty("状态")
private Integer status;
@ApiModelProperty("项目名称")
private String projectName;
}

View File

@ -0,0 +1,20 @@
package com.platform.check.domain.vo.threshold;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author fubo
* @date 2022/9/3 15:24
*/
@Data
public class ThresholdCreateVo {
@ApiModelProperty("上限")
private Double upperLimit;
@ApiModelProperty("下限")
private Double lowerLimit;
@ApiModelProperty("颜色")
private String rgba;
@ApiModelProperty("结论")
private String conclusion;
}

View File

@ -0,0 +1,16 @@
package com.platform.check.domain.vo.threshold;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
/**
* @author fubo
* @date 2022/9/3 15:25
*/
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class ThresholdUpdateVo extends ThresholdCreateVo {
private String id;
}

View File

@ -0,0 +1,31 @@
package com.platform.check.domain.vo.threshold;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* @author fubo
* @date 2022/9/3 15:24
*/
@Data
public class ThresholdViewVo {
private String id;
@ApiModelProperty("上限")
private Double upperLimit;
@ApiModelProperty("下限")
private Double lowerLimit;
@ApiModelProperty("颜色")
private String rgba;
@ApiModelProperty("结论")
private String conclusion;
@ApiModelProperty("创建者")
private String createUserName;
@ApiModelProperty("创建时间")
private Date createTime;
@ApiModelProperty("更新者")
private String updateUserName;
@ApiModelProperty("更新时间")
private Date updateTime;
}

View File

@ -0,0 +1,42 @@
package com.platform.check.enums;
import org.apache.commons.lang3.StringUtils;
/**
* 项目审核状态枚举
* @author 86187
*
*/
public enum AuditStatus {
NOT_AUDIT(0,"未审核"),COMPLATE_AUDIT(1,"已审核"),VIOLATION(2,"违规");
private Integer code;
private String message;
AuditStatus(Integer code,String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return this.code;
}
public String getMessage() {
return this.message;
}
public static String getMsgByCode(Integer code) {
if(code == null) {
return StringUtils.EMPTY;
}
for(AuditStatus checkStatus :values()) {
if(checkStatus.getCode().equals(code)) {
return checkStatus.getMessage();
}
}
return StringUtils.EMPTY;
}
}

View File

@ -0,0 +1,42 @@
package com.platform.check.enums;
import org.apache.commons.lang3.StringUtils;
/**
* 文档对比状态枚举
* @author 86187
*
*/
public enum CheckStatus {
FAIL(-1,"失败"),NOT_STARTED(0,"未开始"),PARSING(1,"解析中"),COMPLETED(2,"待提交"),PROCESS(3,"待审核"),FINISH(4,"已完成"),VIOLATION(5,"违规"),WAITING(6,"等待中");
private Integer code;
private String message;
CheckStatus(Integer code,String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return this.code;
}
public String getMessage() {
return this.message;
}
public static String getMsgByCode(Integer code) {
if(code == null) {
return StringUtils.EMPTY;
}
for(CheckStatus checkStatus :values()) {
if(checkStatus.getCode().equals(code)) {
return checkStatus.getMessage();
}
}
return StringUtils.EMPTY;
}
}

View File

@ -0,0 +1,21 @@
package com.platform.check.enums;
/**
* 查重类型枚举
* @author 86187
*
*/
public enum CheckTaskType {
BATCH_CHECK(1),HISTORY_CHECK(2);
private Integer value;
CheckTaskType(Integer value) {
this.value = value;
}
public Integer getValue() {
return this.value;
}
}

View File

@ -0,0 +1,21 @@
package com.platform.check.enums;
/**
* 文档解析类型枚举本次任务是pdf扫描件还是word
* @author 86187
*
*/
public enum DocumentParsingType {
WORD_TXT("WORD"),PDF("PDF"),IMG("IMG"),TXT("TXT");
private String value;
DocumentParsingType(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
}

View File

@ -0,0 +1,21 @@
package com.platform.check.enums;
/**
* 文件ContentType类型枚举
* @author 86187
*
*/
public enum DocumentType {
DOC("application/msword"),DOCX("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
private String value;
DocumentType(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
}

View File

@ -0,0 +1,21 @@
package com.platform.check.enums;
/**
* 文件下载类型
* @author 86187
*
*/
public enum DownloadType {
SOURCE(1),RESOLVED(2);
private Integer value;
DownloadType(Integer value) {
this.value = value;
}
public Integer getValue() {
return this.value;
}
}

View File

@ -0,0 +1,21 @@
package com.platform.check.enums;
/**
* 文件解析状态
* @author 86187
*
*/
public enum FileParseingStatus {
NOT_PARSING(0),COMPLATE_PARSING(1);
private Integer value;
FileParseingStatus(Integer value) {
this.value = value;
}
public Integer getValue() {
return this.value;
}
}

View File

@ -0,0 +1,16 @@
package com.platform.check.enums;
public enum FileSuffix {
WORD_DOC(".doc"),WORD_DOCX(".docx"),PDF(".pdf"),JPG(".jpg"),JPEG(".jpeg"),PNG(".png"),TXT(".txt");
private String value;
FileSuffix(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
}

View File

@ -0,0 +1,21 @@
package com.platform.check.enums;
/**
* 过滤词类型枚举
* @author 86187
*
*/
public enum FilterWordType {
NOT_FILTER(0),TEXT_FILTER(1),FILE_FILTER(2);
private Integer value;
FilterWordType(Integer value) {
this.value = value;
}
public Integer getValue() {
return this.value;
}
}

View File

@ -0,0 +1,21 @@
package com.platform.check.enums;
/**
* PDF图片解析枚举
* @author 86187
*
*/
public enum PDFImageParsingFlag {
/** 解析失败 */ /** 图片已解析 */ /** 图片已识别 */
PARSING_FAIL(-1),IMG_PARSING(1),IMG_OCR(2);
private Integer value;
PDFImageParsingFlag(Integer value) {
this.value = value;
}
public Integer getValue() {
return this.value;
}
}

View File

@ -0,0 +1,19 @@
package com.platform.check.enums;
public enum PDFParsingSectionPath {
/**存储解析过程中图片和文档路径 */
SECTION("section"),
/** 存储解析完成后的完整文档路径 */
WORD("word");
private String value;
PDFParsingSectionPath(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
}

View File

@ -0,0 +1,16 @@
package com.platform.check.enums;
public enum ProjectCheckFlag {
NOT_CHECK(0),COMPLATE(1);
private Integer value;
ProjectCheckFlag(int value) {
this.value = value;
}
public Integer getValue() {
return value;
}
}

View File

@ -0,0 +1,21 @@
package com.platform.check.enums;
/**
* 任务提交状态枚举
* @author 86187
*
*/
public enum SubmitState {
NOT_SUBMIT(0),SUBMITTED(1);
private Integer value;
SubmitState(Integer value) {
this.value = value;
}
public Integer getValue() {
return this.value;
}
}

View File

@ -0,0 +1,16 @@
package com.platform.check.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.platform.check.domain.CheckDocTask;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface CheckDocTaskMapper extends BaseMapper<CheckDocTask>{
String findProcurementContent(@Param("taskId") String taskId);
List<String> selectNoSubmit(String projectId);
}

View File

@ -0,0 +1,8 @@
package com.platform.check.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.platform.check.domain.CheckDocument;
public interface CheckDocumentMapper extends BaseMapper<CheckDocument> {
}

View File

@ -0,0 +1,13 @@
package com.platform.check.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.platform.check.domain.CheckFile;
import com.platform.check.domain.vo.CheckFileResultVo;
import com.platform.check.domain.vo.CheckFileSearchVo;
public interface CheckFileMapper extends BaseMapper<CheckFile>{
Page<CheckFileResultVo> findFilePage(Page<CheckFileResultVo> page, CheckFileSearchVo checkFileSearchVo);
}

View File

@ -0,0 +1,7 @@
package com.platform.check.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.platform.check.domain.CheckFileUnit;
public interface CheckFileUnitMapper extends BaseMapper<CheckFileUnit> {
}

View File

@ -0,0 +1,8 @@
package com.platform.check.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.platform.check.domain.CheckPaperLibrary;
public interface CheckPaperLibraryMapper extends BaseMapper<CheckPaperLibrary>{
}

View File

@ -0,0 +1,14 @@
package com.platform.check.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.platform.check.domain.CheckRepeatedDocument;
import com.platform.check.domain.vo.SimilarContentVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface CheckRepeatedDocumentMapper extends BaseMapper<CheckRepeatedDocument>{
List<SimilarContentVo> findListByReportId(@Param("reportId") String reportId);
}

View File

@ -0,0 +1,8 @@
package com.platform.check.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.platform.check.domain.CheckReport;
public interface CheckReportMapper extends BaseMapper<CheckReport> {
}

View File

@ -0,0 +1,14 @@
package com.platform.check.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.platform.check.domain.CheckReportSimilarFile;
import com.platform.check.domain.vo.SimilarFileVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface CheckReportSimilarFileMapper extends BaseMapper<CheckReportSimilarFile> {
List<SimilarFileVo> findSimilarFileList(@Param("reportId") String reportId);
}

View File

@ -0,0 +1,15 @@
package com.platform.check.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.platform.check.domain.CheckTaskDescription;
import com.platform.check.domain.vo.CheckTaskDescriptionViewVo;
import java.util.List;
public interface CheckTaskDescriptionMapper extends BaseMapper<CheckTaskDescription> {
String findReturnReason(String taskId);
List<CheckTaskDescriptionViewVo> findList(String taskId);
}

View File

@ -0,0 +1,11 @@
package com.platform.check.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.platform.check.domain.ThresholdEntity;
/**
* @author fubo
* @date 2022/9/3 15:11
*/
public interface ThresholdMapper extends BaseMapper<ThresholdEntity> {
}

View File

@ -0,0 +1,79 @@
package com.platform.check.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.platform.check.domain.CheckDocTask;
import com.platform.check.domain.vo.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;
/**
* 查重任务服务
*/
public interface CheckDocTaskService extends IService<CheckDocTask>{
/**
* 创建查重任务
* @param checkDocTaskVo
*/
void create(CheckDocTaskVo checkDocTaskVo);
CheckReportVo findCheckReport(String taskId, String fileId);
List<CheckReportVo> findAllReport(String taskId);
void deleteTask(String taskId);
String updateSubmitState(String taskId,Integer submitState,String description,String analysis);
CheckDocTaskResultVo findTaskDetail(String taskId);
/**
* 修改项目任务状态
* @param taskId
* @param projectId
* @param status
* @param date
*/
void updateProgressStatus(String taskId,String projectId, Integer status, Date date);
/**
* 修改任务进度
* @param checkTaskId
* @param currProgess
*/
void updateTaskProgress(String checkTaskId, Double currProgess);
/**
* 修改项目任务状态-结束
* @param checkTaskId
* @param projectId
* @param status
* @param date
* @param currProgess
*/
void updateTaskFinish(String checkTaskId,String projectId,Integer status, Date date,Double currProgess);
/**
* 停止任务
* @param projectId
*/
void stopTask(String projectId);
/**
* 下载文件对应报告信息
* @param taskId
* @param fileId
*/
void downloadCheckReport(String taskId, String fileId,HttpServletResponse res);
/**
* 下载过滤文件
* @param filterWordPath
* @param res
*/
void downloadFilterWord(String filterWordPath, String filterWordName, HttpServletRequest req, HttpServletResponse res);
}

View File

@ -0,0 +1,27 @@
package com.platform.check.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.platform.check.domain.CheckDocument;
import java.util.List;
/**
* 查重文档内容结构化存储
* @author 86187
*
*/
public interface CheckDocumentService extends IService<CheckDocument> {
/**
* 创建文档内容结构化数据
* @param checkDocument
*/
void create(CheckDocument checkDocument);
/**
* 查询报告原文内容列表
* @param reportId
* @return
*/
List<CheckDocument> findListByReportId(String id);
}

View File

@ -0,0 +1,52 @@
package com.platform.check.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.platform.check.domain.CheckFile;
import com.platform.check.domain.vo.*;
import com.platform.common.entity.PagedResultVo;
import java.util.List;
import java.util.Map;
/**
* 查重文件服务
*/
public interface CheckFileService extends IService<CheckFile> {
/**
* 验证文件是否存在
* @param fileMD5Value 文件唯一MD5值
* @return
*/
FileExistVo verifyFileExist(String fileMD5Value);
/**
* 创建文件信息
* @param checkFile
*/
void create(CheckFile checkFile);
/**
* 修改文件信息
* @param checkFile
*/
void update(CheckFile checkFile);
/**
* 上传文件
* @param fileVo
*/
FileUploadResultVo uploadFile(FileVo fileVo);
/**
* 根据文件ids数组查询文件信息
* @param ids
* @return
*/
List<CheckFile> findList(List<String> ids);
PagedResultVo<CheckFileResultVo> findFilePage(CheckFileSearchVo checkFileSearchVo);
Map<String,String> findFileMap(List<String> fileIds);
}

View File

@ -0,0 +1,24 @@
package com.platform.check.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.platform.check.domain.CheckPaperLibrary;
/**
* 查重历史库实现
*/
public interface CheckPaperLibraryService extends IService<CheckPaperLibrary>{
/**
* 创建文档历史库记录
* @param taskId
* @param fileId
* @param filePath
*/
void create(String taskId,String fileId,String filePath);
/**
* 根据任务id删除历史库
* @param taskId
*/
void deleteByTaskId(String taskId);
}

View File

@ -0,0 +1,29 @@
package com.platform.check.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.platform.check.domain.CheckRepeatedDocument;
import com.platform.check.domain.vo.SimilarContentVo;
import java.util.List;
/**
* 重复文档内容服务
* @author 86187
*
*/
public interface CheckRepeatedDocumentService extends IService<CheckRepeatedDocument>{
/**
* 创建重复文档内容数据
* @param checkRepeatedDocument
*/
void create(CheckRepeatedDocument checkRepeatedDocument);
/**
* 查询目标文档重复内容
* @param reportId
* @return
*/
List<SimilarContentVo> findListByReportId(String reportId);
}

View File

@ -0,0 +1,38 @@
package com.platform.check.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.platform.check.domain.CheckReport;
/**
* 查重报告Service
* @author 86187
*
*/
public interface CheckReportService extends IService<CheckReport>{
/**
* 创建查重报告信息
* @param checkReport
*/
void create(CheckReport checkReport);
/**
* 根据文档查重id删除报告及相关信息
* @param taskId
*/
void deleteReport(String taskId);
/**
* 修改报告结论
* @param taskId
*/
void updateThreshold(String taskId);
/**
* 查询报告
* @param taskId 任务id
* @param fileId 文件id
* @return
*/
CheckReport findByReport(String taskId,String fileId);
}

View File

@ -0,0 +1,27 @@
package com.platform.check.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.platform.check.domain.CheckReportSimilarFile;
import com.platform.check.domain.vo.SimilarFileVo;
import java.util.List;
/**
* 查重报告相似文献列表
* @author 86187
*/
public interface CheckReportSimilarFileService extends IService<CheckReportSimilarFile>{
/**
* 创建相似文件列表信息
* @param similarFile
*/
void create(CheckReportSimilarFile similarFile);
/**
* 查询相似文献列表
* @param reportId
* @return
*/
List<SimilarFileVo> findSimilarFileList(String reportId);
}

View File

@ -0,0 +1,25 @@
package com.platform.check.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.platform.check.domain.CheckTaskDescription;
import com.platform.check.domain.vo.CheckTaskDescriptionViewVo;
import java.util.List;
public interface CheckTaskDescriptionService extends IService<CheckTaskDescription> {
List<CheckTaskDescriptionViewVo> findList(String taskId);
/**
* 根据任务id查询任务注释列表
* @param taskId
* @return
*/
List<CheckTaskDescription> findByTaskId(String taskId);
/**
* 根据任务id删除任务流程注释
*/
void deleteByTaskId(String taskId);
}

View File

@ -0,0 +1,17 @@
package com.platform.check.service;
import com.platform.check.domain.CheckDocTask;
/**
* 文件解析服务
*
*/
public interface FileParsingService {
/**
* 文件解析
* 支持解析WORDPDF
* @param checkDocTask
*/
public void fileParsing(CheckDocTask checkDocTask);
}

Some files were not shown because too many files have changed in this diff Show More