后面两篇对导出做出来改进以及详细操作:
第二篇: java通过模板生成docx(2)
第三篇:java 导出word 利用freemarker指令更改xml 导出word docx文档 (3)
本篇思路:通过模板导出word doc容易,网上资料很多,大概就是将doc后缀改成xml文本打开通过freemarker指令标记${} 通过java代码动态写入。
导出docx用以上方法不行,docx本质为压缩文件,通过解压取出document.xml(和doc用xml打开中间部分一样) ,取出后修改在写入,生成docx 最后通过工具将docx 转成pdf
1.
新建一个docx文档,放在D盘命名test_template.docx
2.用winrar打开
test_template.docx,取出word/document.xml
3.代码:这个类是把内容填充到xml
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.Map;
public class XmlTplUtil {
private static XmlTplUtil tplm = null;
private Configuration cfg = null;
private XmlTplUtil() {
cfg = new Configuration();
try {
// 注册tmlplate的load路径
// 这的路径是xml的路径
cfg.setDirectoryForTemplateLoading(new File("d:/"));
} catch (Exception e) {
}
}
private static Template getTemplate(String name) throws IOException {
if (tplm == null) {
tplm = new XmlTplUtil();
}
return tplm.cfg.getTemplate(name);
}
/**
*
* @param templatefile 模板文件
* @param param 需要填充的内容
* @param out 填充完成输出的文件
* @throws IOException
* @throws TemplateException
*/
public static void process(String templatefile, Map param, Writer out) throws IOException, TemplateException {
// 获取模板
Template template = XmlTplUtil.getTemplate(templatefile);
template.setOutputEncoding("UTF-8");
// 合并数据
template.process(param, out);
if (out != null) {
out.close();
}
}
}
4.xml转成docx
import freemarker.template.TemplateException;
import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
/**
* 其实docx属于zip的一种,这里只需要操作word/document.xml中的数据,其他的数据不用动
*
* @author
*
*/
public class XmlToDocx {
/**
*
* @param xmlTemplate xml的文件名
* @param docxTemplate docx的路径和文件名
* @param xmlTemp 填充完数据的临时xml
* @param toFilePath 目标文件名
* @param map 需要动态传入的数据
* @throws IOException
* @throws TemplateException
*/
public static void toDocx(String xmlTemplate, String docxTemplate,String xmlTemp ,String toFilePath,Map map) {
try {
// 1.map是动态传入的数据
Writer w = new FileWriter(new File(xmlTemp));
// 2.把map中的数据动态由freemarker传给xml
XmlTplUtil.process(xmlTemplate, map, w);
// 3.把填充完成的xml写入到docx中
XmlToDocx xtd = new XmlToDocx();
xtd.outDocx(new File(xmlTemp), docxTemplate, toFilePath);
}catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* @param documentFile 动态生成数据的docunment.xml文件
* @param docxTemplate docx的模板
* @param toFilePath 需要导出的文件路径
* @throws ZipException
* @throws IOException
*/
public void outDocx(File documentFile, String docxTemplate, String toFilePath) throws ZipException, IOException {
try {
File docxFile = new File(docxTemplate);
ZipFile zipFile = new ZipFile(docxFile);
Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();
ZipOutputStream zipout = new ZipOutputStream(new FileOutputStream(toFilePath));
int len = -1;
byte[] buffer = new byte[1024];
while (zipEntrys.hasMoreElements()) {
ZipEntry next = zipEntrys.nextElement();
InputStream is = zipFile.getInputStream(next);
// 把输入流的文件传到输出流中 如果是word/document.xml由我们输入
zipout.putNextEntry(new ZipEntry(next.toString()));
if ("word/document.xml".equals(next.toString())) {
InputStream in = new FileInputStream(documentFile);
while ((len = in.read(buffer)) != -1) {
zipout.write(buffer, 0, len);
}
in.close();
} else {
while ((len = is.read(buffer)) != -1) {
zipout.write(buffer, 0, len);
}
is.close();
}
}
zipout.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
5.将docx 转pdf
import fr.opensagres.xdocreport.utils.StringUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.poi.xwpf.converter.pdf.PdfConverter;
import org.apache.poi.xwpf.converter.pdf.PdfOptions;
import org.apache.poi.xwpf.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by dengxy on 2018/1/4.
*/
public class DocxToPdf {
protected static final Logger logger = LoggerFactory.getLogger(DocxToPdf.class);
/**
*
* @param docxFilepath docx文件
* @param outPdfpath 输出的PDF文件
* @throws Exception
*/
public static void toPdf(String docxFilepath,String outPdfpath) {
try {
InputStream source = new FileInputStream(docxFilepath);
OutputStream target = new FileOutputStream(outPdfpath);
Map<String, String> params = new HashMap<String, String>();
PdfOptions options = PdfOptions.create();
wordConverterToPdf(source, target, options, params);
}catch (Exception e) {
e.printStackTrace();
}
}
/**
* 将word文档, 转换成pdf, 中间替换掉变量
* @param source 源为word文档, 必须为docx文档
* @param target 目标输出
* @param params 需要替换的变量
* @throws Exception
*/
public static void wordConverterToPdf(InputStream source,OutputStream target, Map<String, String> params) throws Exception {
wordConverterToPdf(source, target, null, params);
}
/**
* 将word文档, 转换成pdf, 中间替换掉变量
* @param source 源为word文档, 必须为docx文档
* @param target 目标输出
* @param params 需要替换的变量
* @param options PdfOptions.create().fontEncoding( "windows-1250" ) 或者其他
* @throws Exception
*/
public static void wordConverterToPdf(InputStream source, OutputStream target,PdfOptions options,Map<String, String> params) throws Exception {
XWPFDocument doc = new XWPFDocument(source);
paragraphReplace(doc.getParagraphs(), params);
for (XWPFTable table : doc.getTables()) {
for (XWPFTableRow row : table.getRows()) {
for (XWPFTableCell cell : row.getTableCells()) {
paragraphReplace(cell.getParagraphs(), params);
}
}
}
PdfConverter.getInstance().convert(doc, target, options);
}
/** 替换段落中内容 */
private static void paragraphReplace(List<XWPFParagraph> paragraphs, Map<String, String> params) {
if (MapUtils.isNotEmpty(params)) {
for (XWPFParagraph p : paragraphs){
for (XWPFRun r : p.getRuns()){
String content = r.getText(r.getTextPosition());
logger.info(content);
if(StringUtils.isNotEmpty(content) && params.containsKey(content)) {
r.setText(params.get(content), 0);
}
}
}
}
}
}
6.main方法测试
public static void main(String[] args) throws IOException, TemplateException {
try {
// xml的文件名
String xmlTemplate = "test.xml";
// docx的路径和文件名
String docxTemplate = "d:\\test_template.docx";
// 填充完数据的临时xml
String xmlTemp = "d:\\temp.xml";
// 目标文件名
String toFilePath = "d:\\test.docx";
// 1.map为需要动态传入的数据
//转Docx
XmlToDocx.toDocx(xmlTemplate, docxTemplate, xmlTemp, toFilePath, map);
//pdf文件
String outPdfFilePath = "test.pdf";
//docx 转pdf
DocxToPdf.toPdf(toFilePath,outPdfFilePath);
File file = new File(outPdfFilePath);
//删除docx文件
new File(toFilePath).delete();
//删除临时xml文件
new File(xmlTemp).delete();
return file;//返回pdf文件
} catch (Exception e) {
e.printStackTrace();
}
}
参考链接 ;http://blog.csdn.net/u010588262/article/details/53666644