使用Java将PDF解析成HTML页面进行展示并从页面中提取Json数据设置到Table中

一、前言

        最近在做一个解析PDF文件的功能,试了很方法,最后终于成功,在这里给大家分享一下。很多PDF解析的API或工具都有一些问题,我尝试过如pdf2htmlEX、xpdf、pdfbox等API或工具,效果都不太理想,后来无意中发现了pdfdom,pdfdom是一个JavaAPI,它是在pdfbox的基础上进行了扩展,专门用于解析PDF文件生成HTML文件,效果非常好,下面我们来看一下具体如何实现。

二、pdfdom的POM依赖

    
        net.sf.cssbox
        pdf2dom
        1.6
    

    
        org.apache.pdfbox
        pdfbox
        2.0.4
    

    
        org.apache.pdfbox
        pdfbox-tools
        2.0.4
    

三、上传PDF文件并解析PDF文件

1、简单的JSP页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title
    
    
    
    


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();
        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("\n" +
                "");
        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 += '' + textValue + '';
            }
            //如果是有用的数据,才会添加到table中
            if (trData.length > 1) {
                var trHtml = '' + tdHtml + '';
                table.find('tbody').append(trHtml);
            }
        }
    }
}


此方式仅供大家参考,如果有不对的地方,欢迎指正!


        

你可能感兴趣的:(开发实践,PDF转换,js,jquery)