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

摘要:
自由标记<版本>2.3.23<&书信电报;3InputStreamin=newFileInputStream(文件);SyntaxKind.Html);14context.put(“文本”;内容);18报告.过程(上下文;输出);

文档地址: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就是后期要替换的变量了。

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

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. 在模版中插入临时图片,选中图片并添加“书签”,书签名称是后续作为替换的变量

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

  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中多图片的动态展示。

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

免责声明:文章转载自《使用XDocReport将HTML格式数据转换为Word》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇基于OpenCV实现Photoshop的17种图层混合安全的即时通讯——基于分布式系统的Tox下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

“display:block-inline形式的Span或Div中添加文字后,导致Span或Div排版掉落、错位”的原因及解决方法

转:http://www.xuebuyuan.com/825857.html 故事: 最近在使用3个span(或div)制作带圆角边框的按钮时,按照常识,把span的display设置成inline-block,这样就可以设置span的width和height了,很爽的~ 可是当我在中间的span写上文字的时候,神奇的事情发生了: 是的,写上字的那个sp...

element-ui Progress、Badge、Alert组件源码分析整理笔记(四)

Progress进度条组件 <template> <!--最外层--> <div :class="[ 'el-progress--' + type, status ? 'is-' + status : '', { 'el-progress--w...

ASP.NET Core MVC Razor小记

_Layout模板 常规的页面一般由头部导航、左侧菜单、中间主体内容主成,而其中唯一变动的基本就只有中间主体内容了,而Layout模板就是用来做这样一件事,编写好模板,需要变动的地方则使用@RenderBody()方法 _ViewStart 我们尝试在_Layout模板的footer标签中增加一点内容,运行程序,发现也会跟着改动,明明在Index文件中未...

python用户管理系统

学Python这么久了,第一次写一个这么多的代码(300多行,重复的代码挺多的,比较水),但是也挺不容易的 自定义函数+装饰器,每一个模块写的一个函数 很多地方能用装饰器(逻辑跟不上,有的地方没用),包括双层装饰器(不会),很多地方需要优化,重复代码太多 我还是把我的流程图拿出来吧,虽然看着比上次的垃圾,但是我也做了一个小时,不容易! 好像是挺丑的(表示...

vue截图界面保存本地

使用html2canvas把界面生成图片 下载 html2canvas 依赖: npm install html2canvas -S 需要使用 html2canvas 页面引入该依赖: import html2canvas from 'html2canvas' html代码: <template> <div>...

pure css简单组件,借鉴bootstrap

   <!doctype html> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <!--缩放比例以及允许缩放--> <meta name="viewport" conte...