JAVA根据word模板生成合同,并能实现网页在线浏览/打印/下载
最近,
项目有这样一个需求:
根据我选择的模板(docx文件),和我表单填的数据,生成相应的合同文件(docx),该合同要能网页在线浏览/打印/下载在合同中还要放置签字图片和身份证图片
我的实现:
1上传一份合同模板,在用户提交表单数据的时候,把数据写进合同模板,生成完整合同单独保存。这里需要用到docx模板插件能插入图片的那种(身份证读卡器和签字生成的图片要放进合同里)
2再把这份文件后缀是docx的合同文件转换成PDF,再存一份(因为要浏览,刚好多数浏览器支持网页浏览PDF文件和打印下载,不用我自己去实现,想着再转存一份pdf文件,就能实现需求了)。这里需要用到转PDF插件
3等于每个生成的合同都有两份,一份docx源文件,一份PDF格式副本。
4当我页面需要网页在线浏览/打印/下载的时候,就把PDF的副本放上去用另外一个PDF浏览打印插件去实现。这里需要用到PDF浏览打印的js(展示在网页上的是合同的PDF文件,可以浏览/打印/下载)
总共三个插件,本着开源(免费)的态度去找,最终淘汰了一些,我选择了以下三款插件
分别是:
1,poi-tl:docx模板引擎,作用是根据输入的符号把他替换成相应的值
模板:
生成后:
坑点:相关依赖jar多,少个包报错排查半天没查出来,还有就是它依赖poi的版本既不能太高,也不能低,不然报错。我用的是3.17
2,PDFObject:PDF浏览打印的js,只要导入这个js,把pdf文件所在的统一资源定位地址输进去就是,记住!不是绝对路径,是映射过的虚拟路径
3,liberOffice:基于office文件转换PDF文件的插件。
这个有点坑,容我细说:
模板生成工具类涉及的插件我查了后就定了两个(免费的)。分别是liberOffice和OpenOffice,他们各有优劣
liberOffice生成的pdf精准度高,配置相对简单,不需要敲指令,但是生成速度很慢,一个文件需要等待数秒以上,影响用户体验,有时会崩溃,感觉没OpenOffice稳定。
OpenOffice生成的pdf精准度低,可能失真和样式混乱。配置麻烦,每次重启服务器都要敲指令,但是生成速度很快很快,很少用时超过一秒的。
这是二者差别,因为插件都是用来生成合同用的,所以要高精准度,我选择了liberOffice,牺牲了速度(性能)。
下面附上我的工具类
根据LiberOffice生成pdf工具类,入参为文件全路径,执行完生成一份地址和名字一模一样的PDF文件,还需要配一下LiberOffice安装路径
package com.hk.Labor.utils;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import org.apache.commons.io.FileUtils;import org.artofsolving.jodconverter.OfficeDocumentConverter;
import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration;
import org.artofsolving.jodconverter.office.OfficeManager;import java.io.*;import java.text.SimpleDateFormat;
import java.util.Date;import java.util.regex.Pattern;/*** 文件格式转换PDF 可转换的文件类型:各种office文件,图片以及普通txt*/
public class DocConverter {protected static final Logger LOG = LoggerFactory.getLogger(DocConverter.class);private String fileString;private String outputPath = "";// 输入路径 ,如果不设置就输出在默认 的位�?private String fileName;private File pdfFile;private File docFile;public DocConverter(String fileString) {ini(fileString);System.out.println("文件路径"+fileString);}public DocConverter() {// TODO 自动生成的构造函数存根}/*** * 重新设置file* * @param fileString* 32.*/public void setFile(String fileString) {ini(fileString);}/*** * 初始* * @param fileString* */private void ini(String fileString) {this.fileString = fileString;fileName = fileString.substring(0, fileString.lastIndexOf("."));docFile = new File(fileString);pdfFile = new File(fileName+ ".pdf");}/*** 转PDF方法(LibleOffice插件)* * @param file docFile, pdfFile* */public void doc2pdf() throws Exception {String LibreOffice_HOME = getLibreOfficeHome();String fileName = docFile.getName();System.out.println(new SimpleDateFormat("yyyy-MM-dd HH-mm-ss").format(new Date()) + "文件" + docFile.getName());System.out.println(fileName.substring(fileName.lastIndexOf(".")));if (fileName.substring(fileName.lastIndexOf(".")).equalsIgnoreCase(".txt")) {System.out.println("处理txt文件");new DocConverter().TXTHandler(docFile);}DefaultOfficeManagerConfiguration configuration = new DefaultOfficeManagerConfiguration();// libreOffice的安装目录configuration.setOfficeHome(new File(LibreOffice_HOME));// 端口号configuration.setPortNumber(8100);configuration.setTaskExecutionTimeout(1000 * 60 * 25L);
// 设置任务执行超时为10分钟configuration.setTaskQueueTimeout(1000 * 60 * 60 * 24L);
// 设置任务队列超时为24小时OfficeManager officeManager = configuration.buildOfficeManager();officeManager.start();System.out.println(new Date().toString() + "开始转换......");OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager);converter.getFormatRegistry();try {converter.convert(docFile, pdfFile);} catch (Exception e) {e.printStackTrace();System.out.println("转换失败");} finally {officeManager.stop();}System.out.println(new Date().toString() + "转换结束....");}static String loadStream(InputStream in) throws IOException {int ptr = 0;in = new BufferedInputStream(in);StringBuffer buffer = new StringBuffer();while ((ptr = in.read()) != -1) {buffer.append((char) ptr);}return buffer.toString();}/*** 打开libreOffice服务的方法** @return*/public String getLibreOfficeHome() {String osName = System.getProperty("os.name");if (Pattern.matches("Linux.*", osName)) {//获取linux系统下libreoffice主程序的位置//这里需要返回libreOffice安装路径,我的路径写在了自己建的Properties文件里return Utils.getProperties("libre_office_linux");} else if (Pattern.matches("Windows.*", osName)) {//获取windows系统下libreoffice主程序的位置//这里需要返回libreOffice安装路径,我的路径写在了自己建的Properties文件里return Utils.getProperties("libre_office_windows");}return null;}//测试方法
public static void main(String[] args) throws Exception {String printfPDFPath = "E:/Labor/tplfile/党建交接.docx";printfPDFPath = printfPDFPath.replace("/", "\\\\");DocConverter demo = new DocConverter(printfPDFPath);demo.doc2pdf();
}/*** 转换txt文件编码的方法** @param file* @return*/public File TXTHandler(File file) {//或GBKString code = "gb2312";byte[] head = new byte[3];try {InputStream inputStream = new FileInputStream(file);inputStream.read(head);if (head[0] == -1 && head[1] == -2) {code = "UTF-16";} else if (head[0] == -2 && head[1] == -1) {code = "Unicode";} else if (head[0] == -17 && head[1] == -69 && head[2] == -65) {code = "UTF-8";}inputStream.close();System.out.println(code);if (code.equals("UTF-8")) {return file;}String str = FileUtils.readFileToString(file, code);FileUtils.writeStringToFile(file, str, "UTF-8");System.out.println("转码结束");} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return file;}}
根据OpenOffice生成pdf工具类,入参为文件全路径,执行完生成一份地址和名字一模一样的PDF文件,但每次开机都需要启动一条dos指令
package com.hk.Labor.utils;import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import com.artofsolving.jodconverter.DocumentConverter;
import com.artofsolving.jodconverter.openoffice.connection.OpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.connection.SocketOpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.converter.OpenOfficeDocumentConverter;
import com.mysql.jdbc.log.Log4JLogger;/*** OpenOffice转换PDF工具* 想使用它还需要dos端口启用指令:soffice -headless - * accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard该指令需在OpenOffice * 安装目录下的DOS窗口输入启用,且每次重启服务器都用重新启动该指令,OpenOffice这点麻烦*/
public class DocOpenOfficeUtil {protected static final Logger LOG = LoggerFactory.getLogger(DocConverter.class);private String fileString;private String outputPath = "";// 输入路径 ,如果不设置就输出在默认 的位private String fileName;private File pdfFile;private File docFile;public DocOpenOfficeUtil(String fileString) {ini(fileString);}/*** * 閲嶆柊璁剧疆file* * @param fileString* 32.*/public void setFile(String fileString) {ini(fileString);}/*** * 鍒濆锟�? * * @param fileString* */private void ini(String fileString) {this.fileString = fileString;fileName = fileString.substring(0, fileString.lastIndexOf("."));docFile = new File(fileString);pdfFile = new File(fileName+ ".pdf");}/*** 转PDF方法(OpenOffice插件) * * @param file* */public void doc2pdf() throws Exception {if (docFile.exists()) {// if (!pdfFile.exists()) {OpenOfficeConnection connection = new SocketOpenOfficeConnection(8100);try {connection.connect();DocumentConverter converter = new OpenOfficeDocumentConverter(connection);converter.convert(docFile, pdfFile);// close the connectionconnection.disconnect();System.out.println("****pdf转换中? "+ pdfFile.getPath() + "****");} catch (java.net.ConnectException e) {e.printStackTrace();System.out.println("****pdf转换失败****");throw e;} catch (com.artofsolving.jodconverter.openoffice.connection.OpenOfficeException e) {e.printStackTrace();System.out.println("****pdf转换失败****");throw e;} catch (Exception e) {e.printStackTrace();throw e;}//} else {// System.out.println("****宸茬粡杞崲涓簆df锛屼笉锟�?瑕佸啀杩涜杞寲 ****");//}} else {System.out.println("*****pdf转换失败,文件不存在****");}}static String loadStream(InputStream in) throws IOException {int ptr = 0;in = new BufferedInputStream(in);StringBuffer buffer = new StringBuffer();while ((ptr = in.read()) != -1) {buffer.append((char) ptr);}return buffer.toString();}}
使用方法:
//liberOfficeDocConverter demo = new DocConverter(文件路径);demo.doc2pdf(); //OpenOfficeDocOpenOfficeUtil demo2 = new DocOpenOfficeUtil(文件路径);demo2.doc2pdf();
docx模板工具方法:
/*** 替换模板字段生成新的合同docx,方法内有详细注解说明* @param InputPath 模板的地址(绝对路径)例:"E:/Labor/tplfile/20181204101817265_146.docx"* @param OutputPath 输出生成的docx文档的路径(绝对路径)例:"E:/Labor/tplfile/20181204101817265_146.docx"* @param replaceMap 要替换的所有字段或图片的Map* @return boolean 成功true,失败false 成功后,会同时生成pdf,docx格式的两份文件,路径跟docx文档的路径一样,名字也一样,只是后缀名不同。* @throws IOException*/public boolean templateChangeAndGenerate(String InputPath,String OutputPath,Map<String, Object> replaceMap) {try {//一行代码XWPFTemplate template = XWPFTemplate.compile(InputPath).render(replaceMap);//输出目录FileOutputStream out;out = new FileOutputStream(OutputPath);template.write(out);out.flush();out.close();OutputPath = OutputPath.replace("/", "\\\\");//DocConverter demo = new DocConverter(OutputPath);//demo.doc2pdf();template.close();} catch (Exception e) {// TODO 自动生成的 catch 块e.printStackTrace();return false;}return true;}
主代码涉及保密协议,我不发了。这个方案是实现了这个需求,我之前是只要用户点生成合同,就同时执行转换PDF方法。但是因为用LiberOffice的转化PDF速度太慢,而合同又是先生成并同时转换PDF,导致生成一个合同就要等半天,批量生成简直噩梦,严重影响用户体验,所以我把转换PDF方法放在了用户点击浏览后才触发生成PDF副本用来页面展示,而生成合同时,仅仅生成一份docx合同原件,不调用转换方法。然后用户体验好多了。
还有就是占存储空间,每份合同附带了分PDF副本。
坑1:如果用户上传的word模板中的字体你电脑中的字体库里没有,那么生成的PDF样式也会混乱,但只要电脑里安装了字体包就没事了
坑2:Liberoffice和OpenOffice是同源产品,如果想使用OpenOffice就必须把Liberoffice卸载干净,相反使用Liberoffice也是一样。
JAVA根据word模板生成合同,并能实现网页在线浏览/打印/下载相关推荐
- JAVA实现模板word文档导入,Java依据word模板生成word文档之后台解析和实现及部分代码(一)...
Java根据word模板生成word文档之后台解析和实现及部分代码(一) 后台主要工作是解析XML定义的标签文件,并获取到数据集,放入到Map中,然后调用Jacob.jar中提供的相关方法来实现替换. ...
- java根据word模板生成pdf
java根据word模板动态赋值某些字段,然后生成pdf,参考文档:http://deepoove.com/poi-tl/#_why_poi_tl
- java 根据word模板生成word文件
Java可以使用Apache POI库来生成Word文件,并且也可以使用freemarker等模板引擎来实现根据Word模板生成Word文件的功能. 下面是一个简单的示例代码,可以帮助您快速入门. 模 ...
- JAVA Freemarker + Word 模板 生成 Word 文档 (变量替换,数据的循环,表格数据的循环,以及图片的东替换)...
1,最近有个需求,动态生成 Word 文当并供前端下载,网上找了一下,发现基本都是用 word 生成 xml 然后用模板替换变量的方式 1.1,这种方式虽然可行,但是生成的 xml 是在是太乱了,整理 ...
- Java根据word模板生成word文档并转成PDF文件
1. 处理word模板 1.1 定义word模版 1.2 定义完我们的模板之后,我们要将文档保存为xml的格式 定义完我们的模板之后,我们要将文档保存为xml的格式 1.3 xml格式化 生成的xml ...
- java 使用word模板生成word
一:导入jar 可能用不到这么多 <dependency> <groupId>org.apache.poi</groupId> <artifactId> ...
- Java 使用word模板创建word文档报告教程
上面是java 利用word模板生成的一个word报告文档,利用的是第三方类库Poi-tl 是实现的. poi-tl是一个基于Apache POI的Word模板引擎,也是一个免费开源的Java类库,你 ...
- python制作合同模板带图片_办公自动化7_用Python操作Word批量生成合同
########## 实例7:用Python操作Word批量生成合同 ################ ''' 来源网上整理 ,供学习使用. 我们建立的模板和合同信息如下图所示:这里有几个注意事项: ...
- apache poi使用例_使用java Apache poi 根据word模板生成word报表例子
[实例简介] 使用java Apache poi 根据word模板生成word报表 仅支持docx格式的word文件,大概是word2010及以后版本,doc格式不支持. 使用说明:https://b ...
最新文章
- mysql表连接算法_如何在MySQL中连接多个表
- ASP.NET Core 2.0 : 三. 项目结构
- python处理流程-python的处理流程
- php jsonp实例 mip无限滚动组件接口注意事项
- Oozie和Azkaban的技术选型和对比
- C#语言实现定时开启或禁用网卡小程序
- 程序员必备的 10 大 GitHub 仓库
- 关于JSON的简介及取值以及常见面试题
- Mobile孵化周即将在加州召开!
- ECMAScript 6网页样式修正器
- 逻辑运算符,位运算符
- Java SecurityManager checkMemberAccess()方法与示例
- 程序员面试金典——18.13 最大字母矩阵
- 由ContactsProvider的升级引发的OTA首次开机卡白米问题分析
- Excel插入斜线表头
- Android使用FFmpeg 解码H264并播放(一)
- 实验二 使用UML进行对ATM系统建模
- 五、网络整理BAT脚本——字符串常规操作
- 聚合支付与智能POS
- 第9周--项目1-Complex类