java文档在线预览实现

Java文档在线预览实现

近期因需要完成对word、excel、ppt、txt等文档的内容检索,在用户检索到相关内容时,需要给用户提供一个在线预览文档的功能。在网上找到部分参考后,实现了该功能。

  • Java文档在线预览实现
    • 主要步骤
    • 组件安装
      • Aspose
      • swftools
      • flexpaper
      • 功能实现
        • 文档转换为PDF
        • pdfjs预览
        • PDF转换为swf
        • flexpaper预览

主要步骤

要实现这些文档的预览,需要先将文档转换为PDF再进行预览。

转换步骤:
* 使用OpenOffice/Aspose 将ppt、word、excel、txt类型的文件转换为pdf

预览步骤:
* 高版本浏览器上,使用pdf.js直接预览PDF文件
* 低版本浏览器上,使用swftools将PDF文件转换为swf文件,再使用flexpaper预览swf

组件安装

Aspose

由于OpenOffice的转换效果并不太佳,这里选择了Aspose

在Aspose官网下载Aspose的java版本,主要选择
* Aspose.words
* Aspose.cells(Excel)
* Aspose.slides(PPT)
* Aspose.pdf

下载完成后,在工程中引用jar包即可。

swftools

swftools主要用于将PDF文件转换为swf文件以便使用flexpaper进行播放。

在swftools下载页面 选择对应的版本下载即可。如windows下载exe后缀的文件,linux下载tar.gz后缀的文件。

java文档在线预览实现_第1张图片

flexpaper

flexpaper的作用是播放swf文件。

flexpaper官网为 https://flowpaper.com

flexpaper 2.3.6版本下载地址

功能实现

这里采用的所有组件版本为:

名称 版本
Aspose.words 16.8.0
Aspose.cells 9.0.0
Aspose.slides 116.7.0
Aspose.pdf 11.8.0
swftools swftools-2013-04-09-1007.exe
flexpaper 2.3.6

文档转换为PDF

使用Aspose进行文档转换很简单,直接引入相应的jar包,调用save方法,转换为PDF即可。

注意:
1. 使用Aspose时,每一个模块(words,cells)都可能有相同的类,如License类,SaveOptions类,SaveFormat类。而在各自模块使用时,一定要用对应模块的类,这个坑我已爬过。

  1. 使用Aspose时,需要每次进行转换操作前调用设置License方法。

获取license示例代码:

package com.dm.docpreview.convert.util;


import org.apache.log4j.Logger;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;

/**
 * Aspose注册工具
 *
 * @author zxb
 * @version 1.0.0
 *          2016年10月17日 17:00
 * @since Jdk1.6
 */
public class AsposeLicenseUtil {

    private static InputStream inputStream = null;

    private static Logger logger = Logger.getLogger(AsposeLicenseUtil.class);

    /**
     * 获取License的输入流
     *
     * @return
     */
    private static InputStream getLicenseInput() {
        if (inputStream == null) {
            ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
            try {
                inputStream = new FileInputStream(contextClassLoader.getResource("license.xml").getPath());
            } catch (FileNotFoundException e) {
                logger.error("license not found!", e);
            }
        }
        return inputStream;
    }

    /**
     * 设置License
     *
     * @return true表示已成功设置License, false表示失败
     */
    public static boolean setWordsLicense() {
        InputStream licenseInput = getLicenseInput();
        if (licenseInput != null) {
            try {
                com.aspose.words.License aposeLic = new com.aspose.words.License();
                aposeLic.setLicense(licenseInput);
                return aposeLic.getIsLicensed();
            } catch (Exception e) {
                logger.error("set words license error!", e);
            }
        }
        return false;
    }

    /**
     * 设置License
     *
     * @return true表示已成功设置License, false表示失败
     */
    public static boolean setCellsLicense() {
        InputStream licenseInput = getLicenseInput();
        if (licenseInput != null) {
            try {
                com.aspose.cells.License aposeLic = new com.aspose.cells.License();
                aposeLic.setLicense(licenseInput);
                return true;
            } catch (Exception e) {
                logger.error("set cells license error!", e);
            }
        }
        return false;
    }

    /**
     * 设置License
     *
     * @return true表示已成功设置License, false表示失败
     */
    public static boolean setSlidesLicense() {
        InputStream licenseInput = getLicenseInput();
        if (licenseInput != null) {
            try {
                com.aspose.slides.License aposeLic = new com.aspose.slides.License();
                aposeLic.setLicense(licenseInput);
                return aposeLic.isLicensed();
            } catch (Exception e) {
                logger.error("set ppt license error!", e);
            }
        }
        return false;
    }

    /**
     * 设置Aspose PDF的license
     * @return true表示设置成功,false表示设置失败
     */
    public static boolean setPdfLicense() {
        InputStream licenseInput = getLicenseInput();
        if (licenseInput != null) {
            try {
                com.aspose.pdf.License aposeLic = new com.aspose.pdf.License();
                aposeLic.setLicense(licenseInput);
                return true;
            } catch (Exception e) {
                logger.error("set pdf license error!", e);
            }
        }
        return false;
    }
}

doc转pdf示例代码,其中加水印功能可用:

package com.dm.docpreview.convert.service.impl;

import com.aspose.words.*;
import com.aspose.words.Shape;
import com.dm.docpreview.convert.domain.ConvertStatus;
import com.dm.docpreview.convert.service.File2PdfService;
import com.dm.docpreview.convert.util.AsposeLicenseUtil;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import java.awt.*;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * 将doc文档转换为pdf文件
 *
 * @author zxb
 * @version 1.0.0
 *          2016年10月17日 16:12
 * @since Jdk1.6
 */
@Service
public class Doc2PdfServiceImpl implements File2PdfService {

    private Logger logger = Logger.getLogger(getClass());

    @Override
    public ConvertStatus convert2Pdf(InputStream inputStream, OutputStream outputStream) {
        try {
            if (AsposeLicenseUtil.setWordsLicense()) {
                long start = System.currentTimeMillis();

                Document doc = new Document(inputStream);

                // insertWatermarkText(doc, "测试水印"); // 添加水印

                PdfSaveOptions pdfSaveOptions = new PdfSaveOptions();
                pdfSaveOptions.setSaveFormat(SaveFormat.PDF);
                pdfSaveOptions.getOutlineOptions().setHeadingsOutlineLevels(3); // 设置3级doc书签需要保存到pdf的heading中
                pdfSaveOptions.getOutlineOptions().setExpandedOutlineLevels(1); // 设置pdf中默认展开1级

                doc.save(outputStream, pdfSaveOptions);
                long end = System.currentTimeMillis();
                logger.debug("convert doc2pdf completed, elapsed " + (end - start) / 1000.0 + " seconds!");
                return ConvertStatus.SUCCESS;
            } else {
                return ConvertStatus.LICENSE_ERROR;
            }
        } catch (Exception e) {
            logger.error("convert doc2pdf error!", e);
            return ConvertStatus.CONVERT_DOC2PDF_ERROR;
        }
    }


    /**
     * Inserts a watermark into a document.
     *
     * @param doc           The input document.
     * @param watermarkText Text of the watermark.
     */
    private void insertWatermarkText(Document doc, String watermarkText) throws Exception {
        // Create a watermark shape. This will be a WordArt shape.
        // You are free to try other shape types as watermarks.
        Shape watermark = new Shape(doc, ShapeType.TEXT_PLAIN_TEXT);

        // Set up the text of the watermark.
        // watermark.getTextPath().setSize(16.0);
        // watermark.getTextPath().setFontFamily("Arial"); // 使用Arial时最后那个字会丢
        watermark.getTextPath().setFontFamily("宋体");
        watermark.getTextPath().setItalic(true);
        watermark.getTextPath().setText(watermarkText);

        // Font size does not have effect if you specify height of the shape.
        // So you can just specify height instead of specifying font size.
        double fontSize = 100.0;
        watermark.setWidth(watermarkText.length() * fontSize);
        watermark.setHeight(fontSize);

        // Text will be directed from the bottom-left to the top-right corner.
        watermark.setRotation(-30);
        // Remove the following two lines if you need a solid black text.
        watermark.getFill().setColor(Color.lightGray); // Try LightGray to get more Word-style watermark
        watermark.setStrokeColor(Color.lightGray); // Try LightGray to get more Word-style watermark

        // Place the watermark in the page center.
        watermark.setRelativeHorizontalPosition(RelativeHorizontalPosition.PAGE);
        watermark.setRelativeVerticalPosition(RelativeVerticalPosition.PAGE);
        watermark.setWrapType(WrapType.NONE);
        watermark.setVerticalAlignment(VerticalAlignment.CENTER);
        watermark.setHorizontalAlignment(HorizontalAlignment.CENTER);
        // watermark.setHorizontalAlignment(HorizontalAlignment.LEFT);

        // Create a new paragraph and append the watermark to this paragraph.
        Paragraph watermarkPara = new Paragraph(doc);
        watermarkPara.appendChild(watermark);

        // Insert the watermark into all headers of each document section.
        for (Section sect : doc.getSections()) {
            // There could be up to three different headers in each section, since we want
            // the watermark to appear on all pages, insert into all headers.
            insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_PRIMARY);
            insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_FIRST);
            insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_EVEN);
        }
    }

    private void insertWatermarkIntoHeader(Paragraph watermarkPara, Section sect, int headerType) throws Exception {
        HeaderFooter header = sect.getHeadersFooters().getByHeaderFooterType(headerType);

        if (header == null) {
            // There is no header of the specified type in the current section, create it.
            header = new HeaderFooter(sect.getDocument(), headerType);
            sect.getHeadersFooters().add(header);
        }

        // Insert a clone of the watermark into the header.
        header.appendChild(watermarkPara.deepClone(true));
    }
}

其余示例代码,在文章最末尾处将给出下载链接。

pdf.js预览

当文档被转换为PDF文件后,就可以使用pdf.js进行预览了。
在官网下载pre-built版的pdf.js,解压出来。

java文档在线预览实现_第2张图片

由于我们要集成到自己的工程中来,所以此处直接copy了viewer.html页面,修改为了我们工程需要的view_pdfjs.vm

view_pdfjs.vm



<html dir="ltr" mozdisallowselectionprint moznomarginboxes>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <meta name="google" content="notranslate">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>PDF.js viewertitle>
    <link rel="stylesheet" href="#springUrl('')/res/js/pdfjs-dist/web/viewer.css">
    <script src="#springUrl('')/res/js/pdfjs-dist/web/compatibility.js">script>
    
    <link rel="resource" type="application/l10n" href="#springUrl('')/res/js/pdfjs-dist/web/locale/locale.properties">
    <script src="#springUrl('')/res/js/pdfjs-dist/web/l10n.js">script>
    <script src="#springUrl('')/res/js/pdfjs-dist/build/pdf.js">script>
    <script src="#springUrl('')/res/js/pdfjs-dist/web/debugger.js">script>
    <script src="#springUrl('')/res/js/pdfjs-dist/web/viewer.js">script>
    <script type="application/javascript">
        PDFJS.workerSrc = "#springUrl('')/res/js/pdfjs-dist/build/pdf.worker.js";

        /*
        PDFJS.onerror = function(message, moreInfo){
            var queryString = document.location.search.substring(1);
            var params = parseQueryStringRegexImpl(queryString);
            var file = 'file' in params ? params.file : null;

            // redirect to file
            if(file){
                location.href = file;
            }
        }

        function parseQueryStringRegexImpl(query){
            var reg = /([^\?\=\&]+)\=([^\&]*)/g;
            var obj = {};
            while (reg.exec (query)) {
                obj[RegExp.$1] = RegExp.$2;
            }
            return obj;
        }
        */
    script>
head>

<body tabindex="1" class="loadingInProgress">
<div id="outerContainer">

    <div id="sidebarContainer">
        <div id="toolbarSidebar">
            <div class="splitToolbarButton toggled">
                <button id="viewThumbnail" class="toolbarButton group toggled" title="Show Thumbnails" tabindex="2" data-l10n-id="thumbs">
                    <span data-l10n-id="thumbs_label">Thumbnailsspan>
                button>
                <button id="viewOutline" class="toolbarButton group" title="Show Document Outline" tabindex="3" data-l10n-id="outline">
                    <span data-l10n-id="outline_label">Document Outlinespan>
                button>
                <button id="viewAttachments" class="toolbarButton group" title="Show Attachments" tabindex="4" data-l10n-id="attachments">
                    <span data-l10n-id="attachments_label">Attachmentsspan>
                button>
            div>
        div>
        <div id="sidebarContent">
            <div id="thumbnailView">
            div>
            <div id="outlineView" class="hidden">
            div>
            <div id="attachmentsView" class="hidden">
            div>
        div>
    div>  

    <div id="mainContainer">
        <div class="findbar hidden doorHanger hiddenSmallView" id="findbar">
            <label for="findInput" class="toolbarLabel" data-l10n-id="find_label">Find:label>
            <input id="findInput" class="toolbarField" tabindex="91">
            <div class="splitToolbarButton">
                <button class="toolbarButton findPrevious" title="" id="findPrevious" tabindex="92" data-l10n-id="find_previous">
                    <span data-l10n-id="find_previous_label">Previousspan>
                button>
                <div class="splitToolbarButtonSeparator">div>
                <button class="toolbarButton findNext" title="" id="findNext" tabindex="93" data-l10n-id="find_next">
                    <span data-l10n-id="find_next_label">Nextspan>
                button>
            div>
            <input type="checkbox" id="findHighlightAll" class="toolbarField" tabindex="94">
            <label for="findHighlightAll" class="toolbarLabel" data-l10n-id="find_highlight">Highlight alllabel>
            <input type="checkbox" id="findMatchCase" class="toolbarField" tabindex="95">
            <label for="findMatchCase" class="toolbarLabel" data-l10n-id="find_match_case_label">Match caselabel>
            <span id="findResultsCount" class="toolbarLabel hidden">span>
            <span id="findMsg" class="toolbarLabel">span>
        div>  

        <div id="secondaryToolbar" class="secondaryToolbar hidden doorHangerRight">
            <div id="secondaryToolbarButtonContainer">
                <button id="secondaryPresentationMode" class="secondaryToolbarButton presentationMode visibleLargeView" title="Switch to Presentation Mode" tabindex="51" data-l10n-id="presentation_mode">
                    <span data-l10n-id="presentation_mode_label">Presentation Modespan>
                button>

                <button id="secondaryOpenFile" class="secondaryToolbarButton openFile visibleLargeView" title="Open File" tabindex="52" data-l10n-id="open_file">
                    <span data-l10n-id="open_file_label">Openspan>
                button>

                <button id="secondaryPrint" class="secondaryToolbarButton print visibleMediumView" title="Print" tabindex="53" data-l10n-id="print">
                    <span data-l10n-id="print_label">Printspan>
                button>

                <button id="secondaryDownload" class="secondaryToolbarButton download visibleMediumView" title="Download" tabindex="54" data-l10n-id="download">
                    <span data-l10n-id="download_label">Downloadspan>
                button>

                <a href="#" id="secondaryViewBookmark" class="secondaryToolbarButton bookmark visibleSmallView" title="Current view (copy or open in new window)" tabindex="55" data-l10n-id="bookmark">
                    <span data-l10n-id="bookmark_label">Current Viewspan>
                a>

                <div class="horizontalToolbarSeparator visibleLargeView">div>

                <button id="firstPage" class="secondaryToolbarButton firstPage" title="Go to First Page" tabindex="56" data-l10n-id="first_page">
                    <span data-l10n-id="first_page_label">Go to First Pagespan>
                button>
                <button id="lastPage" class="secondaryToolbarButton lastPage" title="Go to Last Page" tabindex="57" data-l10n-id="last_page">
                    <span data-l10n-id="last_page_label">Go to Last Pagespan>
                button>

                <div class="horizontalToolbarSeparator">div>

                <button id="pageRotateCw" class="secondaryToolbarButton rotateCw" title="Rotate Clockwise" tabindex="58" data-l10n-id="page_rotate_cw">
                    <span data-l10n-id="page_rotate_cw_label">Rotate Clockwisespan>
                button>
                <button id="pageRotateCcw" class="secondaryToolbarButton rotateCcw" title="Rotate Counterclockwise" tabindex="59" data-l10n-id="page_rotate_ccw">
                    <span data-l10n-id="page_rotate_ccw_label">Rotate Counterclockwisespan>
                button>

                <div class="horizontalToolbarSeparator">div>

                <button id="toggleHandTool" class="secondaryToolbarButton handTool" title="Enable hand tool" tabindex="60" data-l10n-id="hand_tool_enable">
                    <span data-l10n-id="hand_tool_enable_label">Enable hand toolspan>
                button>

                <div class="horizontalToolbarSeparator">div>

                <button id="documentProperties" class="secondaryToolbarButton documentProperties" title="Document Properties…" tabindex="61" data-l10n-id="document_properties">
                    <span data-l10n-id="document_properties_label">Document Properties…span>
                button>
            div>
        div>  

        <div class="toolbar">
            <div id="toolbarContainer">
                <div id="toolbarViewer">
                    <div id="toolbarViewerLeft">
                        <button id="sidebarToggle" class="toolbarButton" title="Toggle Sidebar" tabindex="11" data-l10n-id="toggle_sidebar">
                            <span data-l10n-id="toggle_sidebar_label">Toggle Sidebarspan>
                        button>
                        <div class="toolbarButtonSpacer">div>
                        <button id="viewFind" class="toolbarButton group hiddenSmallView" title="Find in Document" tabindex="12" data-l10n-id="findbar">
                            <span data-l10n-id="findbar_label">Findspan>
                        button>
                        <div class="splitToolbarButton">
                            <button class="toolbarButton pageUp" title="Previous Page" id="previous" tabindex="13" data-l10n-id="previous">
                                <span data-l10n-id="previous_label">Previousspan>
                            button>
                            <div class="splitToolbarButtonSeparator">div>
                            <button class="toolbarButton pageDown" title="Next Page" id="next" tabindex="14" data-l10n-id="next">
                                <span data-l10n-id="next_label">Nextspan>
                            button>
                        div>
                        <label id="pageNumberLabel" class="toolbarLabel" for="pageNumber" data-l10n-id="page_label">Page: label>
                        <input type="number" id="pageNumber" class="toolbarField pageNumber" value="1" size="4" min="1" tabindex="15">
                        <span id="numPages" class="toolbarLabel">span>
                    div>
                    <div id="toolbarViewerRight">
                        <button id="presentationMode" class="toolbarButton presentationMode hiddenLargeView" title="Switch to Presentation Mode" tabindex="31" data-l10n-id="presentation_mode">
                            <span data-l10n-id="presentation_mode_label">Presentation Modespan>
                        button>

                        <button id="openFile" class="toolbarButton openFile hiddenLargeView" title="Open File" tabindex="32" data-l10n-id="open_file">
                            <span data-l10n-id="open_file_label">Openspan>
                        button>

                        <button id="print" class="toolbarButton print hiddenMediumView" title="Print" tabindex="33" data-l10n-id="print">
                            <span data-l10n-id="print_label">Printspan>
                        button>

                        <button id="download" class="toolbarButton download hiddenMediumView" title="Download" tabindex="34" data-l10n-id="download">
                            <span data-l10n-id="download_label">Downloadspan>
                        button>
                        <a href="#" id="viewBookmark" class="toolbarButton bookmark hiddenSmallView" title="Current view (copy or open in new window)" tabindex="35" data-l10n-id="bookmark">
                            <span data-l10n-id="bookmark_label">Current Viewspan>
                        a>

                        <div class="verticalToolbarSeparator hiddenSmallView">div>

                        <button id="secondaryToolbarToggle" class="toolbarButton" title="Tools" tabindex="36" data-l10n-id="tools">
                            <span data-l10n-id="tools_label">Toolsspan>
                        button>
                    div>
                    <div class="outerCenter">
                        <div class="innerCenter" id="toolbarViewerMiddle">
                            <div class="splitToolbarButton">
                                <button id="zoomOut" class="toolbarButton zoomOut" title="Zoom Out" tabindex="21" data-l10n-id="zoom_out">
                                    <span data-l10n-id="zoom_out_label">Zoom Outspan>
                                button>
                                <div class="splitToolbarButtonSeparator">div>
                                <button id="zoomIn" class="toolbarButton zoomIn" title="Zoom In" tabindex="22" data-l10n-id="zoom_in">
                                    <span data-l10n-id="zoom_in_label">Zoom Inspan>
                                button>
                            div>
                            <span id="scaleSelectContainer" class="dropdownToolbarButton">
                     <select id="scaleSelect" title="Zoom" tabindex="23" data-l10n-id="zoom">
                      <option id="pageAutoOption" title="" value="auto" selected="selected" data-l10n-id="page_scale_auto">Automatic Zoomoption>
                      <option id="pageActualOption" title="" value="page-actual" data-l10n-id="page_scale_actual">Actual Sizeoption>
                      <option id="pageFitOption" title="" value="page-fit" data-l10n-id="page_scale_fit">Fit Pageoption>
                      <option id="pageWidthOption" title="" value="page-width" data-l10n-id="page_scale_width">Full Widthoption>
                      <option id="customScaleOption" title="" value="custom">option>
                      <option title="" value="0.5" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 50 }'>50%option>
                      <option title="" value="0.75" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 75 }'>75%option>
                      <option title="" value="1" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 100 }'>100%option>
                      <option title="" value="1.25" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 125 }'>125%option>
                      <option title="" value="1.5" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 150 }'>150%option>
                      <option title="" value="2" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 200 }'>200%option>
                      <option title="" value="3" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 300 }'>300%option>
                      <option title="" value="4" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 400 }'>400%option>
                    select>
                  span>
                        div>
                    div>
                div>
                <div id="loadingBar">
                    <div class="progress">
                        <div class="glimmer">
                        div>
                    div>
                div>
            div>
        div>

        <menu type="context" id="viewerContextMenu">
            <menuitem id="contextFirstPage" label="First Page"
                      data-l10n-id="first_page">menuitem>
            <menuitem id="contextLastPage" label="Last Page"
                      data-l10n-id="last_page">menuitem>
            <menuitem id="contextPageRotateCw" label="Rotate Clockwise"
                      data-l10n-id="page_rotate_cw">menuitem>
            <menuitem id="contextPageRotateCcw" label="Rotate Counter-Clockwise"
                      data-l10n-id="page_rotate_ccw">menuitem>
        menu>

        <div id="viewerContainer" tabindex="0">
            <div id="viewer" class="pdfViewer">div>
        div>

        <div id="errorWrapper" hidden='true'>
            <div id="errorMessageLeft">
                <span id="errorMessage">span>
                <button id="errorShowMore" data-l10n-id="error_more_info">
                    More Information
                button>
                <button id="errorShowLess" data-l10n-id="error_less_info" hidden='true'>
                    Less Information
                button>
            div>
            <div id="errorMessageRight">
                <button id="errorClose" data-l10n-id="error_close">
                    Close
                button>
            div>
            <div class="clearBoth">div>
            <textarea id="errorMoreInfo" hidden='true' readonly="readonly">textarea>
        div>
    div> 

    <div id="overlayContainer" class="hidden">
        <div id="passwordOverlay" class="container hidden">
            <div class="dialog">
                <div class="row">
                    <p id="passwordText" data-l10n-id="password_label">Enter the password to open this PDF file:p>
                div>
                <div class="row">
                    
                    <input id="password" class="toolbarField">
                div>
                <div class="buttonRow">
                    <button id="passwordCancel" class="overlayButton"><span data-l10n-id="password_cancel">Cancelspan>button>
                    <button id="passwordSubmit" class="overlayButton"><span data-l10n-id="password_ok">OKspan>button>
                div>
            div>
        div>
        <div id="documentPropertiesOverlay" class="container hidden">
            <div class="dialog">
                <div class="row">
                    <span data-l10n-id="document_properties_file_name">File name:span> <p id="fileNameField">-p>
                div>
                <div class="row">
                    <span data-l10n-id="document_properties_file_size">File size:span> <p id="fileSizeField">-p>
                div>
                <div class="separator">div>
                <div class="row">
                    <span data-l10n-id="document_properties_title">Title:span> <p id="titleField">-p>
                div>
                <div class="row">
                    <span data-l10n-id="document_properties_author">Author:span> <p id="authorField">-p>
                div>
                <div class="row">
                    <span data-l10n-id="document_properties_subject">Subject:span> <p id="subjectField">-p>
                div>
                <div class="row">
                    <span data-l10n-id="document_properties_keywords">Keywords:span> <p id="keywordsField">-p>
                div>
                <div class="row">
                    <span data-l10n-id="document_properties_creation_date">Creation Date:span> <p id="creationDateField">-p>
                div>
                <div class="row">
                    <span data-l10n-id="document_properties_modification_date">Modification Date:span> <p id="modificationDateField">-p>
                div>
                <div class="row">
                    <span data-l10n-id="document_properties_creator">Creator:span> <p id="creatorField">-p>
                div>
                <div class="separator">div>
                <div class="row">
                    <span data-l10n-id="document_properties_producer">PDF Producer:span> <p id="producerField">-p>
                div>
                <div class="row">
                    <span data-l10n-id="document_properties_version">PDF Version:span> <p id="versionField">-p>
                div>
                <div class="row">
                    <span data-l10n-id="document_properties_page_count">Page Count:span> <p id="pageCountField">-p>
                div>
                <div class="buttonRow">
                    <button id="documentPropertiesClose" class="overlayButton"><span data-l10n-id="document_properties_close">Closespan>button>
                div>
            div>
        div>
    div>  

div> 
<div id="printContainer">div>
<div id="mozPrintCallback-shim" hidden>
    <style>
        @media print {
            #printContainer div {
                page-break-after: always;
                page-break-inside: avoid;
            }
        }
    style>
    <style scoped>
        #mozPrintCallback-shim {
            position: fixed;
            top: 0;
            left: 0;
            height: 100%;
            width: 100%;
            z-index: 9999999;

            display: block;
            text-align: center;
            background-color: rgba(0, 0, 0, 0.5);
        }
        #mozPrintCallback-shim[hidden] {
            display: none;
        }
        @media print {
            #mozPrintCallback-shim {
                display: none;
            }
        }

        #mozPrintCallback-shim .mozPrintCallback-dialog-box {
            display: inline-block;
            margin: -50px auto 0;
            position: relative;
            top: 45%;
            left: 0;
            min-width: 220px;
            max-width: 400px;

            padding: 9px;

            border: 1px solid hsla(0, 0%, 0%, .5);
            border-radius: 2px;
            box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);

            background-color: #474747;

            color: hsl(0, 0%, 85%);
            font-size: 16px;
            line-height: 20px;
        }
        #mozPrintCallback-shim .progress-row {
            clear: both;
            padding: 1em 0;
        }
        #mozPrintCallback-shim progress {
            width: 100%;
        }
        #mozPrintCallback-shim .relative-progress {
            clear: both;
            float: right;
        }
        #mozPrintCallback-shim .progress-actions {
            clear: both;
        }
    style>
    <div class="mozPrintCallback-dialog-box">
        
        Preparing document for printing...
        <div class="progress-row">
            <progress value="0" max="100">progress>
            <span class="relative-progress">0%span>
        div>
        <div class="progress-actions">
            <input type="button" value="Cancel" class="mozPrintCallback-cancel">
        div>
    div>
div>

body>
html>

其中需要注意的是pdf.worker.js默认是在viewer.js中指定路径的,使用相对路径来指定的。

function configure(PDFJS) {
  PDFJS.imageResourcesPath = './images/';
  //PDFJS.workerSrc = '../build/pdf.worker.js';
  PDFJS.cMapUrl = '../web/cmaps/';
  PDFJS.cMapPacked = true;
}

此处注释了 PDFJS.workerSrc = ‘../build/pdf.worker.js’;

然后在我们的view_pdfjs.vm中手动指定了该js路径为绝对路径:

PDFJS.workerSrc = "#springUrl('')/res/js/pdfjs-dist/build/pdf.worker.js";

预览
pdf.js使用参数file来指定需要预览的文件。例如我们的view_pdfjs.vm对应的controller地址为:http://localhost:8080/docpreview/docpreview/Preview_preview.do?file=abc.pdf

跨域
如果pdf.js预览页面同pdf文件资源在同一个域下,此处可以忽略。

pdf.js使用的异步请求来请求的pdf文件资源,这也就意味着会存在跨域问题。pdf.js中主动检测了file参数对应的地址是否是同一个域中。

我目前采用的方式是封装一个同域下的.do请求,该.do请求会拿到请求资源然后再回写。实现后的地址如下:
http://localhost:8080/docpreview/docpreview/Preview_preview.do?file=http://localhost:8080/docpreview/docpreview/Preview_crossDomainSource.do?filePath=ftp://localhost/test.pdf

crossDomainSource.do代码示例:

    /**
     * 将跨域的资源转换为本地的资源
     *
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    public ModelAndView crossDomainSource(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 如果为本域资源
        String filePath = request.getParameter("filePath");
        if (StringUtil.isNotEmpty(filePath)) {
            try {
                writeResponse(response, filePath);
            } catch (FileNotFoundException e) {
                logger.error("file not found!", e);
                write404(request, response);
            } catch (IOException e) {
                logger.error("get file error!", e);
                write500(request, response);
            }
        } else {
            write404(request, response);
        }
        return null;
    }


    /**
     * 取出filePath对应的数据并写入response中
     *
     * @param response 响应
     * @param filePath 文件路径
     * @throws IOException
     */
    private void writeResponse(HttpServletResponse response, String filePath) throws IOException {
        InputStream inputStream = null;
        URLConnection conn = null;
        try {
            URL url = new URL(filePath);
            conn = url.openConnection();
            conn.setConnectTimeout(30000); // 30s
            conn.setReadTimeout(30000);
            conn.connect();

            inputStream = new DataInputStream(conn.getInputStream());
            copyStream(inputStream, response.getOutputStream());
        } finally {
            if (conn != null) {
                if (conn instanceof HttpURLConnection) {
                    ((HttpURLConnection) conn).disconnect();
                }
            }
        }
    }

注意
上面这种url写法,pdf.js默认的获取参数方法是拿不到后面的filePath的,需要手动改一下pdf.js的获取参数方法。

实现效果
java文档在线预览实现_第3张图片

PDF转换为swf

pdf转swf则需要通过swftools工具来完成。由于swftools为外部命令,在java中需要通过Runtime.getRuntime().exec(commandStr);这种方式来调用。

swftools转换pdf为swf文件命令示例:
pdf2swf.exe test.pdf -o "test.swf" -z -s flashversion=9 -s languagedir="xpdf-chinese-simplified" -s storeallcharacters -f -j 100

其中languagedir需要下载xpdf的简体中文包即可。其它参数请自行查看官方文档。

swftools中的java代码示例:

package com.dm.docpreview.convert.service.impl;

import com.dm.docpreview.convert.domain.ConvertStatus;
import com.dm.docpreview.convert.domain.SwfConfig;
import org.apache.commons.io.IOUtils;
import org.junit.Test;

import java.io.*;

import static junit.framework.Assert.assertTrue;

/**
 * @author zxb
 * @version 1.0.0
 *          2016年10月18日 17:15
 * @since Jdk1.6
 */
public class Pdf2SwfServiceImplTest {

    @Test
    public void pdf2swf() throws Exception {
        // 配置输入pdf及输出的swf
        String inputFilePath = getClass().getClassLoader().getResource("convertFile/test.pdf").getPath();
        File inputFile = new File(inputFilePath);
        File outputFile = new File(inputFile.getParentFile().getParent() + File.separator + "outputFile" + File.separator + "test.swf");

        InputStream inputStream = new FileInputStream(inputFile);
        OutputStream outputStream = new FileOutputStream(outputFile);

        // 配置SwfTools参数
        SwfConfig swfConfig = new SwfConfig();
        swfConfig.setFilePath("C:\\zxbProgramFiles\\workdir\\java\\swftools\\pdf2swf.exe");
        swfConfig.setLanguageDir("C:\\zxbProgramFiles\\workdir\\java\\swftools\\xpdf-chinese-simplified");
        swfConfig.setQuality(100);

        // 转换pdf为swf
        Pdf2SwfServiceImpl pdf2SwfService = new Pdf2SwfServiceImpl();
        pdf2SwfService.setSwfConfig(swfConfig);

        ConvertStatus convertStatus = pdf2SwfService.pdf2swf(inputStream, outputStream);

        // 关闭流
        IOUtils.closeQuietly(outputStream);
        IOUtils.closeQuietly(inputStream);

        assertTrue(convertStatus == ConvertStatus.SUCCESS);
    }
}

flexpaper预览

将下载好的flexpaper安装包解压。

java文档在线预览实现_第4张图片

把其中的js、FlexPaperViewer.swf、css、index.html等拷贝到工程目录中。

java文档在线预览实现_第5张图片

其中index.html已经有一个flexpaper的使用示例了,这里直接将index.html的内容copy到我们的 view_flexpaper.vm文件中。

view_flexpaper.vm文件内容:


<html>
<head>
    <title>FlexPapertitle>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="initial-scale=1,user-scalable=no,maximum-scale=1,width=device-width" />
    <style type="text/css" media="screen">
        html, body  { height:100%; }
        body { margin:0; padding:0; overflow:auto; }
        #flashContent { display:none; }
    style>

    <link rel="stylesheet" type="text/css" href="#springUrl('')/res/js/flexpaper/css/flexpaper.css" />
    <script type="text/javascript" src="#springUrl('')/res/js/flexpaper/jquery.min.js">script>
    <script type="text/javascript" src="#springUrl('')/res/js/flexpaper/flexpaper.js">script>
    <script type="text/javascript" src="#springUrl('')/res/js/flexpaper/flexpaper_handlers.js">script>
head>
<body>
<div style="margin:0px auto;">
    <div id="documentViewer" class="flexpaper_viewer" style="width:1024px;height:600px;margin:0px auto;">div>

    <script type="text/javascript">
        $('#documentViewer').FlexPaperViewer(
                { config : {
                    src : '#springUrl('')/res/js/flexpaper/FlexPaperViewer.swf',
                    SWFFile : '$!{swf_address}',

                    Scale : 0.6,
                    ZoomTransition : 'easeOut',
                    ZoomTime : 0.5,
                    ZoomInterval : 0.2,
                    FitPageOnLoad : true,
                    FitWidthOnLoad : false,
                    FullScreenAsMaxWindow : false,
                    ProgressiveLoading : false,
                    MinZoomSize : 0.2,
                    MaxZoomSize : 5,
                    SearchMatchAll : false,
                    InitViewMode : 'Portrait',
                    RenderingOrder : 'flash',
                    StartAtPage : '',

                    ViewModeToolsVisible : true,
                    ZoomToolsVisible : true,
                    NavToolsVisible : true,
                    CursorToolsVisible : true,
                    SearchToolsVisible : true,
                    WMode : 'window',
                    localeChain: 'zh_CN'
                }}
        );
    script>
div>
body>
html>

其中需要注意的是flexpaper.js中使用的为相对路径来指定 FlexPaperViewer.swf 文件的路径。这里我把它改成绝对路径了。

java文档在线预览实现_第6张图片

java文档在线预览实现_第7张图片

而config下的参数SWFFile则指定你的swf文件路径即可完成播放。

实现效果
java文档在线预览实现_第8张图片

参考链接:
Java+FlexPaper+swfTools仿百度文库文档在线预览系统设计与实现

你可能感兴趣的:(java)