公司要求添加一个导出文档功能,翻了下百度,找到一个freemarker好东西。话不多说,继续
注意了,是另存为,不是直接改后缀,楼主在这上面跌过坑
添加<#list userList as user>#list>
这句话就相当于把list userList 循环遍历,每一项是user,类似于
forEach items='userList' var='user'>
怎么加,搜 w:tr ,找到你要循环的部分,然后把它包裹起来
注意我圈出来的东西,这个相当于for循环中的i+1
接下来就是代码,没啥好说的
我非全复制,所以注意点
这个是别人的下载到指定文件夹中的路径
@Test
public void exportSimpleWord() throws Exception{
// 要填充的数据, 注意map的key要和word中${xxx}的xxx一致
Map dataMap = new HashMap();
dataMap.put("username", "张三");
dataMap.put("sex", "男");
//Configuration用于读取ftl文件
Configuration configuration = new Configuration();
configuration.setDefaultEncoding("utf-8");
/*以下是两种指定ftl文件所在目录路径的方式, 注意这两种方式都是
* 指定ftl文件所在目录的路径,而不是ftl文件的路径
*/
//指定路径的第一种方式(根据某个类的相对路径指定)
//configuration.setClassForTemplateLoading(this.getClass(),"");
//指定路径的第二种方式,我的路径是C:/a.ftl
configuration.setDirectoryForTemplateLoading(new File("C:/"));
// 输出文档路径及名称
File outFile = new File("D:/test.doc");
//以utf-8的编码读取ftl文件
Template t = configuration.getTemplate("a.ftl","utf-8");
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"),10240);
t.process(dataMap, out);
out.close();
}
当然你自己获取数据可能是List,我们不管他,也这么放进map,可定义为Map
,然后运行时出现
Don't know how to present an object of this type to a template: com.vixuan.pojo.Animals
巴拉巴拉的一串,我百度了一下,这句话的意思是:
1、无法引述动物类对象到模版,也就是说模板不认识list里面的数据是Animals对象,所以无法通过animals.name来访问属性对象
2、这个是发生在写入word时候
网上的大牛还是很多的,直接给出了答案:
通过查询API文档,可以容易看到Template.process()函数有两种形式,一个是含有两个参数的,而另一个则含有三个参数,他们分别为:
void freemarker.template.Template.process(Object dataModel, Writer out) throws TemplateException,IOException
void freemarker.template.Template.process(Object dataModel, Writer out, ObjectWrapper wrapper) throws TemplateException, IOException
其实二者没什么大的区别,只是第二个方法比第一个多增加了一个ObjectWrapper wrapper参数而已,那个增加这个参数有什么作用呢?
答案是:第一个方法中默认了ObjectWrapper wrapper参数是ObjectWrapper.SIMPLE_WRAPPER型的,但是在我们的情况下需要另一种类型,也即:ObjectWrapper.BEANS_WRAPPER,观看英文单词也理解是什么意思了吧
所以,改成t.process(dataMap, out,ObjectWrapper.BEANS_WRAPPER);
就可以了
模版类的放置问题,万年的百度告诉我们模版有三种放置方法
//3种方法分别是:
public void setClassForTemplateLoading(Class clazz, String pathPrefix);
public void setDirectoryForTemplateLoading(File dir) throws IOException;
public void setServletContextForTemplateLoading(Object servletContext, String path);
第二、第三种没啥好说的。
第二种基于文件系统, 比如加载/home/user/template下的模板文件。
Configuration cfg = new Configuration();
cfg.setDirectoryForTemplateLoading(new File("/home/user/template"));
cfg.getTemplate("Base.ftl");
这样就获得了/home/user/template/Base.ftl这个模板文件。
第三种基于web project。 第二个参数是基于WebRoot下的。
比如: setServletContextForTemplateLoading(context, "/ftl")
就是 /WebRoot/ftl目录。
第一种基于类路径的方法有点小坑
Configuration cfg = new Configuration();
cfg.setClassForTemplateLoading(FreemarkerUtil.class, "/template");
cfg.getTemplate("Base.ftl");
其中FreemarkerUtil所在的包路径是: org.foo.util
那么获得是模板文件就是 ${projectPath}/org/foo/util/template 。
这里注意一下第二个参数需要以 “/” 开头。
网上有许多教程都是下载指定路径,,,,但是耐心找也能发现直接调用浏览器的
//前面map放入数据的部分就不写了
Configuration configuration = new Configuration();
configuration.setDefaultEncoding("utf-8");
configuration.setClassForTemplateLoading(this.getClass(),"");
response.setContentType("application/msword");
String fileName = "你好.doc";//文件名
response.setHeader("Content-Disposition", "attachment;filename=\"" + new String(fileName.getBytes("GBK"), "iso8859-1") + "\"");
response.setCharacterEncoding("utf-8");//此句非常关键,不然word文档全是乱码
PrintWriter out = response.getWriter();
Template t = configuration.getTemplate("wordDemo.ftl","utf-8");//以utf-8的编码读取ftl文件
t.process(dataMap, out,ObjectWrapper.BEANS_WRAPPER); //因为我当时写的有bean类
out.close();
如果出现这个
freemarker.core.ParseException: Encountered "<" at line 3, column 28888 in test.ftl.
Was expecting one of:
...
...
"false" ...
"true" ...
...
...
"." ...
"+" ...
"-" ...
"!" ...
"[" ...
"(" ...
这是由于在写${xxx}
表达式的时候, xxx
与其前方的文字样式不一致, 在另存为xml
后你可以搜索一下 "${"
, 会发现如下图这种情况:
感谢网上大牛的无私奉献
1、http://blog.csdn.net/zhouzhiwengang/article/details/46352107
2、http://blog.csdn.net/pengyufight/article/details/53125818