最近,

项目有这样一个需求:

      根据我选择的模板(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模板生成合同,并能实现网页在线浏览/打印/下载相关推荐

  1. JAVA实现模板word文档导入,Java依据word模板生成word文档之后台解析和实现及部分代码(一)...

    Java根据word模板生成word文档之后台解析和实现及部分代码(一) 后台主要工作是解析XML定义的标签文件,并获取到数据集,放入到Map中,然后调用Jacob.jar中提供的相关方法来实现替换. ...

  2. java根据word模板生成pdf

    java根据word模板动态赋值某些字段,然后生成pdf,参考文档:http://deepoove.com/poi-tl/#_why_poi_tl

  3. java 根据word模板生成word文件

    Java可以使用Apache POI库来生成Word文件,并且也可以使用freemarker等模板引擎来实现根据Word模板生成Word文件的功能. 下面是一个简单的示例代码,可以帮助您快速入门. 模 ...

  4. JAVA Freemarker + Word 模板 生成 Word 文档 (变量替换,数据的循环,表格数据的循环,以及图片的东替换)...

    1,最近有个需求,动态生成 Word 文当并供前端下载,网上找了一下,发现基本都是用 word 生成 xml 然后用模板替换变量的方式 1.1,这种方式虽然可行,但是生成的 xml 是在是太乱了,整理 ...

  5. Java根据word模板生成word文档并转成PDF文件

    1. 处理word模板 1.1 定义word模版 1.2 定义完我们的模板之后,我们要将文档保存为xml的格式 定义完我们的模板之后,我们要将文档保存为xml的格式 1.3 xml格式化 生成的xml ...

  6. java 使用word模板生成word

    一:导入jar 可能用不到这么多 <dependency> <groupId>org.apache.poi</groupId> <artifactId> ...

  7. Java 使用word模板创建word文档报告教程

    上面是java 利用word模板生成的一个word报告文档,利用的是第三方类库Poi-tl 是实现的. poi-tl是一个基于Apache POI的Word模板引擎,也是一个免费开源的Java类库,你 ...

  8. python制作合同模板带图片_办公自动化7_用Python操作Word批量生成合同

    ########## 实例7:用Python操作Word批量生成合同 ################ ''' 来源网上整理 ,供学习使用. 我们建立的模板和合同信息如下图所示:这里有几个注意事项: ...

  9. apache poi使用例_使用java Apache poi 根据word模板生成word报表例子

    [实例简介] 使用java Apache poi 根据word模板生成word报表 仅支持docx格式的word文件,大概是word2010及以后版本,doc格式不支持. 使用说明:https://b ...

最新文章

  1. mysql表连接算法_如何在MySQL中连接多个表
  2. ASP.NET Core 2.0 : 三. 项目结构
  3. python处理流程-python的处理流程
  4. php jsonp实例 mip无限滚动组件接口注意事项
  5. Oozie和Azkaban的技术选型和对比
  6. C#语言实现定时开启或禁用网卡小程序
  7. 程序员必备的 10 大 GitHub 仓库
  8. 关于JSON的简介及取值以及常见面试题
  9. Mobile孵化周即将在加州召开!
  10. ECMAScript 6网页样式修正器
  11. 逻辑运算符,位运算符
  12. Java SecurityManager checkMemberAccess()方法与示例
  13. 程序员面试金典——18.13 最大字母矩阵
  14. 由ContactsProvider的升级引发的OTA首次开机卡白米问题分析
  15. Excel插入斜线表头
  16. Android使用FFmpeg 解码H264并播放(一)
  17. 实验二 使用UML进行对ATM系统建模
  18. 五、网络整理BAT脚本——字符串常规操作
  19. 聚合支付与智能POS
  20. 第9周--项目1-Complex类

热门文章

  1. 魔兽世界私服架设教程—GM命令大全
  2. 微信小程序 radio选中样式改为实心圆<转载>
  3. 循环彩灯编程c语言环境,如何用汇编语言写一个循环彩灯的程序,采用定时器方式1工作...
  4. selenium 操作日期控件
  5. Springboot 项目导出word文档(文档内容包括数据以及服务器图片)
  6. web.xml文件的作用?
  7. Vue实现歌词解析+滚动效果
  8. AE基础教程(22)——第22章 旋转动画初体验
  9. 人工智能数学基础专栏目录
  10. C语言文件读写操作详解