【freemaker實現導出word②】代碼實現導出word(包括導出list數據和導出圖片到word)

前面文章已經分享瞭如何建立導出word須要用到的xml/ftl模板了,接下來這裏要給你們分享的是如何用後臺製做導出word的代碼工具和controller實現。html

一、首先是工具類,沒有工具,談何實現呢?下面貼我這邊導出word的utils,你們能夠直接複製粘貼到大家項目就能夠引用了。java

package com.*.util;

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.Map;

import javax.servlet.http.HttpServletRequest;

import Decoder.BASE64Encoder;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;

/**
 * 類名稱:DocUtil
 * 類描述:導出word工具類
 */
public class DocUtil {
    public Configuration configure=null;
    
    public DocUtil(){
        configure= new Configuration(Configuration.getVersion());
        configure.setDefaultEncoding("utf-8");
    }
    /**
     * 根據Doc模板生成word文件
     * @param dataMap 須要填入模板的數據
     * @param downloadType 文件名稱
     * @param savePath 保存路徑
     */
    public File createDoc(Map<String,Object> dataMap,String modelPath,String downloadType,HttpServletRequest request){
        String name = "temp" + (int) (Math.random() * 100000) + ".doc";  
        File f = new File(name); 
        //加載須要裝填的模板
        Template template=null;
        try {
            
            //設置模板裝置方法和路徑,FreeMarker支持多種模板裝載方法。能夠重servlet,classpath,數據庫裝載。
            //加載模板文件,放在/uploadFiles/file/demoDoc下
            configure.setServletContextForTemplateLoading(request.getServletContext(), modelPath);
            //設置對象包裝器
//            configure.setObjectWrapper(new DefaultObjectWrapper());
            //設置異常處理器
            configure.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
            //定義Template對象,注意模板類型名字與downloadType要一致
            template=configure.getTemplate(downloadType);
           
            Writer out = new OutputStreamWriter(new FileOutputStream(f), "utf-8");
            template.process(dataMap, out);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }
         return f;  
    }
    
    /**
     * 根據Doc模板生成word文件
     * @param dataMap 須要填入模板的數據
     * @param downloadType 文件名稱
     * @param savePath 保存路徑
     */
    public void createXls(Map<String,Object> dataMap,String downloadType,String webPath,String fileName,String savePath){
        System.out.println(savePath.substring(savePath.length()-1));
        if(savePath.substring(savePath.length()-1).equals(File.separator)) {
            savePath = savePath + "uploadFiles" + File.separator + "file" + File.separator + "jdhDailySheet"+ File.separator;
        }else {
            savePath = savePath  + File.separator + "uploadFiles" + File.separator + "file" + File.separator + "jdhDailySheet"+ File.separator;
        }
        File f = new File(savePath+fileName); 
        
        //加載須要裝填的模板
        Template template=null;
        try {
            if(!f.getParentFile().exists()){
                f.getParentFile().mkdirs();
            }
            if(f.exists() && f.isFile()){
                f.delete();
            } else {
                f.createNewFile();
            }
            
            //設置模板裝置方法和路徑,FreeMarker支持多種模板裝載方法。能夠重servlet,classpath,數據庫裝載。
            //加載模板文件,放在/uploadFiles/file/demoDoc下
            configure.setDirectoryForTemplateLoading(new File(webPath + "uploadFiles" + File.separator + "file" + File.separator));
            //設置對象包裝器
//            configure.setObjectWrapper(new DefaultObjectWrapper());
            //設置異常處理器
            configure.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
            //定義Template對象,注意模板類型名字與downloadType要一致
            template=configure.getTemplate(downloadType);
           
            Writer out = new OutputStreamWriter(new FileOutputStream(f), "utf-8");
            template.process(dataMap, out);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }
    }
}

二、接下來是處理圖片的工具類,這裏導出word包含導出圖片到word,因此須要對圖片進行處理,是怎麼個原理呢,在這裏和你們簡單介紹下,具體在後續我會具體詳細另外寫一篇文章分享。
(1)圖片咱們能夠在前臺將要的圖片轉成base64編碼,而後提交給後臺接收
(2)後臺接收base64編碼後使用工具類將base64解碼成圖片而後保存到本地中
(3)在要導出word的時候讀取下本地存儲圖片的路徑而後把圖片導出來就好了。
工具類以下:同第一條同樣可直接複製到大家項目中使用。web

package com.*.util;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import javax.imageio.ImageIO;
import Decoder.BASE64Decoder;
import Decoder.BASE64Encoder;


/**
 * 類名稱:ImageUtil
 * 類描述:圖片處理工具類
 */
public class ImageUtil {
    
     /**
      * 從path這個地址獲取一張圖片而後轉爲base64碼
      * @param imgName  圖片的名字 如:123.png(是帶後綴的)
      * @param path     123.png圖片存放的路徑
      * @return
      * @throws Exception
      */
     public static String getImageFromServer(String imgName,String path)throws Exception{
      BASE64Encoder encoder = new BASE64Encoder();
      File f = new File(path+imgName);
            if(!f.exists()){
        f.createNewFile();
            }
            BufferedImage bi = ImageIO.read(f);    
            ByteArrayOutputStream baos = new ByteArrayOutputStream();    
            ImageIO.write(bi, "png", baos);    
            byte[] bytes = baos.toByteArray();    
            return encoder.encodeBuffer(bytes).trim();      
     }
     
     /**
      * 將一個base64轉換成圖片保存在  path文件夾下  ,命名隨機
      * @param base64String
      * @param path  是一個文件夾路徑
      * @param imgName 圖片名字(沒有後綴)
      * @throws Exception
      */
     public static String savePictoServer(String base64String,String path)throws Exception{
        
         BASE64Decoder decoder = new BASE64Decoder();
         //要把+在上傳時變成的空格再改成+
         base64String = base64String.replaceAll(" ", "+");
         //去掉「data:image/png;base64,」後面纔是base64編碼,去掉以後才能解析
         base64String = base64String.replace("data:image/png;base64,","");
         //在本地指定位置創建文件夾,path由控制檯那邊進行定義
         String realPath = path+"/"+"echarts";
         File dir=new File(realPath);
         if(!dir.exists()){
          dir.mkdirs();
         }
         String fileName=path+"\\"+"echarts"+"\\"+UUID.randomUUID().toString()+".png";
         try {  
             byte[] buffer = decoder.decodeBuffer(base64String);  
             OutputStream os = new FileOutputStream(fileName);
             for(int i =0;i<buffer.length;++i){
                 if(buffer[i]<0){//調整異常數據
                     buffer[i]+=256;
                 }
             }
             os.write(buffer);  
             os.close();  
         } catch (IOException e) {  
             throw new RuntimeException();  
         }  
        
        return fileName;
     }
     /**
      * 讀取圖片在本地存儲的位置
      * @param imgFile
      * @throws Exception
      */
     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 (IOException e) {  
                e.printStackTrace();  
            }  
            BASE64Encoder encoder = new BASE64Encoder();  
            return encoder.encode(data);  
        } 
}

三、接下來就要介紹下在控制檯怎麼使用工具類實現導出word啦,詳細細節看註釋數據庫

static String MODELPATH = "/uploadFiles/…";

@RequestMapping(value = { "/downloadDoc" }, produces = "text/html;charset=UTF-8")
public void downloadDoc(HttpServletRequest request, HttpServletResponse response) {
    //引入導出word的工具類
    DocUtil docUtil = new DocUtil();
    //引入處理圖片的工具類,包含將base64編碼解析爲圖片並保存本地,獲取圖片本地路徑
    ImageUtil imageUtil = new ImageUtil();
    //創建map存儲所要導出到word的各類數據和圖像,不能使用本身項目封裝的類型,例如PageData
    Map<String, Object> dataMap = new HashMap<String, Object>(); 
    
    /*
     *  這一步,請求所須要導出到word的數據quotaList,把大家的數據處理放到這裏就好了
     */
    
    
    //這一步,進行圖片的處理,獲取前臺傳過來的圖片base64編碼,在利用工具類解析圖片保存到本地,而後利用工具類獲取圖片本地地址
    String barBase64Info = request.getParameter("barBase64Info");
    String path = "D:";
    String image1 = ImageUtil.savePictoServer(barBase64Info, path);
    image1  = imageUtil.getImageStr(image1);
    
    //將以上處理的數據都存入dataMap 中
    
    //如下都是進行word文件的處理,直接複製,而後細節按需修改就好了
    request.setCharacterEncoding("utf-8");
    File file = null;
    InputStream fin = null;
    OutputStream out = null;
    String filename = "文件名.doc";
        //dataMap是上面處理完的數據,MODELPATH是模板文件的存儲路徑,"模板.xml"是相應的模板文件
    file = docUtil.createDoc(dataMap, MODELPATH, "模板.xml", request);
    fin = new FileInputStream(file);
    response.setContentLength((int) file.length());//須要傳遞這個長度,否則下載文件後,打開提示內容有問題,如docx等
    response.setCharacterEncoding("utf-8");
    response.setContentType("application/msword");
    response.setHeader("Content-disposition", "attachment;filename=" + new String(filename.getBytes("utf-8"), "iso8859-1"));
    out = response.getOutputStream();
    byte[] buffer = new byte[1024]; // 緩衝區  
    int bytesToRead = -1;
    // 經過循環將讀入的Word文件的內容輸出到瀏覽器中  
    while ((bytesToRead = fin.read(buffer)) != -1) {
        out.write(buffer, 0, bytesToRead);
    }
    if (fin != null)
        fin.close();
    if (out != null)
        out.close();
    if (file != null)
        file.delete(); // 刪除臨時文件
    
    
}

注意:模板的list在後臺構造的時候必須是實體類或者有屬性類型的,若是是本身項目封裝的類型,如在個人項目中有本身封裝的PageData類型的,在模板的list是識別不出list裏面的數據的。segmentfault

各位看官看在本仙女這麼辛苦分享的份上隨手點個讚唄^_^!!!瀏覽器

相關文章
相關標籤/搜索