西双版纳傣族自治州网站建设_网站建设公司_虚拟主机_seo优化
2026/1/22 6:51:44 网站建设 项目流程

从图片到JSON:利用DeepSeek-OCR-WEBUI实现SpringBoot表格数据自动提取

在企业级应用开发中,纸质单据、发票、采购表等结构化文档的数字化处理一直是一个高频且繁琐的任务。传统的人工录入方式不仅效率低,还容易出错。随着AI技术的发展,尤其是OCR(光学字符识别)能力的显著提升,我们已经可以借助大模型实现高精度的表格内容自动提取。

本文将带你使用DeepSeek-OCR-WEBUI这一基于国产自研大模型的高性能OCR系统,结合SpringBoot后端服务,完成一个完整的“图片→HTML表格→JSON结构化数据”的自动化流程。最终目标是:上传一张包含表格的图片,后端调用OCR接口解析内容,并以标准JSON格式返回给前端,供后续业务系统直接消费。

整个过程无需手动编写复杂的图像处理逻辑,也不需要训练模型,只需合理调用API并做好数据转换即可落地。


1. 环境准备与OCR服务部署

要实现表格数据提取,首先必须确保DeepSeek-OCR-WEBUI已正确部署并提供HTTP API服务。该镜像封装了DeepSeek开源的OCR大模型,支持多语言、复杂背景下的文本识别,尤其擅长中文场景下的表格和票据解析。

1.1 部署OCR后端服务

进入项目目录并启动Docker容器:

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

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

docker logs -f deepseek-ocr-webui

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

1.2 OCR核心接口说明

DeepSeek-OCR-WEBUI提供了一个/ocr接口,用于接收图片并返回识别结果。其定义位于web_service.py文件中:

@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) ):

其中关键参数如下:

参数名可选值说明
prompt_typedocument,ocr,free,figure,describe,find,freeform指定识别模式
file图片文件(JPEG/PNG等)待识别的图像

对于表格识别任务,我们必须选择prompt_type=figure,因为该模式专为图表、公式、表格结构设计,能保留原始布局信息,并输出HTML格式的<table>标签。

提示:如果你希望扩展功能(如添加新参数或修改返回格式),可直接修改web_service.py,但修改后需重新构建Docker镜像才能生效。


2. SpringBoot项目集成OCR客户端

接下来,在SpringBoot应用中接入OCR服务,实现“图片上传 → 调用OCR → 解析HTML → 返回JSON”的完整链路。

2.1 定义OCR服务接口

创建OcrService接口,声明表格识别方法:

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

2.2 实现OCR调用逻辑

使用RestTemplate发送POST请求到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"; @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(); } }; // 构建请求参数(multipart/form-data) 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); // 发送请求 ResponseEntity<String> response = restTemplate.postForEntity(OCR_SERVICE_URL, requestEntity, String.class); if (response.getStatusCode().is2xxSuccessful()) { String htmlContent = response.getBody(); return parseHtmlTableToJSON(htmlContent); } else { log.error("OCR服务调用失败,状态码: {}", response.getStatusCode()); throw new RuntimeException("OCR识别失败"); } } catch (Exception e) { log.error("OCR识别过程中发生异常", e); throw new RuntimeException("文件处理失败", e); } } /** * 将HTML表格解析为JSON格式 * * @param html 包含<table>标签的HTML字符串 * @return 转换后的JSON数据(List<Map<String, String>> 形式) */ private Map<String, Object> parseHtmlTableToJSON(String html) { Document doc = Jsoup.parse(html); Element table = doc.selectFirst("table"); List<Map<String, String>> rows = new ArrayList<>(); if (table != null) { 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); // 默认列名 if (!text.isEmpty()) headers.set(i, text); // 使用首行为表头 } 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("data", rows); result.put("total", rows.size()); return result; } }
核心要点说明:
  • 使用RestTemplate构造 multipart 请求上传图片。
  • 必须设置prompt_type=figure才能触发表格识别逻辑。
  • 响应体为纯HTML<table>结构,使用Jsoup解析DOM树。
  • 自动将第一行作为表头字段名,其余每行转为一个Map<String, String>对象。
  • 最终返回结构清晰的JSON:包含data数组和总数统计。

3. 控制器层暴露REST接口

创建控制器类,对外提供HTTP接口供前端调用。

// 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("上传文件不能为空"); } Map<String, Object> result = ocrService.recognitionTable(file); log.info("OCR识别结果: {}", JSON.toJSONString(result)); return result; } }

该接口接受名为file的图片上传请求,调用服务层完成识别后,直接返回JSON结构化数据。

例如,输入一张采购单截图:

返回结果示例:

{ "data": [ { "序号": "1", "条码": "6949123352617", "名称": "飞科PR-5261毛球修剪器", "单位": "个", "订货数量": "0.00", "采购数量": "1.00", "赠送数量": "0.00", "采购单价": "38.5000", "金额小计": "38.5000", "备注": "" }, { "序号": "2", "条码": "6944296500049", "名称": "天香炸酱面180g*50", "单位": "个", "订货数量": "0.00", "采购数量": "1.00", "赠送数量": "0.00", "采购单价": "0.0000", "金额小计": "0.0000", "备注": "" } ], "total": 2 }

4. 编写单元测试验证功能

为了确保服务稳定性,编写JUnit测试用例验证全流程是否通畅。

// 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识别结果: {}", JSON.toJSONString(result)); Assertions.assertNotNull(result); Assertions.assertTrue(((Integer) result.get("total")) > 0); } }

运行测试,观察日志输出,确认能成功解析出表格数据。


5. 前端页面集成(Vue)

项目附带了一个基于Vue的简单UI界面,用于演示图片上传与结果显示。

5.1 页面效果展示

用户点击“选择文件”上传图片,点击“开始识别”后发送请求至/api/ocr/process,后台返回JSON数据并在页面渲染成表格。

5.2 构建与部署

安装Node.js(建议v20+),执行构建命令:

npm i npm run build

生成的dist目录需复制到SpringBoot项目的静态资源路径下(如src/main/resources/static),以便内嵌Tomcat直接提供前端页面访问。


6. 打包与Docker部署

完成前后端开发后,进行整体打包并通过Docker部署。

6.1 Maven打包后端应用

mvn clean package -DskipTests

生成jar包:target/deepseek-web-ui-1.0.0.jar

6.2 编写Dockerfile

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.3 配置docker-compose.yml

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

6.4 启动服务

docker compose up -d --build

访问http://localhost:8080即可打开前端页面,开始使用表格识别功能。


7. 总结

通过本文的实践,我们完成了从“图片到JSON”的全自动表格数据提取系统搭建,核心步骤包括:

  1. 部署DeepSeek-OCR-WEBUI服务,利用其强大的表格识别能力;
  2. SpringBoot集成OCR客户端,通过HTTP调用获取HTML格式表格;
  3. 使用Jsoup解析HTML,将其转化为结构化的JSON数据;
  4. 前后端联调与Docker化部署,实现一键启动、开箱即用。

这套方案特别适用于以下场景:

  • 财务报销单自动化录入
  • 仓库入库单快速登记
  • 教育领域成绩单数字化
  • 物流运单信息抓取

相比传统OCR工具,DeepSeek-OCR-WEBUI的优势在于:

  • 中文识别准确率高
  • 支持复杂表格结构还原
  • 易于集成、无需训练
  • 开源可控、可本地部署

未来还可以在此基础上增加人工校验界面、批量处理队列、错误重试机制等功能,进一步提升系统的实用性与健壮性。


获取更多AI镜像

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

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

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

立即咨询