后面两篇对导出做出来改进以及详细操作:
第二篇: 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