肇庆市网站建设_网站建设公司_支付系统_seo优化
2026/1/22 4:45:12 网站建设 项目流程

SpringBoot接入DeepSeek-OCR实现结构化数据提取

在企业级应用中,纸质单据、发票、合同等文档的数字化处理一直是一个高频且繁琐的任务。传统的人工录入方式不仅效率低下,还容易出错。随着AI技术的发展,尤其是OCR(光学字符识别)能力的显著提升,自动化提取图像中的文本信息已成为可能。

本文将带你一步步实现SpringBoot应用接入DeepSeek-OCR-WEBUI服务,重点解决一个典型业务场景:从包含表格的图片中自动识别并提取结构化数据,最终转换为JSON格式供系统使用。整个过程涵盖后端部署、接口调用、HTML解析、前后端集成与Docker打包发布,是一套可直接落地的企业级解决方案。


1. 部署DeepSeek-OCR-WEBUI服务

要让SpringBoot应用能够调用OCR功能,首先需要确保DeepSeek-OCR-WEBUI服务已经正确部署并运行。该镜像基于DeepSeek开源的大模型,具备强大的文本检测与识别能力,尤其擅长处理复杂布局的文档内容,如表格、公式、多语言混合文本等。

1.1 启动OCR服务

进入项目目录并使用Docker Compose启动服务:

cd ~/DeepSeek-OCR-WebUI docker compose up -d

启动完成后,查看日志确认服务是否正常运行:

docker logs -f deepseek-ocr-webui

当看到类似Uvicorn running on http://0.0.0.0:8080的输出时,说明Web API服务已就绪。

1.2 OCR核心接口说明

服务暴露了一个关键POST接口用于图像识别:

POST /ocr

支持以下参数:

参数名类型可选值说明
fileFile-要上传的图像文件
prompt_typestringdocument,ocr,free,figure,describe,find,freeform指定识别模式
find_termstring自定义关键词仅在find模式下有效
custom_promptstring-自定义提示词
groundingbooleantrue / false是否启用分组

本案例重点使用prompt_type=figure,因为该模式专为图表和表格设计,能更准确地保留原始结构,输出HTML格式的表格代码。

例如,传入一张采购单截图,设置prompt_type=figure,返回结果将是标准的<table>HTML片段,便于后续结构化解析。


2. SpringBoot项目结构设计

我们的目标是构建一个轻量但完整的Web应用,接收用户上传的含表格图片,调用OCR服务完成识别,并将结果以JSON形式返回给前端展示或入库。

2.1 技术栈选择

  • 后端框架:Spring Boot 3.x
  • HTTP客户端:RestTemplate(简化远程调用)
  • JSON处理:Fastjson
  • 前端:Vue3 + Element Plus(静态页面嵌入)
  • 打包部署:Docker + docker-compose

2.2 核心模块划分

模块功能描述
OcrService定义OCR识别接口
DeepSeekOcrService实现类,封装对OCR服务的HTTP调用
OcrController提供REST API供前端调用
HtmlParser将OCR返回的HTML表格转为List结构
Vue UI用户操作界面,支持图片上传与结果显示

3. 实现OCR服务调用逻辑

3.1 定义服务接口

// src/main/java/com/kaifamiao/dswebui/service/OcrService.java public interface OcrService { /** * 识别表格图片并返回结构化数据 * * @param file 上传的包含表格的图片文件 * @return 包含表格数据的Map对象,将以JSON格式返回给前端 */ Map<String, Object> recognitionTable(MultipartFile file); }

3.2 实现远程调用与HTML解析

// 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"; @Override public Map<String, Object> recognitionTable(MultipartFile file) { log.info("开始处理文件: {}", file.getOriginalFilename()); try { RestTemplate restTemplate = new RestTemplate(); // 准备文件资源 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"); // 关键:使用图表模式识别表格 // 设置请求头 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); // 创建请求实体 HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers); // 发送POST请求 ResponseEntity<String> response = restTemplate.postForEntity(OCR_SERVICE_URL, requestEntity, String.class); if (response.getStatusCode().is2xxSuccessful()) { String htmlContent = response.getBody(); log.info("OCR返回HTML长度: {}", htmlContent.length()); return parseHtmlTableToJSON(htmlContent); } else { log.error("OCR服务调用失败,状态码: {}", response.getStatusCode()); throw new RuntimeException("OCR识别失败"); } } catch (Exception e) { log.error("OCR识别过程中发生异常", e); throw new RuntimeException("文件处理失败: " + e.getMessage(), e); } } /** * 将HTML表格解析为JSON格式 * * @param html 包含<table>标签的HTML字符串 * @return 转换后的JSON数据,包含表头和行数据 */ private Map<String, Object> parseHtmlTableToJSON(String html) { Document doc = Jsoup.parse(html); Element table = doc.selectFirst("table"); if (table == null) return Collections.emptyMap(); List<Element> rows = table.select("tr"); if (rows.isEmpty()) return Collections.emptyMap(); // 提取表头 List<String> headers = new ArrayList<>(); Elements headerCells = rows.get(0).select("td, th"); for (Element cell : headerCells) { headers.add(cell.text().trim()); } // 提取数据行 List<Map<String, String>> dataRows = new ArrayList<>(); for (int i = 1; i < rows.size(); i++) { Elements cells = rows.get(i).select("td"); Map<String, String> row = new HashMap<>(); for (int j = 0; j < Math.min(cells.size(), headers.size()); j++) { String key = headers.get(j); String value = cells.get(j).text().trim(); row.put(key, value.isEmpty() ? "" : value); } dataRows.add(row); } // 组装返回结果 Map<String, Object> result = new HashMap<>(); result.put("headers", headers); result.put("data", dataRows); result.put("totalRows", dataRows.size()); return result; } }
依赖说明

需引入以下Maven依赖:

<!-- JSoup用于HTML解析 --> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.16.1</version> </dependency> <!-- Fastjson用于JSON序列化 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> </dependency>

4. 编写控制器暴露API

// 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()) { throw new IllegalArgumentException("上传文件不能为空"); } long startTime = System.currentTimeMillis(); Map<String, Object> result = ocrService.recognitionTable(file); long costTime = System.currentTimeMillis() - startTime; result.put("success", true); result.put("costTimeMs", costTime); log.info("OCR识别完成,耗时{}ms", costTime); return result; } }

该接口接收名为file的图片上传请求,调用服务层处理后返回结构化数据,包含字段名、每行数据及统计信息。


5. 添加测试用例验证功能

为了确保服务稳定性,编写单元测试验证全流程可用性。

// src/test/java/com/kaifamiao/dswebui/service/OcrServiceTest.java @SpringBootTest @Slf4j public class OcrServiceTest { @Autowired private OcrService ocrService; @Test void testRecognitionTableSuccess() throws Exception { ClassPathResource resource = new ClassPathResource("voucher.jpg"); MockMultipartFile file = new MockMultipartFile( "file", "voucher.jpg", "image/jpeg", resource.getInputStream() ); Map<String, Object> result = ocrService.recognitionTable(file); log.info("OCR识别结果: \n{}", JSON.toJSONString(result, true)); Assertions.assertNotNull(result.get("data")); Assertions.assertTrue(((List<?>) result.get("data")).size() > 0); } }

运行测试,观察日志输出是否成功解析出表格内容。


6. 前端页面集成(Vue3)

前端采用Vue3 + Element Plus搭建简易交互界面,主要功能包括:

  • 图片上传区域
  • 实时预览
  • 表格数据显示
  • 错误提示

6.1 页面结构示例

<template> <div class="container"> <h2>表格图片OCR识别</h2> <el-upload action="/api/ocr/process" :auto-upload="true" :show-file-list="false" accept="image/*" :on-success="handleSuccess" :on-error="handleError"> <img v-if="imageUrl" :src="imageUrl" class="preview-img"/> <el-button>点击上传表格图片</el-button> </el-upload> <div v-if="tableData.length > 0" class="result-table"> <h3>识别结果</h3> <el-table :data="tableData" border style="width: 100%"> <el-table-column v-for="col in columns" :key="col" :prop="col" :label="col" /> </el-table> </div> </div> </template>

6.2 构建与集成

进入前端目录执行构建:

npm install npm run build

将生成的dist文件夹内容复制到SpringBoot项目的src/main/resources/static目录下,即可通过内置Tomcat直接访问UI。


7. Docker打包与一键部署

完成开发后,我们将整个应用容器化,便于部署到生产环境。

7.1 编写Dockerfile

FROM openjdk:21-jdk-slim WORKDIR /app COPY target/deepseek-web-ui.jar /app/app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]

7.2 编排服务(docker-compose.yml)

version: '3.8' services: ocr-app: build: . ports: - "8080:8080" environment: - SERVER_PORT=8080 volumes: - ./logs:/app/logs

7.3 构建并启动

mvn clean package -DskipTests docker compose up -d --build

访问http://localhost:8080即可打开OCR识别页面,上传图片即可实时获取结构化数据。


8. 总结

本文完整演示了如何将DeepSeek-OCR-WEBUI这一高性能OCR引擎集成进SpringBoot应用,实现了从“图片→HTML表格→JSON结构化数据”的全链路自动化提取流程。这套方案具有以下优势:

  • 高精度识别:利用DeepSeek大模型的强大能力,准确还原复杂表格结构;
  • 低耦合设计:通过HTTP接口调用,OCR服务可独立升级维护;
  • 易扩展性强:支持多种prompt_type,未来可拓展至合同解析、发票识别等场景;
  • 快速落地:提供完整前后端代码与Docker部署脚本,开箱即用。

无论是财务报销、物流运单、库存管理还是教育阅卷,只要涉及纸质表格电子化,都可以基于此方案进行定制开发,大幅提升数据录入效率,降低人工成本。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询