Java 导出 excel 表格 (Freemarker)

Freemarker报表导出
本文详细介绍如何使用Freemarker框架结合SSM框架和SQLServer2008R2数据库,实现复杂数据报表的导出功能,包括配置、模板创建及数据封装过程。

技术选型:ssm框架、数据库搭配的是SQLServer 2008 R2、maven项目。

业务需求:需要导出数据报表、要求格式标题字体颜色等配置。

选用技术:freemarker 可支持多种标签类型、可以自定义表格样式、使用方便简单。

 

一、

1.首先项目引入 jar 包

<!-- 项目属性 -->
<properties>
    <freemarker.version>2.3.20</freemarker.version>
</properties>
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>${freemarker.version}</version>
</dependency>

二、

1.新建一个 excel 文件、自定义好样式、如下:

 

2.讲表格另存为一下、选择文件类型为 “XML” 类型、如下:

 

3.用浏览器打开会显示如下、个人原因觉得用 Notepad 打开很乱、所以习惯用浏览器打开、然后粘贴到文件中。当然你也可以直接粘贴到文件中、这个随意。

 

三、

1.回到开发工具项目中建立一个文件夹、专门放 freemarker 的模板。如下:

2.在该文件夹下新建一个 .ftl 文件、把新建好的 xml 文件内容粘贴到 .ftl 文件中。如下:

用 wps excel 生成的 xml 文件没有指定版本。

用 ms excel 生成的 xml 文件头前多两句:

<?xml version="1.0"?>    显示普通的xml版本信息

<?mso-application progid="Excel.Sheet"?>   让Office去打开EXCEL处理XML

这两句话有没有并没有什么影响。

3.简单的说一下 .ftl 文件中的标签。

所有 <style> 都在 <styles> 里面。

<Style ss:ID="s59">  设定 ss:ID  在需要使用样式的地方调用该 ID 则可,调用方式:<Cell ss:StyleID="s59"/>  使用 ss:StyleID="s59"  则可。

<Data ss:Type="String"> "数据 "</Data>、data标签中写数据、ss:Type 指单元格类型、可以是 String、Number等。

<Worksheet ss:Name="Sheet2">  worksheet 指代工作簿、只需要一个工作簿的话、后面的 worksheet 标签全部删除则可。

4.创建 Util 工具类。一个将 xml 生成 excel 的工具类、一个下载类。如下:

public class TemplateParseUtil {
	/**
	 * 解析模板生成Excel
	 * @param templateDir  模板目录
	 * @param templateName 模板名称
	 * @param path 生成的文件路径
	 * @param data 数据参数
	 * @throws IOException
	 * @throws TemplateException
	 */
	@SuppressWarnings("deprecation")
	public static void parse(String templateDir,String templateName,String path,Map<String,Object> data) throws IOException, TemplateException {
		//初始化工作
		Configuration cfg = new Configuration();
		//设置默认编码格式为UTF-8
		cfg.setDefaultEncoding("UTF-8"); 
		//全局数字格式
		cfg.setNumberFormat("0.00");
		//设置模板文件位置
		cfg.setDirectoryForTemplateLoading(new File(templateDir));
		cfg.setObjectWrapper(new DefaultObjectWrapper());
		//加载模板
		Template template = cfg.getTemplate(templateName,"utf-8");
		OutputStreamWriter writer = null;
		try{
			//填充数据至Excel
			writer = new OutputStreamWriter(new FileOutputStream(path),"UTF-8");
			template.process(data, writer);
			writer.flush();
		}finally{
			writer.close();
		}	
	}


	/**
	 * 解析模板返回字节数组
	 * @param templateDir  模板目录
	 * @param templateName 模板名称
	 * @param data 数据参数
	 * @throws IOException
	 * @throws TemplateException
	 */
	public static byte[] parse(String templateDir,String templateName,Map<String,Object> data) throws TemplateException, IOException{
		Configuration cfg = new Configuration();
		cfg.setDefaultEncoding("UTF-8");
		cfg.setNumberFormat("0.00");
		cfg.setDirectoryForTemplateLoading(new File(templateDir));
		cfg.setObjectWrapper(new DefaultObjectWrapper());
		Template template = cfg.getTemplate(templateName,"utf-8");
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		Writer out = new OutputStreamWriter(outStream,"UTF-8");
		template.process(data, out);
		return outStream.toByteArray();
	}
	
	/**
	 * 自定义模板字符串解析
	 * @param templateStr  模板字符串
	 * @param data 数据  
	 * @return 解析后的字符串
	 * @throws IOException
	 * @throws TemplateException
	 */
	public static String parse(String templateStr, Map<String, Object> data)
			throws IOException, TemplateException {
		Configuration cfg = new Configuration();
		cfg.setNumberFormat("#.##");
		//设置装载模板
		StringTemplateLoader stringLoader = new StringTemplateLoader();	
		stringLoader.putTemplate("myTemplate", templateStr);	
		cfg.setTemplateLoader(stringLoader);
		//加载装载的模板
		Template temp = cfg.getTemplate("myTemplate", "utf-8");
		Writer out = new StringWriter();
		temp.process(data, out);
		return out.toString();
	}
	
}
public class DownloadFile {
	
	public static void downloadFile(String filePath,HttpServletResponse response){
		BufferedInputStream bis = null;  
	    BufferedOutputStream bos = null;
	    try {
	    	 // path是指欲下载的文件的路径。
            File file = new File(filePath);
            // 取得文件名。
            String filename = file.getName();
            // 设置response的Header
            String downLoadName = new String(filename.getBytes("gbk"), "iso8859-1");
            response.setHeader("Content-Disposition", "attachment; filename=" + downLoadName);
            response.addHeader("Content-Length", "" + file.length());
            response.setContentType("application/octet-stream");
            bis = new BufferedInputStream(new FileInputStream(filePath));
            bos = new BufferedOutputStream(response.getOutputStream());  
            byte[] buff = new byte[2048];
            int bytesRead;  
            while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {  
                bos.write(buff, 0, bytesRead);  
            }  
            bis.close();  
            bos.close();  
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public static boolean deleteFile(String filePath){
		boolean flag = false;
		File file = new File(filePath);
		  if(file.exists()){
		    flag = file.delete();
		   }
		 return flag;
	}

}

5. 封装数据。

1. 使用 map 封装

/**
 * 日月报导出
 */
@RequestMapping(value = "exportElectric/{type}")
public void exportElectric(@PathVariable(value = "type")int type,Technology technology, HttpServletRequest request, HttpServletResponse response) throws Exception {
		// type == 1  是 日报
		String fileName;
		Date start = technology.getDate(),end;
		if(type == 1){
			fileName = "电能消耗统计日报";
			if(technology.getDate()==null){
				start = Global.getDay(0);
			}
			Calendar cal = Calendar.getInstance();
			cal.setTime(start);
			cal.add(Calendar.DATE,1);
			end = cal.getTime();
		}else{
			fileName = "电能消耗统计月报";
			if(technology.getDate() == null){
				start = new Date();
			}
			Map mapDate = FactoryDateUtils.monthDate2FactoryDate(start);
			Calendar cal = Calendar.getInstance();
			cal.setTime((Date) mapDate.get("startDate"));
			cal.add(Calendar.DATE,1);
			end = cal.getTime();
			start = (Date) mapDate.get("endDate");
		}
		// 获取小班组
		List<Technology> technologyList = technologyService.queryTeamList(technology);
		Map<String,Object> map = data(technologyList,start,end);
		List<Map<String,Object>> reslist = (List<Map<String,Object>>)map.get("list");
		// 要导出的数据
		Map<String, Object> dataMap = new HashMap<String, Object>();
		dataMap.put("clist", reslist);
		dataMap.put("dataSize", reslist.size() + 10);
		dataMap.put("fileName", fileName);
		dataMap.put("zMap", map);
		String basePath = request.getSession().getServletContext().getRealPath("/");
		// 模板保存路径
		String demoPath = basePath + "exportTemp";
		// 导出后文件存储位置
		String savePath = fileName+".xls";
		// 要导出的数据的集合
		TemplateParseUtil.parse(demoPath, "test.ftl", savePath, dataMap);
		DownloadFile.downloadFile(savePath, response);
		DownloadFile.deleteFile(savePath);
	}

dataMap:封装好数据

basePath:模板保存路径也就是你创建的 .ftl 文件的位置

savePath:保存文件路径名称

table 标签下的 第一行 row 为标题、可以自定义、也可以从后台传、接收方式 ${}

在你的标题后的 <Row> 标签后、删除多余的 <Row> 标签,做一个循环。

<#list clist as item> </#list>

标签固定写法、clist 是后端封装好的数据名称、这个随意更换。

我的这里 clist 是 List<Map<String,Object>> 格式、取值方式:${item["team"]!} 、后面跟 “!”的作用是解决数据空的问题。

2. 使用 entity 封装

其操作与 Map 封装一直、其中循环方式取参不一样、直接取参则可。如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值