Freemarker 导出 Word 文档

  • Post author:
  • Post category:其他


本文内容:对freemarker 的介绍以及在springboot 中整合freemarker 以实现word 导出功能的代码实现。

1

介绍

FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据,并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。

FreeMarker是免费的,基于Apache许可证2.0版本发布。其模板编写为FreeMarker Template Language(FTL),属于简单、专用的语言。需要准备数据在真实编程语言中来显示,比如数据库查询和业务运算,之后模板显示已经准备好的数据。在模板中,主要用于如何展现数据,而在模板之外注意于要展示什么数据。

2

引入依赖

pom.xml

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

3

修改配置文件

application.properties

# 是否允许HttpServletRequest属性覆盖(隐藏)控制器生成的同名模型属性。
spring.freemarker.allow-request-override=false
# 是否允许HttpSession属性覆盖(隐藏)控制器生成的同名模型属性。
spring.freemarker.allow-session-override=false
# 是否启用模板缓存。
spring.freemarker.cache=false
# 模板编码。
spring.freemarker.charset=UTF-8
# 是否检查模板位置是否存在。
spring.freemarker.check-template-location=true
# Content-Type value.
spring.freemarker.content-type=text/html
# 是否启用freemarker
spring.freemarker.enabled=true
# 设定所有request的属性在merge到模板的时候,是否要都添加到model中.
spring.freemarker.expose-request-attributes=false
# 是否在merge模板的时候,将HttpSession属性都添加到model中
spring.freemarker.expose-session-attributes=false
# 设定是否以springMacroRequestContext的形式暴露RequestContext给Spring’s macro library使用
spring.freemarker.expose-spring-macro-helpers=true
# 是否优先从文件系统加载template,以支持热加载,默认为true
spring.freemarker.prefer-file-system-access=true
# 设定模板的后缀.
spring.freemarker.suffix=.ftl
# 设定模板的加载路径,多个以逗号分隔,默认: 
spring.freemarker.template-loader-path=classpath:/templates/
# 设定FreeMarker keys.
spring.freemarker.settings.template_update_delay=0
spring.freemarker.settings.default_encoding=UTF-8
#spring.freemarker.settings.classic_compatible=true

4

编写模板文件


新建word 模板

新建一个word文档wordLoading.doc,将模板内容替换成变量,这里变量要一次性写完如${user.userName}。

注意:如果变量和符号没有一次性写完,例如先写${},再统一加上变量名,这时当你打开xml的时候”${user.userName}”的“$”,“{}” ,“user.userName”就会分开,导出时会出错。


另存为xml 文件

将wordLoading.doc另存为xml 文件。

注意:这里选择的是2003 版本的,这样的模板可以兼容wps与office 。

打开wordLoading.xml 文件,Ctrl + F 查找 $  字符,检查变量和符号是否正常。如果$ 分离开来,建议重新修改上一步的word 文档。


保存模板文件到项目中

将wordLoading.xml的后缀名改成ftl,即wordLoading.ftl 模板,将模板放到项目中去。这里我选择的是resources/template 目录。

5

编写工具类

DocumentHandler.java

public class DocumentHandler {
	
	// Configuration存储一些全局常量和常用设置
	private Configuration configuration = null;
	// 构造函数生成实例并设置编码
	@SuppressWarnings("deprecation")
	public DocumentHandler() {
		configuration = new Configuration();
		configuration.setDefaultEncoding("utf-8");
	}
	/**
	 * 
	 * 导出word文档,导出到本地
	 * 
	 * @param tempName,要使用的模板
	 * 
	 * @param docName,导出文档名称
	 * 
	 * @param dataMap,模板中变量数据
	 * 
	 * @param outFile,输出文档路径
	 * 
	 */
	@SuppressWarnings("deprecation")
	public boolean exportDoc(String tempName, Map<?, ?> dataMap, File outFile) {
		boolean status = false;
		// 设置模本装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载,
		configuration.setClassForTemplateLoading(this.getClass(), "/template");
		Template t = null;
		try {
			// tempName.ftl为要装载的模板
			t = configuration.getTemplate(tempName + ".ftl");
			t.setEncoding("utf-8");
		} catch (IOException e) {
			e.printStackTrace();
		}
		Writer out = null;
		try {
			out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
			status = true;
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		try {
			t.process(dataMap, out);
			out.close();
		} catch (TemplateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return status;
	}
	/**
	 * 
	 * 导出word文档,响应到请求端
	 * 
	 * @param tempName,要使用的模板
	 * 
	 * @param docName,导出文档名称
	 * 
	 * @param dataMap,模板中变量数据
	 * 
	 * @param resp,HttpServletResponse
	 * 
	 */
	@SuppressWarnings("deprecation")
	public boolean exportDoc(String tempName, String docName, Map<?, ?> dataMap, HttpServletResponse resp) {
		boolean status = false;
		ServletOutputStream sos = null;
		InputStream fin = null;
		if (resp != null) {
			resp.reset();
		}
		// 设置模本装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载。参数2为模板路径
		configuration.setClassForTemplateLoading(this.getClass(), "/template");
		Template t = null;
		try {
			// tempName.ftl为要装载的模板
			t = configuration.getTemplate(tempName + ".ftl");
			t.setEncoding("utf-8");
			System.out.println(t.getName());
		} catch (IOException e) {
			e.printStackTrace();
		}
		// 输出文档路径及名称 ,以临时文件的形式导出服务器,再进行下载
		String name = "temp" + (int) (Math.random() * 100000) + ".doc";
		File outFile = new File(name);
		Writer out = null;
		try {
			out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
			status = true;
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		try {
			t.process(dataMap, out);
			out.close();
		} catch (TemplateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			fin = new FileInputStream(outFile);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		// 文档下载
		resp.setCharacterEncoding("utf-8");
		resp.setContentType("application/msword");
		try {
			docName = new String(docName.getBytes("UTF-8"), "ISO-8859-1");
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		}
		resp.setHeader("Content-disposition", "attachment;filename=" + docName + ".doc");
		try {
			sos = resp.getOutputStream();
		} catch (IOException e) {
			e.printStackTrace();
		}
		byte[] buffer = new byte[512]; // 缓冲区
		int bytesToRead = -1;
		// 通过循环将读入的Word文件的内容输出到浏览器中
		try {
			while ((bytesToRead = fin.read(buffer)) != -1) {
				sos.write(buffer, 0, bytesToRead);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (fin != null)
				try {
					fin.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			if (sos != null)
				try {
					sos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			if (outFile != null)
				outFile.delete(); // 删除临时文件
		}
		return status;
	}
}

6

编写测试方法

FreemarkerController.java

@Controller
public class WordDownLoading {
	
	// localhost:8080/freemarker/exportWord
	@RequestMapping("exportWord")
	@ResponseBody
	public String freemaker(HttpServletRequest req,HttpServletResponse resp) {
		List<Map<String, Object>> users=initMap();
		System.out.println(users);
		Map<String,Object> map=new HashMap<String,Object>();
		map.put("userList",users);
		System.out.println(map);
		boolean b =new DocumentHandler().exportDoc("wordLoading", "exportWord", map, resp);
		System.out.println(b);
		return "Success";
	}
	public List<Map<String, Object>> initMap(){
		List<Map<String, Object>> users=new ArrayList<Map<String,Object>>(); 		
        Map<String, Object> map=new HashMap<String, Object>();  
        map.put("userName", "张三");  
        map.put("userPassword", "890123");    
        map.put("age", 18);    
        users.add(map);  
        map=new HashMap<String, Object>();
        map.put("userName", "李四");  
        map.put("userPassword", "901234");    
        map.put("age", 23);    
        users.add(map); 
        map=new HashMap<String, Object>();  
        map.put("userName", "王五");  
        map.put("userPassword", "012345");    
        map.put("age", 14);    
        users.add(map);  
        map=new HashMap<String, Object>();
        map.put("userName", "赵六");  
        map.put("userPassword", "901234");    
        map.put("age", 23);    
        users.add(map);  
        map=new HashMap<String, Object>();
        map.put("userName", "田七");  
        map.put("userPassword", "234567");    
        map.put("age", 32);    
        users.add(map);         
		return users;
	}
}

7

浏览器访问测试

启动springboot项目,使用浏览器访问以下网址:

localhost:8080/freemarker/exportWord

能下载exportWord.doc 文档即为成功。

至此,本文结束。欢迎各位关注我的公众号:暗星涌动。



版权声明:本文为qq_42449106原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。