13 Jun 2018
java使用模板生成word,java使用模板生成pdf
spring boot 项目想导出word文档。
使用技术: velocity
# pom.xml
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
- word 另存为xml。
- xml 用word打开,与源文件看着没有区别
- 编辑需要填写的字符。
时间:${date}
最大值:${max}
- 检查编写的需要替换的字符是否正常。使用sublime 打开xml, 如果我们编写的字符可以搜到,则正常。
代码
- VelocityUtil
import java.io.StringWriter;
import java.util.Map;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
/**
* 模板数据
**/
public class VelocityUtil {
public static String evaluateString(String template,
Map<String, Object> data) throws Exception {
VelocityContext context = new VelocityContext();
data.entrySet().forEach(entry -> {
context.put(entry.getKey(), entry.getValue());
});
StringWriter writer = new StringWriter();
Velocity.evaluate(context, writer, "template", template);
return writer.toString();
}
}
- vm.vm
$rankMap.get("cq")
${rankMap.get("cq").get(0)}
${rankMap.get("cq").get(0).getValue()}
- ExportWord
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author: pnunu
* @Date: Created in 10:03 2018/6/7
* @Description: 导出word
*/
public class ExportWord {
private static Logger logger = LoggerFactory.getLogger(ExportWord.class);
//
// public static String export2(Map<String,Object> data) throws Exception {
// File f = new File("E:\\word\\wm.vm");
// String vmContext = FileUtils.readFileToString(f,"UTF-8");
// String re = VelocityUtil.evaluateString(vmContext, data);
// String filePathName = "E:\\word\\vm.txt";
// writeFileTxt(re, filePathName);
// return filePathName;
// }
public static String export(Map<String,Object> data, String filePathName) throws Exception {
String xmlFile = "template/bdz/pre-bdz.xml";
String vmContext = getXmlString(xmlFile);
String re = VelocityUtil.evaluateString(vmContext, data);
writeFileTxt(re, filePathName);
return filePathName;
}
public static String getXmlString(String xmlName) {
logger.info("xmlName==={}",xmlName);
StringBuffer xml = new StringBuffer();
try {
InputStream is = ExportWord.class.getClassLoader().getResourceAsStream(xmlName);
BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
String line = "";
while ((line = br.readLine()) != null) {
xml.append(line);
}
return xml.toString();
} catch (IOException e) {
throw new MyException("无法找到要处理的文件,解析配置文件[" + xmlName + "]出错", e);
}
}
public static void writeFileTxt(String re,String filePathName) throws Exception {
File file = new File(filePathName).getParentFile();
if (!file.exists()) {
file.mkdirs();
}
FileOutputStream outSTr = new FileOutputStream(new File(filePathName));
BufferedOutputStream buff = new BufferedOutputStream(outSTr);
buff.write(re.getBytes("UTF-8"));
buff.flush();
buff.close();
outSTr.close();
logger.info("文件保存成功。保存路径是:" + filePathName);
}
}
以上导出的word文件会存在文件。手机打开会显示源码。。。。。
导出真正的word
使用 freemarker
# pom.xml
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author: pnunu
* @Date: Created in 17:47 2018/6/12
* @Description:
*/
public class DownloadService {
private Configuration configuration = null;
public DownloadService() {
configuration = new Configuration();
configuration.setDefaultEncoding("UTF-8");
}
public static void main(String[] args) {
DownloadService test = new DownloadService();
test.createWord();
}
public void createWord() {
Map<String, Object> dataMap = new HashMap<String, Object>();
getData(dataMap);
configuration.setClassForTemplateLoading(this.getClass(), "/");//模板文件所在路径
Template t = null;
try {
t = configuration.getTemplate("pre-bdz.ftl"); //获取模板文件
} catch (IOException e) {
e.printStackTrace();
}
File outFile = new File("D:/outFile" + Math.random() * 10000 + ".doc"); //导出文件
Writer out = null;
try {
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile)));
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
try {
t.process(dataMap, out); //将填充数据填入模板文件并输出到目标文件
} catch (TemplateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void getData(Map<String, Object> dataMap) {
dataMap.put("title", "标题");
dataMap.put("nian", "2016");
dataMap.put("yue", "3");
dataMap.put("ri", "6");
dataMap.put("shenheren", "lc");
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
for (int i = 0; i < 10; i++) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("xuehao", i);
map.put("neirong", "内容" + i);
list.add(map);
}
dataMap.put("list", list);
}
}
至此一切没有问题。。。。。
客户说,我们想加个水印。。。
客户说,要不导出pdf吧,这样可以保护公司数据安全。。。
一万个不情愿,但依旧老老实实码代码。
解决方案:
-
1、之前的word 转pdf
-
2、放弃之前的word,直接导出pdf
方案1,实在可笑。但是还真有人这么干。
不建议这么做的一个重大原因是不能夸平台。。
使用jacob
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import java.io.File;
/**
* @Author: pnunu
* @Date: Created in 19:26 2018/6/12
* @Description:
*/
public class Word2PdfUtil {
public static void main(String args[]) {
ActiveXComponent app = null;
String wordFile = "C:/Users/nunu/Desktop/word.doc";
String pdfFile = "C:/Users/nunu/Desktop/pdf.pdf";
System.out.println("开始转换...");
// 开始时间
long start = System.currentTimeMillis();
try {
// 打开word
app = new ActiveXComponent("Word.Application");
// 设置word不可见,很多博客下面这里都写了这一句话,其实是没有必要的,因为默认就是不可见的,如果设置可见就是会打开一个word文档,对于转化为pdf明显是没有必要的
//app.setProperty("Visible", false);
// 获得word中所有打开的文档
Dispatch documents = app.getProperty("Documents").toDispatch();
System.out.println("打开文件: " + wordFile);
// 打开文档
Dispatch document = Dispatch.call(documents, "Open", wordFile, false, true).toDispatch();
// 如果文件存在的话,不会覆盖,会直接报错,所以我们需要判断文件是否存在
File target = new File(pdfFile);
if (target.exists()) {
target.delete();
}
System.out.println("另存为: " + pdfFile);
// 另存为,将文档报错为pdf,其中word保存为pdf的格式宏的值是17
Dispatch.call(document, "SaveAs", pdfFile, 17);
// 关闭文档
Dispatch.call(document, "Close", false);
// 结束时间
long end = System.currentTimeMillis();
System.out.println("转换成功,用时:" + (end - start) + "ms");
}catch(Exception e) {
System.out.println("转换失败"+e.getMessage());
e.printStackTrace();
}finally {
// 关闭office
// app.invoke("Quit", 0);
}
}
// public static void main(String[] args) {
// doc2pdf("C:/Users/nunu/Desktop/word.doc", "C:/Users/nunu/Desktop/pdf.pdf");
// }
// 此方式有水印,不建议使用
// public static boolean getLicense() {
// boolean result = false;
// try {
//// InputStream is = Word2PdfUtil.class.getClassLoader().getResourceAsStream("license.xml"); // license.xml应放在..\WebRoot\WEB-INF\classes路径下
//// License aposeLic = new License();
//// aposeLic.setLicense();
// result = true;
// } catch (Exception e) {
// e.printStackTrace();
// }
// return result;
// }
//
// public static void doc2pdf(String inPath, String outPath) {
// if (!getLicense()) { // 验证License 若不验证则转化出的pdf文档会有水印产生
// return;
// }
// try {
// long old = System.currentTimeMillis();
// File file = new File(outPath); // 新建一个空白pdf文档
// FileOutputStream os = new FileOutputStream(file);
// Document doc = new Document(inPath); // Address是将要被转化的word文档
// doc.save(os, SaveFormat.PDF);// 全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF,
// // EPUB, XPS, SWF 相互转换
// long now = System.currentTimeMillis();
// System.out.println("共耗时:" + ((now - old) / 1000.0) + "秒"); // 转化用时
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
}
jacob 导出的结果简直完美。跟手动点击另存为的结果一模一样。但是他依赖于office的基础控件,且不能兼容Linux,部署很麻烦
最终解决方案 — 直接导出pdf
使用技术: itextpdf
# pom.xml
<!-- https://mvnrepository.com/artifact/com.itextpdf/itextpdf -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.10</version>
</dependency>
- 实现方案1
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.*;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @Author: pnunu
* @Date: Created in 23:12 2018/6/12
* @Description: pdf
*/
public class PdfUtil {
// 利用模板生成pdf
public static void fillTemplate() {
// 模板路径
String templatePath = "E:/word/pdf/ceshi.pdf";
// 生成的新文件路径
String newPDFPath = "E:/word/pdf/out.pdf";
PdfReader reader;
FileOutputStream out;
ByteArrayOutputStream bos;
PdfStamper stamper;
try {
out = new FileOutputStream(newPDFPath);// 输出流
reader = new PdfReader(templatePath);// 读取pdf模板
bos = new ByteArrayOutputStream();
stamper = new PdfStamper(reader, bos);
AcroFields form = stamper.getAcroFields();
String[] str = {"123456789", "TOP__ONE", "男", "1991-01-01", "130222111133338888", "河北省保定市"};
int i = 0;
java.util.Iterator<String> it = form.getFields().keySet().iterator();
while (it.hasNext()) {
String name = it.next().toString();
System.out.println(name);
form.setField(name, name + "00");
}
stamper.setFormFlattening(true);// 如果为false那么生成的PDF文件还能编辑,一定要设为true
stamper.close();
Document doc = new Document();
PdfCopy copy = new PdfCopy(doc, out);
doc.open();
PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), 1);
copy.addPage(importPage);
doc.close();
} catch (IOException e) {
System.out.println(1);
} catch (DocumentException e) {
System.out.println(2);
}
}
public static void main(String[] args) {
fillTemplate();
}
}
- 实现2
import com.itextpdf.text.Document;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.*;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.net.URL;
import java.util.Map;
import java.util.Set;
/**
* @Author: pnunu
* @Date: Created in 23:25 2018/6/12
* @Description: pdf 生成
*/
public class PdfUtils {
// 利用模板生成pdf
public static void pdfOut(Map<String, Object> dateMap, String newPDFPath) {
PdfReader reader;
FileOutputStream out;
ByteArrayOutputStream bos;
PdfStamper stamper;
try {
// BaseFont bf = BaseFont.createFont(ttfURL.getPath(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
BaseFont bf = BaseFont.createFont("font/simhei.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
Font FontChinese = new Font(bf, 5, Font.NORMAL);
out = new FileOutputStream(newPDFPath);// 输出流
reader = new PdfReader(PdfUtils.class.getClassLoader().getResourceAsStream("template/bdz/pre-bdz.pdf"));// 读取pdf模板
bos = new ByteArrayOutputStream();
stamper = new PdfStamper(reader, bos);
AcroFields form = stamper.getAcroFields();
//文字类的内容处理
form.addSubstitutionFont(bf);
// for (String key : dateMap.keySet()) {
//// Object value = dateMap.get(key);
// String value = VelocityUtil.evaluateString(key, dateMap);
//
// form.setField(key, value);
// }
Set<String> keySet = form.getFields().keySet();
for (String key : keySet) {
String value = VelocityUtil.evaluateString(key, dateMap);
form.setField(key, value);
}
stamper.setFormFlattening(true);// 如果为false,生成的PDF文件可以编辑,如果为true,生成的PDF文件不可以编辑
stamper.close();
Document doc = new Document();
// Font font = new Font(bf, 32);
PdfCopy copy = new PdfCopy(doc, out);
doc.open();
PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), 1);
copy.addPage(importPage);
doc.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
完美解决问题
【参考文章】 1、 https://blog.csdn.net/top__one/article/details/65442390 2、 https://www.cnblogs.com/wangpeng00700/p/8418594.html
业精于勤,荒于嬉; 行成于思,毁于随。
pnunu
at 22:46