根据word模板定制报表
踩过的坑
在网上看到不少关于word模板生成报表的例子,踩了不少的坑。最大的问题就是生成的word文档在电脑打开显示正常,而用手机打开显示的是全是xml标签。
本质
docx格式的文档本质上是一个ZIP文件。docx 格式文件的主要内容是保存为XML格式的,但文件并非直接保存于磁盘。它是保存在一个ZIP文件中,然后取扩展名为docx。将.docx 格式的文件后缀改为ZIP后解压, 可以看到解压出来的文件夹中有word这样一个文件夹,它包含了Word文档的大部分内容。而其中的document.xml文件则包含了文档的主要文本内容。
步骤
第一步【新建文档】
新建一个test.docx文档,内容如下。
第二步【zip目录文件说明】
把test.docx的文档后缀改为zip。打开压缩文件我们主要进入word目录下,结构如下。
media:存放word文档里面插入的图片。
theme:主题样式。
document.xml:文档主要内容。
header1.xml:文档页眉内容。
footer1.xml:文档页脚内容。
第三步【修改xml文件】
例如我现在需要对文档主体内容进行修改。把document.xml文件内容剪切,进行代码格式化,再把格式化的内容粘贴回去。
把我们的中文替换成FTL标签,参考如下链接。
https://blog.csdn.net/asa_prince/article/details/82018446
https://blog.csdn.net/asa_prince/article/details/82017976
https://blog.csdn.net/qq_33616529/article/details/78291103
https://blog.csdn.net/jayainuo/article/details/69220728
https://www.cnblogs.com/zhaoYuQing-java2015/p/6046697.html
例如表格可以删除掉李四这一行的内容,把张三这一行的内容循环遍历<#list userList! as user> </#list>,再把张三替换成${!user.name},其他属性类似操作。
第四步【执行代码】
- 生成word报表相关代码
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import freemarker.template.Configuration;
import freemarker.template.Template;public class WordUtils {private static Logger LOGGER = LoggerFactory.getLogger(WordUtils.class);/*** 往xml文件填充数据* @param dataMap 数据* @param templatePath 模板路径* @param templateName 模板名称* @param generatePath 生成的文件路径*/public static void process(Map<String,Object> dataMap,String templatePath,String templateName, String generatePath) {Writer out = null;try {Configuration configuration = new Configuration(Configuration.getVersion());configuration.setDefaultEncoding("utf-8");configuration.setDirectoryForTemplateLoading(new File(templatePath));Template t = configuration.getTemplate(templateName, "utf-8");out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(generatePath)), "utf-8"));t.process(dataMap, out);} catch (Exception e) {LOGGER.error("往xml文件填充数据失败:{}",e.getMessage());} finally {close(out);}}/*** 替换某个 item,* @param zipInputStreamPath zip文件的zip输入流路径* @param zipOutputStreamPath 输出的zip输出流路径* @param itemInputStreamMap 要替换的 item 的内容输入流路径*/public static void replaceItem(String zipInputStreamPath, String zipOutputStreamPath, Map<String,String> itemInputStreamMap) {ZipInputStream zipInputStream = null;ZipOutputStream zipOutputStream = null;try {zipInputStream = new ZipInputStream(new FileInputStream(new File(zipInputStreamPath)));zipOutputStream = new ZipOutputStream(new FileOutputStream(new File(zipOutputStreamPath)));ZipEntry entryIn;int len = -1;// 缓冲区byte[] buf = new byte[8 * 1024];while ((entryIn = zipInputStream.getNextEntry()) != null) {String entryName = entryIn.getName();ZipEntry entryOut = new ZipEntry(entryName);// 只使用 namezipOutputStream.putNextEntry(entryOut);if(itemInputStreamMap.containsKey(entryName)) {String path = itemInputStreamMap.get(entryName);InputStream inputStream = new FileInputStream(new File(path));// 使用替换流while ((len = (inputStream.read(buf))) > 0) {zipOutputStream.write(buf, 0, len);}close(inputStream);itemInputStreamMap.remove(entryName);}else {// 输出普通Zip流while ((len = (zipInputStream.read(buf))) > 0) {zipOutputStream.write(buf, 0, len);}}}// 关闭此 entryzipInputStream.closeEntry();zipOutputStream.closeEntry();} catch (IOException e) {LOGGER.error("替换item失败:{}",e.getMessage());} finally {close(zipInputStream);close(zipOutputStream);}}private static void close(InputStream inputStream) {if (null != inputStream) {try {inputStream.close();} catch (IOException e) {LOGGER.error(e.getMessage());}}}private static void close(OutputStream outputStream) {if (null != outputStream) {try {outputStream.flush();outputStream.close();} catch (IOException e) {LOGGER.error(e.getMessage());}}}private static void close(Writer out) {if (null != out) {try {out.flush();out.close();} catch (IOException e) {LOGGER.error(e.getMessage());}}}
}
- 后台生成统计图表图片相关代码,需要安装phantomjs,引入相关的js。[无需生成统计图表可以忽略此代码]
import java.io.File;
import java.io.FileOutputStream;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class EchartsUtils {private static final Logger LOG = LoggerFactory.getLogger(EchartsUtils.class);public static final String FILETYPE = ".js";public static final String IMGTYPE = ".png";public static final float SCALE = 0.25f;public static final int WIDTH = 800;public static final int HEIGHT = 400;/*** 生成echarts图片* @param json * @param rootPath 生成的临时文件夹目录* @param name 图片名称* @return* @throws Exception*/public static boolean getEchartsImg(String json,String upgradePath,String rootPath,String name){boolean flag = true;Process process = null;try {rootPath += name; //生成js文件writeEchartsJs(json,rootPath+FILETYPE);//生成echarts图片Runtime rt = Runtime.getRuntime();process = rt.exec("phantomjs " + upgradePath + File.separator + ReportConst.PATH_ECHARTS + "echarts-convert.js -infile " + rootPath + FILETYPE + " -outfile " + rootPath + IMGTYPE + " -scale " + SCALE + " -width " + WIDTH + " -height" + HEIGHT);//等待图片生成process.waitFor();} catch (Exception e) {flag = false;LOG.error("生成EchartsIMG失败:{}",e.getMessage());}finally {if(process != null) {process.destroy();}}return flag;}public static void writeEchartsJs(String json, String path) {FileOutputStream outSTr = null;try {File file = new File(path);outSTr = new FileOutputStream(file);outSTr.write(json.getBytes());} catch (Exception e) {LOG.error("生成EchartsJS文件失败:{}",e.getMessage());} finally {FileUtils.close(outSTr);}}
}
@Testpublic void generateWord() {Map<String, Object> dataMap = new HashMap<String, Object>();dataMap.put("title", "XXX报表");List<Map<String, Object>> list = new ArrayList<>();for (int i = 1; i <= 50; i++) {Map<String, Object> map = new HashMap<String, Object>();dataMap.put("name", "张三"+i);dataMap.put("sex", "男");dataMap.put("age", i);list.add(map);}dataMap.put("userList", list);String json = getPieOption();boolean flag = EchartsUtils.getEchartsImg(json, "",IMGURL, "test_pie");if(flag) {WordUtils.process(dataMap, PATH, "test_document.xml", PATH+"data.xml");Map<String, String> itemInputStreamMap = new HashMap<>();itemInputStreamMap.put("word/document.xml", PATH+"data.xml");itemInputStreamMap.put("word/media/image1.png", IMGURL+"test_pie.png");WordUtils.replaceItem(PATH+"test.zip", PATH+"test_generate.docx", itemInputStreamMap );}}
根据word模板定制报表相关推荐
- POI 3.9根据word模板生成报表
XWPFDocument对象 POI是apache提供的可以操作word文档的第三方jar.POI能操作word是使用XWPFDocument对象. XWPFDocument对象可以解析docx文件, ...
- word模板生成word报表文档
主要功能为根据word模板生成word报表文档,注意引用Interop.Word.dll; 首先要生成word程序对象 Word.Application app = new Word.Applicat ...
- C#根据word模板生成word表格报表文档
主要功能为根据word模板生成word报表文档,注意引用Interop.Word.dll; 首先要生成word程序对象 Word.Application app = new Word.Applicat ...
- apache poi使用例_使用java Apache poi 根据word模板生成word报表例子
[实例简介] 使用java Apache poi 根据word模板生成word报表 仅支持docx格式的word文件,大概是word2010及以后版本,doc格式不支持. 使用说明:https://b ...
- POI利用word模板动态生成word报表以及动态生成word表格
目录 核心依赖 动态表格 测试类 工具类 动态数据 测试类 工具类 核心依赖 <dependency><groupId>org.apache.poi</groupId&g ...
- 使用java Apache poi 根据word模板生成word报表
使用java Apache poi 根据word模板生成word报表 使用poi读取word模板,替换word中的{text}标签,并根据自定义标签循环生成表格或表格中的行. 代码示例下载:https ...
- java使用Apache poi根据word模板生成word报表(增加插入符号、控制分页功能)
原文链接:https://blog.csdn.net/u012775558/article/details/79678701 根据原代码新增了插入符号和控制分页功能.改了类名,一些方法,新增一个符号类 ...
- 【QT】word文档操作实例——根据word模板生成word报表
文章目录 引言 一.word模板准备 二.WordDemo实现 1.mainwindow.ui 2.mainwindow.h 3.mainwindow.cpp 三.实现效果 引言 在QT5.3中,在. ...
- 基于Easypoi+jfree,使用SpringBoot架构,Java编程实现word模板导出Word报表
目录 1.项目目录结构 2.pom.xml添加的依赖 3.编写jfreeutil工具类 4.编写wordutil工具类 5.编写word模板 7.运行效果 8.复杂布局实现 8.1如何实现图片并排 S ...
最新文章
- MegEngine推理性能优化
- SAP ABAP BAPI_GOODSMVT_CREATE的几个应用
- Android studio 4.1 不显示光标当前的类名、方法名
- WPF DataGrid横向显示
- android linearllayout 隐藏 动画,AnimatedLinearLayout:带删除动画的LinearLayout
- 电机控制pid_微电机控制如此简单,揭秘微电机调速的控制,PID控制之双环调速...
- 2015 03 03 复习 上课笔记(一)
- 【高数+AI】中山大学的学霸小哥开源了一个能帮你做高数题的AI
- java数列的个位数求和_java二位数组相加
- 转载 java序列化与反序列化
- 在Android中Unity3D透明背景的实现
- ROS开发--Qt接收摇杆话题
- matlab矩阵里面星号,矩阵中出现加号和星号 什么意思
- Windows的sc命令详解
- 蓝桥 卷“兔”来袭编程竞赛专场-07明码加密 题解
- 成功解决ValueError: Duplicate plugins for name projector
- JavaScript中Set的使用
- ProcessOn在线画图
- std::thread vs CreateThread
- 小米红米Note4X(高配版)解BL锁教程申请BootLoader解锁教程