基于Freemarker和xml实现Java导出word
作者:经典鸡翅 发布时间:2022-07-11 23:15:12
前言
最近做了一个调查问卷导出的功能,需求是将维护的题目,答案,导出成word,参考了几种方案之后,选择功能强大的freemarker+固定格式之后的wordxml实现导出功能。导出word的代码是可以直接复用的,于是在此贴出,并进行总结,方便大家拿走。
实现过程概览
先在word上,调整好自己想要的样子。然后存为xml文件。保存为freemarker模板,以ftl后缀结尾。将需要替换的变量使用freemarker的语法进行替换。最终将数据准备好,和模板进行渲染,生成文件并返回给浏览器流。
详细的实现过程准备好word的样式
我们新建一个word,我们应该使用Microsoft office,如果使用wps可能会造成样式有些不兼容。在新建的office中,设置好我们的表格样式。我们的调查问卷涉及到四种类型,单选,多选,填空,简答。我们做出四种类型的示例。
样式没有问题后,我们选择另存为word xml 2003版本。将会生成一个xml文件。
格式化xml,并用freemarker语法替换xml
我们可以先下载一个工具 firstobject xml editor,这个可以帮助我们查看xml,同时方便我们定位我们需要改的位置。
复制过去之后,按f8可以将其进行格式化,左侧是标签,右侧是内容,我们只需要关注w:body即可。
像右侧的调查问卷这个就是个标题,我们实际渲染的时候应该将其进行替换,比如我们的程序数据map中,有title属性,我们想要这里展示,我们就使用语法${title}即可。
freemarker的具体语法,可以参考freemarker的问题,在这里我给出几个简单的例子。
比如我们将所有的数据放置在dataList中,所以我们需要判断,dataList是不是空,是空,我们不应该进行下面的逻辑,不是空,我们应该先循环题目是必须的,答案是需要根据类型进行再次循环的。语法参考文档,这里不再赘述。
程序端引入freemarker
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
将我们的flt文件放在resources下的templates下。
后端代码实现
此代码可以复用,在此贴出
public class WordUtils {
private static Configuration configuration = null;
private static final String templateFolder = WordUtils.class.getClassLoader().getResource("").getPath()+"/templates/word";
static {
configuration = new Configuration();
configuration.setDefaultEncoding("utf-8");
try {
configuration.setDirectoryForTemplateLoading(new File(templateFolder));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* @Description:导出word,传入request,response,map就是值,title是导出问卷名,ftl是你要使用的模板名
*/
public static void exportWord(HttpServletRequest request, HttpServletResponse response, Map map, String title, String ftlFile) throws Exception {
Template freemarkerTemplate = configuration.getTemplate(ftlFile);
File file = null;
InputStream fin = null;
ServletOutputStream out = null;
try {
file = createDocFile(map,freemarkerTemplate);
fin = new FileInputStream(file);
String fileName = title + ".doc";
response.setCharacterEncoding("utf-8");
response.setContentType("application/msword");
response.setHeader("Content-Disposition", "attachment;filename="
+fileName);
out = response.getOutputStream();
byte[] buffer = new byte[512];
int bytesToRead = -1;
while((bytesToRead = fin.read(buffer)) != -1) {
out.write(buffer, 0, bytesToRead);
}
}finally {
if(fin != null) fin.close();
if(out != null) out.close();
if(file != null) file.delete();
}
}
/**
* @Description:创建doc文件
*/
private static File createDocFile(Map<?, ?> dataMap, Template template) {
File file = new File("init.doc");
try {
Writer writer = new OutputStreamWriter(new FileOutputStream(file), "utf-8");
template.process(dataMap, writer);
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
}
有了工具类后,我们准备好我们的map数据。map里面的数据大家可以自行定义。然后调用utils中的导出方法即可。
WordUtils.exportWord(request, response, dataMap, "word", "demo.ftl");
来源:https://www.cnblogs.com/jichi/p/11921541.html


猜你喜欢
- 项目开发中对于一些数据的处理需要用到多线程,比如文件的批量上传,数据库的分批写入,大文件的分段下载等。 通常会使用spring自带的线程池处
- 本文实例讲述了Android开发之imageView图片按比例缩放的实现方法。分享给大家供大家参考,具体如下:android:scaleTy
- fifter、servlet、interceptorfifter用来处理请求头、请求参数、编码的一些设置,然后转交给servlet,处理业务
- 简介线段树是一种二叉搜索树,是用来维护区间信息的数据结构。可以在O(logN)的时间复杂度内实现单点修改、区间修改、区间查询(区间求和,求区
- 前言 * 体系是Struts2框架的重要组成部分,不夸张的说,没有 * 体系,也就没有这么好用的Struts2框架了。在Struts2框架中
- 这里以电视遥控器的一个例子来引出桥接模式解决的问题,首先,我们每个牌子的电视机都有一个遥控器,此时我们能想到的一个设计是——把遥控器做为一个
- 1. 什么是 spring-boot-devtoolsspring-boot-devtools 是 spring-boot项目开发时的一个热
- 拼图小游戏,学习阶段。很多不足,改进了一下演示图片:J_Puzzle.javaimport java.awt.BorderLayout;im
- 本文实例分析了Android编程中activity的完整生命周期。分享给大家供大家参考,具体如下:android中 activity有自己的
- Feign简介Feign 是一个声明web服务客户端,这便得编写web服务客户端更容易,使用Feign 创建一个接口并对它进行注解,它具有可
- 本文实例为大家分享了android实现注册登录程序的具体代码,供大家参考,具体内容如 * 册页面:user_register.xml:<
- OAuth 简介OAuth 是由 Blaine Cook、Chris Messina、Larry Halff 及 David Recordo
- 一、前言无论承接什么样的需求,是不是身边总有那么几个人代码写的烂,但是却时常有测试小姐姐过来聊天(求改bug)、有产品小伙伴送吃的(求写需求
- 本文实例展示了C#利用反射来判断对象是否包含某个属性的实现方法,对于C#程序设计人员来说有一定的学习借鉴价值。具体实现代码如下:/// &l
- 问题描述:某天打开项目的activity的java文件界面突然变成下面这样了,但是用Notepad++打开代码什么的都正常,不知道什么原因造
- 本文实例讲述了Android实现调用震动的方法。分享给大家供大家参考,具体如下:调用Android系统的震动,只需要一个类 那就是Vibra
- 我们在安卓开发中安卓自带的控件满足不了我们的需求,因此我们就需要用到自定义View来满足我们的需求,在这里我要讲解的是自定义View实现选座
- Android中的Service和其调用者既可以在同一个App中,也可以在不同的App。如果Service在App1中,而调用Service
- 序列化是将对象转换成字节流的过程,反序列化是把字节流转换成对象的过程。对象一旦被序列化,就可以把对象状态保存到硬盘的某个位置,甚至还可以通过
- 定时任务,是指定一个未来的时间范围执行一定任务的功能。在当前WEB应用中,多数应用都具备任务调度功能,针对不同的语音,不同的操作系统, 都有