FreeMarker生成带图片的word文档(浏览器输出)

所需依赖

<!--生成word文档所需-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>

<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>

制作模板的步骤参见上篇博客,有一点需要注意的是document.xml中图片路径保存成本地路径格式以支持各种图片格式写入至文档。

 这里的路径搞了好长时间,简单记录一下:

 这里的文件名要使用这种格式才能在xml文件中保存为全路径名称,不知道是不是我wps的问题,最后是使用了这种方法完成的。

下面记录一下使用的主要代码:

FreeMarker工具类:
public class FreeMarkerUtil {


    public static Configuration getConfiguration() throws IOException{
        //创建配置实例
        Configuration configuration = new Configuration(Configuration.VERSION_2_3_28);
        //设置编码
        configuration.setDefaultEncoding("utf-8");
        //设置模板加载文件夹(模板路径)
        String pathName = ConstantFactory.me().getFilePath()+"templates"+File.separator;
        configuration.setDirectoryForTemplateLoading(new File(pathName));
        return configuration;
    }


    /**
     * 获取模板字符串
     * @param dataMap   参数
     * @param templateName  模板名称
     * @return
     */
    public static String getFreemarkerContent(Map dataMap, String templateName) {
        String result = "";
        try {
            Configuration configuration = getConfiguration();
            //获取模板
            Template template = configuration.getTemplate(templateName,"utf-8");

            StringWriter swriter = new StringWriter();
            //生成文件
            template.process(dataMap, swriter);
            result = swriter.toString();


        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 获取模板字符串输入流
     * @param dataMap   参数
     * @param templateName  模板名称
     * @return
     */
    public static ByteArrayInputStream getFreemarkerContentInputStream(Map dataMap, String templateName) {
        ByteArrayInputStream in = null;

        try {
            Configuration configuration = getConfiguration();
            //获取模板
            Template template = configuration.getTemplate(templateName,"utf-8");

            StringWriter swriter = new StringWriter();
            //生成文件
            template.process(dataMap, swriter);
            in = new ByteArrayInputStream(swriter.toString().getBytes("utf-8"));

        } catch (Exception e) {
            e.printStackTrace();
        }
        return in;
    }

}

word工具类:

生成本地文件时更改outputStream 输出流形式即可

public class WordUtil {

    private final static String separator = File.separator;
    private final static String xmlDocument = "document.xml";
    private final static String xmlDocumentXmlRels = "document.xml.rels";
    private final static String xmlContentTypes = "[Content_Types].xml";

    /**
     * 生成评价数据word文档
     * @param outputStream 浏览器输出流
     * @param dataMap 填充数据
     * @param templateDocxPathName docx模板全路径名称
     * @return
     * @author xWang
     * @Date 2020-06-17
     */
    public void createDocx(OutputStream outputStream,Map dataMap, String templateDocxPathName) {

        try {

            //获取 document.xml 输入流
            ByteArrayInputStream documentInput = FreeMarkerUtil.getFreemarkerContentInputStream(dataMap, xmlDocument);

            //获取 document.xml.rels 输入流
            String xmlDocumentXmlRelsComment = FreeMarkerUtil.getFreemarkerContent(dataMap, xmlDocumentXmlRels);

            ByteArrayInputStream documentXmlRelsInput =
                    new ByteArrayInputStream(xmlDocumentXmlRelsComment.getBytes("utf-8"));

            //获取 header1.xml 输入流
            //ByteArrayInputStream headerInput = FreeMarkUtils.getFreemarkerContentInputStream(dataMap, xmlHeader, templatePath);

            //获取 [Content_Types].xml 输入流
            ByteArrayInputStream contentTypesInput = FreeMarkerUtil.getFreemarkerContentInputStream(dataMap, xmlContentTypes);

            //读取 document.xml.rels  文件 并获取rId 与 图片的关系 (如果没有图片 此文件不用编辑直接读取就行了)
            Document document = DocumentHelper.parseText(xmlDocumentXmlRelsComment);
            Element rootElt = document.getRootElement(); // 获取根节点
            Iterator iter = rootElt.elementIterator();// 获取根节点下的子节点head

            List<Map> titleList = JSON.parseArray(JSON.toJSONString(dataMap.get("titleList")), Map.class);
            for (Map<String,Object> map:titleList
            ) {
                List<Map> list = JSON.parseArray(JSON.toJSONString(map.get("optionsList")), Map.class);

                // 遍历Relationships节点
                while (iter.hasNext()) {
                    Element recordEle = (Element) iter.next();
                    String id = recordEle.attribute("Id").getData().toString();
                    String target = recordEle.attribute("Target").getData().toString();
                    if (target.indexOf("media") == 0) {
                        for (Map<String, String> picMap : list) {
                            if (target.endsWith(picMap.get("name"))) {
                                picMap.put("rId", id);
                            }
                        }
                    }
                }
            }

            File docxFile = new File(templateDocxPathName);
            if (!docxFile.exists()) {
                docxFile.createNewFile();
            }

            ZipFile zipFile = new ZipFile(docxFile);
            Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();
            ZipOutputStream zipout = new ZipOutputStream(outputStream);

            //覆盖文档
            int len = -1;
            byte[] buffer = new byte[1024];
            while (zipEntrys.hasMoreElements()) {
                ZipEntry next = zipEntrys.nextElement();
                InputStream is = zipFile.getInputStream(next);
                if (next.toString().indexOf("media") < 0) {
                    // 把输入流的文件传到输出流中
                    zipout.putNextEntry(new ZipEntry(next.getName()));
                    //写入图片配置类型
                    if (next.getName().equals("[Content_Types].xml")) {
                        if (contentTypesInput != null) {
                            while ((len = contentTypesInput.read(buffer)) != -1) {
                                zipout.write(buffer, 0, len);
                            }
                            contentTypesInput.close();
                        }

                    } else if (next.getName().indexOf("document.xml.rels") > 0) {
                        //写入主数据配置信息
                        if (documentXmlRelsInput != null) {
                            while ((len = documentXmlRelsInput.read(buffer)) != -1) {
                                zipout.write(buffer, 0, len);
                            }
                            documentXmlRelsInput.close();
                        }
                    } else if ("word/document.xml".equals(next.getName())) {
                        //写入主数据信息
                        if (documentInput != null) {
                            while ((len = documentInput.read(buffer)) != -1) {
                                zipout.write(buffer, 0, len);
                            }
                            documentInput.close();
                        }

                    } else if ("word/header1.xml".equals(next.getName())) {
                        //写入页眉信息
//                        if (headerInput != null) {
//                            while ((len = headerInput.read(buffer)) != -1) {
//                                zipout.write(buffer, 0, len);
//                            }
//                            headerInput.close();
//                        }
                    } else {
                        while ((len = is.read(buffer)) != -1) {
                            zipout.write(buffer, 0, len);
                        }
                        is.close();
                    }
                }
            }

            //写入新图片
            for (Map<String,Object> map:titleList
            ) {
                List<Map> picList = JSON.parseArray(JSON.toJSONString(map.get("optionsList")), Map.class);
                len = -1;
                if (picList != null && !picList.isEmpty()) {
                    for (Map<String, String> pic : picList) {
                        ZipEntry next = new ZipEntry("word" + separator + "media" + separator + pic.get("name"));
                        zipout.putNextEntry(new ZipEntry(next.toString()));
                        InputStream in = new FileInputStream(pic.get("path"));
                        while ((len = in.read(buffer)) != -1) {
                            zipout.write(buffer, 0, len);
                        }
                        in.close();
                    }
                }
            }
            zipout.close();
        } catch (Exception e) {
//            System.err.println(e.getMessage());
            e.getStackTrace();
        }
    }
原文地址:https://www.cnblogs.com/xiaowangxiao/p/13158757.html