PDF转excel+json ,vue3+SpringBoot在线演示+附带源码

news2025/5/11 3:41:21

在线演示地址:Vite + Vuehttp://www.xpclm.online/pdf-h5 源码gitee前后端地址:
javapdfexcel: javaPDF转excelhttps://gitee.com/gaiya001/javapdfexcel.git

盖亚/vuepdfhttps://gitee.com/gaiya001/vuepdf.git

后续会推出 前端版本跟nestjs版本

识别复杂表格不是很准确,建议获取json格式坐标,可以配合我得另一篇使用传参替换表格内容展示更佳前端界面在线excel编辑器 。node编写post接口获取文件流,使用传参替换表格内容展示、前后端一把梭。-CSDN博客

目录结构预览:

 基于Spring Boot和Tabula的PDF表格数据提取系统


项目概述

本项目使用Spring Boot框架结合Tabula库,实现从PDF文件中提取表格数据并转换为Excel和JSON格式的功能。


核心技术栈

  • Spring Boot - 提供快速应用开发框架
  • Tabula - 专业的PDF表格数据提取库
  • Apache POI - 用于Excel文件操作
  • Jackson - 处理JSON数据转换

核心代码实现

1. 主应用入口

PdfExcelConverterApplication.java
package com.example.pdfexcelconverter;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class PdfExcelConverterApplication {
    public static void main(String[] args) {
        SpringApplication.run(PdfExcelConverterApplication.class, args);
    }
}

2. PDF解析服务

PdfExtractorService.java
package com.example.pdfexcelconverter.service;

import technology.tabula.*;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;
import java.util.List;

public class PdfExtractorService {
    
    public List<Table> extractTablesFromPdf(String filePath) throws Exception {
        ObjectExtractor oe = new ObjectExtractor(new PageIterator(filePath));
        SpreadsheetExtractionAlgorithm sea = new SpreadsheetExtractionAlgorithm();
        return sea.extract(oe.next());
    }
}

3. Excel导出服务

ExcelExportService.java
package com.example.pdfexcelconverter.service;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import technology.tabula.Table;
import java.io.FileOutputStream;

public class ExcelExportService {
    
    public void exportToExcel(List<Table> tables, String outputPath) throws Exception {
        Workbook workbook = new XSSFWorkbook();
        
        for(int i=0; i<tables.size(); i++) {
            Sheet sheet = workbook.createSheet("Sheet"+(i+1));
            Table table = tables.get(i);
            
            // 填充Excel表格数据...
        }
        
        try(FileOutputStream out = new FileOutputStream(outputPath)) {
            workbook.write(out);
        }
    }
}

4. JSON转换服务

sonConverterService.java
package com.example.pdfexcelconverter.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import technology.tabula.Table;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;

public class JsonConverterService {
    
    public String convertToJson(List<Table> tables) throws Exception {
        List<Map<String, Object>> result = new ArrayList<>();
        
        for(Table table : tables) {
            Map<String, Object> tableData = new HashMap<>();
            // 转换表格数据为JSON结构...
            result.add(tableData);
        }
        
        return new ObjectMapper().writeValueAsString(result);
    }
}

基于Vue.js框架的PDF转Excel/JSON应用核心代码

1. 文件上传组件

FileUploader.vue
<template>
  <div class="upload-container">
    <div class="upload-card">
      <h2>PDF 文件转换</h2>
      <div class="upload-area" @dragover.prevent @drop="handleDrop">
        <input 
          type="file" 
          ref="fileInput" 
          @change="handleFileChange" 
          accept=".pdf" 
          class="file-input"
        />
        <div class="upload-icon">
          <svg viewBox="0 0 24 24" width="48" height="48">
            <path fill="currentColor" d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20M15,13V18H9V13H7L12,8L17,13H15Z" />
          </svg>
        </div>
        <p>拖放PDF文件到此处或点击选择文件</p>
      </div>
      
      <div class="button-group">
        <button 
          @click="uploadFile('excel')" 
          :disabled="!file" 
          class="btn btn-excel"
        >
          转换为Excel
        </button>
        <button 
          @click="uploadFile('json')" 
          :disabled="!file" 
          class="btn btn-json"
        >
          转换为JSON
        </button>
      </div>
      
      <div v-if="loading" class="loading-overlay">
        <div class="spinner"></div>
        <p>文件处理中...</p>
        <div class="progress-bar">
          <div class="progress" :style="{width: progress + '%'}"></div>
        </div>
      </div>
    </div>
    
    <div v-if="jsonResult" class="result-container">
      <h3>JSON 结果</h3>
      <vue-json-pretty
        :data="jsonResult"
        :deep="3"
        :showLength="true"
        :showLine="true"
        :showDoubleQuotes="true"
        :collapsedOnClickBrackets="true"
        class="json-viewer"
      />
    </div>
    
    <div v-if="downloadUrl" class="download-section">
      <a :href="downloadUrl" download class="download-btn">
        下载Excel文件
      </a>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import axios from 'axios';
import VueJsonPretty from 'vue-json-pretty';
import 'vue-json-pretty/lib/styles.css';

const file = ref(null);
const jsonResult = ref(null);
const downloadUrl = ref(null);
const loading = ref(false);
const fileInput = ref(null);

const handleFileChange = (e) => {
  file.value = e.target.files[0];
};

const handleDrop = (e) => {
  e.preventDefault();
  const droppedFile = e.dataTransfer.files[0];
  if (droppedFile && droppedFile.type === 'application/pdf') {
    file.value = droppedFile;
  }
};

const uploadFile = async (type) => {
  if (!file.value) return;
  
  loading.value = true;
  jsonResult.value = null;
  downloadUrl.value = null;
  
  const formData = new FormData();
  formData.append('file', file.value);
  
  try {
    const endpoint = type === 'excel' 
      ? '/api/pdf/excel'
      : '/api/pdf/json';

    const response = await axios.post(endpoint, formData, {
      responseType: type === 'excel' ? 'arraybuffer' : 'json', // 修改为arraybuffer
      headers: {
        'Content-Type': 'multipart/form-data'
      }
    });

    if (type === 'excel') {
      const blob = new Blob([response.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
      downloadUrl.value = URL.createObjectURL(blob);
    } else {
      jsonResult.value = response.data;
    }
  } catch (error) {
    console.error('上传失败:', error);
    alert('文件处理失败,请重试');
  } finally {
    loading.value = false;
  }
};
</script>

<style scoped>
.upload-container {
  max-width: 800px;
  margin: 0 auto;
  padding: 2rem;
}

.upload-card {
  background: white;
  border-radius: 10px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
  padding: 2rem;
  position: relative;
  overflow: hidden;
}

h2 {
  text-align: center;
  color: #2c3e50;
  margin-bottom: 1.5rem;
}

.upload-area {
  border: 2px dashed #ccc;
  border-radius: 8px;
  padding: 2rem;
  text-align: center;
  cursor: pointer;
  transition: all 0.3s;
  margin-bottom: 1.5rem;
}

.upload-area:hover {
  border-color: #42b983;
}

.upload-icon {
  color: #42b983;
  margin-bottom: 1rem;
}

.file-input {
  display: none;
}

.button-group {
  display: flex;
  gap: 1rem;
  justify-content: center;
}

.btn {
  padding: 0.75rem 1.5rem;
  border: none;
  border-radius: 5px;
  font-weight: bold;
  cursor: pointer;
  transition: all 0.3s;
}

.btn:hover {
  transform: translateY(-2px);
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
}

.btn-excel {
  background-color: #21a366;
  color: white;
}

.btn-json {
  background-color: #f0db4f;
  color: #323330;
}

.loading-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(255, 255, 255, 0.8);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  z-index: 10;
}

.spinner {
  border: 4px solid rgba(0, 0, 0, 0.1);
  border-radius: 50%;
  border-top: 4px solid #42b983;
  width: 40px;
  height: 40px;
  animation: spin 1s linear infinite;
  margin-bottom: 1rem;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

.result-container {
  margin-top: 2rem;
  background: #f8f9fa;
  border-radius: 8px;
  padding: 1.5rem;
  text-align: left; /* 容器也左对齐 */
}

.json-viewer {
  background: white;
  padding: 1rem;
  border-radius: 5px;
  max-height: 400px;
  overflow-y: auto;
  text-align: left;
}

.download-section {
  text-align: center;
  margin-top: 2rem;
}

.download-btn {
  display: inline-block;
  padding: 0.75rem 1.5rem;
  background-color: #42b983;
  color: white;
  text-decoration: none;
  border-radius: 5px;
  font-weight: bold;
  transition: all 0.3s;
}

.download-btn:hover {
  background-color: #369b6d;
  transform: translateY(-2px);
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2338583.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何高效使用 Text to SQL 提升数据分析效率?四个关键应用场景解析

数据分析师和业务人员常常面临这样的困境&#xff1a;有大量数据等待分析&#xff0c;但 SQL 编写却成为效率瓶颈。即使对于经验丰富的数据分析师来说&#xff0c;编写复杂 SQL 查询也需要耗费大量时间&#xff1b;而对于不具备 SQL 专业知识的业务人员&#xff0c;数据分析则更…

分享一个DeepSeek+自建知识库实现人工智能,智能回答高级用法。

这个是我自己搞的DeepSeek大模型自建知识库相结合到一起实现了更强大的回答问题能力还有智能资源推荐等功能。如果感兴趣的小伙伴可以联系进行聊聊&#xff0c;这个成品已经有了实现了&#xff0c;所以可以融入到你的项目&#xff0c;或者毕设什么的还可以去参加比赛等等。 1.项…

jangow靶机笔记(Vulnhub)

环境准备&#xff1a; 靶机下载地址&#xff1a; https://download.vulnhub.com/jangow/jangow-01-1.0.1.ova kali地址&#xff1a;192.168.144.128 靶机&#xff08;jangow&#xff09;地址&#xff1a;192.168.144.180 一.信息收集 1.主机探测 使用arp-scan进行主机探…

PyTorch `flatten()` 和 `squeeze()` 区别

PyTorch flatten() 和 squeeze() 区别 在 PyTorch 里,flatten() 和 squeeze(0) 是两个不同的张量操作, 1. flatten() 方法 flatten() 方法用于把一个多维张量展开成一维张量。它会将张量里的所有元素按顺序排列成一个一维序列。 语法 torch.flatten(input, start_dim=

wordpress SMTP配置qq邮箱发送邮件,新版QQ邮箱授权码获取方法

新版的QQ邮箱界面不同了&#xff0c;以下是新版的设置方法&#xff1a; 1. 进入邮箱后&#xff0c;点右上角的设置图标&#xff1a; 2. 左下角的菜单里&#xff0c;选择“账号与安全” &#xff1a; 3. 然后如下图&#xff0c;开启SMTP 服务&#xff1a; 4. 按提示验证短信&am…

2025年最新版 Git和Github的绑定方法,以及通过Git提交文件至Github的具体流程(详细版)

文章目录 Git和Github的绑定方法与如何上传至代码仓库一. 注册 GitHub 账号二.如何创建自己的代码仓库&#xff1a;1.登入Github账号&#xff0c;完成登入后会进入如下界面&#xff1a;2.点击下图中红色框选的按钮中的下拉列表3.选择New repostitory4.进入创建界面后&#xff0…

基于LSTM-AutoEncoder的心电信号时间序列数据异常检测(PyTorch版)

心电信号&#xff08;ECG&#xff09;的异常检测对心血管疾病早期预警至关重要&#xff0c;但传统方法面临时序依赖建模不足与噪声敏感等问题。本文使用一种基于LSTM-AutoEncoder的深度时序异常检测框架&#xff0c;通过编码器-解码器结构捕捉心电信号的长期时空依赖特征&#…

JavaScript中的Event事件对象详解

一、事件对象&#xff08;Event&#xff09;概述 1. 事件对象的定义 event 对象是浏览器自动生成的对象&#xff0c;当用户与页面进行交互时&#xff08;如点击、键盘输入、鼠标移动等&#xff09;&#xff0c;事件触发时就会自动传递给事件处理函数。event 对象包含了与事件…

王牌学院,25西电通信工程学院(考研录取情况)

1、通信工程学院各个方向 2、通信工程学院近三年复试分数线对比 学长、学姐分析 由表可看出&#xff1a; 1、信息与通信工程25年相较于24年上升5分、军队指挥学25年相较于24年上升30分 2、新一代电子信息技术&#xff08;专硕&#xff09;25年相较于24年下降25分、通信工程&…

深入理解 Java 多线程:锁策略与线程安全

文章目录 一、常见的锁策略1. 乐观锁&&悲观锁2. 读写锁3. 重量级锁&&轻量级锁4. 自旋锁5. 公平锁&&不公平锁6. 可重入锁 && 不可重入锁 二、CAS1. 什么是 CAS2. CAS 是怎么实现的3.CAS 有哪些应用1) 实现原子类2) 实现自旋锁 4. CAS 的 ABA 问…

Java数据结构——ArrayList

Java中ArrayList 一 ArrayList的简介二 ArrayList的构造方法三 ArrayList常用方法1.add()方法2.remove()方法3.get()和set()方法4.index()方法5.subList截取方法 四 ArrayList的遍历for循环遍历增强for循环(for each)迭代器遍历 ArrayList问题及其思考 前言 ArrayList是一种 顺…

科学量化AI对品牌产品印象 首个AI印象(AII)指数发布

2025年4月18日&#xff0c;营销传播数据研究领先机构四度传播研究院(SAC)&#xff0c;正式推出了量化AI大模型对产品整体印象的AI印象&#xff0c;简称AII&#xff08;ARTIFICIAL INTELLIGENCE IMPRESSIONS&#xff09;&#xff0c;同时发布了首个“汽车AI印象榜”。为企业和消…

FFmpeg 硬核指南:从底层架构到播放器全链路开发实战 基础

目录 1.ffmpeg的基本组成2.播放器的API2.1 复用器阶段2.1.1 分配解复用上下文2.1.2 文件信息操作2.1.3 综合示例 2. 2 编解码部分2.2.1 分配解码器上下文2.2.2编解码操作2.2.3 综合示例 3 ffmpeg 内存模型3.1 基本概念3.2API 1.ffmpeg的基本组成 模块名称功能描述主要用途AVFo…

UE5有些场景的导航生成失败解决方法

如果导航丢失&#xff0c;就在项目设置下将&#xff1a; 即可解决问题&#xff1a; 看了半个小时的导航生成代码发现&#xff0c;NavDataSet这个数组为空&#xff0c;导致异步构建导航失败。 解决 NavDataSet 空 无法生成如下&#xff1a; 当 NavDataSet 为空的化 如果 bAut…

MCP(Model Context Protocol 模型上下文协议)科普

MCP&#xff08;Model Context Protocol&#xff0c;模型上下文协议&#xff09;是由人工智能公司 Anthropic 于 2024年11月 推出的开放标准协议&#xff0c;旨在为大型语言模型&#xff08;LLM&#xff09;与外部数据源、工具及服务提供标准化连接&#xff0c;从而提升AI在实际…

健康养生指南

在快节奏的现代生活中&#xff0c;健康养生成为人们关注的焦点。它不仅关乎身体的强健&#xff0c;更是提升生活质量、预防疾病的关键。掌握科学的养生方法&#xff0c;能让我们在岁月流转中始终保持活力。 饮食是健康养生的基础。遵循 “均衡膳食” 原则&#xff0c;每日饮食需…

Linux系统:进程终止的概念与相关接口函数(_exit,exit,atexit)

本节目标 理解进程终止的概念理解退出状态码的概念以及使用方法掌握_exit与exit函数的用法以及区别atexit函数注册终止时执行的函数相关宏 一、进程终止 进程终止&#xff08;Process Termination&#xff09;是指操作系统结束一个进程的执行&#xff0c;回收其占用的资源&a…

Linux下 文件的查找、复制、移动和解压缩

1、在/var/log目录下创建一个hehe.log的文件&#xff0c;其文件内容是&#xff1a; myhostname ghl mydomain localdomain relayhost [smtp.qq.com]:587 smtp_use_tls yes smtp_sasl_auth_enable yes smtp_sasl_security_options noanonymous smtp_sasl_tls_security_opt…

C语言学习之预处理指令

目录 预定义符号 #define的应用 #define定义常量 #define定义宏 带有副作用的宏参数 宏替换的规则 函数和宏定义的区别 #和## #运算符 ##运算符 命名约定 #undef ​编辑 命令行定义 条件编译 头文件包含 头文件被包含的方式 1.本地头文件包含 2.库文件包含 …

【STM32单片机】#10 USART串口通信

主要参考学习资料&#xff1a; B站江协科技 STM32入门教程-2023版 细致讲解 中文字幕 开发资料下载链接&#xff1a;https://pan.baidu.com/s/1h_UjuQKDX9IpP-U1Effbsw?pwddspb 单片机套装&#xff1a;STM32F103C8T6开发板单片机C6T6核心板 实验板最小系统板套件科协 实验&…