最近在做一个简报导出的功能,要求导出word格式,上网找了很多资料,一开始选择了poi后来发现poi只能导出简单的word数据,后来偶然发现了通过FreeMaker模板生成word,说实话,还挺好用的!下面是我的一个demo!
最近因为客户的要求,需要做一个关于项目具体信息导出到word的功能。java处理word已经存在很多种方法了,但是用起来都不是那么方便,而且不太灵活,而使用xml的方法可以做到非常灵活,你可以先建好模板,然后往里面填数,模板怎么建,填出来的效果就是怎么样的。首先说说word和xml的关系,每个word它都对应着一个xml文件,也就是说你修改了xml,对应的word文件也就跟着修改了。通过word的保存功能可以将一个word文件保存为xml文件,该文件虽然是.xml格式的,但是直接双击打开的话还是使用word打开,所以你只能用txt将它打开,用txt打开之后将里面的一句话:<?mso-application progid="Word.Document"?>去掉,然后保存,接着就可以双击直接打开了,这样使用的就是IE打开的,你这样就可以查看里面的节点具体的构造。
最上面的主节点是<w:wordDocument>(如果不是的话,相信你将word文件保存成xml的时候使用的是07word,选择的是:word xml文档(*.xml),你可以选择word 2003 xml文档(*.xml)试试);该主节点下面有大致8个节点,其中我们要操作的就是<w:body>节点,该节点是word的正文节点,其他的节点没有去研究;<w:body>下面包含的节点可能会有:<w:p>段落节点、<w:tbl>表格节点。
第一步:制定word模板
第二步:另存为xml格式
第三步:将修改后的xml模版保存为ftl格式
1、修改生成的xml文件
2、<#list newsList as listKey>为FreeMaker的用法,迭代newsList中的数据
图片:
如果你需要在word中添加图片,那你就在第一步制作模板时,加入一张图片占位,然后打开xml文档,可以看到如下的一片base64编码后的代码:
<w:binData w:name="wordml://03000001.png" xml:space="preserve">iVBORw0…(很省略很省略)…CC</w:binData>
只要将 base64 的代码替换成例如: ${image} ,如下:
//后台代码如下
//word生成工具类,可直接本地生成
- package com.tgb.web;
-
- import java.io.BufferedWriter;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStreamWriter;
- import java.io.Writer;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
-
- import sun.misc.BASE64Encoder;
- import freemarker.template.Configuration;
- import freemarker.template.Template;
- import freemarker.template.TemplateException;
-
- public class t2 {
-
- private Configuration configuration = null;
-
- public t2() {
- configuration = new Configuration();
- configuration.setDefaultEncoding("UTF-8");
- }
-
- /**
- * 以下载的方式生成word,自定义路径
- * @param dataMap
- * @param out
- */
- public void createDoc(Map<String, Object> dataMap,Writer out) {
-
- // 设置模本装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载,
- // ftl文件存放路径
- configuration.setClassForTemplateLoading(this.getClass(), "/config/spring");
-
- Template t = null;
- try {
- // test.ftl为要装载的模板
- t = configuration.getTemplate("yuqing_brief_template2.ftl");
- t.setEncoding("utf-8");
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- try {
- t.process(dataMap, out);
- } catch (TemplateException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- }
-
- /**
- * 传入数据 可直接本地生成word
- * @param dataMap
- */
- public void createDoc(Map<String, Object> dataMap) {
-
- // 设置模本装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载,
- // ftl文件存放路径
- configuration.setClassForTemplateLoading(this.getClass(), "/config/spring");
-
- Template t = null;
- try {
- // test.ftl为要装载的模板
- t = configuration.getTemplate("t2_img.ftl");
- t.setEncoding("utf-8");
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // 输出文档路径及名称
- File outFile = new File("H:/'" + Math.random()*10000 + "'t2_img.doc");
- Writer out = null;
- try {
- out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
- } catch (Exception e1) {
- e1.printStackTrace();
- }
-
- try {
- t.process(dataMap, out);
- out.close();
- } catch (TemplateException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- }
-
- /**
- *
- * 注意dataMap里存放的数据Key值要与模板中的参数相对应
- *
- * @param dataMap
- */
- private Map<String, Object> getData() {
- Map<String, Object> dataMap = new HashMap<String, Object>();
- Map<String, Object> map1 = new HashMap<String, Object>();
- Map<String, Object> map2 = new HashMap<String, Object>();
-
- map1.put("title", "国泰君安*公司研究*广发证券:定增完成,如虎添翼*000776*投资银行业与经纪业行业*梁静");
- map1.put("content","报告类型=公司事件点评公司简称=广发证券公司代码=000776报告日期=Thu Aug 25 09:05:29 CST 2011研究员 =梁静报告标题=定增完成");
- map1.put("site", "上海证卷报");
- String img1 = getImageStr("H:/Tulips.jpg");
- map1.put("image", img1);
- map1.put("i", 1);//标识图片
-
- map2.put("title", "[申万销售夏敬慧] 基金仓位周报----开基仓位下降1.51%");
- map2.put("content","理财产品部分析师: 杨鹏(18930809297) 开基仓位有所下降:本周,开放式基金平均仓位继续下降。");
- map2.put("site", "上海证卷报");
- String img2 = getImageStr("H:/Penguins.jpg");
- map2.put("image", img2);
- map2.put("i", 2);//标识图片
-
- List<Map<String, Object>> newsList = new ArrayList<Map<String, Object>>();
- newsList.add(map1);
- newsList.add(map2);
- dataMap.put("newsList", newsList);
- return dataMap;
- }
-
- public String getImageStr(String imgFile) {
- InputStream in = null;
- byte[] data = null;
- try {
- in = new FileInputStream(imgFile);
- data = new byte[in.available()];
- in.read(data);
- in.close();
- } catch (FileNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- BASE64Encoder encoder = new BASE64Encoder();
- return encoder.encode(data);
- }
-
- public static void main(String[] args) {
- t2 word = new t2();
- Map<String,Object> map = word.getData();
- word.createDoc(map);
- }
-
- }
- <span style="white-space:pre"> </span>@RequestMapping(value="/exportword")
- @ResponseBody
- public String exportWord(HttpServletRequest request,HttpServletResponse response) throws IOException{
- response.setContentType("application/octet-stream; charset=UTF-8");
- response.setHeader("content-disposition", "attachment;filename=" + new SimpleDateFormat("yyyyMMddHH:mm:ss").format(new Date()) + ".doc");
- Writer out = new BufferedWriter(new OutputStreamWriter(response.getOutputStream(),"utf-8"));//重点:一定要注意编码格式,漏写编码格式将导致word无法打开(xml非法字符)
- t2 word = new t2();
- Map<String, Object> map = userService.getData();
- word.createDoc(map,out);
- out.flush();
- out.close();
- return null;
- }
OK!搞定,希望对有需要的人有用!