话不多说直接进入正题,记录一次使用freemarker模板导出excel的过程:
1.先写个导出文件的工具类。代码如下:
package com.xxxx.web.action.xxx;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.net.URLEncoder;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import freemarker.cache.FileTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
public class FtlHandler {
/**
* 生成文件
* @param fileName 模板文件全名(含后缀)
* @param outName 导出后文件的全名(含后缀)
* @param response
* @param map 模板中需要的数据
* @throws IOException
* @throws Exception
* @throws TemplateException
*/
public static void directResponseFile(String fileName, String outName,HttpServletResponse response, Map map) throws IOException, Exception, TemplateException {
//配置响应文件类型
if(outName.contains(".xls") || outName.contains(".xlsx")) {
response.setContentType("application/x-xls");//excel
}else {
response.setContentType("application/msword");//word
}
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(outName, "UTF-8"));
createFile(fileName, response.getWriter(), map);
response.reset(); // 清除非常重要
}
/**
* freemaker通过模板生成文件
* @param fileName 文件全名(含后缀)
* @param writer
* @param writeData 模板需要的数据
* @throws TemplateException
* @throws Exception
* @throws IOException
*/
private static void createFile(String fileName,Writer writer,Map writeData) throws TemplateException, Exception, IOException {
if(fileName == null || !fileName.contains("."))
throw new Exception("请输入正确的文件名");
Configuration cfg=new Configuration();
String path =FtlHandler.class.getResource("/").getPath()+"ftl";
TemplateLoader templateLoader = new FileTemplateLoader(new File(path));
cfg.setTemplateLoader(templateLoader);
cfg.setDefaultEncoding("UTF-8");//设置模板读取的编码方式,用于处理乱码
Template template = cfg.getTemplate(fileName,"UTF-8");//模板文件,支持xml,ftl 也支持html
template.process(writeData, writer);//将模板写到文件中
writer.flush();
cfg.clearTemplateCache();
writer.close();
}
}
2.在action或者controller里面把需要传入到excel中的数据获取到,然后调用工具类;
注意事项:a.在调试的过程中发现如果传入的参数为null的时候会报错,所以需要处理一下,要么在后台判断一下 xxx== null ? "" : xxx;要么就在模板中${code!' '}处理一下。
3.客户提供excel模板后把需要填充的地方都写上内容,然后用office把excel另存为《XML电子表格2003》;
注意事项:a.xml中只能存储文本,所以excel模板中不能有图片;
b.说一下踩得一个坑以及解决方案:另存为以后发现xml中在
4.把处理之后xml放到系统中,然后根据在excel中填入的数据对照着action里自己传的参数把数据替换成参数;例如:${mcdSum}等等,需要遍历输出行的话就用list
<#if mcdList?exists >
<#list mcdList as mcd>
${mcd.partName} |
${mcd.pointQty} |
${mcd.qty} |
${mcd.price} |
${mcd.cost} |
#list>
#if>
5.之后就是逐步调试,直到最后没有问能够满足需求进行导出。
注意事项:最后发现一个问题,导出之后的excel在wps中可以打开,在office中打不开就像下图一样,点击是就会报错
怎么处理呢?我是这么干的,既然报错了也给了日志就去看日志呗。找日志的时候发现是找不到的,文件夹被隐藏了,所以我直接在盘符里面搜索的日志,找到以后打开是这样的
拿到错误信息直接去找错误点就好了,第一个StyleID s418值无效,如果传过来的参数不是null就把s418改成其他的同类型的s420啥的;第二个跟第三个一样都是ss:ExpandedRowCount值是多少的时候报错,查了一圈资料,推测了一下这东西的意思大概就是最大行数之类的,可能是超过了限制吧,所以就把报错的都改成999就搞定了。最后还有一个问题就是office在打开的时候会给提示,如下图,不过点击是的时候是可以打开的,且内容无误,希望有懂的大佬解释一下。