FreeMaker+Xml导出word(含图片)

最近在做一个简报导出的功能,要求导出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生成工具类,可直接本地生成

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.tgb.web;  
  2.   
  3. import java.io.BufferedWriter;  
  4. import java.io.File;  
  5. import java.io.FileInputStream;  
  6. import java.io.FileNotFoundException;  
  7. import java.io.FileOutputStream;  
  8. import java.io.IOException;  
  9. import java.io.InputStream;  
  10. import java.io.OutputStreamWriter;  
  11. import java.io.Writer;  
  12. import java.util.ArrayList;  
  13. import java.util.HashMap;  
  14. import java.util.List;  
  15. import java.util.Map;  
  16.   
  17. import sun.misc.BASE64Encoder;  
  18. import freemarker.template.Configuration;  
  19. import freemarker.template.Template;  
  20. import freemarker.template.TemplateException;  
  21.   
  22. public class t2 {  
  23.   
  24.     private Configuration configuration = null;  
  25.   
  26.     public t2() {  
  27.         configuration = new Configuration();  
  28.         configuration.setDefaultEncoding("UTF-8");  
  29.     }  
  30.   
  31.     /**  
  32.      * 以下载的方式生成word,自定义路径  
  33.      * @param dataMap  
  34.      * @param out  
  35.      */  
  36.     public void createDoc(Map<String, Object> dataMap,Writer out) {  
  37.   
  38.         // 设置模本装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载,  
  39.         // ftl文件存放路径  
  40.         configuration.setClassForTemplateLoading(this.getClass(), "/config/spring");  
  41.   
  42.         Template t = null;  
  43.         try {  
  44.             // test.ftl为要装载的模板  
  45.             t = configuration.getTemplate("yuqing_brief_template2.ftl");  
  46.             t.setEncoding("utf-8");  
  47.         } catch (IOException e) {  
  48.             e.printStackTrace();  
  49.         }  
  50.   
  51.         try {  
  52.             t.process(dataMap, out);  
  53.         } catch (TemplateException e) {  
  54.             e.printStackTrace();  
  55.         } catch (IOException e) {  
  56.             e.printStackTrace();  
  57.         }  
  58.   
  59.     }  
  60.       
  61.     /**  
  62.      * 传入数据 可直接本地生成word  
  63.      * @param dataMap  
  64.      */  
  65.     public void createDoc(Map<String, Object> dataMap) {  
  66.   
  67.         // 设置模本装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载,  
  68.         // ftl文件存放路径  
  69.         configuration.setClassForTemplateLoading(this.getClass(), "/config/spring");  
  70.   
  71.         Template t = null;  
  72.         try {  
  73.             // test.ftl为要装载的模板  
  74.             t = configuration.getTemplate("t2_img.ftl");  
  75.             t.setEncoding("utf-8");  
  76.         } catch (IOException e) {  
  77.             e.printStackTrace();  
  78.         }  
  79.   
  80.         // 输出文档路径及名称  
  81.         File outFile = new File("H:/'" + Math.random()*10000 + "'t2_img.doc");  
  82.         Writer out = null;  
  83.         try {  
  84.             out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));  
  85.         } catch (Exception e1) {  
  86.             e1.printStackTrace();  
  87.         }  
  88.   
  89.         try {  
  90.             t.process(dataMap, out);  
  91.             out.close();  
  92.         } catch (TemplateException e) {  
  93.             e.printStackTrace();  
  94.         } catch (IOException e) {  
  95.             e.printStackTrace();  
  96.         }  
  97.   
  98.     }  
  99.   
  100.     /**  
  101.      *   
  102.      * 注意dataMap里存放的数据Key值要与模板中的参数相对应  
  103.      *   
  104.      * @param dataMap  
  105.      */  
  106.     private Map<String, Object> getData() {  
  107.         Map<String, Object> dataMap = new HashMap<String, Object>();  
  108.         Map<String, Object> map1 = new HashMap<String, Object>();  
  109.         Map<String, Object> map2 = new HashMap<String, Object>();  
  110.   
  111.         map1.put("title", "国泰君安*公司研究*广发证券:定增完成,如虎添翼*000776*投资银行业与经纪业行业*梁静");  
  112.         map1.put("content","报告类型=公司事件点评公司简称=广发证券公司代码=000776报告日期=Thu Aug 25 09:05:29 CST 2011研究员 =梁静报告标题=定增完成");  
  113.         map1.put("site", "上海证卷报");  
  114.         String img1 = getImageStr("H:/Tulips.jpg");  
  115.         map1.put("image", img1);  
  116.         map1.put("i", 1);//标识图片  
  117.   
  118.         map2.put("title", "[申万销售夏敬慧] 基金仓位周报----开基仓位下降1.51%");  
  119.         map2.put("content","理财产品部分析师: 杨鹏(18930809297) 开基仓位有所下降:本周,开放式基金平均仓位继续下降。");  
  120.         map2.put("site", "上海证卷报");  
  121.         String img2 = getImageStr("H:/Penguins.jpg");  
  122.         map2.put("image", img2);  
  123.         map2.put("i", 2);//标识图片  
  124.   
  125.         List<Map<String, Object>> newsList = new ArrayList<Map<String, Object>>();  
  126.         newsList.add(map1);  
  127.         newsList.add(map2);  
  128.         dataMap.put("newsList", newsList);  
  129.         return dataMap;  
  130.     }  
  131.   
  132.     public String getImageStr(String imgFile) {  
  133.         InputStream in = null;  
  134.         byte[] data = null;  
  135.         try {  
  136.             in = new FileInputStream(imgFile);  
  137.             data = new byte[in.available()];  
  138.             in.read(data);  
  139.             in.close();  
  140.         } catch (FileNotFoundException e) {  
  141.             // TODO Auto-generated catch block  
  142.             e.printStackTrace();  
  143.         } catch (IOException e) {  
  144.             // TODO Auto-generated catch block  
  145.             e.printStackTrace();  
  146.         }  
  147.         BASE64Encoder encoder = new BASE64Encoder();  
  148.         return encoder.encode(data);  
  149.     }  
  150.   
  151.     public static void main(String[] args) {  
  152.         t2 word = new t2();  
  153.         Map<String,Object> map = word.getData();  
  154.         word.createDoc(map);  
  155.     }  
  156.   
  157. }  


 
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //控制层代码(本人用的是springmvc)  
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <span style="white-space:pre">    </span>@RequestMapping(value="/exportword")  
  2.     @ResponseBody  
  3.     public String exportWord(HttpServletRequest request,HttpServletResponse response) throws IOException{  
  4.         response.setContentType("application/octet-stream; charset=UTF-8");    
  5.         response.setHeader("content-disposition", "attachment;filename=" + new SimpleDateFormat("yyyyMMddHH:mm:ss").format(new Date()) + ".doc");  
  6.         Writer out = new BufferedWriter(new OutputStreamWriter(response.getOutputStream(),"utf-8"));//重点:一定要注意编码格式,漏写编码格式将导致word无法打开(xml非法字符)         
  7.         t2 word = new t2();  
  8.         Map<String, Object> map = userService.getData();  
  9.         word.createDoc(map,out);  
  10.         out.flush();  
  11.         out.close();  
  12.         return null;  
  13.     }  

OK!搞定,希望对有需要的人有用!
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值