近期因需要完成对word、excel、ppt、txt等文档的内容检索,在用户检索到相关内容时,需要给用户提供一个在线预览文档的功能。在网上找到部分参考后,实现了该功能。
要实现这些文档的预览,需要先将文档转换为PDF再进行预览。
转换步骤:
* 使用OpenOffice/Aspose 将ppt、word、excel、txt类型的文件转换为pdf
预览步骤:
* 高版本浏览器上,使用pdf.js直接预览PDF文件
* 低版本浏览器上,使用swftools将PDF文件转换为swf文件,再使用flexpaper预览swf
由于OpenOffice的转换效果并不太佳,这里选择了Aspose
在Aspose官网下载Aspose的java版本,主要选择
* Aspose.words
* Aspose.cells(Excel)
* Aspose.slides(PPT)
* Aspose.pdf
下载完成后,在工程中引用jar包即可。
swftools主要用于将PDF文件转换为swf文件以便使用flexpaper进行播放。
在swftools下载页面 选择对应的版本下载即可。如windows下载exe后缀的文件,linux下载tar.gz后缀的文件。
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 |
使用Aspose进行文档转换很简单,直接引入相应的jar包,调用save方法,转换为PDF即可。
注意:
1. 使用Aspose时,每一个模块(words,cells)都可能有相同的类,如License类,SaveOptions类,SaveFormat类。而在各自模块使用时,一定要用对应模块的类
,这个坑我已爬过。
- 使用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文件后,就可以使用pdf.js进行预览了。
在官网下载pre-built版的pdf.js,解压出来。
由于我们要集成到自己的工程中来,所以此处直接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的获取参数方法。
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安装包解压。
把其中的js、FlexPaperViewer.swf、css、index.html
等拷贝到工程目录中。
其中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 文件的路径。这里我把它改成绝对路径了。
而config下的参数SWFFile则指定你的swf文件路径即可完成播放。
参考链接:
Java+FlexPaper+swfTools仿百度文库文档在线预览系统设计与实现