zoukankan      html  css  js  c++  java
  • Java 用Freemarker完美导出word文档(带图片)

    前言

    最近在项目中,因客户要求,将页面内容(如合同协议)导出成word,在网上翻了好多,感觉太乱了,不过最后还是较好解决了这个问题。

    准备材料

    1.word原件 2.编辑器(推荐Firstobject free XML editor)

    实现步骤

    1.用Microsoft Office Word打开word原件;

    2.把需要动态修改的内容替换成***,如果有图片,尽量选择较小的图片几十K左右,并调整好位置;

    3.另存为,选择保存类型Word 2003 XML 文档(*.xml)【这里说一下为什么用Microsoft Office Word打开且要保存为Word 2003XML,本人亲测,用WPS找不到Word 2003XML选项,如果保存为Word XML,会有兼容问题,避免出现导出的word文档不能用Word 2003打开的问题】;

    4.用Firstobject free XML editor打开文件,选择Tools下的Indent【或者按快捷键F8】格式化文件内容。左边是文档结构,右边是文档内容;

    5. 将文档内容中需要动态修改内容的地方,换成freemarker的标识。其实就是Map<String, Object>中key,如${landName};

    6.在加入了图片占位的地方,会看到一片base64编码后的代码,把base64替换成${image},也就是Map<String, Object>中key,值必须要处理成base64;

      代码如:<w:binData w:name="wordml://自定义.png" xml:space="preserve">${image}</w:binData>

      注意:“>${image}<”这尖括号中间不能加任何其他的诸如空格,tab,换行等符号。

      如果需要循环,则使用:<#list maps as map></#list>  maps是Map<String, Object>中key,值为数组,map为自定义;

    7. 标识替换完之后,模板就弄完了,另存为.ftl后缀文件即可。注意:一定不要用word打开ftl模板文件,否则xml内容会发生变化,导致前面的工作白做了。

    代码实现

    工具类WordUtils.Java

    复制代码
     1 import java.io.File;
     2 import java.io.FileInputStream;
     3 import java.io.FileOutputStream;
     4 import java.io.IOException;
     5 import java.io.InputStream;
     6 import java.io.OutputStreamWriter;
     7 import java.io.Writer;
     8 import java.net.URLEncoder;
     9 import java.util.Date;
    10 import java.util.Map;
    11 
    12 import javax.servlet.ServletOutputStream;
    13 import javax.servlet.http.HttpServletRequest;
    14 import javax.servlet.http.HttpServletResponse;
    15 
    16 import freemarker.template.Configuration;
    17 import freemarker.template.Template;
    18 
    19 public class WordUtils {
    20      //配置信息,代码本身写的还是很可读的,就不过多注解了  
    21     private static Configuration configuration = null;  
    22     //这里注意的是利用WordUtils的类加载器动态获得模板文件的位置  
    23    // private static final String templateFolder = WordUtils.class.getClassLoader().getResource("../../").getPath() + "WEB-INF/templetes/";  
    24     private static final String templateFolder = "H:/我的项目/lm/lm/web/src/main/webapp/WEB-INF/templates";  
    25     static {  
    26         configuration = new Configuration();  
    27         configuration.setDefaultEncoding("utf-8");  
    28         try {  
    29             configuration.setDirectoryForTemplateLoading(new File(templateFolder));  
    30         } catch (IOException e) {  
    31             e.printStackTrace();  
    32         }  
    33    }  
    34   
    35     private WordUtils() {  
    36         throw new AssertionError();  
    37     }  
    38   
    39     public static void exportMillCertificateWord(HttpServletRequest request, HttpServletResponse response, Map map,String title,String ftlFile) throws IOException {  
    40         Template freemarkerTemplate = configuration.getTemplate(ftlFile);  
    41         File file = null;  
    42         InputStream fin = null;  
    43         ServletOutputStream out = null;  
    44         try {  
    45             // 调用工具类的createDoc方法生成Word文档  
    46             file = createDoc(map,freemarkerTemplate);  
    47             fin = new FileInputStream(file);  
    48   
    49             response.setCharacterEncoding("utf-8");  
    50             response.setContentType("application/msword");  
    51             // 设置浏览器以下载的方式处理该文件名  
    52             String fileName = title+DateUtil.formatDateDetailTime(new Date()) + ".doc";  
    53             response.setHeader("Content-Disposition", "attachment;filename="  
    54                     .concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8"))));  
    55   
    56             out = response.getOutputStream();  
    57             byte[] buffer = new byte[512];  // 缓冲区  
    58             int bytesToRead = -1;  
    59             // 通过循环将读入的Word文件的内容输出到浏览器中  
    60             while((bytesToRead = fin.read(buffer)) != -1) {  
    61                 out.write(buffer, 0, bytesToRead);  
    62             }  
    63         } finally {  
    64             if(fin != null) fin.close();  
    65             if(out != null) out.close();  
    66             if(file != null) file.delete(); // 删除临时文件  
    67         }  
    68     }  
    69   
    70     private static File createDoc(Map<?, ?> dataMap, Template template) {  
    71         String name =  "sellPlan.doc";  
    72         File f = new File(name);  
    73         Template t = template;  
    74         try {  
    75             // 这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开  
    76             Writer w = new OutputStreamWriter(new FileOutputStream(f), "utf-8");  
    77             t.process(dataMap, w);  
    78             w.close();  
    79         } catch (Exception ex) {  
    80             ex.printStackTrace();  
    81             throw new RuntimeException(ex);  
    82         }  
    83         return f;  
    84     }  
    85 }
    复制代码

    Action

    复制代码
     1 @RequestMapping("/exportSellPlan")
     2     public @ResponseBody void exportSellPlan(Long id){
     3         Calendar calendar = Calendar.getInstance();// 取当前日期。
     4         if(id!=null){
     5             SellPlan plan=sellService.getSellPlanInfo(id);
     6              //获得数据  
     7             Map<String, Object> map = new HashMap<String, Object>(); 
     8             map.put("bYear", plan.getBusinessYear()!=null?plan.getBusinessYear():"");
     9             map.put("lYear", plan.getLiveYear()!=null?plan.getLiveYear():"");
    10             map.put("leader",plan.getLeader()!=null?plan.getLeader():""); 
    11             map.put("phone", plan.getPhone()!=null?plan.getPhone():"");
    12             map.put("curYear", calendar.get(Calendar.YEAR)+"");
    13             map.put("image", getImageBase(plan.getPositionImage()));
    14             try {
    15                 WordUtils.exportMillCertificateWord(getRequest(),getResponse(),map,"方案","sellPlan.ftl");
    16             } catch (IOException e) {
    17                 // TODO Auto-generated catch block
    18                 e.printStackTrace();
    19             }    
    20         }
    21     }
    复制代码

    Base64处理

    复制代码
     1  //获得图片的base64码
     2     @SuppressWarnings("deprecation")
     3     public String getImageBase(String src) {
     4         if(src==null||src==""){
     5             return "";
     6         }
     7         File file = new File(getRequest().getRealPath("/")+src.replace(getRequest().getContextPath(), ""));
     8         if(!file.exists()) {
     9             return "";
    10         }
    11         InputStream in = null;
    12         byte[] data = null;  
    13         try {
    14             in = new FileInputStream(file);
    15         } catch (FileNotFoundException e1) {
    16             e1.printStackTrace();
    17         }
    18         try {  
    19             data = new byte[in.available()];  
    20             in.read(data);  
    21             in.close();  
    22         } catch (IOException e) {  
    23           e.printStackTrace();  
    24         } 
    25         BASE64Encoder encoder = new BASE64Encoder();
    26         return encoder.encode(data);
    27     }
    复制代码

    Javascript

    1 window.location.href="<%=path%>/exportSellPlan?id=" + id;

    pom.xml

        <dependency>
                <groupId>org.freemarker</groupId>
                <artifactId>freemarker</artifactId>
                <version>2.3.20</version>
            </dependency>

    结束语

    如果对Freemarker标签不熟的,可以在网上先学习下,了解文档结构。

    相关链接

    Firstobject free XML editor下载地址:http://www.firstobject.com/dn_editor.htm

    freemarker 官网:http://freemarker.org/

  • 相关阅读:
    .NET Core 1.0正式发布
    【Azure Active Directory】单一登录 (SAML 协议)
    js原型链prototype与__proto__以及new表达式
    Claims Based Authentication and Token Based Authentication和WIF
    try-catch-finally对返回值的影响
    基于任务的异步编程模式,Task-based Asynchronous Pattern
    Session.Abandon-Session.Clear-Session.RemoveAll
    Html.Partial方法和Html.RenderPartial方法
    dynamic和nullable一起使用时的注意
    C#获取文件的Content-Type(MIME Type)的方法
  • 原文地址:https://www.cnblogs.com/taiyanhong/p/8532250.html
Copyright © 2011-2022 走看看