使用XDocReport将HTML格式数据转换为Word

文档地址:https://github.com/opensagres/xdocreport/wiki/DocxReportingQuickStart

本文采用XDocReport集合Freemaiker进行处理

1. 引入Maven依赖:

<dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>xdocreport</artifactId>
    <version>2.0.1</version>
</dependency>
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.0</version>
</dependency>
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.23</version>
</dependency>

2. 创建Word模版

新建Word,在光标处通过快捷键Ctrl+F9 或 工具栏“插入”->“文档部件或文本”->“域”

根据电脑系统不同出现的界面不同,但内容都差不多,${text} 这个text就是后期要替换的变量了。

3. Java代码处理逻辑

 1 String templateFilePath = request.getSession().getServletContext().getRealPath("/WEB-INF/templates/freemarkerTest.docx");
 2 File file = new File(templateFilePath);
 3 InputStream in = new FileInputStream(file);
 4 IXDocReport report;
 5 String targetPath = basePath + lawDownDto.getLawsName() + ".docx";
 6 try {
 7     report = XDocReportRegistry.getRegistry().loadReport(in, TemplateEngineKind.Freemarker);
 8     // 设置内容为HTML格式
 9     FieldsMetadata metadata = report.createFieldsMetadata();
10     metadata.addFieldAsTextStyling("text", SyntaxKind.Html);   
11 
12     // 创建内容-text为模版中对应都变量名称
13     IContext context = report.createContext();
14     context.put("text", content);
15             
16     // 生成文件
17     OutputStream out = new FileOutputStream(targetPath);
18     report.process(context, out);
19 } catch (XDocReportException e) {
20     e.printStackTrace();
21 }

文件下载:在生成文件逻辑后创建读取流返回即可。

=============================================================

如果文件中有图片需要处理:

  图片方案一:单个图片且位置固定,可通过XDocReport配置模版处理

  图片方案二:多个图片且位置不固定,可通过POI结合Freemarker进行处理

图片方案一:

  1. 在模版中插入临时图片,选中图片并添加“书签”,书签名称是后续作为替换的变量

  

  2. 代码中追加逻辑

  在上面代码10后追加

// logo为模版中标签名称
metadata.addFieldAsImage("logo");
report.setFieldsMetadata(metadata);

  在上面代码14行后追加

// IImageProvider可通过3种方式创建(File/IO流/ClassPath下文件)具体可参考顶部文档-Dynamic Image
IImageProvider logo = new FileImageProvider(new File("1950737_195902644.png"));
context.put("logo", logo);

图片方案二:

  1. 在上面读取模版之前进行数据替换

// 处理文本中的图片,使用imgReplace变量替换
Map<String, Object> param = new HashMap<String, Object>();
if (StringUtils.isNotBlank(content)) {
    content = HtmlUtils.htmlUnescape(content);
    List<HashMap<String, String>> imgs = getImgStrContent(content);
    int count = 0;
    for (HashMap<String, String> img : imgs) {
        count++;
        //处理替换以“/>”结尾的img标签
        content = content.replace(img.get("img"), "${imgReplace" + count + "}");
        //处理替换以“>”结尾的img标签
        content = content.replace(img.get("img1"), "${imgReplace" + count + "}");
        Map<String, Object> header = new HashMap<String, Object>();
        String result = "";
        result = img.get("src");
        //如果没有宽高属性,默认设置为
        if(img.get("width") == null || img.get("height") == null) {
            header.put("width", 150);
            header.put("height", 150);
        }else {
            header.put("width", (int)(Double.parseDouble(img.get("width"))));
            header.put("height", (int) (Double.parseDouble(img.get("height"))));
        }
        if( StringUtils.isNotBlank(result) ){
            String type1 = result.substring(result.lastIndexOf(".") , result.length());
            header.put("type", type1);
            header.put("content",this.imageToInputStream(result));
        }
        param.put("${imgReplace" + count + "}", header);
    }
}        
//获取html中的图片元素信息
private  List<HashMap<String, String>> getImgStrContent(String htmlStr) {
    List<HashMap<String, String>> pics = new ArrayList<HashMap<String, String>>();
    Document doc = Jsoup.parse(htmlStr);
    if( doc != null ){
        Elements imgs = doc.select("img");
        if( imgs != null && imgs.size() > 0 ){
            for (Element img : imgs) {
                HashMap<String, String> map = new HashMap<String, String>();
                if(!"".equals(img.attr("width"))) {
                    map.put("width", img.attr("width"));
                }
                if(!"".equals(img.attr("height"))) {
                    map.put("height", img.attr("height"));
                }
                map.put("img", img.toString().substring(0, img.toString().length() - 1) + "/>");
                map.put("img1", img.toString());
                map.put("src", img.attr("src"));
                pics.add(map);
            }
        }
    }
    return pics;
}
// 读取生成的文件
readStream = new FileInputStream(targetPath);
ByteArrayOutputStream docxOs = new ByteArrayOutputStream();
int b = 0;
byte[] buf = new byte[1024];
while ((b = readStream.read(buf)) != -1) {
    docxOs.write(buf, 0, b);
}
docxResponseStream = new ByteArrayInputStream(docxOs.toByteArray());
// 创建word 对象
XWPFDocument document = new XWPFDocument(docxResponseStream);
newOS = new ByteArrayOutputStream();
if (document != null && param != null) {
    // 生成带图片的word(如需工具类请给我发邮件)
    XWPFDocument customXWPFDocument = WordUtil.getWord(param, document);
    // 设置表格边框样式(另外一片文章会介绍)
    // List<XWPFTable> list = formatTableBorder(customXWPFDocument);
    // 处理合并单元格(另外一片文章会介绍)
    // mergeCell(content, list);
    // 写入输出流返回
    customXWPFDocument.write(newOS);
    document.close();
    customXWPFDocument.close();
    resultInpu = new ByteArrayInputStream(newOS.toByteArray());
}else{
    resultInpu = docxResponseStream;
}

以上内容即可完成Word中多图片的动态展示。

后续会写处理表格边框、单元格合并及段落都相关内容。

posted @ 2019-06-16 23:49  Commissar-Xia  阅读(2162)  评论(1编辑  收藏  举报