使用Java将PDF解析成HTML页面进行展示并从页面中提取Json数据设置到Table中
2018-03-08 23:06
986 查看
一、前言
最近在做一个解析PDF文件的功能,试了很方法,最后终于成功,在这里给大家分享一下。很多PDF解析的API或工具都有一些问题,我尝试过如pdf2htmlEX、xpdf、pdfbox等API或工具,效果都不太理想,后来无意中发现了pdfdom,pdfdom是一个JavaAPI,它是在pdfbox的基础上进行了扩展,专门用于解析PDF文件生成HTML文件,效果非常好,下面我们来看一下具体如何实现。二、pdfdom的POM依赖
<dependency> <groupId>net.sf.cssbox</groupId> <artifactId>pdf2dom</artifactId> <version>1.6</version> </dependency> <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>2.0.4</version> </dependency> <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox-tools</artifactId> <version>2.0.4</version> </dependency>
三、上传PDF文件并解析PDF文件
1、简单的JSP页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> <script type="text/javascript" src="js/jquery-3.2.1.js"></script> <script type="text/javascript" src="js/ajaxfileupload.js"></script> <script charset="UTF-8" type="text/javascript" src="js/demo.js"></script> <style> #dataTable tbody tr td { border: 1px solid black; white-space: nowrap; width: auto; } </style> </head> <body> <div> <input id="file" type="file" name="file" value="打开PDF文件"> <input id="getData" type="button" value="生成表格数据" onclick="getData()"> </div> <div> <iframe id="text_iframe" src="" name="text_iframe" style="width: 800px;height: 500px;float: left"></iframe> </div> <div style="width: 800px;height: 500px;"> <table id="dataTable" border="0" cellspacing="0" style="height: auto;border-collapse: collapse;width: 100%;"> <tbody></tbody> </table> </div> </body> </html>
2、前端的异步上传
这里使用的是异步上传,使用了一个js插件ajaxfileupload.js$(function () {//当file的内容发生改变时,上传pdf文件并将文件转换成html文件
$('#file').change(function () {
uploadPdf();
});
});
/**
* 异步上传pdf文件
*/
function uploadPdf() {
//异步上传文件
$.ajaxFileUpload({
url: 'pdftohtml',//请求的url
secureuri: false,//设置是否需要安全协议,一般为false
type: 'post',//请求方式
fileElementId: 'file',//文件域的id属性值
dataType: 'json',
success: function (data) {
if (data.code == 0) {
alert(data.message);
} else {
//将返回的文件名设置到内嵌框架的src属性中进行展示(本来是想把html文件引入jsp的,结果发现生成的是xhtml,不兼容,就使用了内嵌框架)
$('#text_iframe').attr('src', 'pdfhtml/' + data.message);
}
}
});
//再次绑定改变事件
$('#file').change(function () {
uploadPdf();
});
}
3、Controller层
package com.mengfei.controller; import com.mengfei.util.PdfConvertUtil; import com.mengfei.util.ResponseInfoUtil; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; @Controller public class PdfConvertController { @PostMapping("/pdftohtml") @ResponseBody public ResponseInfoUtil pdftohtml(MultipartFile file, HttpServletRequest request) { ResponseInfoUtil responseInfo = new ResponseInfoUtil(); cd5e responseInfo.setCode(0); PdfConvertUtil pdfConvertUtil = new PdfConvertUtil(); String pdfName = file.getOriginalFilename(); int lastIndex = pdfName.lastIndexOf(".pdf"); String fileName = pdfName.substring(0, lastIndex); String htmlName = fileName + ".html"; String realPath = request.getSession().getServletContext().getRealPath("/pdfhtml"); String htmlPath = realPath + "\\" + htmlName; try { pdfConvertUtil.pdftohtml(file.getBytes(), htmlPath); responseInfo.setCode(1); responseInfo.setMessage(htmlName); } catch (Exception e) { responseInfo.setMessage("读写文件出现异常,请重新尝试!"); e.printStackTrace(); } return responseInfo; } }
4、转换PDF文件的工具类
package com.mengfei.util; import org.apache.pdfbox.pdmodel.PDDocument; import org.fit.pdfdom.PDFDomTree; import java.io.*; public class PdfConvertUtil { public void pdftohtml(byte[] bytes, String htmlPath) throws Exception { //加载PDF文档 PDDocument document = PDDocument.load(bytes); //将字节流转换成字符流 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(htmlPath)),"UTF-8")); //实例化pdfdom树对象 PDFDomTree pdfDomTree = new PDFDomTree(); //开始写入html文件 pdfDomTree.writeText(document, out); //在文件末尾写入要引入的js,因为我将转换的html文件放在了webapp/pdfhtml文件夹下,所以这两个js文件也要放在pdfhtml文件夹下 out.write("<script type=\"text/javascript\" src=\"jquery-3.2.1.js\"></script>\n" + "<script type=\"text/javascript\" src=\"pdfhtml.js\"></script>"); out.flush(); out.close(); document.close(); } }
四、从转换好的html文件中提取json数据
有了转换PDF文件的工具类,再去转换PDF文件并不难,但是要从html文件中提取json数据,并按照文本的顺序进行从上到下的排列并设置到表格中,这个过程还是蛮麻烦的。我们先观察转换好的HTML,会发现HTML文档中的节点都是使用了绝对定位,这也是保持文档不乱的最好方法。本来想使用每个节点的id属性进行从上到下的排序,结果发现有些地方不知道什么原因,id值很大跑到了最下面,但top值为负数,所以这里使用top值来进行分行,top值相同的肯定是在同一行,通过截取top值前面的数字来判断大小进行上下顺序的排列,行排出来了再分出列,同样的道理将每一行中的节点left值通过截取前面的数字来判断大小进行左右顺序的排列,下面看代码实现。/*** 获取整个html页面的json数据
* @returns {Array}
*/
function getPageJson() {
var pages = $('.page');
var pageJson = [];
$.each(pages, function () {
//将html中的数据提取成json格式的数组
var rowJson = [];
var rows = $(this).find('.p');
for (var i = 0; i < rows.length; i++) {
var topValue = $(rows[i]).css('top');
var leftValue = $(rows[i]).css('left');
var id = rows[i].id;
var textValue = $(rows[i]).text();
var topFloatValue = getFloatValue(topValue);
var leftFloatValue = getFloatValue(leftValue);
rowJson.push({
id: id,
topFloatValue: topFloatValue,
leftFloatValue: leftFloatValue,
textValue: textValue
});
}
//根据top值对json数组进行排序,默认为升序
rowJson.sort(sequenceTop);
//对json数组进行分组,分出行数据
var map = {},
groupJson = [];
for (var i = 0; i < rowJson.length; i++) {
var row = rowJson[i];
//如果为undefined,就添加一个以topFloatValue为键的数组,用来存放行数据
if (map[row.topFloatValue] == undefined) {
groupJson.push({trKey: row.topFloatValue, trData: [row]});
//为map[row.topFloatValue]添加值,防止添加重复的键
map[row.topFloatValue] = row;
} else {
for (var j = 0; j < groupJson.length; j++) {
var groupRow = groupJson[j];
//如果groupJson数组中已经存在以topFloatValue为键的数组,则在此行中添加行数据
if (row.topFloatValue == groupRow.trKey) {
groupRow.trData.push(row);
}
}
}
}
//根据left值对json数组再次进行排序,默认为升序
for (var t = 0; t < groupJson.length; t++) {
var trData = groupJson[t].trData;
if (trData.length > 1) {
trData.sort(sequenceLeft);
}
}
//将分组后的json添加进pageJson中
var pageId = this.id;
pageJson.push({pageId: pageId, pageData: groupJson});
});
return pageJson;
}
/**
* 根据top值进行排序的方法
* @param {Object} a
* @param {Object} b
*/
function sequenceTop(a, b) {
return a.topFloatValue - b.topFloatValue;
}
/**
* 根据left值进行排序的方法
* @param {Object} a
* @param {Object} b
*/
function sequenceLeft(a, b) {
return a.leftFloatValue - b.leftFloatValue;
}
/**
* 获取绝对定位的数值
* @param {Object} value
*/
function getFloatValue(value) {
var pxIndex = value.lastIndexOf('px');
var strValue = value.substring(0, pxIndex);
var floatValue = parseFloat(strValue);
return floatValue;
}
五、将获取的json数据进行业务处理并添加到表格中
/** * 将解析的json数据再次进行处理并添加到内嵌框架的table中 */ function intoTable() { var table = table_iframe.window.getTable(); //将table中的html节点清空 table.find('tbody').html(''); //获取iframe中pdfhtml文件中的json格式数据 var pageJson = text_iframe.window.getPageJson(); var maxLengths = []; for (var t = 0; t < pageJson.length; t++) { var pageData = pageJson[t].pageData; //计算出trData中length最大的值,作为列的最大值 var lengths = []; for (var k = 0; k < pageData.length; k++) { lengths.push(pageData[k].trData.length); } var maxLength = Math.max.apply(null, lengths); maxLengths.push(maxLength); } var finalMaxLength = Math.max.apply(null, maxLengths); for (var t = 0; t < pageJson.length; t++) { var pageData = pageJson[t].pageData; for (var i = 0; i < pageData.length; i++) { var trData = pageData[i].trData; var tdHtml = ''; for (var j = 0; j < finalMaxLength; j++) { //如果length<=1,一般为无用数据,排除掉 if (trData.length <= 1) { continue; } //如果行数据下标的值 >=最大length时,才会使用下标取textValue,否则textValue值为'' var textValue = ''; if (j <= trData.length - 1) { textValue = trData[j].textValue; } tdHtml += '<td>' + textValue + '</td>'; } //如果是有用的数据,才会添加到table中 if (trData.length > 1) { var trHtml = '<tr>' + tdHtml + '</tr>'; table.find('tbody').append(trHtml); } } } }
此方式仅供大家参考,如果有不对的地方,欢迎指正!
相关文章推荐
- 从页面接收json格式的数据,在java类里面进行解析
- 使用Java进行Json数据的解析(对象数组的相互嵌套)
- JAVA中使用JSON进行数据传递
- java中使用net.sf.json对json进行解析
- Java解析JSON数据 使用org.json
- java中对JSON格式数据进行解析和映射
- Android网络开发中如何使用JSON进行网络通信---Android JSON数据通讯方法解析
- Android使用JSON进行数据解析
- JAVA中使用JSON进行 4000 数据传递
- java通过url获取页面数据 java解析xml 基金净值接口使用方法
- JAVA中使用JSON进行数据传递
- Java中使用Jsoup对Html文档进行解析和操作
- Android网络开发中如何使用JSON进行网络通信---Android JSON数据通讯方法解析
- Java - 抓取优酷网视频播放页面(使用jsoup解析html,正则表达式处理字符串)
- json数据解析与JAVA对象转换以及在JQUERY中的使用
- 使用BO JAVA SDK打开WEBI报表,并进行PDF、EXCEL、CSV、HTML导出
- 讲解在java环境下使用jQuery进行JSON数据传送的交互过程
- java中使用net.sf.json对json进行解析
- JAVA中使用JSON进行数据传递
- JAVA中使用JSON进行数据传递