• Easypoi实现单模板生成多页word文档


        EasyPoi可以很方便的通过一个word模板,然后通过填充模板的方式生成我们想要的word文档。但是碰到了一个单模板生成多页数据的场景,比如一个订单详情信息模板,但是有很多订单,需要导入到一个word里面,提供给用户下载这个word文档。这就需要进行word合并了,Easypoi可以生成多个XWPFDocumenmt,我们将它合并成一个就行了。
        特意找了下Easypoi官方文档,没有看到多个word合并的案例,官方文档还是对于单模板生成多页的说明还是空白的,链接为:https://opensource.afterturn.cn/doc/easypoi.html#602因此特意在网络上了找了word合并相关的博客,通过我自己的一些改动,实现了想要的功能。记录下该工具类,方便后续查阅。

    一、合并word文档工具类代码

    import org.apache.poi.xwpf.usermodel.Document;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;
    import org.apache.poi.xwpf.usermodel.XWPFPictureData;
    import org.apache.xmlbeans.XmlOptions;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;
    import org.springframework.util.CollectionUtils;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * WordUtils
     *
     * @author ZENG.XIAO.YAN
     * @version 1.0
     * @Date 2019-09-20
     */
    public final class WordUtils {
    
        /**
         * word文件合并
         * @param wordList
         * @return
         * @throws Exception
         */
        public static  XWPFDocument mergeWord(List<XWPFDocument> wordList) throws Exception{
            if (CollectionUtils.isEmpty(wordList)) {
                throw  new RuntimeException("待合并的word文档list为空");
            }
            XWPFDocument doc = wordList.get(0);
            int size = wordList.size();
            if (size > 1) {
                doc.createParagraph().setPageBreak(true);
                for (int i = 1; i < size; i++) {
                    // 从第二个word开始合并
                    XWPFDocument nextPageDoc = wordList.get(i);
                    // 最后一页不需要设置分页符
                    if (i != (size-1)) {
                        nextPageDoc.createParagraph().setPageBreak(true);
                    }
                    appendBody(doc, nextPageDoc);
                }
            }
            return doc;
        }
    
        private static void appendBody(XWPFDocument src, XWPFDocument append) throws Exception {
            CTBody src1Body = src.getDocument().getBody();
            CTBody src2Body = append.getDocument().getBody();
            List<XWPFPictureData> allPictures = append.getAllPictures();
            // 记录图片合并前及合并后的ID
            Map<String,String> map = new HashMap<>();
            for (XWPFPictureData picture : allPictures) {
                String before = append.getRelationId(picture);
                //将原文档中的图片加入到目标文档中
                String after = src.addPictureData(picture.getData(), Document.PICTURE_TYPE_PNG);
                map.put(before, after);
            }
            appendBody(src1Body, src2Body,map);
    
        }
    
        private static void appendBody(CTBody src, CTBody append,Map<String,String> map) throws Exception {
            XmlOptions optionsOuter = new XmlOptions();
            optionsOuter.setSaveOuter();
            String appendString = append.xmlText(optionsOuter);
            String srcString = src.xmlText();
            String prefix = srcString.substring(0,srcString.indexOf(">")+1);
            String mainPart = srcString.substring(srcString.indexOf(">")+1,srcString.lastIndexOf("<"));
            String sufix = srcString.substring( srcString.lastIndexOf("<") );
            String addPart = appendString.substring(appendString.indexOf(">") + 1, appendString.lastIndexOf("<"));
            if (map != null && !map.isEmpty()) {
                //对xml字符串中图片ID进行替换
                for (Map.Entry<String, String> set : map.entrySet()) {
                    addPart = addPart.replace(set.getKey(), set.getValue());
                }
            }
            //将两个文档的xml内容进行拼接
            CTBody makeBody = CTBody.Factory.parse(prefix+mainPart+addPart+sufix);
            src.set(makeBody);
        }
    
    }

    二、使用案例

      使用套路:
        (1)通过easypoi生成word文档放在一个List集合中
        (2)将List集合中的word文档合并成一个
        (3)将合成后的word输出到文件
    参考下面图片:
            

    防止图片失效,代码也贴上来了
        List<XWPFDocument> wordList = new ArrayList<>();
        // 1.通过easypoi生成word文档并放在集合里
        for (int i = 0; i < studInocCardVOS.size(); i++) {
            ExportStudInocCardVO studInocCardVO = studInocCardVOS.get(i);
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("birthday", studInocCardVO.getBirthday());
            map.put("mobile", studInocCardVO.getMobile());
            map.put("mother", studInocCardVO.getMother());
            map.put("schoolName", studInocCardVO.getSchoolName());
            map.put("className", studInocCardVO.getClassName());
            map.put("corpName", studInocCardVO.getCorpName());
            map.put("bactNo", studInocCardVO.getBactNo());
            map.put("validity", studInocCardVO.getValidity());
            map.put("standard", studInocCardVO.getStandard());
            map.put("dosage", studInocCardVO.getDosage());
            map.put("sex", studInocCardVO.getSex());
            map.put("inocDate", studInocCardVO.getInocDate());
            // 通过easyPoi生成word文档(即XWPFDocument)
            XWPFDocument doc = WordExportUtil.exportWord07(
                    "接种管理-接种凭证(详细).docx", map);
            wordList.add(doc);
        }
        // 2.把集合里面的word文档全部合并在一个文档
        XWPFDocument word = WordUtils.mergeWord(wordList);
        File outDir = new File("c:/excel");
        if (!outDir.exists()) {
            outDir.mkdirs();
        }
        // 3.将合并后的word文档输出到文件
        FileOutputStream fos = new FileOutputStream(new File(outDir, "接种管理-接种凭证-导出(详细).docx"));
        word.write(fos);
        fos.close();

    三、小结

        实现单模板生成多页文件关键点如下:
            (1)通过Easypoi生成word文档
            (2)通过原生的Poi的api进行word合并
  • 相关阅读:
    Vue3小知识
    Eslint小知识
    微信小程序注意点
    vue常用方法2
    vue常用方法
    vue组件常用方法
    013 --TypeScript之高级类型
    012--TypeScript之类型推断
    jenkins window unity 控制台输出中文乱码
    Unity 生成 Android App Bundle(aab) (二)
  • 原文地址:https://www.cnblogs.com/zeng1994/p/bef8f7ab14486d489db8ee72b9f8ffc0.html
Copyright © 2020-2023  润新知