49 changed files with 5110 additions and 6 deletions
-
40ocr-service/.classpath
-
3ocr-service/.gitignore
-
23ocr-service/.project
-
187ocr-service/pom.xml
-
19ocr-service/src/main/java/com/bw/ocr/Application.java
-
37ocr-service/src/main/java/com/bw/ocr/cache/ConfigCache.java
-
39ocr-service/src/main/java/com/bw/ocr/controller/TaskReceiveController.java
-
31ocr-service/src/main/java/com/bw/ocr/entity/AppResultDoc.java
-
50ocr-service/src/main/java/com/bw/ocr/entity/Constants.java
-
208ocr-service/src/main/java/com/bw/ocr/handler/MainHandler.java
-
24ocr-service/src/main/java/com/bw/ocr/service/OcrTaskService.java
-
17ocr-service/src/main/java/com/bw/ocr/service/TaskReceiveService.java
-
329ocr-service/src/main/java/com/bw/ocr/service/impl/OcrTaskServiceImpl.java
-
55ocr-service/src/main/java/com/bw/ocr/service/impl/TaskReceiveServiceImpl.java
-
48ocr-service/src/main/java/com/bw/ocr/utils/DataUtil.java
-
177ocr-service/src/main/java/com/bw/ocr/utils/DateUtil.java
-
1004ocr-service/src/main/java/com/bw/ocr/utils/DownLoadUtil.java
-
27ocr-service/src/main/java/com/bw/ocr/utils/EncryptionUtil.java
-
41ocr-service/src/main/java/com/bw/ocr/utils/FileUtil.java
-
53ocr-service/src/main/java/com/bw/ocr/utils/GPTResultParseUtil.java
-
33ocr-service/src/main/java/com/bw/ocr/utils/OtherUtils.java
-
18ocr-service/src/main/java/com/bw/ocr/utils/QueueUtil.java
-
45ocr-service/src/main/java/com/bw/ocr/utils/SpringBootKafka.java
-
23ocr-service/src/main/java/com/bw/ocr/utils/ThrowMessageUtil.java
-
52ocr-service/src/main/resources/bootstrap.yml
-
36ocr-service/src/main/resources/logback-spring.xml
-
40opai-api/.classpath
-
3opai-api/.gitignore
-
23opai-api/.project
-
173opai-api/pom.xml
-
19opai-api/src/main/java/com/bw/opai/Application.java
-
83opai-api/src/main/java/com/bw/opai/app/controller/AppController.java
-
60opai-api/src/main/java/com/bw/opai/app/dto/App.java
-
49opai-api/src/main/java/com/bw/opai/app/entity/AppResultDoc.java
-
18opai-api/src/main/java/com/bw/opai/app/mapper/AppMapper.java
-
44opai-api/src/main/java/com/bw/opai/app/service/AppService.java
-
358opai-api/src/main/java/com/bw/opai/app/service/impl/AppServiceImpl.java
-
81opai-api/src/main/java/com/bw/opai/common/Res.java
-
30opai-api/src/main/java/com/bw/opai/common/ResponseCode.java
-
34opai-api/src/main/java/com/bw/opai/file/controller/FileController.java
-
16opai-api/src/main/java/com/bw/opai/file/service/FileService.java
-
107opai-api/src/main/java/com/bw/opai/file/service/impl/FileServiceImpl.java
-
19opai-api/src/main/java/com/bw/opai/utils/Constants.java
-
177opai-api/src/main/java/com/bw/opai/utils/DateUtil.java
-
1005opai-api/src/main/java/com/bw/opai/utils/DownLoadUtil.java
-
23opai-api/src/main/java/com/bw/opai/utils/ThrowMessageUtil.java
-
52opai-api/src/main/resources/bootstrap.yml
-
36opai-api/src/main/resources/logback-spring.xml
-
37pom.xml
@ -0,0 +1,40 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<classpath> |
||||
|
<classpathentry kind="src" output="target/classes" path="src/main/java"> |
||||
|
<attributes> |
||||
|
<attribute name="optional" value="true"/> |
||||
|
<attribute name="maven.pomderived" value="true"/> |
||||
|
</attributes> |
||||
|
</classpathentry> |
||||
|
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"> |
||||
|
<attributes> |
||||
|
<attribute name="maven.pomderived" value="true"/> |
||||
|
<attribute name="optional" value="true"/> |
||||
|
</attributes> |
||||
|
</classpathentry> |
||||
|
<classpathentry kind="src" output="target/test-classes" path="src/test/java"> |
||||
|
<attributes> |
||||
|
<attribute name="optional" value="true"/> |
||||
|
<attribute name="maven.pomderived" value="true"/> |
||||
|
<attribute name="test" value="true"/> |
||||
|
</attributes> |
||||
|
</classpathentry> |
||||
|
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"> |
||||
|
<attributes> |
||||
|
<attribute name="maven.pomderived" value="true"/> |
||||
|
<attribute name="test" value="true"/> |
||||
|
<attribute name="optional" value="true"/> |
||||
|
</attributes> |
||||
|
</classpathentry> |
||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"> |
||||
|
<attributes> |
||||
|
<attribute name="maven.pomderived" value="true"/> |
||||
|
</attributes> |
||||
|
</classpathentry> |
||||
|
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> |
||||
|
<attributes> |
||||
|
<attribute name="maven.pomderived" value="true"/> |
||||
|
</attributes> |
||||
|
</classpathentry> |
||||
|
<classpathentry kind="output" path="target/classes"/> |
||||
|
</classpath> |
||||
@ -0,0 +1,3 @@ |
|||||
|
/target/ |
||||
|
/logs/ |
||||
|
/.settings/ |
||||
@ -0,0 +1,23 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<projectDescription> |
||||
|
<name>ocr-service</name> |
||||
|
<comment></comment> |
||||
|
<projects> |
||||
|
</projects> |
||||
|
<buildSpec> |
||||
|
<buildCommand> |
||||
|
<name>org.eclipse.jdt.core.javabuilder</name> |
||||
|
<arguments> |
||||
|
</arguments> |
||||
|
</buildCommand> |
||||
|
<buildCommand> |
||||
|
<name>org.eclipse.m2e.core.maven2Builder</name> |
||||
|
<arguments> |
||||
|
</arguments> |
||||
|
</buildCommand> |
||||
|
</buildSpec> |
||||
|
<natures> |
||||
|
<nature>org.eclipse.jdt.core.javanature</nature> |
||||
|
<nature>org.eclipse.m2e.core.maven2Nature</nature> |
||||
|
</natures> |
||||
|
</projectDescription> |
||||
@ -0,0 +1,187 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<project |
||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" |
||||
|
xmlns="http://maven.apache.org/POM/4.0.0" |
||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
||||
|
<modelVersion>4.0.0</modelVersion> |
||||
|
<parent> |
||||
|
<groupId>com.bw</groupId> |
||||
|
<artifactId>opai-service-center</artifactId> |
||||
|
<version>0.0.1-SNAPSHOT</version> |
||||
|
</parent> |
||||
|
<groupId>com.bw</groupId> |
||||
|
<artifactId>ocr-service</artifactId> |
||||
|
<version>0.0.1-SNAPSHOT</version> |
||||
|
<name>ocr-service</name> |
||||
|
<url>http://maven.apache.org</url> |
||||
|
<properties> |
||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
||||
|
</properties> |
||||
|
<dependencies> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-web</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>com.alibaba.cloud</groupId> |
||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.cloud</groupId> |
||||
|
<artifactId>spring-cloud-starter-openfeign</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>com.alibaba.cloud</groupId> |
||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-actuator</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.projectlombok</groupId> |
||||
|
<artifactId>lombok</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>com.alibaba</groupId> |
||||
|
<artifactId>fastjson</artifactId> |
||||
|
<version>2.0.17</version> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.apache.httpcomponents</groupId> |
||||
|
<artifactId>httpclient</artifactId> |
||||
|
<version>4.5.3</version> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.apache.httpcomponents</groupId> |
||||
|
<artifactId>httpmime</artifactId> |
||||
|
<version>4.5.13</version> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>commons-lang</groupId> |
||||
|
<artifactId>commons-lang</artifactId> |
||||
|
<version>2.6</version> |
||||
|
</dependency> |
||||
|
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp --> |
||||
|
<dependency> |
||||
|
<groupId>com.squareup.okhttp3</groupId> |
||||
|
<artifactId>okhttp</artifactId> |
||||
|
<version>4.9.3</version> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.kafka</groupId> |
||||
|
<artifactId>spring-kafka</artifactId> |
||||
|
</dependency> |
||||
|
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi --> |
||||
|
<dependency> |
||||
|
<groupId>org.apache.poi</groupId> |
||||
|
<artifactId>poi</artifactId> |
||||
|
<version>4.1.2</version> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.apache.poi</groupId> |
||||
|
<artifactId>poi-ooxml</artifactId> |
||||
|
<version>4.1.2</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<!-- 可选,处理复杂 .docx 文件时可能需要 --> |
||||
|
<dependency> |
||||
|
<groupId>org.apache.poi</groupId> |
||||
|
<artifactId>ooxml-schemas</artifactId> |
||||
|
<version>1.4</version> |
||||
|
</dependency> |
||||
|
</dependencies> |
||||
|
<build> |
||||
|
<!-- <pluginManagement> --><!-- lock down plugins versions to avoid using Maven defaults (may be |
||||
|
moved |
||||
|
to parent pom) --> |
||||
|
<plugins> |
||||
|
<!-- clean lifecycle, see |
||||
|
https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle --> |
||||
|
<plugin> |
||||
|
<artifactId>maven-clean-plugin</artifactId> |
||||
|
<version>3.1.0</version> |
||||
|
</plugin> |
||||
|
<!-- default lifecycle, jar packaging: see |
||||
|
https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging --> |
||||
|
<plugin> |
||||
|
<artifactId>maven-resources-plugin</artifactId> |
||||
|
<version>3.0.2</version> |
||||
|
</plugin> |
||||
|
<plugin> |
||||
|
<artifactId>maven-compiler-plugin</artifactId> |
||||
|
<version>3.8.0</version> |
||||
|
</plugin> |
||||
|
<plugin> |
||||
|
<artifactId>maven-surefire-plugin</artifactId> |
||||
|
<version>2.22.1</version> |
||||
|
</plugin> |
||||
|
<plugin> |
||||
|
<artifactId>maven-jar-plugin</artifactId> |
||||
|
<version>3.0.2</version> |
||||
|
</plugin> |
||||
|
<plugin> |
||||
|
<artifactId>maven-install-plugin</artifactId> |
||||
|
<version>2.5.2</version> |
||||
|
</plugin> |
||||
|
<plugin> |
||||
|
<artifactId>maven-deploy-plugin</artifactId> |
||||
|
<version>2.8.2</version> |
||||
|
</plugin> |
||||
|
<!-- site lifecycle, see |
||||
|
https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle --> |
||||
|
<plugin> |
||||
|
<artifactId>maven-site-plugin</artifactId> |
||||
|
<version>3.7.1</version> |
||||
|
</plugin> |
||||
|
<plugin> |
||||
|
<artifactId>maven-project-info-reports-plugin</artifactId> |
||||
|
<version>3.0.0</version> |
||||
|
</plugin> |
||||
|
<!-- spring-boot-maven-plugin插件就是打包spring boot应用的 --> |
||||
|
|
||||
|
<plugin> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-maven-plugin</artifactId> |
||||
|
<configuration> |
||||
|
<mainClass>com.bw.ocr.Application</mainClass> |
||||
|
<layout>ZIP</layout> |
||||
|
<includes> |
||||
|
<include> |
||||
|
<groupId>${project.groupId}</groupId> |
||||
|
<artifactId>${project.artifactId}</artifactId> |
||||
|
</include> |
||||
|
</includes> |
||||
|
</configuration> |
||||
|
<executions> |
||||
|
<execution> |
||||
|
<goals> |
||||
|
<goal>repackage</goal> |
||||
|
</goals> |
||||
|
</execution> |
||||
|
</executions> |
||||
|
</plugin> |
||||
|
<plugin> |
||||
|
<groupId>org.apache.maven.plugins</groupId> |
||||
|
<artifactId>maven-dependency-plugin</artifactId> |
||||
|
<version>3.1.1</version> |
||||
|
<executions> |
||||
|
<execution> |
||||
|
<id>copy</id> |
||||
|
<phase>package</phase> |
||||
|
<goals> |
||||
|
<goal>copy-dependencies</goal> |
||||
|
</goals> |
||||
|
<configuration> |
||||
|
<type>jar</type> |
||||
|
<includeTypes>jar</includeTypes> |
||||
|
<includeScope>runtime</includeScope> |
||||
|
<outputDirectory>${project.build.directory}/libs</outputDirectory> |
||||
|
</configuration> |
||||
|
</execution> |
||||
|
</executions> |
||||
|
</plugin> |
||||
|
</plugins> |
||||
|
<!-- </pluginManagement> --> |
||||
|
</build> |
||||
|
</project> |
||||
@ -0,0 +1,19 @@ |
|||||
|
package com.bw.ocr; |
||||
|
|
||||
|
import org.springframework.boot.SpringApplication; |
||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 系统接口启动类 |
||||
|
* @author jian.mao |
||||
|
* @date 2025年12月30日 |
||||
|
* @description |
||||
|
*/ |
||||
|
@SpringBootApplication |
||||
|
public class Application { |
||||
|
|
||||
|
public static void main(String[] args) { |
||||
|
SpringApplication.run(Application.class, args); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
package com.bw.ocr.cache; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
import java.util.concurrent.LinkedBlockingDeque; |
||||
|
|
||||
|
/** |
||||
|
* @author jian.mao |
||||
|
* @date 2022年11月11日 |
||||
|
* @description 静态变量类 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
public class ConfigCache { |
||||
|
|
||||
|
/**启动条件**/ |
||||
|
public static boolean isStart = true; |
||||
|
/*****任务队列*****/ |
||||
|
public static LinkedBlockingDeque<Map<String, Object>> taskQueue = new LinkedBlockingDeque<Map<String,Object>>(); |
||||
|
/****结果队列****/ |
||||
|
public static LinkedBlockingDeque<Map<String, Object>> resultQueue = new LinkedBlockingDeque<Map<String,Object>>(); |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 队列录入任务 |
||||
|
* @param queue |
||||
|
* @param task |
||||
|
*/ |
||||
|
public static void putQueue(LinkedBlockingDeque<Map<String, Object>> queue,Map<String, Object> task){ |
||||
|
//next app 写入队列准备调出 |
||||
|
try { |
||||
|
queue.put(task); |
||||
|
} catch (InterruptedException e) { |
||||
|
log.error("队列写入data失败---"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
package com.bw.ocr.controller; |
||||
|
|
||||
|
import javax.annotation.Resource; |
||||
|
|
||||
|
import org.springframework.stereotype.Controller; |
||||
|
import org.springframework.web.bind.annotation.PostMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestBody; |
||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestMethod; |
||||
|
import org.springframework.web.bind.annotation.ResponseBody; |
||||
|
|
||||
|
import com.bw.ocr.service.TaskReceiveService; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
|
||||
|
/** |
||||
|
* 任务接收控制层 |
||||
|
* @author jian.mao |
||||
|
* @date 2025年1月14日 |
||||
|
* @description |
||||
|
*/ |
||||
|
@Controller |
||||
|
@RequestMapping("/task") |
||||
|
@Slf4j |
||||
|
public class TaskReceiveController { |
||||
|
@Resource |
||||
|
private TaskReceiveService taskReceiveService; |
||||
|
@PostMapping("/put") |
||||
|
@ResponseBody |
||||
|
public String put(@RequestBody String param){ |
||||
|
String response = taskReceiveService.put(param); |
||||
|
return response; |
||||
|
} |
||||
|
@RequestMapping(value = "/hello", method = RequestMethod.GET) |
||||
|
@ResponseBody |
||||
|
public String hello(String param, String token) { |
||||
|
return "123"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
package com.bw.ocr.entity; |
||||
|
|
||||
|
|
||||
|
import java.io.Serializable; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
/** |
||||
|
* ES 索引:opai_app_result |
||||
|
* 应用执行结果文档 |
||||
|
* |
||||
|
* @author jian.mao |
||||
|
*/ |
||||
|
@Data |
||||
|
public class AppResultDoc implements Serializable { |
||||
|
|
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
/** 完成时间(毫秒时间戳) */ |
||||
|
private Long finishTime; |
||||
|
|
||||
|
/** 执行状态 */ |
||||
|
private Integer status; |
||||
|
|
||||
|
/** 执行结果(可索引) */ |
||||
|
private Map<String, Object> result; |
||||
|
|
||||
|
/** 最后修改时间(毫秒时间戳) */ |
||||
|
private Long lastEdit; |
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
package com.bw.ocr.entity; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 常量实体类 |
||||
|
* @author jian.mao |
||||
|
* @date 2022年11月15日 |
||||
|
* @description |
||||
|
*/ |
||||
|
public class Constants { |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 空字符串常量 |
||||
|
*/ |
||||
|
public static final String EMPTY = ""; |
||||
|
|
||||
|
/************************应用参数*************************************/ |
||||
|
public static final String CODE = "code"; |
||||
|
public static final String MESSAGE = "message"; |
||||
|
/******************************api使用*******************************/ |
||||
|
public static final String CONTENT = "content"; |
||||
|
public static final String WROD_COUNT = "wordCount"; |
||||
|
public static final String TRACE = "trace"; |
||||
|
public static final String PARSE_FIAL = "解析失败"; |
||||
|
public static final String FILEURL = "fileUrl"; |
||||
|
public static final String CREATEURL = "createUrl"; |
||||
|
public static final String JOBURL = "jobUrl"; |
||||
|
public static final String QUERYURL = "queryUrl"; |
||||
|
public static final String FILECONTENTS = "FileContents"; |
||||
|
public static final String FILENAME = "FileName"; |
||||
|
public static final String OPENPASSWORD = "OpenPassword"; |
||||
|
public static final String OWNERPASSWORD = "OwnerPassword"; |
||||
|
public static final String LOCATIONPATH = "LocationPath"; |
||||
|
public static final String SUCCESS = "success"; |
||||
|
public static final String FAILED = "failed"; |
||||
|
public static final String WORDS_RESULT = "words_result"; |
||||
|
public static final String WORDS = "words"; |
||||
|
public static final String JOBID = "jobId"; |
||||
|
public static final String PROGRESS = "Progress"; |
||||
|
public static final String JOBDOCUMENTS = "JobDocuments"; |
||||
|
public static final String OutputDocuments = "OutputDocuments"; |
||||
|
public static final String FILES = "Files"; |
||||
|
public static final String IDRENAME = "#id"; |
||||
|
|
||||
|
/** |
||||
|
* 任务id |
||||
|
*/ |
||||
|
public static final String TASKID = "taskId"; |
||||
|
} |
||||
@ -0,0 +1,208 @@ |
|||||
|
package com.bw.ocr.handler; |
||||
|
|
||||
|
import java.io.File; |
||||
|
import java.io.IOException; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
import java.util.concurrent.LinkedBlockingDeque; |
||||
|
import java.util.concurrent.LinkedBlockingQueue; |
||||
|
import java.util.concurrent.ThreadPoolExecutor; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
|
||||
|
|
||||
|
import org.apache.commons.io.FileUtils; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.boot.ApplicationArguments; |
||||
|
import org.springframework.boot.ApplicationRunner; |
||||
|
import org.springframework.cloud.context.config.annotation.RefreshScope; |
||||
|
import org.springframework.core.annotation.Order; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
import com.alibaba.fastjson.JSONObject; |
||||
|
import com.bw.ocr.cache.ConfigCache; |
||||
|
import com.bw.ocr.service.OcrTaskService; |
||||
|
import com.bw.ocr.utils.DateUtil; |
||||
|
import com.bw.ocr.utils.FileUtil; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* @author jian.mao |
||||
|
* @date 2025年1月13日 |
||||
|
* @description |
||||
|
*/ |
||||
|
@Component |
||||
|
@Order(value = 1) |
||||
|
@RefreshScope |
||||
|
@Slf4j |
||||
|
public class MainHandler implements ApplicationRunner { |
||||
|
|
||||
|
@Value("${task.task-queue-path}") |
||||
|
private String taskPath; |
||||
|
@Value("${task.result-task-queue-path}") |
||||
|
private String resultTaskPath; |
||||
|
@Autowired |
||||
|
private OcrTaskService ocrTaskService; |
||||
|
/***线程池参数***/ |
||||
|
@Value("${threadPool.corePoolSize}") |
||||
|
private int corePoolSize; |
||||
|
@Value("${threadPool.maximumPoolSize}") |
||||
|
private int maximumPoolSize; |
||||
|
@Value("${threadPool.keepAliveTime}") |
||||
|
private long keepAliveTime; |
||||
|
@Value("${threadPool.queueSize}") |
||||
|
private int queueSize; |
||||
|
|
||||
|
/** |
||||
|
*执行入口 |
||||
|
*/ |
||||
|
@Override |
||||
|
public void run(ApplicationArguments args) throws Exception { |
||||
|
//线程池方式 |
||||
|
ThreadPoolExecutor executor = new ThreadPoolExecutor( |
||||
|
corePoolSize, |
||||
|
maximumPoolSize, |
||||
|
keepAliveTime, |
||||
|
TimeUnit.SECONDS, |
||||
|
new LinkedBlockingQueue<>(queueSize), |
||||
|
new ThreadPoolExecutor.CallerRunsPolicy() |
||||
|
); |
||||
|
//消费创建任务队列数据 |
||||
|
Thread consumerThread = new Thread(() -> { |
||||
|
while (true) { |
||||
|
try { |
||||
|
// 从队列中获取任务 |
||||
|
Map<String, Object> task = ConfigCache.taskQueue.take(); |
||||
|
// 提交给线程池执行 |
||||
|
executor.execute(() -> createTask(task)); |
||||
|
} catch (InterruptedException e) { |
||||
|
// 恢复中断状态 |
||||
|
Thread.currentThread().interrupt(); |
||||
|
log.error("任务消费线程被中断"); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
consumerThread.start(); |
||||
|
log.info("创建任务消费线程启动-----"); |
||||
|
|
||||
|
|
||||
|
//消费结果任务队列数据 |
||||
|
Thread resultConsumerThread = new Thread(() -> { |
||||
|
while (true) { |
||||
|
try { |
||||
|
// 从队列中获取任务 |
||||
|
Map<String, Object> task = ConfigCache.resultQueue.take(); |
||||
|
// 提交给线程池执行 |
||||
|
executor.execute(() -> getResult(task)); |
||||
|
} catch (InterruptedException e) { |
||||
|
// 恢复中断状态 |
||||
|
Thread.currentThread().interrupt(); |
||||
|
log.error("任务消费线程被中断"); |
||||
|
break; |
||||
|
} |
||||
|
DateUtil.sleep(3000); |
||||
|
} |
||||
|
}); |
||||
|
resultConsumerThread.start(); |
||||
|
log.info("结果任务消费线程启动-----"); |
||||
|
//启动加载缓存任务 |
||||
|
readTask(taskPath, ConfigCache.taskQueue); |
||||
|
readTask(resultTaskPath, ConfigCache.resultQueue); |
||||
|
//停止处理 |
||||
|
waitDown(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 创建任务执行方法 |
||||
|
* @param task |
||||
|
*/ |
||||
|
private void createTask(Map<String, Object> task) { |
||||
|
ocrTaskService.create(task); |
||||
|
} |
||||
|
|
||||
|
private void getResult(Map<String, Object> task) { |
||||
|
ocrTaskService.parse(task); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/****************************************************************load******************************************************************************/ |
||||
|
/** |
||||
|
* 加载文件中的任务 |
||||
|
* @param path 文件地址 |
||||
|
* @param queue 队列 |
||||
|
*/ |
||||
|
@SuppressWarnings("unchecked") |
||||
|
public static void readTask(String path, LinkedBlockingDeque<Map<String, Object>> queue) { |
||||
|
File file = new File(path); |
||||
|
if (file.exists()) { |
||||
|
List<String> tasks = null; |
||||
|
try { |
||||
|
tasks = FileUtils.readLines(file, "UTF-8"); |
||||
|
} catch (IOException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
for (String taskStr : tasks) { |
||||
|
Map<String, Object> task = JSONObject.parseObject(taskStr); |
||||
|
try { |
||||
|
queue.put(task); |
||||
|
} catch (InterruptedException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
file.delete(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/*******************************************************************stop************************************************************************/ |
||||
|
|
||||
|
/** |
||||
|
* 结束触发钩子 |
||||
|
*/ |
||||
|
public void waitDown() { |
||||
|
Runtime.getRuntime().addShutdownHook(new Thread() { |
||||
|
@Override |
||||
|
public void run() { |
||||
|
// 停止线程 |
||||
|
ConfigCache.isStart = false; |
||||
|
log.info("stop-------"); |
||||
|
writeTsskToFile(); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 任务持久化到硬盘 |
||||
|
*/ |
||||
|
public void writeTsskToFile() { |
||||
|
while (true) { |
||||
|
if (ConfigCache.taskQueue.size() > 0) { |
||||
|
try { |
||||
|
Map<String, Object> task = ConfigCache.taskQueue.take(); |
||||
|
FileUtil.writeFile(taskPath, JSONObject.toJSONString(task)); |
||||
|
} catch (InterruptedException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} else { |
||||
|
log.info("taskQueue write is file end"); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
while (true) { |
||||
|
if (ConfigCache.resultQueue.size() > 0) { |
||||
|
try { |
||||
|
Map<String, Object> task = ConfigCache.resultQueue.take(); |
||||
|
FileUtil.writeFile(resultTaskPath, JSONObject.toJSONString(task)); |
||||
|
} catch (InterruptedException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} else { |
||||
|
log.info("taskQueue write is file end"); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
package com.bw.ocr.service; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
|
||||
|
/** |
||||
|
* ocr识别处理接口 |
||||
|
* @author jian.mao |
||||
|
* @date 2025年2月18日 |
||||
|
* @description |
||||
|
*/ |
||||
|
public interface OcrTaskService { |
||||
|
|
||||
|
/** |
||||
|
* ocr远端任务 |
||||
|
* @param task |
||||
|
*/ |
||||
|
public void create(Map<String, Object> task); |
||||
|
|
||||
|
/** |
||||
|
* 解析结果 |
||||
|
* @param task |
||||
|
*/ |
||||
|
public void parse(Map<String, Object> task); |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
package com.bw.ocr.service; |
||||
|
|
||||
|
/** |
||||
|
* 任务接收服务层 |
||||
|
* @author jian.mao |
||||
|
* @date 2025年1月14日 |
||||
|
* @description |
||||
|
*/ |
||||
|
public interface TaskReceiveService { |
||||
|
|
||||
|
/** |
||||
|
* 任务新增 |
||||
|
* @param dataJson |
||||
|
* @return |
||||
|
*/ |
||||
|
public String put(String dataJson); |
||||
|
} |
||||
329
ocr-service/src/main/java/com/bw/ocr/service/impl/OcrTaskServiceImpl.java
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,55 @@ |
|||||
|
package com.bw.ocr.service.impl; |
||||
|
|
||||
|
import java.util.HashMap; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import com.alibaba.fastjson.JSONObject; |
||||
|
import com.bw.ocr.cache.ConfigCache; |
||||
|
import com.bw.ocr.entity.Constants; |
||||
|
import com.bw.ocr.service.TaskReceiveService; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
|
||||
|
/** |
||||
|
* 任务接收服务层实现类 |
||||
|
* @author jian.mao |
||||
|
* @date 2025年1月14日 |
||||
|
* @description |
||||
|
*/ |
||||
|
@Service |
||||
|
@Slf4j |
||||
|
public class TaskReceiveServiceImpl implements TaskReceiveService { |
||||
|
|
||||
|
@Override |
||||
|
public String put(String dataJson) { |
||||
|
Map<String, Object> response = new HashMap<>(16); |
||||
|
int code = 200; |
||||
|
String message = "success"; |
||||
|
Map<String, Object> task = null; |
||||
|
try { |
||||
|
task = JSONObject.parseObject(dataJson); |
||||
|
} catch (Exception e) { |
||||
|
log.error("参数结构不合法,", e); |
||||
|
code = 100010; |
||||
|
message = "参数不合法"; |
||||
|
} |
||||
|
// 写入队列 |
||||
|
try { |
||||
|
if(task.containsKey(Constants.TRACE) && (boolean)task.get(Constants.TRACE)){ |
||||
|
ConfigCache.taskQueue.putFirst(task); |
||||
|
}else{ |
||||
|
ConfigCache.taskQueue.put(task); |
||||
|
} |
||||
|
} catch (InterruptedException e) { |
||||
|
log.error("任务写入队列异常,", e); |
||||
|
code = 100011; |
||||
|
message = "任务写入队列失败"; |
||||
|
} |
||||
|
response.put(Constants.CODE, code); |
||||
|
response.put(Constants.MESSAGE, message); |
||||
|
return JSONObject.toJSONString(response); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,48 @@ |
|||||
|
package com.bw.ocr.utils; |
||||
|
|
||||
|
import com.alibaba.fastjson.JSON; |
||||
|
import com.alibaba.fastjson.JSONObject; |
||||
|
import com.alibaba.fastjson.JSONPath; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
|
||||
|
/** |
||||
|
* @author:jinming |
||||
|
* @className:DataUtil |
||||
|
* @version:1.0 |
||||
|
* @description: 获取dataValue的值 |
||||
|
* @Date:2023/11/1 9:54 |
||||
|
*/ |
||||
|
public class DataUtil { |
||||
|
/** |
||||
|
* |
||||
|
* @param key 传入的key |
||||
|
* @param dataMap 数据map |
||||
|
* @return 根据传入的参数进行判断解析,返回正确的dataValue |
||||
|
*/ |
||||
|
public static Object getValue(String key, Map dataMap) { |
||||
|
Object dataValue; |
||||
|
String isJson = "#json#"; |
||||
|
if (key.contains(isJson)) { |
||||
|
//进行第一次拆分,获取#json#前面的部分 |
||||
|
String[] keySplit = key.split(isJson); |
||||
|
String firstDataKey = keySplit[0]; |
||||
|
String[] firstDataKeySplit = firstDataKey.split(":"); |
||||
|
//取出前半部分对应的JSON数据并转换为JSONObject |
||||
|
String dataJson = (String) dataMap.get(firstDataKeySplit[0]); |
||||
|
JSONObject dataJsonObject = JSON.parseObject(dataJson); |
||||
|
//根据key的后半部分取出对应JSONObject中的值 |
||||
|
String firstDataKeyJson = (String) JSONPath.eval(dataJsonObject, firstDataKeySplit[1]); |
||||
|
String secDataKey = keySplit[1]; |
||||
|
JSONObject firstDataJsonObject = JSON.parseObject(firstDataKeyJson); |
||||
|
dataValue = JSONPath.eval(firstDataJsonObject, secDataKey); |
||||
|
return dataValue; |
||||
|
} |
||||
|
String[] keySplit = key.split(":"); |
||||
|
String jsonPath = keySplit[1]; |
||||
|
String dataJson = (String) dataMap.get(keySplit[0]); |
||||
|
JSONObject dataJsonObject = JSON.parseObject(dataJson); |
||||
|
dataValue = JSONPath.eval(dataJsonObject, jsonPath); |
||||
|
return dataValue; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,177 @@ |
|||||
|
package com.bw.ocr.utils; |
||||
|
|
||||
|
|
||||
|
import java.math.BigInteger; |
||||
|
import java.security.MessageDigest; |
||||
|
import java.security.NoSuchAlgorithmException; |
||||
|
import java.text.ParseException; |
||||
|
import java.text.SimpleDateFormat; |
||||
|
import java.time.LocalDateTime; |
||||
|
import java.time.format.DateTimeFormatter; |
||||
|
import java.util.Date; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
|
||||
|
import com.alibaba.fastjson.JSON; |
||||
|
import com.alibaba.fastjson.JSONObject; |
||||
|
|
||||
|
/** |
||||
|
* 日期工具类 |
||||
|
* |
||||
|
* @author jian.mao |
||||
|
* @date 2022年11月15日 |
||||
|
* @description |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
public class DateUtil { |
||||
|
|
||||
|
/** |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String getTimeStrForNow() { |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHH"); |
||||
|
return sdf.format(new Date()); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public static String getTimeStrForDay(long time) { |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); |
||||
|
|
||||
|
return sdf.format(new Date(time * 1000)); |
||||
|
} |
||||
|
|
||||
|
public static String getTimeStrForDay() { |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); |
||||
|
|
||||
|
return sdf.format(new Date()); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public static String getDateTime() { |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
||||
|
String time = sdf.format(new Date()); |
||||
|
return time; |
||||
|
} |
||||
|
|
||||
|
public static String getDateTime(Long timestap) { |
||||
|
|
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
||||
|
String time = sdf.format(new Date(timestap)); |
||||
|
return time; |
||||
|
} |
||||
|
|
||||
|
public static String getDate(Long timestap) { |
||||
|
|
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
||||
|
String time = sdf.format(new Date(timestap)); |
||||
|
return time; |
||||
|
} |
||||
|
|
||||
|
public static String getDateTimeForMonth() { |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM"); |
||||
|
String time = sdf.format(new Date()); |
||||
|
return time; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 休眠 |
||||
|
* |
||||
|
* @param millis 毫秒 |
||||
|
*/ |
||||
|
public static void sleep(long millis) { |
||||
|
try { |
||||
|
Thread.sleep(millis); |
||||
|
} catch (InterruptedException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 1. @Description:时间戳转时间 |
||||
|
* 2. @Author: ying.zhao |
||||
|
* 3. @Date: 2023/3/28 |
||||
|
*/ |
||||
|
|
||||
|
public static String timestampToDate(String time) { |
||||
|
int thirteen = 13; |
||||
|
int ten = 10; |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
||||
|
// if (time.length() == thirteen) { |
||||
|
if (time.length() > ten) { |
||||
|
return sdf.format(new Date(Long.parseLong(time))); |
||||
|
} else { |
||||
|
return sdf.format(new Date(Integer.parseInt(time) * 1000L)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static String parseCreated(String jsonTime){ |
||||
|
String formattedDateTime = getDateTime(); |
||||
|
try { |
||||
|
// 使用fastjson解析JSON数据 |
||||
|
JSONObject jsonObject = JSON.parseObject(jsonTime); |
||||
|
// 获取日期和时间的值 |
||||
|
JSONObject dateObject = jsonObject.getJSONObject("date"); |
||||
|
int day = dateObject.getIntValue("day"); |
||||
|
int month = dateObject.getIntValue("month"); |
||||
|
int year = dateObject.getIntValue("year"); |
||||
|
|
||||
|
JSONObject timeObject = jsonObject.getJSONObject("time"); |
||||
|
int hour = timeObject.getIntValue("hour"); |
||||
|
int minute = timeObject.getIntValue("minute"); |
||||
|
int second = timeObject.getIntValue("second"); |
||||
|
|
||||
|
// 创建LocalDateTime对象 |
||||
|
LocalDateTime dateTime = LocalDateTime.of(year, month, day, hour, minute, second); |
||||
|
|
||||
|
// 定义日期时间格式化器 |
||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); |
||||
|
|
||||
|
// 格式化日期时间 |
||||
|
formattedDateTime = dateTime.format(formatter); |
||||
|
} catch (Exception e) { |
||||
|
log.info("日期转换失败:{}",e); |
||||
|
} |
||||
|
return formattedDateTime; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 字符串转换日期 |
||||
|
* @param format |
||||
|
* @param date |
||||
|
* @return |
||||
|
*/ |
||||
|
public static Date strToDate(String format,String date){ |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat(format); |
||||
|
if (date == null || date.equals("")){ |
||||
|
return new Date(); |
||||
|
}else{ |
||||
|
Date ru = null; |
||||
|
try { |
||||
|
ru = sdf.parse(date); |
||||
|
} catch (ParseException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
return ru; |
||||
|
} |
||||
|
} |
||||
|
/** |
||||
|
* 日期格式话 |
||||
|
* @param format 日期格式 |
||||
|
* @param dater 要转换的日期,默认当前时间 |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String FormatDate(String format,Date date){ |
||||
|
String fromatDate = null; |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat(format); |
||||
|
if (date == null){ |
||||
|
fromatDate = sdf.format(new Date()); |
||||
|
}else{ |
||||
|
fromatDate = sdf.format(date); |
||||
|
} |
||||
|
return fromatDate; |
||||
|
} |
||||
|
public static void main(String[] args) { |
||||
|
String time = timestampToDate("955814400000"); |
||||
|
System.out.println(time); |
||||
|
} |
||||
|
} |
||||
1004
ocr-service/src/main/java/com/bw/ocr/utils/DownLoadUtil.java
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,27 @@ |
|||||
|
package com.bw.ocr.utils; |
||||
|
|
||||
|
import java.security.MessageDigest; |
||||
|
import java.security.NoSuchAlgorithmException; |
||||
|
|
||||
|
/** |
||||
|
* @author jian.mao |
||||
|
* @date 2023年3月10日 |
||||
|
* @description |
||||
|
*/ |
||||
|
public class EncryptionUtil { |
||||
|
public static String md5(String text) { |
||||
|
try { |
||||
|
MessageDigest md = MessageDigest.getInstance("MD5"); |
||||
|
md.update(text.getBytes()); |
||||
|
byte[] bytes = md.digest(); |
||||
|
StringBuilder sb = new StringBuilder(); |
||||
|
for (byte b : bytes) { |
||||
|
sb.append(String.format("%02x", b & 0xff)); |
||||
|
} |
||||
|
return sb.toString(); |
||||
|
} catch (NoSuchAlgorithmException e) { |
||||
|
e.printStackTrace(); |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
package com.bw.ocr.utils; |
||||
|
|
||||
|
import java.io.File; |
||||
|
import java.io.FileWriter; |
||||
|
import java.io.IOException; |
||||
|
|
||||
|
/** |
||||
|
* 文件工具类 |
||||
|
* @author jian.mao |
||||
|
* @date 2023年7月14日 |
||||
|
* @description |
||||
|
*/ |
||||
|
public class FileUtil { |
||||
|
|
||||
|
/** |
||||
|
* 数据写入文件 |
||||
|
* @param Path 文件路径 |
||||
|
* @param result 数据 |
||||
|
* @throws IOException |
||||
|
*/ |
||||
|
public static void writeFile(String path,String result){ |
||||
|
try { |
||||
|
FileWriter fw = new FileWriter(path,true); |
||||
|
fw.write(result+"\n"); |
||||
|
fw.flush(); |
||||
|
fw.close(); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static void delFile(String path) { |
||||
|
try { |
||||
|
File file = new File(path); |
||||
|
file.delete(); |
||||
|
} catch (Exception e) { |
||||
|
// TODO: handle exception |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,53 @@ |
|||||
|
package com.bw.ocr.utils; |
||||
|
import com.alibaba.fastjson.JSON; |
||||
|
import com.alibaba.fastjson.JSONObject; |
||||
|
import com.alibaba.fastjson.JSONException; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.Map; |
||||
|
import java.util.regex.Matcher; |
||||
|
import java.util.regex.Pattern; |
||||
|
|
||||
|
/** |
||||
|
* @author:jinming |
||||
|
* @className:GPTResultParseUtil |
||||
|
* @version:1.0 |
||||
|
* @description: |
||||
|
* @Date:2024/6/28 10:11 |
||||
|
*/ |
||||
|
public class GPTResultParseUtil { |
||||
|
public static Map<String, Object> parseGPTResult(Map<String, Object> output, String gptContent) { |
||||
|
Map<String, Object> jsonResult = new HashMap<>(); |
||||
|
try { |
||||
|
// 替换```json, ``` 和 \n |
||||
|
String jsonContent = gptContent.replace("```json", "").replace("```", "").replace("\n", ""); |
||||
|
JSONObject jsonGPT = JSON.parseObject(jsonContent); |
||||
|
|
||||
|
for (String key : output.keySet()) { |
||||
|
if (jsonGPT.containsKey(key)) { |
||||
|
jsonResult.put(key, jsonGPT.get(key)); |
||||
|
} |
||||
|
} |
||||
|
return jsonResult; |
||||
|
} catch (JSONException e) { |
||||
|
try { |
||||
|
// 直接解析失败,使用正则表达式匹配外层的 {} |
||||
|
Pattern pattern = Pattern.compile("\\{.*\\}", Pattern.DOTALL); |
||||
|
Matcher matcher = pattern.matcher(gptContent.replace("\n", "")); |
||||
|
if (matcher.find()) { |
||||
|
JSONObject jsonGPT = JSON.parseObject(matcher.group()); |
||||
|
for (String key : output.keySet()) { |
||||
|
if (jsonGPT.containsKey(key)) { |
||||
|
jsonResult.put(key, jsonGPT.get(key)); |
||||
|
} |
||||
|
} |
||||
|
return jsonResult; |
||||
|
} else { |
||||
|
return null; |
||||
|
} |
||||
|
} catch (Exception ex) { |
||||
|
ex.printStackTrace(); |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
package com.bw.ocr.utils; |
||||
|
|
||||
|
import java.security.MessageDigest; |
||||
|
|
||||
|
/** |
||||
|
* 其他工具类 |
||||
|
* @author jian.mao |
||||
|
* @date 2023年9月19日 |
||||
|
* @description |
||||
|
*/ |
||||
|
public class OtherUtils { |
||||
|
|
||||
|
|
||||
|
|
||||
|
public static String getMd5(String string) { |
||||
|
try { |
||||
|
MessageDigest md5 = MessageDigest.getInstance("MD5"); |
||||
|
byte[] bs = md5.digest(string.getBytes("UTF-8")); |
||||
|
StringBuilder sb = new StringBuilder(40); |
||||
|
for (byte x : bs) { |
||||
|
if ((x & 0xff) >> 4 == 0) { |
||||
|
sb.append("0").append(Integer.toHexString(x & 0xff)); |
||||
|
} else { |
||||
|
sb.append(Integer.toHexString(x & 0xff)); |
||||
|
} |
||||
|
} |
||||
|
return sb.toString(); |
||||
|
} catch (Exception e) { |
||||
|
|
||||
|
return "nceaform" + System.currentTimeMillis(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
package com.bw.ocr.utils; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
import java.util.concurrent.LinkedBlockingDeque; |
||||
|
|
||||
|
/** |
||||
|
* @author:jinming |
||||
|
* @className:QueueUtil |
||||
|
* @version:1.0 |
||||
|
* @description: |
||||
|
* @Date:2023/7/13 15:00 |
||||
|
*/ |
||||
|
public class QueueUtil { |
||||
|
|
||||
|
public static LinkedBlockingDeque<Map<String, Object>> taskQueue = new LinkedBlockingDeque<Map<String, Object>>(); |
||||
|
|
||||
|
public static LinkedBlockingDeque<String> sendQueue = new LinkedBlockingDeque<String>(); |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
package com.bw.ocr.utils; |
||||
|
|
||||
|
import com.alibaba.fastjson.JSONObject; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.kafka.core.KafkaTemplate; |
||||
|
import org.springframework.kafka.support.SendResult; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.springframework.util.concurrent.ListenableFuture; |
||||
|
import org.springframework.util.concurrent.ListenableFutureCallback; |
||||
|
|
||||
|
/** |
||||
|
* @PROJECT_NAME: companybusinesscrawl |
||||
|
* @DESCRIPTION:SpringBootKafka 工具类 |
||||
|
* @DATE: 2023/4/6 11:09 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Component |
||||
|
public class SpringBootKafka { |
||||
|
@Autowired |
||||
|
private KafkaTemplate<String, Object> kafkaTemplate; |
||||
|
/** |
||||
|
* 自定义topicKafkaTemplate |
||||
|
*/ |
||||
|
/** |
||||
|
* public static final String TOPIC = "companyBussTest"; |
||||
|
**/ |
||||
|
public void send(String topic, String message) { |
||||
|
//发送消息 |
||||
|
ListenableFuture<SendResult<String, Object>> future = kafkaTemplate.send(topic, message); |
||||
|
future.addCallback(new ListenableFutureCallback<SendResult<String, Object>>() { |
||||
|
@Override |
||||
|
public void onFailure(Throwable throwable) { |
||||
|
//发送失败的处理 |
||||
|
log.info(topic + " - 生产者 发送消息失败:" + throwable.getMessage()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onSuccess(SendResult<String, Object> stringObjectSendResult) { |
||||
|
//成功的处理 |
||||
|
log.info(topic + " - 生产者 发送消息成功" ); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
package com.bw.ocr.utils; |
||||
|
|
||||
|
import java.io.PrintWriter; |
||||
|
import java.io.StringWriter; |
||||
|
|
||||
|
/** |
||||
|
* @author jian.mao |
||||
|
* @date 2023年3月22日 |
||||
|
* @description |
||||
|
*/ |
||||
|
public class ThrowMessageUtil { |
||||
|
|
||||
|
/** |
||||
|
* 获取异常信息 |
||||
|
* @param t |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String getErrmessage(Throwable t){ |
||||
|
StringWriter stringWriter=new StringWriter(); |
||||
|
t.printStackTrace(new PrintWriter(stringWriter,true)); |
||||
|
return stringWriter.getBuffer().toString(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,52 @@ |
|||||
|
# ==================== 必须文件:bootstrap.yml ==================== |
||||
|
# 这个文件用于配置Nacos客户端,优先级最高 |
||||
|
spring: |
||||
|
application: |
||||
|
name: ocr-service # 服务名,对应Nacos中的Data ID |
||||
|
|
||||
|
cloud: |
||||
|
nacos: |
||||
|
# ======== 配置中心 ======== |
||||
|
config: |
||||
|
server-addr: 127.0.0.1:8848 # Nacos地址 |
||||
|
username: nacos # 用户名 |
||||
|
password: nacos # 密码 |
||||
|
group: public_dev # 分组 |
||||
|
namespace: opai # 命名空间(默认public) |
||||
|
file-extension: yaml # 配置文件格式 |
||||
|
timeout: 5000 # 超时时间(ms) |
||||
|
|
||||
|
# 核心配置:开启动态刷新 |
||||
|
refresh-enabled: true # 必须为true! |
||||
|
|
||||
|
# 主配置文件(从Nacos加载) |
||||
|
data-id: ${spring.application.name}.${spring.cloud.nacos.config.file-extension} |
||||
|
|
||||
|
# 共享配置文件(可选) |
||||
|
shared-configs[0]: |
||||
|
data-id: application.yaml # 公共配置 |
||||
|
group: public_dev # 公共分组 |
||||
|
namespace: opai |
||||
|
refresh: true # 公共配置也要刷新 |
||||
|
|
||||
|
# 扩展配置(可选) |
||||
|
# extension-configs[0]: |
||||
|
# data-id: datasource.yaml |
||||
|
# group: dev |
||||
|
# refresh: true |
||||
|
|
||||
|
# ======== 服务发现 ======== |
||||
|
discovery: |
||||
|
server-addr: ${spring.cloud.nacos.config.server-addr} |
||||
|
username: ${spring.cloud.nacos.config.username} |
||||
|
password: ${spring.cloud.nacos.config.password} |
||||
|
group: ${spring.cloud.nacos.config.group} |
||||
|
namespace: ${spring.cloud.nacos.config.namespace} |
||||
|
|
||||
|
logging: |
||||
|
level: |
||||
|
root: info |
||||
|
com.alibaba.nacos.client.config.impl: WARN |
||||
|
file: |
||||
|
path: ../logs |
||||
|
|
||||
@ -0,0 +1,36 @@ |
|||||
|
<configuration> |
||||
|
<!-- 属性文件:在properties文件中找到对应的配置项 --> |
||||
|
<springProperty scope="context" name="log-path" source="logging.file.path"/> |
||||
|
<!--<springProperty scope="context" name="logging.level" source="logging.level.com.bfd"/>--> |
||||
|
<!-- 默认的控制台日志输出,一般生产环境都是后台启动,这个没太大作用 --> |
||||
|
<!-- <appender name="STDOUT" |
||||
|
class="ch.qos.logback.core.ConsoleAppender"> |
||||
|
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> |
||||
|
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %line %-5level %logger{50} - %msg%n</Pattern> |
||||
|
</encoder> |
||||
|
</appender> --> |
||||
|
|
||||
|
<appender name="GLMAPPER-LOGGERONE" |
||||
|
class="ch.qos.logback.core.rolling.RollingFileAppender"> |
||||
|
<append>true</append> |
||||
|
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> |
||||
|
<level>${logging.level}</level> |
||||
|
</filter> |
||||
|
<file> |
||||
|
${log-path}/ocr-service.log |
||||
|
</file> |
||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
||||
|
<FileNamePattern>${log-path}/ocr-service.log.%d{yyyy-MM-dd}</FileNamePattern> |
||||
|
<MaxHistory>7</MaxHistory> |
||||
|
</rollingPolicy> |
||||
|
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> |
||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %line %-5level %logger{50} - %msg%n</pattern> |
||||
|
<charset>UTF-8</charset> |
||||
|
</encoder> |
||||
|
</appender> |
||||
|
|
||||
|
<root level="info"> |
||||
|
<appender-ref ref="GLMAPPER-LOGGERONE"/> |
||||
|
<!-- <appender-ref ref="STDOUT"/> --> |
||||
|
</root> |
||||
|
</configuration> |
||||
@ -0,0 +1,40 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<classpath> |
||||
|
<classpathentry kind="src" output="target/classes" path="src/main/java"> |
||||
|
<attributes> |
||||
|
<attribute name="optional" value="true"/> |
||||
|
<attribute name="maven.pomderived" value="true"/> |
||||
|
</attributes> |
||||
|
</classpathentry> |
||||
|
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"> |
||||
|
<attributes> |
||||
|
<attribute name="maven.pomderived" value="true"/> |
||||
|
<attribute name="optional" value="true"/> |
||||
|
</attributes> |
||||
|
</classpathentry> |
||||
|
<classpathentry kind="src" output="target/test-classes" path="src/test/java"> |
||||
|
<attributes> |
||||
|
<attribute name="optional" value="true"/> |
||||
|
<attribute name="maven.pomderived" value="true"/> |
||||
|
<attribute name="test" value="true"/> |
||||
|
</attributes> |
||||
|
</classpathentry> |
||||
|
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"> |
||||
|
<attributes> |
||||
|
<attribute name="maven.pomderived" value="true"/> |
||||
|
<attribute name="test" value="true"/> |
||||
|
<attribute name="optional" value="true"/> |
||||
|
</attributes> |
||||
|
</classpathentry> |
||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"> |
||||
|
<attributes> |
||||
|
<attribute name="maven.pomderived" value="true"/> |
||||
|
</attributes> |
||||
|
</classpathentry> |
||||
|
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> |
||||
|
<attributes> |
||||
|
<attribute name="maven.pomderived" value="true"/> |
||||
|
</attributes> |
||||
|
</classpathentry> |
||||
|
<classpathentry kind="output" path="target/classes"/> |
||||
|
</classpath> |
||||
@ -0,0 +1,3 @@ |
|||||
|
/target/ |
||||
|
/logs/ |
||||
|
/.settings/ |
||||
@ -0,0 +1,23 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<projectDescription> |
||||
|
<name>opai-api</name> |
||||
|
<comment></comment> |
||||
|
<projects> |
||||
|
</projects> |
||||
|
<buildSpec> |
||||
|
<buildCommand> |
||||
|
<name>org.eclipse.jdt.core.javabuilder</name> |
||||
|
<arguments> |
||||
|
</arguments> |
||||
|
</buildCommand> |
||||
|
<buildCommand> |
||||
|
<name>org.eclipse.m2e.core.maven2Builder</name> |
||||
|
<arguments> |
||||
|
</arguments> |
||||
|
</buildCommand> |
||||
|
</buildSpec> |
||||
|
<natures> |
||||
|
<nature>org.eclipse.jdt.core.javanature</nature> |
||||
|
<nature>org.eclipse.m2e.core.maven2Nature</nature> |
||||
|
</natures> |
||||
|
</projectDescription> |
||||
@ -0,0 +1,173 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<project |
||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" |
||||
|
xmlns="http://maven.apache.org/POM/4.0.0" |
||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
||||
|
<modelVersion>4.0.0</modelVersion> |
||||
|
<parent> |
||||
|
<groupId>com.bw</groupId> |
||||
|
<artifactId>opai-service-center</artifactId> |
||||
|
<version>0.0.1-SNAPSHOT</version> |
||||
|
<relativePath>../pom.xml</relativePath> |
||||
|
</parent> |
||||
|
<groupId>com.bw</groupId> |
||||
|
<artifactId>opai-api</artifactId> |
||||
|
<version>0.0.1-SNAPSHOT</version> |
||||
|
<name>opai-api</name> |
||||
|
<url>http://maven.apache.org</url> |
||||
|
<properties> |
||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
||||
|
</properties> |
||||
|
<dependencies> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-web</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>com.alibaba.cloud</groupId> |
||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.cloud</groupId> |
||||
|
<artifactId>spring-cloud-starter-openfeign</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>com.alibaba.cloud</groupId> |
||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-actuator</artifactId> |
||||
|
</dependency> |
||||
|
<!-- Spring Boot JDBC / MySQL 数据源 --> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-jdbc</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>mysql</groupId> |
||||
|
<artifactId>mysql-connector-java</artifactId> |
||||
|
<scope>runtime</scope> |
||||
|
</dependency> |
||||
|
|
||||
|
<!-- MyBatis-Plus Boot Starter --> |
||||
|
<dependency> |
||||
|
<groupId>com.baomidou</groupId> |
||||
|
<artifactId>mybatis-plus-boot-starter</artifactId> |
||||
|
<version>3.4.3.4</version> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.projectlombok</groupId> |
||||
|
<artifactId>lombok</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>com.alibaba</groupId> |
||||
|
<artifactId>fastjson</artifactId> |
||||
|
<version>2.0.17</version> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.apache.httpcomponents</groupId> |
||||
|
<artifactId>httpclient</artifactId> |
||||
|
<version>4.5.3</version> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.apache.httpcomponents</groupId> |
||||
|
<artifactId>httpmime</artifactId> |
||||
|
<version>4.5.13</version> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>commons-lang</groupId> |
||||
|
<artifactId>commons-lang</artifactId> |
||||
|
<version>2.6</version> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>com.baomidou</groupId> |
||||
|
<artifactId>mybatis-plus-boot-starter</artifactId> |
||||
|
<version>3.4.3.4</version> |
||||
|
</dependency> |
||||
|
|
||||
|
</dependencies> |
||||
|
<build> |
||||
|
<plugins> |
||||
|
<plugin> |
||||
|
<artifactId>maven-clean-plugin</artifactId> |
||||
|
<version>3.1.0</version> |
||||
|
</plugin> |
||||
|
<plugin> |
||||
|
<artifactId>maven-resources-plugin</artifactId> |
||||
|
<version>3.0.2</version> |
||||
|
</plugin> |
||||
|
<plugin> |
||||
|
<artifactId>maven-compiler-plugin</artifactId> |
||||
|
<version>3.8.0</version> |
||||
|
</plugin> |
||||
|
<plugin> |
||||
|
<artifactId>maven-surefire-plugin</artifactId> |
||||
|
<version>2.22.1</version> |
||||
|
</plugin> |
||||
|
<plugin> |
||||
|
<artifactId>maven-jar-plugin</artifactId> |
||||
|
<version>3.0.2</version> |
||||
|
</plugin> |
||||
|
<plugin> |
||||
|
<artifactId>maven-install-plugin</artifactId> |
||||
|
<version>2.5.2</version> |
||||
|
</plugin> |
||||
|
<plugin> |
||||
|
<artifactId>maven-deploy-plugin</artifactId> |
||||
|
<version>2.8.2</version> |
||||
|
</plugin> |
||||
|
<plugin> |
||||
|
<artifactId>maven-site-plugin</artifactId> |
||||
|
<version>3.7.1</version> |
||||
|
</plugin> |
||||
|
<plugin> |
||||
|
<artifactId>maven-project-info-reports-plugin</artifactId> |
||||
|
<version>3.0.0</version> |
||||
|
</plugin> |
||||
|
|
||||
|
<plugin> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-maven-plugin</artifactId> |
||||
|
<configuration> |
||||
|
<mainClass>com.bw.opai.Application</mainClass> |
||||
|
<layout>ZIP</layout> |
||||
|
<includes> |
||||
|
<include> |
||||
|
<groupId>${project.groupId}</groupId> |
||||
|
<artifactId>${project.artifactId}</artifactId> |
||||
|
</include> |
||||
|
</includes> |
||||
|
</configuration> |
||||
|
<executions> |
||||
|
<execution> |
||||
|
<goals> |
||||
|
<goal>repackage</goal> |
||||
|
</goals> |
||||
|
</execution> |
||||
|
</executions> |
||||
|
</plugin> |
||||
|
<plugin> |
||||
|
<groupId>org.apache.maven.plugins</groupId> |
||||
|
<artifactId>maven-dependency-plugin</artifactId> |
||||
|
<version>3.1.1</version> |
||||
|
<executions> |
||||
|
<execution> |
||||
|
<id>copy</id> |
||||
|
<phase>package</phase> |
||||
|
<goals> |
||||
|
<goal>copy-dependencies</goal> |
||||
|
</goals> |
||||
|
<configuration> |
||||
|
<type>jar</type> |
||||
|
<includeTypes>jar</includeTypes> |
||||
|
<includeScope>runtime</includeScope> |
||||
|
<outputDirectory>${project.build.directory}/libs</outputDirectory> |
||||
|
</configuration> |
||||
|
</execution> |
||||
|
</executions> |
||||
|
</plugin> |
||||
|
</plugins> |
||||
|
<!-- </pluginManagement> --> |
||||
|
</build> |
||||
|
</project> |
||||
@ -0,0 +1,19 @@ |
|||||
|
package com.bw.opai; |
||||
|
|
||||
|
import org.springframework.boot.SpringApplication; |
||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 系统接口启动类 |
||||
|
* @author jian.mao |
||||
|
* @date 2025年12月30日 |
||||
|
* @description |
||||
|
*/ |
||||
|
@SpringBootApplication |
||||
|
public class Application { |
||||
|
|
||||
|
public static void main(String[] args) { |
||||
|
SpringApplication.run(Application.class, args); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,83 @@ |
|||||
|
package com.bw.opai.app.controller; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
|
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.cloud.context.config.annotation.RefreshScope; |
||||
|
import org.springframework.web.bind.annotation.GetMapping; |
||||
|
import org.springframework.web.bind.annotation.PathVariable; |
||||
|
import org.springframework.web.bind.annotation.PostMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestBody; |
||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestParam; |
||||
|
import org.springframework.web.bind.annotation.RestController; |
||||
|
|
||||
|
import com.bw.opai.app.service.AppService; |
||||
|
import com.bw.opai.common.Res; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
|
||||
|
/** |
||||
|
* 应用控制层 |
||||
|
* @author jian.mao |
||||
|
* @date 2025年12月31日 |
||||
|
* @description |
||||
|
*/ |
||||
|
@RestController |
||||
|
@Slf4j |
||||
|
@RefreshScope |
||||
|
@RequestMapping("/apps") |
||||
|
|
||||
|
public class AppController { |
||||
|
|
||||
|
@Autowired |
||||
|
private AppService appService; |
||||
|
/** |
||||
|
* 获取应用列表 |
||||
|
* @param page 页码,默认第1页 |
||||
|
* @param limit 每页条数,默认10条 |
||||
|
* @return 应用列表 |
||||
|
*/ |
||||
|
@GetMapping("/list") |
||||
|
public Res<?> getApps( |
||||
|
@RequestParam(value = "page", defaultValue = "1", required = false) Integer page, |
||||
|
@RequestParam(value = "size", defaultValue = "10", required = false) Integer size) { |
||||
|
|
||||
|
return appService.getApps(page, size); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据应用 ID 查询详情 |
||||
|
* @param id 应用 ID |
||||
|
* @return 应用详情 |
||||
|
*/ |
||||
|
@GetMapping("/detail/{id}") |
||||
|
public Res<?> getAppDetail(@PathVariable("id") Integer id) { |
||||
|
return appService.getAppDetail(id); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 启动应用 |
||||
|
* @param param JSON 请求参数 |
||||
|
* @return 启动结果 |
||||
|
*/ |
||||
|
@PostMapping("/start") |
||||
|
public Res<?> startApp(@RequestBody Map<String, Object> param) { |
||||
|
|
||||
|
return appService.startApp(param); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 查询当前登录用户的任务列表(ES) |
||||
|
*/ |
||||
|
@GetMapping("/tasks") |
||||
|
public Res<?> getMyTasks( |
||||
|
@RequestParam(value = "page", defaultValue = "1", required = false) Integer page, |
||||
|
@RequestParam(value = "size", defaultValue = "10", required = false) Integer size) { |
||||
|
|
||||
|
return appService.getMyTasks(page, size); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,60 @@ |
|||||
|
package com.bw.opai.app.dto; |
||||
|
import com.baomidou.mybatisplus.annotation.*; |
||||
|
import lombok.Data; |
||||
|
import java.time.LocalDateTime; |
||||
|
|
||||
|
/** |
||||
|
* 应用表 |
||||
|
* @author jian.mao |
||||
|
* @date 2026年1月4日 |
||||
|
* @description |
||||
|
*/ |
||||
|
@Data |
||||
|
@TableName("app") |
||||
|
public class App { |
||||
|
|
||||
|
/** |
||||
|
* 应用id |
||||
|
*/ |
||||
|
@TableId(value = "id", type = IdType.AUTO) |
||||
|
private Integer id; |
||||
|
|
||||
|
private Integer createUserId; |
||||
|
private String createUser; |
||||
|
private Integer updateUserId; |
||||
|
private String updateUser; |
||||
|
|
||||
|
@TableField(fill = FieldFill.INSERT) |
||||
|
private LocalDateTime createTime; |
||||
|
|
||||
|
@TableField(fill = FieldFill.INSERT_UPDATE) |
||||
|
private LocalDateTime updateTime; |
||||
|
|
||||
|
/** |
||||
|
* 删除标识 |
||||
|
*/ |
||||
|
@TableLogic |
||||
|
private Integer del; |
||||
|
|
||||
|
/** |
||||
|
* 应用logo |
||||
|
*/ |
||||
|
private String logo; |
||||
|
|
||||
|
/** |
||||
|
* 功能 |
||||
|
*/ |
||||
|
private String feature; |
||||
|
/** |
||||
|
* 名称 |
||||
|
*/ |
||||
|
private String name; |
||||
|
/** |
||||
|
* 说明 |
||||
|
*/ |
||||
|
private String description; |
||||
|
/** |
||||
|
* 应用接口地址 |
||||
|
*/ |
||||
|
private String api; |
||||
|
} |
||||
@ -0,0 +1,49 @@ |
|||||
|
package com.bw.opai.app.entity; |
||||
|
|
||||
|
|
||||
|
import java.io.Serializable; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
/** |
||||
|
* ES 索引:opai_app_result |
||||
|
* 应用执行结果文档 |
||||
|
* |
||||
|
* @author jian.mao |
||||
|
*/ |
||||
|
@Data |
||||
|
public class AppResultDoc implements Serializable { |
||||
|
|
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
/** 应用ID */ |
||||
|
private Integer appId; |
||||
|
|
||||
|
/** 应用名称 */ |
||||
|
private String appName; |
||||
|
|
||||
|
/** 用户ID */ |
||||
|
private String userId; |
||||
|
|
||||
|
/** 任务参数(可索引) */ |
||||
|
private Map<String, Object> task; |
||||
|
|
||||
|
/** 创建时间(毫秒时间戳) */ |
||||
|
private Long createTime; |
||||
|
|
||||
|
/** 完成时间(毫秒时间戳) */ |
||||
|
private Long finishTime; |
||||
|
|
||||
|
/** 执行状态 */ |
||||
|
private Integer status; |
||||
|
|
||||
|
/** 执行结果(可索引) */ |
||||
|
private Map<String, Object> result; |
||||
|
|
||||
|
/** 逻辑删除标识:0-未删除 1-已删除 */ |
||||
|
private Integer del; |
||||
|
|
||||
|
/** 最后修改时间(毫秒时间戳) */ |
||||
|
private Long lastEdit; |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
package com.bw.opai.app.mapper; |
||||
|
|
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||
|
import com.bw.opai.app.dto.App; |
||||
|
|
||||
|
/** |
||||
|
* 应用mapper |
||||
|
* @author jian.mao |
||||
|
* @date 2026年1月4日 |
||||
|
* @description |
||||
|
*/ |
||||
|
@Mapper |
||||
|
public interface AppMapper extends BaseMapper<App> { |
||||
|
|
||||
|
|
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
package com.bw.opai.app.service; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
|
||||
|
import com.bw.opai.common.Res; |
||||
|
|
||||
|
/** |
||||
|
* 应用服务层接口 |
||||
|
* @author jian.mao |
||||
|
* @date 2026年1月4日 |
||||
|
* @description |
||||
|
*/ |
||||
|
public interface AppService { |
||||
|
|
||||
|
/** |
||||
|
* 应用列表 |
||||
|
* @param page 页码数 |
||||
|
* @param limit 条数 |
||||
|
* @return |
||||
|
*/ |
||||
|
public Res<?> getApps(Integer page,Integer size); |
||||
|
|
||||
|
/** |
||||
|
* 根据id查询应用 |
||||
|
* @param id |
||||
|
* @return |
||||
|
*/ |
||||
|
public Res<?> getAppDetail(Integer id); |
||||
|
|
||||
|
/** |
||||
|
* 应用启动 |
||||
|
* @param param |
||||
|
* @return |
||||
|
*/ |
||||
|
public Res<?> startApp(Map<String, Object> param); |
||||
|
|
||||
|
/** |
||||
|
* 查询当前账号任务 |
||||
|
* @param page |
||||
|
* @param size |
||||
|
* @return |
||||
|
*/ |
||||
|
public Res<?> getMyTasks(Integer page, Integer size); |
||||
|
} |
||||
@ -0,0 +1,358 @@ |
|||||
|
package com.bw.opai.app.service.impl; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
import org.apache.http.HttpResponse; |
||||
|
import org.apache.http.auth.AuthScope; |
||||
|
import org.apache.http.auth.UsernamePasswordCredentials; |
||||
|
import org.apache.http.client.CredentialsProvider; |
||||
|
import org.apache.http.client.methods.HttpPost; |
||||
|
import org.apache.http.entity.ContentType; |
||||
|
import org.apache.http.entity.StringEntity; |
||||
|
import org.apache.http.impl.client.BasicCredentialsProvider; |
||||
|
import org.apache.http.impl.client.CloseableHttpClient; |
||||
|
import org.apache.http.impl.client.HttpClients; |
||||
|
import org.apache.http.util.EntityUtils; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.cloud.context.config.annotation.RefreshScope; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import com.alibaba.fastjson.JSONArray; |
||||
|
import com.alibaba.fastjson.JSONObject; |
||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
|
import com.bw.opai.app.dto.App; |
||||
|
import com.bw.opai.app.entity.AppResultDoc; |
||||
|
import com.bw.opai.app.mapper.AppMapper; |
||||
|
import com.bw.opai.app.service.AppService; |
||||
|
import com.bw.opai.common.Res; |
||||
|
import com.bw.opai.utils.Constants; |
||||
|
import com.bw.opai.utils.DownLoadUtil; |
||||
|
|
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
|
||||
|
@Service |
||||
|
@Slf4j |
||||
|
@RefreshScope |
||||
|
@RequiredArgsConstructor |
||||
|
public class AppServiceImpl implements AppService { |
||||
|
|
||||
|
private final AppMapper appMapper; |
||||
|
|
||||
|
|
||||
|
@Value("${elasticsearch.url}") |
||||
|
private String esUrl; |
||||
|
|
||||
|
@Value("${elasticsearch.username}") |
||||
|
private String esUser; |
||||
|
|
||||
|
@Value("${elasticsearch.password}") |
||||
|
private String esPassword; |
||||
|
|
||||
|
@Value("${elasticsearch.index-name}") |
||||
|
private String indexName; |
||||
|
|
||||
|
@Override |
||||
|
public Res<?> getApps(Integer page, Integer size) { |
||||
|
// 参数校验 |
||||
|
if (page == null || page < 1) { |
||||
|
page = 1; |
||||
|
} |
||||
|
if (size == null || size < 1 || size > 100) { |
||||
|
// 限制最大查询条数,防止过度查询 |
||||
|
size = 10; |
||||
|
} |
||||
|
try { |
||||
|
Page<App> pageParam = new Page<>(page, size); |
||||
|
QueryWrapper<App> queryWrapper = new QueryWrapper<>(); |
||||
|
queryWrapper.eq("del", 0); |
||||
|
Page<App> result = appMapper.selectPage(pageParam, queryWrapper); |
||||
|
// 调用公共分页封装方法 |
||||
|
return Res.page(result); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
log.error("查询应用列表失败", e); |
||||
|
return Res.fail("查询应用列表失败"); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
@Override |
||||
|
public Res<?> getAppDetail(Integer id) { |
||||
|
try { |
||||
|
if (id == null || id <= 0) { |
||||
|
return Res.fail("应用ID不合法"); |
||||
|
} |
||||
|
// 根据 ID 查询 |
||||
|
App app = appMapper.selectById(id); |
||||
|
// del = 0 表示未删除 |
||||
|
if (app == null || app.getDel() != 0) { |
||||
|
return Res.fail("未找到对应应用"); |
||||
|
} |
||||
|
return Res.ok(app); |
||||
|
} catch (Exception e) { |
||||
|
log.error("查询应用详情失败, id={}", id, e); |
||||
|
return Res.fail("查询应用详情失败"); |
||||
|
} |
||||
|
} |
||||
|
@Override |
||||
|
public Res<?> startApp(Map<String, Object> param) { |
||||
|
// TODO Auto-generated method stub |
||||
|
if (param == null || param.isEmpty()) { |
||||
|
return Res.fail("请求参数不能为空"); |
||||
|
} |
||||
|
try { |
||||
|
// 这里写你的启动逻辑 |
||||
|
// 比如:获取应用ID -> 更新状态 -> 返回结果 |
||||
|
Integer appId = param.get("id") == null ? null : Integer.valueOf(param.get("id").toString()); |
||||
|
if (appId == null) { |
||||
|
return Res.fail("应用ID不能为空"); |
||||
|
} |
||||
|
//任务id校验 |
||||
|
String taskId = param.get("taskId") == null||param.get("taskId").toString().equals("")? null : param.get("taskId").toString(); |
||||
|
if (taskId == null) { |
||||
|
return Res.fail("任务ID不能为空"); |
||||
|
} |
||||
|
// 伪示例:根据 ID 查询应用并启动 |
||||
|
App app = appMapper.selectById(appId); |
||||
|
if (app == null || app.getDel() != 0) { |
||||
|
return Res.fail("未找到对应应用"); |
||||
|
} |
||||
|
//应用调用 |
||||
|
String appUrl = app.getApi(); |
||||
|
String downloadRes = DownLoadUtil.doPost(appUrl, JSONObject.toJSONString(param)); |
||||
|
if (downloadRes.contains(Constants.DOWNLOAD_ERROR_SUFFIX)) { |
||||
|
//下载失败直接返回 |
||||
|
log.error("启动应用请求异常, param={},download error:{}", param, downloadRes); |
||||
|
return Res.fail("启动应用请求异常"); |
||||
|
} |
||||
|
//任务记录写入es |
||||
|
long now = System.currentTimeMillis(); |
||||
|
|
||||
|
AppResultDoc esEntity = new AppResultDoc(); |
||||
|
esEntity.setAppId(app.getId()); |
||||
|
esEntity.setAppName(app.getName()); |
||||
|
//用户token -- 先给默认值 |
||||
|
esEntity.setUserId("1"); |
||||
|
|
||||
|
esEntity.setTask(param); |
||||
|
esEntity.setResult(null); |
||||
|
|
||||
|
esEntity.setCreateTime(now); |
||||
|
esEntity.setFinishTime(null); |
||||
|
// 运行中 0 是运行中,1是完成,2是失败 |
||||
|
esEntity.setStatus(0); |
||||
|
esEntity.setDel(0); |
||||
|
esEntity.setLastEdit(now); |
||||
|
|
||||
|
// ---------- 写入 ES ---------- |
||||
|
boolean isSuccess = save(esEntity, taskId); |
||||
|
if(!isSuccess) { |
||||
|
//记录写入失败,直接返回错误信息 |
||||
|
log.error("启动应用记录写入异常, param={}", param); |
||||
|
return Res.fail("启动应用记录写入异常"); |
||||
|
} |
||||
|
// ---------- 返回 ---------- |
||||
|
return Res.ok(esEntity); |
||||
|
} catch (Exception e) { |
||||
|
log.error("启动应用未知异常, param={}", param, e); |
||||
|
return Res.fail("启动应用未知异常"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 节点数据持久化 |
||||
|
* @param esEntity |
||||
|
* @return |
||||
|
*/ |
||||
|
private boolean save(AppResultDoc esEntity,String docId){ |
||||
|
// 创建凭据提供者 |
||||
|
CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); |
||||
|
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(esUser, esPassword)); |
||||
|
// 创建一个 HttpClient,设置凭据提供者 |
||||
|
CloseableHttpClient httpClient = null; |
||||
|
try { |
||||
|
// 创建一个 HTTP POST 请求用于写入数据到索引 |
||||
|
if(esUser != null && !esUser.trim().equals(Constants.EMPTY)){ |
||||
|
// 创建凭据提供者 |
||||
|
httpClient = HttpClients.custom() |
||||
|
.setDefaultCredentialsProvider(credentialsProvider) |
||||
|
.build(); |
||||
|
}else{ |
||||
|
httpClient = HttpClients.custom().build(); |
||||
|
} |
||||
|
|
||||
|
StringBuffer host = new StringBuffer(); |
||||
|
host.append(esUrl); |
||||
|
host.append("/"); |
||||
|
host.append(indexName); |
||||
|
host.append("/_doc/"); |
||||
|
// Elasticsearch主机、索引名称和文档ID |
||||
|
host.append(docId); |
||||
|
HttpPost httpPost = new HttpPost(host.toString()); |
||||
|
// 设置请求体,包含要写入的文档数据 |
||||
|
StringEntity entity = new StringEntity(JSONObject.toJSONString(esEntity), ContentType.APPLICATION_JSON); |
||||
|
httpPost.setEntity(entity); |
||||
|
// 发送请求并获取响应 |
||||
|
HttpResponse response = httpClient.execute(httpPost); |
||||
|
// 处理响应 |
||||
|
int statusCode = response.getStatusLine().getStatusCode(); |
||||
|
String responseBody = EntityUtils.toString(response.getEntity()); |
||||
|
int code = 201; |
||||
|
int updateCode = 200; |
||||
|
if (statusCode == code) { |
||||
|
log.info("数据成功写入到索引:{},文档ID:{},appid:{},userId:{}",indexName,docId,esEntity.getAppId(),esEntity.getUserId()); |
||||
|
return true; |
||||
|
}else if(statusCode == updateCode){ |
||||
|
log.info("数据成功更新到索引:{},文档ID:{},appid:{},userId:{}",indexName,docId,esEntity.getAppId(),esEntity.getUserId()); |
||||
|
return true; |
||||
|
} else { |
||||
|
log.error("数据写入失败:{},文档ID:{},appid:{},es响应内容:{}",indexName,docId,esEntity.getAppId(),responseBody); |
||||
|
return false; |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
log.error("数据写入异常:",e); |
||||
|
return false; |
||||
|
} finally { |
||||
|
try { |
||||
|
if(httpClient != null) { |
||||
|
httpClient.close(); |
||||
|
} |
||||
|
} catch (Exception ignored){} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Res<?> getMyTasks(Integer page, Integer size) { |
||||
|
|
||||
|
if (page == null || page < 1) { |
||||
|
page = 1; |
||||
|
} |
||||
|
if (size == null || size < 1 || size > 100) { |
||||
|
size = 10; |
||||
|
} |
||||
|
|
||||
|
// 从登录上下文获取 userId(你项目里已有) 先写死 |
||||
|
String userId = "1"; |
||||
|
if (userId == null || userId.trim().equals("")) { |
||||
|
return Res.fail("未获取到用户信息"); |
||||
|
} |
||||
|
|
||||
|
CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); |
||||
|
credentialsProvider.setCredentials( |
||||
|
AuthScope.ANY, |
||||
|
new UsernamePasswordCredentials(esUser, esPassword) |
||||
|
); |
||||
|
|
||||
|
CloseableHttpClient httpClient = null; |
||||
|
try { |
||||
|
if (esUser != null && !esUser.trim().equals("")) { |
||||
|
httpClient = HttpClients.custom() |
||||
|
.setDefaultCredentialsProvider(credentialsProvider) |
||||
|
.build(); |
||||
|
} else { |
||||
|
httpClient = HttpClients.custom().build(); |
||||
|
} |
||||
|
|
||||
|
// ================== 构建查询 DSL ================== |
||||
|
int from = (page - 1) * size; |
||||
|
|
||||
|
Map<String, Object> query = new HashMap<String, Object>(); |
||||
|
query.put("from", from); |
||||
|
query.put("size", size); |
||||
|
|
||||
|
// must 条件 |
||||
|
List<Map<String, Object>> mustList = new ArrayList<Map<String, Object>>(); |
||||
|
|
||||
|
Map<String, Object> termUser = new HashMap<String, Object>(); |
||||
|
termUser.put("userId", userId); |
||||
|
Map<String, Object> termUserWrap = new HashMap<String, Object>(); |
||||
|
termUserWrap.put("term", termUser); |
||||
|
mustList.add(termUserWrap); |
||||
|
|
||||
|
Map<String, Object> termDel = new HashMap<String, Object>(); |
||||
|
termDel.put("del", 0); |
||||
|
Map<String, Object> termDelWrap = new HashMap<String, Object>(); |
||||
|
termDelWrap.put("term", termDel); |
||||
|
mustList.add(termDelWrap); |
||||
|
|
||||
|
Map<String, Object> bool = new HashMap<String, Object>(); |
||||
|
bool.put("must", mustList); |
||||
|
|
||||
|
Map<String, Object> queryBody = new HashMap<String, Object>(); |
||||
|
queryBody.put("bool", bool); |
||||
|
|
||||
|
query.put("query", queryBody); |
||||
|
|
||||
|
// sort |
||||
|
List<Map<String, Object>> sortList = new ArrayList<Map<String, Object>>(); |
||||
|
Map<String, Object> order = new HashMap<String, Object>(); |
||||
|
order.put("order", "desc"); |
||||
|
Map<String, Object> sortField = new HashMap<String, Object>(); |
||||
|
sortField.put("createTime", order); |
||||
|
sortList.add(sortField); |
||||
|
query.put("sort", sortList); |
||||
|
|
||||
|
// ================== 发起 HTTP 请求 ================== |
||||
|
StringBuffer host = new StringBuffer(); |
||||
|
host.append(esUrl) |
||||
|
.append("/") |
||||
|
.append(indexName) |
||||
|
.append("/_search"); |
||||
|
|
||||
|
HttpPost httpPost = new HttpPost(host.toString()); |
||||
|
httpPost.setHeader("Content-Type", "application/json"); |
||||
|
|
||||
|
StringEntity entity = new StringEntity( |
||||
|
JSONObject.toJSONString(query), |
||||
|
ContentType.APPLICATION_JSON |
||||
|
); |
||||
|
httpPost.setEntity(entity); |
||||
|
|
||||
|
HttpResponse response = httpClient.execute(httpPost); |
||||
|
int statusCode = response.getStatusLine().getStatusCode(); |
||||
|
String responseBody = EntityUtils.toString(response.getEntity(), "UTF-8"); |
||||
|
|
||||
|
if (statusCode != 200) { |
||||
|
log.error("ES 查询失败 status={}, body={}", statusCode, responseBody); |
||||
|
return Res.fail("ES 查询失败"); |
||||
|
} |
||||
|
|
||||
|
// ================== 解析返回 ================== |
||||
|
JSONObject json = JSONObject.parseObject(responseBody); |
||||
|
JSONObject hits = json.getJSONObject("hits"); |
||||
|
|
||||
|
Long total = hits.getJSONObject("total").getLong("value"); |
||||
|
|
||||
|
List<AppResultDoc> list = new ArrayList<AppResultDoc>(); |
||||
|
JSONArray hitList = hits.getJSONArray("hits"); |
||||
|
for (int i = 0; i < hitList.size(); i++) { |
||||
|
JSONObject source = hitList.getJSONObject(i).getJSONObject("_source"); |
||||
|
AppResultDoc item = source.toJavaObject(AppResultDoc.class); |
||||
|
list.add(item); |
||||
|
} |
||||
|
|
||||
|
Map<String, Object> result = new HashMap<String, Object>(); |
||||
|
result.put("page", page); |
||||
|
result.put("size", size); |
||||
|
result.put("total", total); |
||||
|
result.put("list", list); |
||||
|
|
||||
|
return Res.ok(result); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
log.error("查询用户任务失败 userId={}", userId, e); |
||||
|
return Res.fail("查询任务失败"); |
||||
|
} finally { |
||||
|
if (httpClient != null) { |
||||
|
try { |
||||
|
httpClient.close(); |
||||
|
} catch (Exception ignored) {} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,81 @@ |
|||||
|
package com.bw.opai.common; |
||||
|
|
||||
|
import java.util.HashMap; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
|
|
||||
|
/** |
||||
|
* 通用返回对象 |
||||
|
* |
||||
|
* @author jian.mao |
||||
|
* @date 2025年9月17日 |
||||
|
* @description |
||||
|
* @param <T> |
||||
|
*/ |
||||
|
|
||||
|
public class Res<T> { |
||||
|
private int resCode; |
||||
|
private String resMsg; |
||||
|
private T data; |
||||
|
|
||||
|
public Res() { |
||||
|
} |
||||
|
|
||||
|
public Res(int resCode, String resMsg, T data) { |
||||
|
this.resCode = resCode; |
||||
|
this.resMsg = resMsg; |
||||
|
this.data = data; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 分页结果封装 |
||||
|
* @param page MyBatis-Plus 分页对象 |
||||
|
* @param <T> 实体类型 |
||||
|
* @return Res<Map> 包含 total/page/size/records |
||||
|
*/ |
||||
|
public static <T> Res<Map<String, Object>> page(Page<T> page) { |
||||
|
Map<String, Object> pageData = new HashMap<>(); |
||||
|
pageData.put("total", page.getTotal()); |
||||
|
pageData.put("page", page.getCurrent()); |
||||
|
pageData.put("size", page.getSize()); |
||||
|
pageData.put("records", page.getRecords()); |
||||
|
return Res.ok(pageData); |
||||
|
} |
||||
|
|
||||
|
public static <T> Res<T> ok(T data) { |
||||
|
return new Res<T>(ResponseCode.SUCCESS.code(), ResponseCode.SUCCESS.message(), data); |
||||
|
} |
||||
|
|
||||
|
public static <T> Res<T> fail(String msg) { |
||||
|
return new Res<T>(ResponseCode.FAIL.code(), msg, null); |
||||
|
} |
||||
|
public static <T> Res<T> checkError(T error) { |
||||
|
return new Res<T>(ResponseCode.FAIL.code(), ResponseCode.CHECKERROR.message(), error); |
||||
|
} |
||||
|
|
||||
|
// getter & setter |
||||
|
public int getResCode() { |
||||
|
return resCode; |
||||
|
} |
||||
|
|
||||
|
public void setResCode(int resCode) { |
||||
|
this.resCode = resCode; |
||||
|
} |
||||
|
|
||||
|
public String getResMsg() { |
||||
|
return resMsg; |
||||
|
} |
||||
|
|
||||
|
public void setResMsg(String resMsg) { |
||||
|
this.resMsg = resMsg; |
||||
|
} |
||||
|
|
||||
|
public T getData() { |
||||
|
return data; |
||||
|
} |
||||
|
|
||||
|
public void setData(T data) { |
||||
|
this.data = data; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
package com.bw.opai.common; |
||||
|
|
||||
|
/** |
||||
|
* 状态码管理 |
||||
|
* @author jian.mao |
||||
|
* @date 2025年9月17日 |
||||
|
* @description |
||||
|
*/ |
||||
|
public enum ResponseCode { |
||||
|
|
||||
|
SUCCESS(0, "success"), |
||||
|
FAIL(-1, "fail"), |
||||
|
CHECKERROR(400, "paramsError"); |
||||
|
|
||||
|
private final int code; |
||||
|
private final String message; |
||||
|
|
||||
|
ResponseCode(int code, String message) { |
||||
|
this.code = code; |
||||
|
this.message = message; |
||||
|
} |
||||
|
|
||||
|
public int code() { |
||||
|
return code; |
||||
|
} |
||||
|
|
||||
|
public String message() { |
||||
|
return message; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
package com.bw.opai.file.controller; |
||||
|
|
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.cloud.context.config.annotation.RefreshScope; |
||||
|
import org.springframework.web.bind.annotation.PostMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestParam; |
||||
|
import org.springframework.web.bind.annotation.RestController; |
||||
|
import org.springframework.web.multipart.MultipartFile; |
||||
|
|
||||
|
import com.bw.opai.common.Res; |
||||
|
import com.bw.opai.file.service.FileService; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
|
||||
|
/** |
||||
|
* 文件操作控制层 |
||||
|
* @author jian.mao |
||||
|
* @date 2026年1月6日 |
||||
|
* @description |
||||
|
*/ |
||||
|
@RestController |
||||
|
@Slf4j |
||||
|
@RefreshScope |
||||
|
@RequestMapping("/file") |
||||
|
public class FileController { |
||||
|
|
||||
|
@Autowired |
||||
|
private FileService fileService; |
||||
|
@PostMapping("/upload") |
||||
|
public Res<?> uploadFile(@RequestParam("file") MultipartFile file) { |
||||
|
return fileService.uploadFile(file); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
package com.bw.opai.file.service; |
||||
|
|
||||
|
import org.springframework.web.multipart.MultipartFile; |
||||
|
|
||||
|
import com.bw.opai.common.Res; |
||||
|
|
||||
|
/** |
||||
|
* 文件操作业务接口 |
||||
|
* @author jian.mao |
||||
|
* @date 2026年1月6日 |
||||
|
* @description |
||||
|
*/ |
||||
|
public interface FileService { |
||||
|
|
||||
|
public Res<?> uploadFile(MultipartFile file); |
||||
|
} |
||||
@ -0,0 +1,107 @@ |
|||||
|
package com.bw.opai.file.service.impl; |
||||
|
|
||||
|
import java.util.HashMap; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
import org.apache.http.HttpEntity; |
||||
|
import org.apache.http.client.methods.CloseableHttpResponse; |
||||
|
import org.apache.http.client.methods.HttpPost; |
||||
|
import org.apache.http.entity.ContentType; |
||||
|
import org.apache.http.entity.mime.HttpMultipartMode; |
||||
|
import org.apache.http.entity.mime.MultipartEntityBuilder; |
||||
|
import org.apache.http.impl.client.CloseableHttpClient; |
||||
|
import org.apache.http.impl.client.HttpClients; |
||||
|
import org.apache.http.util.EntityUtils; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.cloud.context.config.annotation.RefreshScope; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.web.multipart.MultipartFile; |
||||
|
|
||||
|
import com.alibaba.fastjson.JSONObject; |
||||
|
import com.bw.opai.common.Res; |
||||
|
import com.bw.opai.file.service.FileService; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
|
||||
|
/** |
||||
|
* 文件操作服务实现类 |
||||
|
* @author jian.mao |
||||
|
* @date 2026年1月6日 |
||||
|
* @description |
||||
|
*/ |
||||
|
@Service |
||||
|
@Slf4j |
||||
|
@RefreshScope |
||||
|
public class FileServiceImpl implements FileService { |
||||
|
|
||||
|
@Value("${gofast.upload-url}") |
||||
|
private String gofastUploadUrl; |
||||
|
|
||||
|
@Value("${gofast.access-prefix}") |
||||
|
private String gofastAccessPrefix; |
||||
|
|
||||
|
|
||||
|
@Override |
||||
|
public Res<?> uploadFile(MultipartFile file) { |
||||
|
|
||||
|
if (file == null || file.isEmpty()) { |
||||
|
return Res.fail("上传文件不能为空"); |
||||
|
} |
||||
|
|
||||
|
CloseableHttpClient httpClient = HttpClients.createDefault(); |
||||
|
|
||||
|
try { |
||||
|
HttpPost httpPost = new HttpPost(gofastUploadUrl); |
||||
|
|
||||
|
MultipartEntityBuilder builder = MultipartEntityBuilder.create(); |
||||
|
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); |
||||
|
|
||||
|
// 文件流 |
||||
|
builder.addBinaryBody( |
||||
|
"file", |
||||
|
file.getInputStream(), |
||||
|
ContentType.APPLICATION_OCTET_STREAM, |
||||
|
file.getOriginalFilename() |
||||
|
); |
||||
|
// 👇 关键:要求 GoFast 返回 JSON |
||||
|
builder.addTextBody("output", "json"); |
||||
|
HttpEntity entity = builder.build(); |
||||
|
httpPost.setEntity(entity); |
||||
|
|
||||
|
CloseableHttpResponse response = httpClient.execute(httpPost); |
||||
|
|
||||
|
int statusCode = response.getStatusLine().getStatusCode(); |
||||
|
String responseBody = EntityUtils.toString(response.getEntity(), "UTF-8"); |
||||
|
|
||||
|
log.info("GoFast upload response: {}", responseBody); |
||||
|
|
||||
|
if (statusCode != 200) { |
||||
|
return Res.fail("文件服务器上传失败"); |
||||
|
} |
||||
|
|
||||
|
// 解析返回 JSON |
||||
|
JSONObject json = JSONObject.parseObject(responseBody); |
||||
|
|
||||
|
// ⚠️ 根据你 GoFast 实际返回字段调整 |
||||
|
String path = json.getString("path"); |
||||
|
String url = gofastAccessPrefix + path; |
||||
|
|
||||
|
Map<String, Object> result = new HashMap<String, Object>(); |
||||
|
result.put("fileName", file.getOriginalFilename()); |
||||
|
result.put("fileSize", file.getSize()); |
||||
|
result.put("url", url); |
||||
|
|
||||
|
return Res.ok(result); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
log.error("上传到 GoFast 失败", e); |
||||
|
return Res.fail("文件上传失败"); |
||||
|
} finally { |
||||
|
try { |
||||
|
httpClient.close(); |
||||
|
} catch (Exception ignored) {} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
package com.bw.opai.utils; |
||||
|
|
||||
|
/** |
||||
|
* 常量类 |
||||
|
* @author jian.mao |
||||
|
* @date 2025年11月6日 |
||||
|
* @description |
||||
|
*/ |
||||
|
public class Constants { |
||||
|
|
||||
|
|
||||
|
/***空常量****/ |
||||
|
public static final String EMPTY = ""; |
||||
|
|
||||
|
/** |
||||
|
* 请求失败结果前缀 |
||||
|
*/ |
||||
|
public static final String DOWNLOAD_ERROR_SUFFIX = "Download failed error is:"; |
||||
|
} |
||||
@ -0,0 +1,177 @@ |
|||||
|
package com.bw.opai.utils; |
||||
|
|
||||
|
|
||||
|
import java.math.BigInteger; |
||||
|
import java.security.MessageDigest; |
||||
|
import java.security.NoSuchAlgorithmException; |
||||
|
import java.text.ParseException; |
||||
|
import java.text.SimpleDateFormat; |
||||
|
import java.time.LocalDateTime; |
||||
|
import java.time.format.DateTimeFormatter; |
||||
|
import java.util.Date; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
|
||||
|
import com.alibaba.fastjson.JSON; |
||||
|
import com.alibaba.fastjson.JSONObject; |
||||
|
|
||||
|
/** |
||||
|
* 日期工具类 |
||||
|
* |
||||
|
* @author jian.mao |
||||
|
* @date 2022年11月15日 |
||||
|
* @description |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
public class DateUtil { |
||||
|
|
||||
|
/** |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String getTimeStrForNow() { |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHH"); |
||||
|
return sdf.format(new Date()); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public static String getTimeStrForDay(long time) { |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); |
||||
|
|
||||
|
return sdf.format(new Date(time * 1000)); |
||||
|
} |
||||
|
|
||||
|
public static String getTimeStrForDay() { |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); |
||||
|
|
||||
|
return sdf.format(new Date()); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public static String getDateTime() { |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
||||
|
String time = sdf.format(new Date()); |
||||
|
return time; |
||||
|
} |
||||
|
|
||||
|
public static String getDateTime(Long timestap) { |
||||
|
|
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
||||
|
String time = sdf.format(new Date(timestap)); |
||||
|
return time; |
||||
|
} |
||||
|
|
||||
|
public static String getDate(Long timestap) { |
||||
|
|
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
||||
|
String time = sdf.format(new Date(timestap)); |
||||
|
return time; |
||||
|
} |
||||
|
|
||||
|
public static String getDateTimeForMonth() { |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM"); |
||||
|
String time = sdf.format(new Date()); |
||||
|
return time; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 休眠 |
||||
|
* |
||||
|
* @param millis 毫秒 |
||||
|
*/ |
||||
|
public static void sleep(long millis) { |
||||
|
try { |
||||
|
Thread.sleep(millis); |
||||
|
} catch (InterruptedException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 1. @Description:时间戳转时间 |
||||
|
* 2. @Author: ying.zhao |
||||
|
* 3. @Date: 2023/3/28 |
||||
|
*/ |
||||
|
|
||||
|
public static String timestampToDate(String time) { |
||||
|
int thirteen = 13; |
||||
|
int ten = 10; |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
||||
|
// if (time.length() == thirteen) { |
||||
|
if (time.length() > ten) { |
||||
|
return sdf.format(new Date(Long.parseLong(time))); |
||||
|
} else { |
||||
|
return sdf.format(new Date(Integer.parseInt(time) * 1000L)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static String parseCreated(String jsonTime){ |
||||
|
String formattedDateTime = getDateTime(); |
||||
|
try { |
||||
|
// 使用fastjson解析JSON数据 |
||||
|
JSONObject jsonObject = JSON.parseObject(jsonTime); |
||||
|
// 获取日期和时间的值 |
||||
|
JSONObject dateObject = jsonObject.getJSONObject("date"); |
||||
|
int day = dateObject.getIntValue("day"); |
||||
|
int month = dateObject.getIntValue("month"); |
||||
|
int year = dateObject.getIntValue("year"); |
||||
|
|
||||
|
JSONObject timeObject = jsonObject.getJSONObject("time"); |
||||
|
int hour = timeObject.getIntValue("hour"); |
||||
|
int minute = timeObject.getIntValue("minute"); |
||||
|
int second = timeObject.getIntValue("second"); |
||||
|
|
||||
|
// 创建LocalDateTime对象 |
||||
|
LocalDateTime dateTime = LocalDateTime.of(year, month, day, hour, minute, second); |
||||
|
|
||||
|
// 定义日期时间格式化器 |
||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); |
||||
|
|
||||
|
// 格式化日期时间 |
||||
|
formattedDateTime = dateTime.format(formatter); |
||||
|
} catch (Exception e) { |
||||
|
log.info("日期转换失败:{}",e); |
||||
|
} |
||||
|
return formattedDateTime; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 字符串转换日期 |
||||
|
* @param format |
||||
|
* @param date |
||||
|
* @return |
||||
|
*/ |
||||
|
public static Date strToDate(String format,String date){ |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat(format); |
||||
|
if (date == null || date.equals("")){ |
||||
|
return new Date(); |
||||
|
}else{ |
||||
|
Date ru = null; |
||||
|
try { |
||||
|
ru = sdf.parse(date); |
||||
|
} catch (ParseException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
return ru; |
||||
|
} |
||||
|
} |
||||
|
/** |
||||
|
* 日期格式话 |
||||
|
* @param format 日期格式 |
||||
|
* @param dater 要转换的日期,默认当前时间 |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String FormatDate(String format,Date date){ |
||||
|
String fromatDate = null; |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat(format); |
||||
|
if (date == null){ |
||||
|
fromatDate = sdf.format(new Date()); |
||||
|
}else{ |
||||
|
fromatDate = sdf.format(date); |
||||
|
} |
||||
|
return fromatDate; |
||||
|
} |
||||
|
public static void main(String[] args) { |
||||
|
String time = timestampToDate("955814400000"); |
||||
|
System.out.println(time); |
||||
|
} |
||||
|
} |
||||
1005
opai-api/src/main/java/com/bw/opai/utils/DownLoadUtil.java
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,23 @@ |
|||||
|
package com.bw.opai.utils; |
||||
|
|
||||
|
import java.io.PrintWriter; |
||||
|
import java.io.StringWriter; |
||||
|
|
||||
|
/** |
||||
|
* @author jian.mao |
||||
|
* @date 2023年3月22日 |
||||
|
* @description |
||||
|
*/ |
||||
|
public class ThrowMessageUtil { |
||||
|
|
||||
|
/** |
||||
|
* 获取异常信息 |
||||
|
* @param t |
||||
|
* @return |
||||
|
*/ |
||||
|
public static String getErrmessage(Throwable t){ |
||||
|
StringWriter stringWriter=new StringWriter(); |
||||
|
t.printStackTrace(new PrintWriter(stringWriter,true)); |
||||
|
return stringWriter.getBuffer().toString(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,52 @@ |
|||||
|
# ==================== 必须文件:bootstrap.yml ==================== |
||||
|
# 这个文件用于配置Nacos客户端,优先级最高 |
||||
|
spring: |
||||
|
application: |
||||
|
name: opai-api # 服务名,对应Nacos中的Data ID |
||||
|
|
||||
|
cloud: |
||||
|
nacos: |
||||
|
# ======== 配置中心 ======== |
||||
|
config: |
||||
|
server-addr: 127.0.0.1:8848 # Nacos地址 |
||||
|
username: nacos # 用户名 |
||||
|
password: nacos # 密码 |
||||
|
group: public_dev # 分组 |
||||
|
namespace: opai # 命名空间(默认public) |
||||
|
file-extension: yaml # 配置文件格式 |
||||
|
timeout: 5000 # 超时时间(ms) |
||||
|
|
||||
|
# 核心配置:开启动态刷新 |
||||
|
refresh-enabled: true # 必须为true! |
||||
|
|
||||
|
# 主配置文件(从Nacos加载) |
||||
|
data-id: ${spring.application.name}.${spring.cloud.nacos.config.file-extension} |
||||
|
|
||||
|
# 共享配置文件(可选) |
||||
|
shared-configs[0]: |
||||
|
data-id: application.yaml # 公共配置 |
||||
|
group: public_dev # 公共分组 |
||||
|
namespace: opai |
||||
|
refresh: true # 公共配置也要刷新 |
||||
|
|
||||
|
# 扩展配置(可选) |
||||
|
# extension-configs[0]: |
||||
|
# data-id: datasource.yaml |
||||
|
# group: dev |
||||
|
# refresh: true |
||||
|
|
||||
|
# ======== 服务发现 ======== |
||||
|
discovery: |
||||
|
server-addr: ${spring.cloud.nacos.config.server-addr} |
||||
|
username: ${spring.cloud.nacos.config.username} |
||||
|
password: ${spring.cloud.nacos.config.password} |
||||
|
group: ${spring.cloud.nacos.config.group} |
||||
|
namespace: ${spring.cloud.nacos.config.namespace} |
||||
|
|
||||
|
logging: |
||||
|
level: |
||||
|
root: info |
||||
|
com.alibaba.nacos.client.config.impl: WARN |
||||
|
file: |
||||
|
path: ../logs |
||||
|
|
||||
@ -0,0 +1,36 @@ |
|||||
|
<configuration> |
||||
|
<!-- 属性文件:在properties文件中找到对应的配置项 --> |
||||
|
<springProperty scope="context" name="log-path" source="logging.file.path"/> |
||||
|
<!--<springProperty scope="context" name="logging.level" source="logging.level.com.bfd"/>--> |
||||
|
<!-- 默认的控制台日志输出,一般生产环境都是后台启动,这个没太大作用 --> |
||||
|
<!-- <appender name="STDOUT" |
||||
|
class="ch.qos.logback.core.ConsoleAppender"> |
||||
|
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> |
||||
|
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %line %-5level %logger{50} - %msg%n</Pattern> |
||||
|
</encoder> |
||||
|
</appender> --> |
||||
|
|
||||
|
<appender name="GLMAPPER-LOGGERONE" |
||||
|
class="ch.qos.logback.core.rolling.RollingFileAppender"> |
||||
|
<append>true</append> |
||||
|
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> |
||||
|
<level>${logging.level}</level> |
||||
|
</filter> |
||||
|
<file> |
||||
|
${log-path}/opai-api.log |
||||
|
</file> |
||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
||||
|
<FileNamePattern>${log-path}/opai-api.log.%d{yyyy-MM-dd}</FileNamePattern> |
||||
|
<MaxHistory>7</MaxHistory> |
||||
|
</rollingPolicy> |
||||
|
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> |
||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %line %-5level %logger{50} - %msg%n</pattern> |
||||
|
<charset>UTF-8</charset> |
||||
|
</encoder> |
||||
|
</appender> |
||||
|
|
||||
|
<root level="info"> |
||||
|
<appender-ref ref="GLMAPPER-LOGGERONE"/> |
||||
|
<!-- <appender-ref ref="STDOUT"/> --> |
||||
|
</root> |
||||
|
</configuration> |
||||
@ -1,6 +1,41 @@ |
|||||
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|
||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||
|
<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> |
<modelVersion>4.0.0</modelVersion> |
||||
<groupId>com.bw</groupId> |
<groupId>com.bw</groupId> |
||||
<artifactId>opai-service-center</artifactId> |
<artifactId>opai-service-center</artifactId> |
||||
<version>0.0.1-SNAPSHOT</version> |
<version>0.0.1-SNAPSHOT</version> |
||||
|
<packaging>pom</packaging> |
||||
|
<modules> |
||||
|
<module>opai-api</module> |
||||
|
<module>ocr-service</module> |
||||
|
</modules> |
||||
|
|
||||
|
<parent> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-parent</artifactId> |
||||
|
<version>2.2.4.RELEASE</version> |
||||
|
<relativePath/> <!-- lookup parent from repository --> |
||||
|
</parent> |
||||
|
|
||||
|
<dependencyManagement> |
||||
|
<dependencies> |
||||
|
<!-- Spring Cloud --> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.cloud</groupId> |
||||
|
<artifactId>spring-cloud-dependencies</artifactId> |
||||
|
<version>Hoxton.SR9</version> |
||||
|
<type>pom</type> |
||||
|
<scope>import</scope> |
||||
|
</dependency> |
||||
|
|
||||
|
<!-- Spring Cloud Alibaba --> |
||||
|
<dependency> |
||||
|
<groupId>com.alibaba.cloud</groupId> |
||||
|
<artifactId>spring-cloud-alibaba-dependencies</artifactId> |
||||
|
<version>2.2.6.RELEASE</version> |
||||
|
<type>pom</type> |
||||
|
<scope>import</scope> |
||||
|
</dependency> |
||||
|
</dependencies> |
||||
|
</dependencyManagement> |
||||
</project> |
</project> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue