基于DeepSeek-OCR-WEBUI的文档识别实践|SpringBoot应用无缝对接
1. 背景与业务场景
在企业级应用中,大量纸质单据如采购订单、发票、入库凭证等仍需人工录入系统,不仅效率低下,还容易出错。随着AI技术的发展,光学字符识别(OCR)已成为自动化数据采集的关键手段。
DeepSeek-OCR-WEBUI 是基于深度学习的大模型OCR解决方案,具备高精度、多语言支持和复杂场景适应能力。其开源特性与Web API设计,使其非常适合集成到现有Java后端系统中,实现“拍照→识别→结构化输出→人工校验→一键入库”的完整流程。
本文将详细介绍如何将DeepSeek-OCR-WEBUI部署为独立服务,并通过SpringBoot应用调用其API完成表格图像识别,最终实现前端可视化展示与数据结构化转换。
2. DeepSeek-OCR-WEBUI 核心功能解析
2.1 技术架构概述
DeepSeek-OCR-WEBUI 采用 CNN + Attention 的混合架构,结合文本检测(Text Detection)与文本识别(Text Recognition)双阶段模型,能够精准定位图像中的文字区域并进行高准确率解码。系统内置后处理模块,可自动修复断字、纠正拼写错误、统一标点格式。
该服务以 Docker 容器形式提供,包含以下核心组件:
web_service.py:Flask 实现的 RESTful API 接口- OCR 模型文件:预训练权重,支持中文为主、多语言扩展
- 前端 WebUI:用于本地测试与调试的图形界面
2.2 关键接口说明
服务启动后,默认监听http://localhost:8080,主要接口如下:
@app.post("/ocr") async def ocr_endpoint( file: UploadFile = File(...), prompt_type: str = Form("document"), find_term: str = Form(""), custom_prompt: str = Form(""), grounding: bool = Form(False) )| 参数名 | 类型 | 可选值 | 说明 |
|---|---|---|---|
file | 文件上传 | - | 待识别的图片文件(JPG/PNG等) |
prompt_type | 字符串 | document,ocr,free,figure,describe,find,freeform | 控制识别模式 |
find_term | 字符串 | 自定义关键词 | 用于字段定位(如“发票号”) |
custom_prompt | 字符串 | 用户自定义提示词 | 扩展识别逻辑 |
grounding | 布尔值 | true/false | 是否启用实体分组 |
特别注意:本文目标是识别表格内容,因此应使用
prompt_type=figure,此模式专为图表、公式、表格设计,能有效提取<table>结构的 HTML 输出。
3. SpringBoot 后端集成方案
3.1 系统架构设计
整体架构分为三层:
- 前端层:Vue 构建的操作页面,支持图片上传与结果显示
- 业务层:SpringBoot 提供 REST API,负责调用 OCR 服务并处理响应
- AI 层:DeepSeek-OCR-WEBUI 容器服务,执行实际 OCR 识别任务
各层之间通过 HTTP 协议通信,松耦合设计便于部署与维护。
3.2 环境准备与依赖配置
确保已安装:
- JDK 21+
- Maven 3.8+
- Node.js 20+(用于前端构建)
- Docker & Docker Compose
Maven 添加关键依赖:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.16.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>其中jsoup用于解析 OCR 返回的 HTML 表格内容。
4. 核心代码实现
4.1 OcrService 接口定义
// src/main/java/com/kaifamiao/dswebui/service/OcrService.java public interface OcrService { /** * 识别表格图片并返回结构化数据 * * @param file 上传的包含表格的图片文件 * @return 包含表格数据的Map对象,将以JSON格式返回给前端 */ Map<String, Object> recognitionTable(MultipartFile file); }4.2 OCR 服务实现类
// src/main/java/com/kaifamiao/dswebui/service/DeepSeekOcrService.java @Service @Slf4j public class DeepSeekOcrService implements OcrService { private static final String OCR_SERVICE_URL = "http://localhost:8080/ocr"; private RestTemplate restTemplate; public DeepSeekOcrService() { SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); factory.setConnectTimeout(30000); factory.setReadTimeout(60000); this.restTemplate = new RestTemplate(factory); } @Override public Map<String, Object> recognitionTable(MultipartFile file) { log.info("开始识别表格图片: {}", file.getOriginalFilename()); try { // 准备文件资源 ByteArrayResource resource = new ByteArrayResource(file.getBytes()) { @Override public String getFilename() { return file.getOriginalFilename(); } }; // 构建请求参数 MultiValueMap<String, Object> body = new LinkedMultiValueMap<>(); body.add("file", resource); body.add("prompt_type", "figure"); // 关键:使用 figure 模式识别表格 body.add("grounding", false); // 设置请求头 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); // 创建请求实体 HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers); // 发送POST请求到OCR服务 ResponseEntity<String> response = restTemplate.postForEntity(OCR_SERVICE_URL, requestEntity, String.class); if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) { log.info("OCR识别成功,返回HTML长度: {}", response.getBody().length()); return parseHtmlTableToJSON(response.getBody()); } else { log.error("OCR服务返回异常状态码: {}", response.getStatusCode()); throw new RuntimeException("OCR识别失败:" + response.getStatusCode()); } } catch (Exception e) { log.error("调用OCR服务发生异常", e); throw new RuntimeException("OCR识别请求失败: " + e.getMessage(), e); } } /** * 将HTML表格解析为JSON格式 * * @param html 包含表格的HTML字符串 * @return 转换后的JSON数据 */ private Map<String, Object> parseHtmlTableToJSON(String html) { Document doc = Jsoup.parse(html); Element table = doc.selectFirst("table"); if (table == null) { throw new IllegalArgumentException("未找到<table>标签"); } List<Map<String, String>> rows = new ArrayList<>(); Elements trList = table.select("tr"); boolean isFirstRow = true; List<String> headers = new ArrayList<>(); for (Element tr : trList) { Elements tds = tr.select("td"); Map<String, String> row = new HashMap<>(); for (int i = 0; i < tds.size(); i++) { String text = tds.get(i).text().trim(); if (isFirstRow) { headers.add("col_" + i); } else { String key = i < headers.size() ? headers.get(i) : "col_" + i; row.put(key, text); } } if (!isFirstRow) { rows.add(row); } isFirstRow = false; } Map<String, Object> result = new HashMap<>(); result.put("success", true); result.put("data", rows); result.put("totalRows", rows.size()); return result; } }代码要点说明:
- 使用
RestTemplate发起带文件上传的 multipart/form-data 请求 prompt_type="figure"是识别表格的关键参数- 利用
Jsoup解析返回的 HTML<table>并转换为 JSON 数组 - 表头动态生成(
col_0,col_1...),避免硬编码列名
4.3 Controller 层暴露接口
// src/main/java/com/kaifamiao/dswebui/controller/OcrController.java @RestController @RequestMapping("/api/ocr") @Slf4j public class OcrController { @Autowired private OcrService ocrService; @PostMapping("/process") public Map<String, Object> processFile(@RequestParam("file") MultipartFile file) { if (file.isEmpty()) { return Map.of("success", false, "message", "文件为空"); } try { Map<String, Object> result = ocrService.recognitionTable(file); log.info("OCR识别结果: {}", result); return result; } catch (Exception e) { log.error("处理文件时发生错误", e); return Map.of("success", false, "message", "识别失败:" + e.getMessage()); } } }该接口接收前端上传的图片,调用服务层完成识别,并返回结构化 JSON 数据。
4.4 编写单元测试验证功能
// src/test/java/com/kaifamiao/dswebui/service/OcrServiceTest.java @SpringBootTest @Slf4j public class OcrServiceTest { @Autowired private OcrService ocrService; @Test void testRecognitionTableSuccess() throws Exception { // 从测试资源目录加载voucher.jpg文件 ClassPathResource resource = new ClassPathResource("voucher.jpg"); // 创建MultipartFile对象 MockMultipartFile file = new MockMultipartFile( "file", "voucher.jpg", "image/jpeg", resource.getInputStream() ); // 调用OCR服务进行识别 Map<String, Object> result = ocrService.recognitionTable(file); log.info("OCR识别结果: {}", JSON.toJSONString(result)); // 断言结果基本结构 Assertions.assertTrue((Boolean) result.get("success")); Assertions.assertNotNull(result.get("data")); Assertions.assertTrue(((List<?>) result.get("data")).size() > 0); } }测试用例确保服务在本地环境下正常运行,可在 CI/CD 流程中加入自动化测试环节。
5. 前端页面集成与打包
5.1 Vue 页面功能说明
前端项目位于ui/目录下,主要功能包括:
- 图片上传组件
- 实时进度提示
- 表格数据渲染
- 错误信息展示
页面通过 Axios 调用/api/ocr/process接口,接收 JSON 数据并在页面上以表格形式呈现。
5.2 构建与集成步骤
cd ui npm install npm run build构建完成后,dist/目录生成静态资源文件,将其复制到 SpringBoot 项目的src/main/resources/static/下:
cp -r ui/dist/* src/main/resources/static/SpringBoot 默认会托管static目录下的静态资源,访问http://localhost:8080即可打开操作界面。
6. Docker 容器化部署
6.1 后端 Dockerfile
# Java运行时阶段 FROM openjdk:21-jdk-slim # 设置工作目录 WORKDIR /app # 复制前端构建产物到后端静态资源目录 COPY target/deepseek-web-ui-1.0.0.jar /app/deepseek-web-ui.jar # 暴露端口 EXPOSE 8080 # 运行应用 ENTRYPOINT ["java", "-jar", "deepseek-web-ui.jar"]6.2 docker-compose.yml 统一编排
version: '3.8' services: deepseek-ocr-webui: image: deepseek-ocr-webui:latest container_name: deepseek-ocr-webui ports: - "8080:8080" volumes: - ./logs:/app/logs restart: unless-stopped ocr-app: build: . ports: - "8081:8080" environment: - SERVER_PORT=8080 depends_on: - deepseek-ocr-webui volumes: - ./logs:/app/logs注意:OCR 服务运行在 8080 端口,SpringBoot 应用改为 8081 或其他端口避免冲突。
6.3 启动命令
docker compose up -d --build服务启动后:
- 访问
http://localhost:8081查看前端页面 - SpringBoot 自动调用
http://deepseek-ocr-webui:8080/ocr完成识别
7. 总结
7.1 实践价值总结
本文实现了DeepSeek-OCR-WEBUI与SpringBoot的无缝集成,完成了从图像输入到结构化数据输出的全流程闭环。该方案具有以下优势:
- 高可用性:OCR 服务独立部署,不影响主业务系统稳定性
- 易扩展性:可通过修改
prompt_type支持合同、发票、手写体等多种场景 - 低成本接入:无需自研OCR模型,直接调用成熟AI能力
- 国产化支持:DeepSeek 作为国产大模型,在中文识别上表现优异
7.2 最佳实践建议
- 错误重试机制:对网络不稳定场景添加重试逻辑(如 Spring Retry)
- 异步处理优化:对于大图或批量识别,建议引入消息队列(RabbitMQ/Kafka)异步处理
- 缓存策略:相同图片可做 MD5 缓存,避免重复识别
- 安全控制:限制上传文件类型与大小,防止恶意攻击
- 日志监控:记录识别耗时、成功率等指标,便于性能分析
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。