集成 OCR
This commit is contained in:
parent
75c8ab3350
commit
e9925a6419
|
|
@ -1,35 +0,0 @@
|
||||||
package com.bonus.web.controller.common;
|
|
||||||
|
|
||||||
import com.bonus.common.core.domain.AjaxResult;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 会话检查控制器
|
|
||||||
*/
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/session")
|
|
||||||
public class SessionCheckController {
|
|
||||||
|
|
||||||
// @Autowired
|
|
||||||
// private SessionManagementService sessionManagementService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查会话状态
|
|
||||||
*/
|
|
||||||
/*@GetMapping("/check")
|
|
||||||
public AjaxResult checkSession(HttpServletRequest request) {
|
|
||||||
String sessionId = request.getSession().getId();
|
|
||||||
|
|
||||||
if (sessionManagementService.isSessionForcedLogout(sessionId)) {
|
|
||||||
String message = sessionManagementService.getForceLogoutMessage(sessionId);
|
|
||||||
return AjaxResult.error(403, message).put("forceLogout", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return AjaxResult.success().put("forceLogout", false);
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
# MinIO 配置
|
||||||
|
minio:
|
||||||
|
url: http://192.168.0.14:9090
|
||||||
|
endpoint: http://192.168.0.14:9090
|
||||||
|
access-key: minio
|
||||||
|
secret-key: bonus@admin123
|
||||||
|
bucket-name: smart-bid
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
ocr:
|
||||||
|
service:
|
||||||
|
url: http://192.168.0.37:8000/ocr/ # ocr 请求地址
|
||||||
|
healthUrl: http://192.168.0.37:8000/ # ocr 服务健康检查
|
||||||
|
timeout: 30000 # ocr 请求超时时间
|
||||||
|
max-connections: 100
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
spring:
|
||||||
|
rabbitmq:
|
||||||
|
# 连接配置
|
||||||
|
host: localhost
|
||||||
|
port: 15672
|
||||||
|
username: guest
|
||||||
|
password: guest
|
||||||
|
virtual-host: /
|
||||||
|
|
||||||
|
# 连接超时和心跳
|
||||||
|
connection-timeout: 30000
|
||||||
|
requested-heartbeat: 60
|
||||||
|
|
||||||
|
# 通道缓存配置
|
||||||
|
cache:
|
||||||
|
channel:
|
||||||
|
size: 25
|
||||||
|
checkout-timeout: 2000
|
||||||
|
|
||||||
|
# 发布确认
|
||||||
|
publisher-confirm-type: correlated
|
||||||
|
publisher-returns: true
|
||||||
|
|
||||||
|
# 模板配置
|
||||||
|
template:
|
||||||
|
mandatory: true
|
||||||
|
receive-timeout: 30000
|
||||||
|
reply-timeout: 30000
|
||||||
|
retry:
|
||||||
|
enabled: true
|
||||||
|
initial-interval: 2000
|
||||||
|
max-attempts: 3
|
||||||
|
multiplier: 1.5
|
||||||
|
max-interval: 10000
|
||||||
|
|
||||||
|
# 监听器配置
|
||||||
|
listener:
|
||||||
|
type: simple
|
||||||
|
simple:
|
||||||
|
acknowledge-mode: auto
|
||||||
|
concurrency: 2
|
||||||
|
max-concurrency: 10
|
||||||
|
prefetch: 1
|
||||||
|
# 重要:解决队列检查超时问题
|
||||||
|
missing-queues-fatal: false
|
||||||
|
auto-startup: true
|
||||||
|
default-requeue-rejected: false
|
||||||
|
retry:
|
||||||
|
enabled: true
|
||||||
|
initial-interval: 3000
|
||||||
|
max-attempts: 3
|
||||||
|
max-interval: 10000
|
||||||
|
multiplier: 2.0
|
||||||
|
|
||||||
|
# Actuator 配置
|
||||||
|
management:
|
||||||
|
endpoints:
|
||||||
|
web:
|
||||||
|
exposure:
|
||||||
|
include: health,info,metrics
|
||||||
|
endpoint:
|
||||||
|
health:
|
||||||
|
show-details: always
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
spring:
|
spring:
|
||||||
profiles:
|
profiles:
|
||||||
active: @profiles.active@,druid
|
active: @profiles.active@,druid,ocr
|
||||||
# 解决SpringBoot 2.6+与SpringFox兼容性问题
|
# 解决SpringBoot 2.6+与SpringFox兼容性问题
|
||||||
mvc:
|
mvc:
|
||||||
pathmatch:
|
pathmatch:
|
||||||
|
|
|
||||||
|
|
@ -169,6 +169,18 @@
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
<version>4.5.13</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpmime</artifactId>
|
||||||
|
<version>4.5.14</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.bonus.common.domain.ocr.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @className:OcrRequest
|
||||||
|
* @author:cwchen
|
||||||
|
* @date:2025-10-16-10:45
|
||||||
|
* @version:1.0
|
||||||
|
* @description:OCR请求DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class OcrRequest {
|
||||||
|
|
||||||
|
@JsonProperty("file")
|
||||||
|
private File file; // 文件对象
|
||||||
|
|
||||||
|
@JsonProperty("type")
|
||||||
|
private String type; // 文件类型
|
||||||
|
|
||||||
|
@JsonProperty("analysisContent")
|
||||||
|
private String analysisContent;
|
||||||
|
|
||||||
|
public OcrRequest(File file, String type, String analysisContent) {
|
||||||
|
this.file = file;
|
||||||
|
this.type = type;
|
||||||
|
this.analysisContent = analysisContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OcrRequest() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.bonus.common.domain.ocr.vo;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @className:OcrData
|
||||||
|
* @author:cwchen
|
||||||
|
* @date:2025-10-16-10:43
|
||||||
|
* @version:1.0
|
||||||
|
* @description: OCR数据DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class OcrData {
|
||||||
|
|
||||||
|
@JsonProperty("text")
|
||||||
|
private String text; // 识别出的文本
|
||||||
|
|
||||||
|
@JsonProperty("confidence")
|
||||||
|
private Double confidence; // 置信度
|
||||||
|
|
||||||
|
@JsonProperty("words")
|
||||||
|
private List<WordInfo> words; // 单词列表
|
||||||
|
|
||||||
|
@JsonProperty("processing_time")
|
||||||
|
private Double processingTime; // 处理时间
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package com.bonus.common.domain.ocr.vo;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @className:OcrResponse
|
||||||
|
* @author:cwchen
|
||||||
|
* @date:2025-10-16-9:53
|
||||||
|
* @version:1.0
|
||||||
|
* @description:Ocr响应结果
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class OcrResponse {
|
||||||
|
|
||||||
|
@JsonProperty("code")
|
||||||
|
private Integer code; // 状态码
|
||||||
|
|
||||||
|
@JsonProperty("message")
|
||||||
|
private String message; // 消息
|
||||||
|
|
||||||
|
@JsonProperty("data")
|
||||||
|
private OcrData data; // 识别数据
|
||||||
|
|
||||||
|
@JsonProperty("request_id")
|
||||||
|
private String requestId; // 请求ID
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.bonus.common.domain.ocr.vo;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @className:WordInfo
|
||||||
|
* @author:cwchen
|
||||||
|
* @date:2025-10-16-10:43
|
||||||
|
* @version:1.0
|
||||||
|
* @description: 单词信息DTO
|
||||||
|
*/
|
||||||
|
public class WordInfo {
|
||||||
|
|
||||||
|
@JsonProperty("text")
|
||||||
|
private String text; // 单词文本
|
||||||
|
|
||||||
|
@JsonProperty("confidence")
|
||||||
|
private Double confidence; // 单词置信度
|
||||||
|
|
||||||
|
@JsonProperty("bbox")
|
||||||
|
private List<Integer> bbox; // 边界框 [x1, y1, x2, y2, x3, y3, x4, y4]
|
||||||
|
}
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package com.bonus;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
System.out.println("Hello, World!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
package com.bonus.ocr.service;
|
||||||
|
|
||||||
|
import com.bonus.common.domain.ocr.dto.OcrRequest;
|
||||||
|
import com.bonus.common.domain.ocr.vo.OcrResponse;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.http.HttpEntity;
|
||||||
|
import org.apache.http.client.config.RequestConfig;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
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.stereotype.Service;
|
||||||
|
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
||||||
|
import org.apache.http.entity.mime.HttpMultipartMode;
|
||||||
|
import org.apache.http.entity.mime.content.FileBody;
|
||||||
|
import org.apache.http.entity.ContentType;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @className:OcrService
|
||||||
|
* @author:cwchen
|
||||||
|
* @date:2025-10-16-10:35
|
||||||
|
* @version:1.0
|
||||||
|
* @description: OCR服务实现类
|
||||||
|
*/
|
||||||
|
@Service(value = "OcrService")
|
||||||
|
@Slf4j
|
||||||
|
public class OcrService {
|
||||||
|
|
||||||
|
|
||||||
|
@Value("${ocr.service.url}")
|
||||||
|
private String ocrServiceUrl;
|
||||||
|
|
||||||
|
@Value("${ocr.service.healthUrl}")
|
||||||
|
private String healthUrl;
|
||||||
|
|
||||||
|
@Value("${ocr.service.timeout}")
|
||||||
|
private int timeout;
|
||||||
|
|
||||||
|
private final CloseableHttpClient httpClient;
|
||||||
|
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
public OcrService() {
|
||||||
|
// 配置HTTP客户端
|
||||||
|
RequestConfig requestConfig = RequestConfig.custom()
|
||||||
|
.setConnectTimeout(timeout)
|
||||||
|
.setSocketTimeout(timeout)
|
||||||
|
.setConnectionRequestTimeout(timeout)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
this.httpClient = HttpClients.custom()
|
||||||
|
.setDefaultRequestConfig(requestConfig)
|
||||||
|
.build();
|
||||||
|
this.objectMapper = new ObjectMapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用OCR服务
|
||||||
|
*/
|
||||||
|
private OcrResponse callOcrService(OcrRequest ocrRequest) throws IOException {
|
||||||
|
HttpPost httpPost = new HttpPost(ocrServiceUrl);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 创建 multipart entity builder
|
||||||
|
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
|
||||||
|
builder.setCharset(StandardCharsets.UTF_8);
|
||||||
|
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
|
||||||
|
|
||||||
|
// 添加文件字段
|
||||||
|
builder.addPart("file",
|
||||||
|
new FileBody(ocrRequest.getFile(), ContentType.MULTIPART_FORM_DATA, ocrRequest.getFile().getName()));
|
||||||
|
// 添加类型字段
|
||||||
|
builder.addTextBody("type", ocrRequest.getType(),
|
||||||
|
ContentType.TEXT_PLAIN.withCharset("UTF-8"));
|
||||||
|
// 添加解析内容字段
|
||||||
|
builder.addTextBody("analysisContent", ocrRequest.getAnalysisContent(),
|
||||||
|
ContentType.TEXT_PLAIN.withCharset("UTF-8"));
|
||||||
|
|
||||||
|
// 设置请求实体 - 注意:这里会自动设置正确的 Content-Type 和 boundary
|
||||||
|
httpPost.setEntity(builder.build());
|
||||||
|
// 设置 Accept 头
|
||||||
|
httpPost.setHeader("Accept", "application/json");
|
||||||
|
log.debug("发送OCR请求到: {}", ocrServiceUrl);
|
||||||
|
|
||||||
|
// 执行请求
|
||||||
|
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
|
||||||
|
HttpEntity entity = response.getEntity();
|
||||||
|
String responseBody = EntityUtils.toString(entity, "UTF-8");
|
||||||
|
log.debug("OCR服务响应状态: {}", response.getStatusLine().getStatusCode());
|
||||||
|
log.debug("OCR服务响应内容: {}", responseBody);
|
||||||
|
|
||||||
|
// 解析响应
|
||||||
|
OcrResponse ocrResponse = objectMapper.readValue(responseBody, OcrResponse.class);
|
||||||
|
|
||||||
|
if (ocrResponse.getCode() != null && ocrResponse.getCode() == 200) {
|
||||||
|
/*log.info("OCR识别成功,识别字符数: {}",
|
||||||
|
ocrResponse.getData() != null && ocrResponse.getData().getText() != null ?
|
||||||
|
ocrResponse.getData().getText().length() : 0);*/
|
||||||
|
} else {
|
||||||
|
log.warn("OCR识别失败: {}", ocrResponse.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ocrResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("调用OCR服务失败", e);
|
||||||
|
throw new IOException("OCR服务调用失败: " + e.getMessage(), e);
|
||||||
|
} finally {
|
||||||
|
httpPost.releaseConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭HTTP客户端
|
||||||
|
*/
|
||||||
|
public void close() {
|
||||||
|
try {
|
||||||
|
httpClient.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("关闭HTTP客户端失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.bonus.ocr;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @className:test
|
||||||
|
* @author:cwchen
|
||||||
|
* @date:2025-10-16-9:42
|
||||||
|
* @version:1.0
|
||||||
|
* @description:测试
|
||||||
|
*/
|
||||||
|
public class test {
|
||||||
|
|
||||||
|
|
||||||
|
public void testOcr() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -19,7 +19,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
|
||||||
<sql id="selectNoticeVo">
|
<sql id="selectNoticeVo">
|
||||||
select notice_id, notice_title, notice_type, cast(notice_content as char) as notice_content, status, create_by, create_time, update_by, update_time, remark
|
select notice_id, notice_title, notice_type, cast(notice_content as char) as notice_content, status, create_by, create_time, update_by, update_time, remark
|
||||||
from da_ky_sys_menu
|
from sys_notice
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="selectNoticeById" parameterType="Long" resultMap="SysNoticeResult">
|
<select id="selectNoticeById" parameterType="Long" resultMap="SysNoticeResult">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue