后台生成单个Word文档
在实际项目开发中经常会遇到一种场景,客户希望点击页面上的生成文件按钮,执行程序动态填充数据到Word模板,直接在后台生成Word文档,而无需显示Word文档。目前网上有一些针对此需求的方案,但每个方案都存在很多各自的问题。
与其他方案对比
采用 Jacob 生成Word文档方案动态生成的Word文档,与PageOffice一样,文档格式是最完美的,因为都是调用的Office原生接口生成的文件,所以生成的是原汁原味的Word文档,但是Jacob局限于 windows 平台,往往许多 Java 程序运行于 Linux 等其他操作系统,而且Jacob的代码复杂、运行稳定性差且不安全,因为调用Office的自动化接口需要服务器端安装Office软件,服务器自动化调用有很大的风险,容易导致Office进程死锁、页面无响应、阻塞Web服务进程,从而影响整个网站的吞吐量,如果再考虑到多个用户同时并发操作生成Word文档的情况,Jacob程序对服务器端造成的压力足以卡死整个网站,并且Web Server需配置交互账户权限。针对这个问题,微软在MSDN上公开声明Word、Excel不适宜运行在服务进程里,因为Word、Excel仅被设计为桌面运行的程序。而PageOffice在客户端运行,100%的标准托管代码,服务器端不用安装Office,也不用引入自动化类型库,所以运行安全稳定,不必担心Web服务崩溃的风险。另外服务器自动化调用的API接口复杂难用,参数传递繁琐;而PageOffice提供了简化的对象调用模型,所以调用代码简单,开发效率高,运行稳定可靠。服务器自动化编程对于定位Word、Excel要填充内容的位置和定位要读取内容的位置比较困难,而PageOffice的简易对象模型可以轻松定位,精确填充和读取文档内容。所以Jacob已经是一个十几年前就淘汰的技术,仅限于个人研究,无法应用于实际项目。
再就是使用OpenXML SDK、POI、iText等开源库的方案。OpenXML SDK是Microsoft提供的一组库和工具,用于创建、修改和提取Office Open XML格式的文件,但是操作OpenXML SDK需要对Open XML文档结构有一定的了解,因此在处理Word文档时可能需要编写大量的代码,使用OpenXML SDK还需要学习Open XML标记语言和SDK的API,这可能需要一些时间和精力来掌握,并且由于 OpenXML SDK 是用 C# 编写的,因此在 Java 中直接调用 OpenXML SDK 是很困难的。而使用 POI 生成文档对服务器的压力很大,而且它的 Excel 处理勉强可以, Word 模块还局限于读取 Word 的文本内容,写 Word 文件的功能就更弱;另一个致命的问题是,处理 doc 格式和处理 docx 格式的类几乎完全不同,要分开针对不同的格式写不同的代码,这就意味着用户上传的 docx 格式文件如果使用了 doc 的扩展名,程序马上崩溃。目前已知POI用来解析.doc、.xls那部分的组件是残缺不全的并且也已经不再更新了。而且 POI 结构混乱,编码比较复杂,开发过程非常消耗时间和精力。从性能上看,POI使用的xml处理对象本身就消耗内存,它要把整个文档都加载到内存,加上其他开销,比实际Word、Excel文档还大,遇到打开较大的Word、Excel文档时,JVM很容易内存溢出。而iText是一个用于处理PDF文件的Java库,它是可以操作Word文档,但是iText主要是用来处理PDF文档的,不支持Excel,且对于Word支持很有限,iText 生成的 Word 文件在不同版本的 Word 软件中可能会出现排版或样式兼容性的问题。iText 也需要较大的学习曲线,特别是对于没有使用过该库的开发人员来说。总的来说,使用开源库方案存在调用代码复杂、中文乱码,功能较弱等许多问题,最大的问题还是在生成文件的格式、样式、排版等方面存在很大问题,由于这些方案不是直接调用原生Office接口操作文件内容的,所以即使已经有一个模板文档做基础了,但是生成的文档中字体、样式、段落等还是会出现错乱的情况,尤其是处理页眉页脚、表格等内容时,出现的排版格式问题会更大。
所以针对这一系列的问题,PageOffice 开发了 FileMaker 组件,该组件完全符合 PageOffice 的架构设计,提供了最简单的对象模型,没有任何学习成本。FileMaker 在客户端后台填充数据到Office模板生成文档并自动上传到服务器,不会打开显示生成的文档。由于FileMaker是调用Office原生接口操作文档内容的,所以生成的是原汁原味的Office文档格式,而且由于FileMaker调用的是客户端电脑上的Office,所以服务器上无需安装Office软件,也不要求服务器必须是Windows平台,生成文档的工作不会对服务器端造成任何压力,更不存在并发问题,实现了完美生成文档的目的,且避免了上述的所有问题。
FileMakerCtrl 和 PageOfficeCtrl 的区别
FileMakerCtrl 本质上就是一个没有界面的 PageOfficeCtrl,也是调用客户端 Office 程序处理文件的,FileMakerCtrl和PageOfficeCtrl都可以实现对文档进行动态填充、动态转 PDF 等功能,唯一的区别就是 FileMakerCtrl 在线打开填充和转换文档的时候,Web页面不会打开显示文档内容,而 PageOfficeCtrl 会弹出窗口打开显示文档内容。
PageOffice的解决方案
下面就以生成一份荣誉证书的效果为例,介绍一下如何使用FileMaker组件动态生成Word文档。
需求效果:用户点击生成word文件按钮,执行程序把某公司信息动态填充到荣誉证书模板中,生成一份荣誉证书文件。
荣誉证书模板如下图所示,为了简单起见,模板中只使用了公司名称来代表公司的所有信息,所以只用了一个数据区域“PO_company”来标记公司名称的位置。

点击按钮后,执行把公司信息动态填充到Word模板中生成荣誉证书的后台代码(比如:FileMakerSingle.jsp),在服务器端文件夹下生成一份荣誉证书文件:maker.doc,文件内容如下图所示。

后端代码
- 在后端编写代码实现文档动态填充(比如FileMakerSingle.jsp),关键代码如下:
// 获取id后可以根据id从数据库中查询公司信息,为简单起见,就不再演示
String id = request.getParameter("id");
FileMakerCtrl fmCtrl = new FileMakerCtrl(request);
WordDocument doc = new WordDocument();
//给数据区域赋值,即把数据填充到模板中相应的位置
doc.openDataRegion("PO_company").setValue("北京卓正志远软件有限公司");
fmCtrl.setSaveFilePage("SaveMaker.jsp");
fmCtrl.setWriter(doc);
fmCtrl.fillDocument("doc/template.doc", DocumentOpenType.Word);
- 保存文件:在SaveFilePage指向的地址接口中,创建FileSaver对象保存文件。
FileSaver fs = new FileSaver(request, response);
String fileName = "maker" + fs.getFileExtName();
fs.saveToFile(request.getSession().getServletContext().getRealPath("FileMakerSingle/doc") + "/" + fileName);
fs.close();
前端代码
编写前端网页代码,调用执行后端生成文件代码,并实现生成文件进度条的效果。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title></title>
<script type="text/javascript" src="../pageoffice.js"></script>
<script type="text/javascript">
function ConvertFile() {
document.getElementById("Button1").disabled = true;
CallFileMaker({
url: "FileMakerSingle.jsp?id=1", //FileMakerSingle.jsp实现动态生成文件
success: function () {
setProgress(100);
},
progress: function (pos) {
setProgress(pos);
},
error: function (msg) {
console.log("error occurred: "+msg);
}
});
}
function setProgress(percent) {
var progressBar = document.getElementById("progressBar");
progressBar.style.width = percent + '%';
progressBar.innerText = percent + '%';
}
</script>
<style>
#progressBarContainer {
width: 500px;
background-color: #e0e0e0;
border-radius: 5px;
padding: 3px;
margin: 10px auto;
}
#progressBar {
height: 20px;
width: 0%;
background-color: #76b900;
border-radius: 5px;
text-align: center;
line-height: 20px; /* 使文字垂直居中 */
color: white;
}
</style>
</head>
<body>
<div style="text-align: center;">
<input id="Button1" type="button" value="生成Word文件" onclick="ConvertFile()"/>
<div id="progressBarContainer">
<div id="progressBar"></div>
</div>
</div>
</body>
</html>
参考链接:后台生成单个Word文档
后台生成单个Word文档的更多相关文章
- Android开发——使用Jword生成本地word文档
本文主要介绍如何使用Jword生成本地word文档,这里涉及到Jword的使用技巧,本文给出相应的代码,需要的朋友可以参考下. 为什么使用Jword呢?因为IText .Freemark在安卓平台上压 ...
- java生成复杂word文档
在Web应用中,有时需要按照固定的模板将数据导出到Word,如流程审批单,在流程处理完成后将处理过程按照流程单的要求导出,有时程序中需要实现生成 标准Word文档,要求能够打印,并且保持页面样式不变, ...
- 调用Microsoft.Office.Interop.Word生成自定义Word文档
具体思路: 1.先制作Word模版,使用文本框+书签的方式来设计模版: 2.模版制作完之后,根据模版生成新文件,使用File.Copy方法,生成.doc格式新文件: 3.后台取得数据,参照网页渲染的方 ...
- NPOI插件生成导出word文档
因为之前没有接触NPOI过这个插件,所以几乎都是自己一边百度摸索一边学习. 这个插件对于Excel的数据导入和导出,可以说是很方便了, 但是对于导出word文档,可以说是很少的,百度了很多....也不 ...
- 向Docx4j生成的word文档添加图片和布局--第一部分
原文标题:Adding images and layout to your Docx4j-generated word documents, part 1 原文链接:http://blog.iprof ...
- 前端调用后台接口下载word文档的两种方法
1传统的ajax虽然能提交到后台,但是返回的数据被解析成json,html,text等字符串,无法响应浏览器下载.就算使用bob模拟下载,数据量大时也不方便 废话不多说:上代码(此处是Layui监听提 ...
- 向Docx4j生成的word文档中添加布局--第二部分
原文标题:Adding layout to your Docx4j-generated word documents, part 2 原文链接:http://blog.iprofs.nl/2012/1 ...
- [转载]Java动态生成word文档(图文并茂)
很多情况下,软件开发者需要从数据库读取数据,然后将数据动态填充到手工预先准备好的Word模板文档里,这对于大批量生成拥有相同格式排版的正式文件非常有用,这个功能应用PageOffice的基本动态填充功 ...
- [原创]Java动态生成word文档(图文并茂)
很多情况下,软件开发者需要从数据库读取数据,然后将数据动态填充到手工预先准备好的Word模板文档里,这对于大批量生成拥有相同格式排版的正式文件非常有用,这个功能应用PageOffice的基本动态填充功 ...
- JAVAWEB使用FreeMarker利用ftl把含有图片的word模板生成word文档,然后打包成压缩包进行下载
这是写的另一个导出word方法:https://www.cnblogs.com/pxblog/p/13072711.html 引入jar包,freemarker.jar.apache-ant-zip- ...
随机推荐
- Python 数组和列表:创建、访问、添加和删除数组元素
Python 没有内置支持数组,但可以使用 Python 列表来代替. 数组 本页将向您展示如何使用列表作为数组,但要在 Python 中使用数组,您需要导入一个库,比如 NumPy 库.数组用于在一 ...
- 当JDBC遇上返回Cursor
当 JDBC 遇上返回 Cursor 本文出处:https://www.modb.pro/db/400426 使用 jdbc 访问 PostgreSQL 或者 MogDB(openGauss)数据库里 ...
- 开发指导—利用组件&插值器动画实现HarmonyOS动效
一. 组件动画 在组件上创建和运行动画的快捷方式.具体用法请参考通用方法. 获取动画对象 通过调用animate方法获得animation对象,animation对象支持动画属性.动画方法和动画事件. ...
- 【直播回顾】Hello HarmonyOS进阶课程第四课——ArkUI动画开发
5 月 25 日晚上 19 点,由知名HarmonyOS开发领域的up主九弓子主讲的Hello HarmonyOS进阶系列应用篇第四课<ArkUI动画开发>,在众多HarmonyOS社群内 ...
- BTC的数据结构
区块链是一个个block所构成的链,或者链表状的数据结构,在比特币中或者区块链中,一个重要的组成部分是哈希指针 指针 在程序运行过程中,需要用到数据.最简单的是直接获取数据,但当数据本身较大,需要占用 ...
- xml转voc,voc转coco,coco转yolo,coco划分,coco检查,yolo检查,coco可视化
平常用coco格式的数据集比较多,所有这里整合一下数据集相关的常用的脚本. pycocotools安装 这个非常重要,因为处理coco数据集时,用pycocotools包非常方便. 自行搜索一下怎么安 ...
- javascript现代编程之四——数值的进制和表示方法
在JavaScript中,数值可以以不同的进制表示: 十进制:这是我们最常用的进制系统.例如:let decimal = 123; 二进制:数值前面加上 0b 或者 0B.例如:let binary ...
- 力扣125(java)-验证回文串(简单)
题目: 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写. 说明:本题中,我们将空字符串定义为有效的回文串. 示例 1: 输入: "A man, a plan ...
- NICA 校际交流赛#2 游记
\(1\!:\!15\) 到达考场,检测好网络和电脑. 分配任务,sxshm 打前 \(5\) 题,tcy01_QAQ_ 打 \(6,\!7\) 两题,我打后面的题. \(1\!:\!30\) 显得无 ...
- mPaas 研发流程和线上运维介绍
简介: mPaas 研发流程和线上运维介绍 一. 背景 金融级移动开发平台 mPaaS[1](Mobile PaaS)为 App 开发.测试.运营及运维提供云到端的一站式解决方案,能有效降低技术门槛. ...