一、下载或配置:
- 下载jar包 :freemaker的jar包下载
- 下载jar包 :aspose-words的jar包下载
- 或者配置maven依赖:
pom.xml添加aspose的依赖包(maven仓库不提供aspose的依赖包,可以自行下载添加进maven仓库)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>com.aspose</groupId>
<artifactId>aspose-words</artifactId>
<version>15.12.0</version>
</dependency>
二、创建模板文件:(Demo讲解)
1.先新建一个word文档,将 word 中需要填充的数据用占位符${变量名}替换。
- 效果如下:
- 注:图片随便放一张上去,主要是得到图片标签,后面会改。表格里的序号默认这种写法,后面会改成变量自增。
- 复选框符号设置:
2.将word文档另存为xml格式的文件。
- 效果如下:
3.用Notepad++打开xml模板文件,把 pkg:binaryData 标签里的图片base64编码删除,用占位符${变量名}替换。
- 注:建议先用Notepad++的xml格式化插件格式化下标签
- 替换效果
4.处理复选框(00A3:是未选中状态 ,0052:是选中状态
先设置复选框标签,复选框标签显示的是 <w:t>☐</w:t>,将下面标签替换到你复选框显示的位置<w:sym w:font=“Wingdings 2” w:char=“00A3”/>- 以下标签是复选框默认未选中
<w:sym w:font="Wingdings" w:char="00A8"/>
- 处理复选框标签,加上if,else标签处理逻辑,gender是性别变量
- 男
<#if gender=="1">
<w:sym w:font="Wingdings" w:char="00FE"/>
<#else>
<w:sym w:font="Wingdings" w:char="00A8"/>
</#if>
- 女
<#if gender=="2">
<w:sym w:font="Wingdings" w:char="00FE"/>
<#else>
<w:sym w:font="Wingdings" w:char="00A8"/>
</#if>
5.集合数据填充进表格
- 表格标签讲解
- 用list标签包裹第二个tr标签
- 注:第一个tr标签是是固定的标题,数据从第二个tr标签开始循环填充
tr标签里的变量改完${list对象.变量}
${bg.变量}
注:序号变量的写法不同,要改为{list对象_index+1}自增
${bg_index+1}
- 日期格式变量需要转换
${(bg.date)?string('yyyy年MM月dd日')}
6.最后将xml文件后缀改为ftl文件格式保存即可。
三、开始测试:
- 生成word文档,word转pdf,pdf预览、下载工具类
package com.text.util;
import com.aspose.words.Document;
import com.aspose.words.SaveFormat;
import com.hebtx.exception.PDFServerSignException;
import com.hebtx.seal.sign.RemoteSign;
import org.apache.commons.lang3.StringUtils;
import com.supervise.common.config.HxzkConfig;
import freemarker.core.ParseException;
import freemarker.log.Logger;
import freemarker.template.Configuration;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateNotFoundException;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
/**
* Word转PDF工具类
* @author luvJie-7c
* */
public class WordToPdfUtils {
private static Logger log = Logger.getLogger(WordToPdfUtil.class.toString());
/**
* 用freemaker模板生成word文档
* @author luvJie-7c
* @date
* @param dataMap 要填充的数据
* @param templateName 模板名称
* @param fileName 要输出的文件名称
* @param CoType 文件类型
* @return java.lang.String
*/
public static String createWord(Map<String, String> dataMap, String templateName, String fileName, String CoType){
long start = System.currentTimeMillis();
//定义word路径
String wordPath = "";
//定义pdf路径
String pdfPath = "";
try {
//设置FreeMarker的版本和编码格式 版本和jar包版本要一致
Configuration config = new Configuration(Configuration.VERSION_2_3_22);
//设置FreeMarker生成Word文档所需要的模板路径 此次进行类加载 找到资源目录resources目录下template包
config.setClassForTemplateLoading(WordToPdfUtils.class, "/template");
//加载web项目webapp/ftl文件夹下
//config.setDirectoryForTemplateLoading(new File(request.getSession().getServletContext().getRealPath("/ftl")));
//设置模板编码格式
config.setDefaultEncoding("UTF-8");
Template template = null;
try {
//设置FreeMarker生成Word文档所需要的模板
template = config.getTemplate(templateName,"UTF-8");
} catch (TemplateNotFoundException e) {
log.error("模板文件未找到", e);
e.printStackTrace();
} catch (MalformedTemplateNameException e) {
log.error("模板类型不正确", e);
e.printStackTrace();
} catch (ParseException e) {
log.error("解析模板出错,请检查模板格式", e);
e.printStackTrace();
} catch (IOException e) {
log.error("IO读取失败", e);
e.printStackTrace();
}
//创建日期年月日 组文件路径
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");
String dfDate = df.format(new Date());
String dateYear = dfDate.substring(0,4);
String dateMonth = dfDate.substring(5,7);
String dateDay = dfDate.substring(8,10);
//存放路径
wordPath = "存储盘路径" + CoType + "/" + dateYear + "/"+ dateMonth + "/" + dateDay +"/" + fileName + "/";
//将word路径赋值给pdf路径
pdfPath = wordPath;
//创建文件夹
File f = new File(wordPath+fileName+".doc");
//判断文件夹是否存在,不存在,则新建一个文件夹
if (!f.getParentFile().exists()) {
f.getParentFile().mkdirs();
}
//创建一个Word文档输出流
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), "UTF-8"));
try {
template.process(dataMap, out);
} catch (TemplateException e) {
log.error("填充模板时异常", e);
e.printStackTrace();
} catch (IOException e) {
log.error("IO读取时异常", e);
e.printStackTrace();
}
log.info("由模板文件:" + templateName + " 生成文件 :" + fileName + ".doc" + " 成功!!");
out.flush();
out.close();
//word文档转PDF
wordOrPdf(wordPath+fileName+".doc", null);
//pdf路径
pdfPath = pdfPath+fileName+".pdf";
log.info("Pdf文档转换成功!! 生成地址:"+ pdfPath);
long end = System.currentTimeMillis();
log.info("Pdf文档生成耗时:" + ((end - start) / 1000.0) + "秒");
} catch (Exception e) {
e.printStackTrace();
log.info("Word模板生成失败!!");
}
return pdfPath;
}
/**
* 使用aspose.word把word文档转为pdf文档
*
* @param sourceFile word文档绝对路径
* @param destFile pdf文档绝对路径
*/
public static String wordOrPdf(String sourceFile, String destFile) throws Exception {
destFile = StringUtils.isEmpty(destFile) ? sourceFile.replace(".doc", ".pdf") : destFile;
// 验证License 若不验证则转化出的pdf文档会有水印产生
if (!getLicense()) {
throw new Exception("生成PDF文档,验证License失败!");
}
try {
File file = new File(destFile); //新建一个空白pdf文档
FileOutputStream os = new FileOutputStream(file);
Document doc = new Document(sourceFile);//通过sourceFile创建word文档对象
//本地项目不设置此路径 只针对服务器上的字体文件路径
//FontSettings.setFontsFolder("/usr/share/fonts/windowsFont/", true);
doc.save(os, SaveFormat.PDF);
os.close();
} catch (Exception e) {
e.printStackTrace();
throw new Exception("生成PDF文档失败!");
}
return destFile;
}
/**
* @Description: 验证aspose.word组件是否授权:无授权的文件有水印标记
*/
public static boolean getLicense() {
boolean result = false;
try {
String s = "<License><Data><Products><Product>Aspose.Total for Java</Product><Product>Aspose.Words for Java</Product></Products><EditionType>Enterprise</EditionType><SubscriptionExpiry>20991231</SubscriptionExpiry><LicenseExpiry>20991231</LicenseExpiry><SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber></Data><Signature>sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=</Signature></License>";
ByteArrayInputStream inputStream = new ByteArrayInputStream(s.getBytes());
com.aspose.words.License license = new com.aspose.words.License();
license.setLicense(inputStream);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* pdf预览、下载
* @author luvJie-7c
* @date
* @param fileName 文件名
* @param path 文件路径
* @return void
*/
public static String previewPdf(String fileName, String path){
//默认状态'0' 文件不存在 '1'文件存在 '2'文件异常
String exist = "0";
//获取HttpServletResponse (静态自创建)
HttpServletResponse response =((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
// 验证该文件是否是存在
if(new File(path).exists()){
//添加跨域访问
response.setHeader("Access-Control-Allow-Origin", "*");
//以流的形式传输
response.setContentType("application/octet-stream");
// 设置文件流编码格式
response.setCharacterEncoding("UTF-8");
//Content-Disposition属性名 (attachment表示以附件的方式下载;inline表示在页面内打开)
response.setHeader("Content-Disposition", "attachment; fileName="+fileName+".pdf");
try { //输入输出
FileInputStream is = new FileInputStream(path);
ServletOutputStream out = response.getOutputStream();
byte[] buffer = new byte[1024];
int i = 0;
while ((i = is.read(buffer)) != -1) {
out.write(buffer,0,i);
}
//缓存区的数据进行输出
out.flush();
//关闭流
out.close();
is.close();
exist = "1";
log.info("已输出Pdf文档:"+fileName+".pdf");
} catch (IOException e) {
exist = "2";
log.error("IO读取时异常", e);
e.printStackTrace();
}
}
return exist;
}
- 新建测试数据
public class test {
private String calendar;
private Date date;
public String getCalendar() {
return calendar;
}
public void setCalendar(String calendar) {
this.calendar = calendar;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
- 调用工具类:
public static void main(String[] args) {
HashMap hashMap = new HashMap();
//模拟5条测试数据
List list = new ArrayList();
for (int i = 0; i < 5;i++) {
test test = new test();
test.setCalendar("周日");
test.setDate(new Date());
list.add(test);
}
//姓名
hashMap.put("name", "测试");
//存入一个图片的base64编码
hashMap.put("img", "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");
//性别
hashMap.put("gender", "1");
//集合数据
hashMap.put("bgList",list);
try {
//返回pdf路径
String pdfPath = WordToPdfUtils.createWord(hashMap, "测试文档.ftl", "测试文档", "hz");
} catch (Exception e) {
e.printStackTrace();
}
}
- 文档生成地址:
- 最终生成效果:
四、将实体对象数据插入进word模板方式:
将实体对象数据转换为map对象数据,插入进word模板数据(FreeMarker实现方式)