java中Freemaker模板导出Word(统计图)和Excel详解(附工具类)
为什么不用jxl、poi的方式进行导出呢?如果模板复杂、又包含一些动态的判断,就要在后台写很多很多判断的代码,费时费力又容易出错,使用freemaker定制模板就方便很多很多。话不多说,一再强调,思路很重要。
使用freemaker思路(相当于mvc模式下的一次请求,便于理解):
1、定制模板(新建模板里放值的地方先随便写个汉字站位,另存为xml文件类型,最后改为.ftl后缀的文件)。(相当于jsp页面)
2、后台方法查询要导出的数据,所有的数据都保存到一个map中。(相当于Contrller中获取数据的方法)
3、将map中的数据填充到模板中的站位的汉字处。(相当于jsp中用el表达式、jstl等赋值变量)
4、调用freemarker相关的类的方法及下载的方法,实现导出下载。(相当于controller中的方法带着数据响应到jsp页面的过程)
下来图文介绍每一步:
1、定制模板:
汉字"站位"进行站位;保存为xml
2、后台方法查询要导出的数据,所有的数据都保存到一个map中。
创建Map将要展示的集合,变量,对象等保存进去,如图:
3、将map中的数据填充到模板中的站位的汉字处。
将xml后缀的文件放入的开发工具中(一般放到web-info下新建的文件夹中),如下进行赋值,赋值完成后修改后缀为ftl;
扩充:
一.变量后的感叹号是如果变量不存在就给默认值,语法:variable!default_variable,不写默认值就取单元格类型的默认值。
二.<#list listAll as qingAll中取序号:${qingAll_index+1},qingAll是集合中的每一个元素的别名(as后面跟的)
三.if判断如下:s93和s95是单元格字体颜色(可以在<style>中设置)。
四。还有“??”判空的可以在网上搜索使用。
4、调用freemarker相关的类的方法及下载的方法,实现导出下载。
这里使用工具类:
import freemarker.template.Configuration;
import freemarker.template.Template;
/**
* 导出 Utils
* @author Administrator
*
*/
public class ExcelUtils {
private static final Logger logger = Logger.getLogger(ExcelUtils.class);
private static final String ENCODING ="UTF-8";
private ExcelUtils(){
throw new AssertionError();
}
/**
* 导出exce
* @param dataMap 导出的数据Map
* @param type 一个标识,可以随便写
* @param valueName web-info下.ftl文件名称(后缀也要写上)
* @param response 响应到浏览器 用于下载的一些设置
* @param request 前台请求对象,获取一些路径等
* @param excelName 导出文件的名称
* @throws IOException
*/
public static void createExcel(Map<?, ?> dataMap, String type,String valueName,HttpServletResponse response,HttpServletRequest request,String excelName) throws IOException{
InputStream inputStream = null;
ServletOutputStream out = null;
Map<String, Template> allTemplates = new HashMap<String, Template>();
String realPath = request.getSession().getServletContext().getRealPath("/");
Random random = new Random();
try {
request.setCharacterEncoding(ENCODING);
Configuration configuration = new Configuration();
configuration.setDefaultEncoding(ENCODING);
configuration.setDirectoryForTemplateLoading(new File(realPath+"WEB-INF/mailtemplate"));
allTemplates.put(type, configuration.getTemplate(valueName));
} catch (IOException ex) {
logger.error("错误信息",ex);
}
String name = "temp" + (random.nextInt(100000)) + ".xls";
File file = new File(name);
Template template = allTemplates.get(type);
try {
Writer w = new OutputStreamWriter(new FileOutputStream(file), ENCODING);
template.process(dataMap, w);
w.close();
inputStream = new FileInputStream(file);
response.setCharacterEncoding(ENCODING);
response.setContentType("application/msexcel");
response.setHeader("content-disposition", "attachment;filename="+ URLEncoder.encode(excelName + ".xls", ENCODING));
out = response.getOutputStream();
byte[] buffer = new byte[512]; // 缓冲区
int bytesToRead = -1;
// 通过循环将读入的Excel文件的内容输出到浏览器中
while ((bytesToRead = inputStream.read(buffer)) != -1) {
out.write(buffer, 0, bytesToRead);
}
out.flush();
} catch (Exception e) {
logger.error("错误信息",e);
}finally {
if (inputStream != null){
inputStream.close();
}
if (out != null){
out.close();
}
if(file.delete()){ // 删除临时文件
logger.debug("删除成功");
}
}
}
/**
* 导出exce
* @param dataMap 导出的数据Map
* @param type 一个标识,可以随便写
* @param valueName web-info下.ftl文件名称(后缀也要写上)
* @param response 响应到浏览器 用于下载的一些设置
* @param request 前台请求对象,获取一些路径等
* @param excelName 导出文件的名称
* @throws IOException
*/
public static void createWord(Map<?, ?> dataMap, String type,String valueName,HttpServletResponse response,HttpServletRequest request,String wordName) throws IOException{
InputStream inputStream = null;
ServletOutputStream out = null;
Map<String, Template> allTemplates = new HashMap<String, Template>();
String realPath = request.getSession().getServletContext().getRealPath("/");
try {
request.setCharacterEncoding(ENCODING);
Configuration configuration = new Configuration();
configuration.setDefaultEncoding(ENCODING);
configuration.setDirectoryForTemplateLoading(new File(realPath+"WEB-INF/mailtemplate"));
allTemplates.put(type, configuration.getTemplate(valueName));
} catch (IOException ex) {
logger.error("错误信息",ex);
}
String name = "temp" + (int) (Math.random() * 100000) + ".doc";
File file = new File(name);
Template template = allTemplates.get(type);
try {
Writer w = new OutputStreamWriter(new FileOutputStream(file), ENCODING);
template.process(dataMap, w);
w.close();
inputStream = new FileInputStream(file);
response.setCharacterEncoding(ENCODING);
response.setContentType("application/msword");
response.setHeader("content-disposition", "attachment;filename="+ URLEncoder.encode(wordName + ".doc", ENCODING));
out = response.getOutputStream();
byte[] buffer = new byte[512]; // 缓冲区
int bytesToRead = -1;
// 通过循环将读入的Excel文件的内容输出到浏览器中
while ((bytesToRead = inputStream.read(buffer)) != -1) {
out.write(buffer, 0, bytesToRead);
}
out.flush();
} catch (Exception e) {
logger.error("错误信息",e);
}finally {
if (inputStream != null)
inputStream.close();
if (out != null)
out.close();
}
}
}
word下载和excel一样,word中有统计图的思路如下:(将统计图生成变量替换占位符)
1、插入一张图片占位。
2、获取ECharts图形生成的Base64编码格式的数据,保存到Map中。
3、在模板文件中,在占位的位置放入Map中的数据。
具体图文代码如下:
1.word中插入一张图片
2.获取ECharts图形生成的Base64编码格式的数据,保存到Map中。
一:前台获取Base64编码格式的数据如下:图片在word中的大小可在ECharts所在的jsp中调节。(怎样生成echarts和echarts赋值在上一篇中有介绍):下图中是两个ECharts。
二:后台对获得的数据进行特殊处理:
3、在模板文件中,在占位的位置放入Map中的数据。
实现效果:点击页面的导出按钮,浏览器下载文件。