Java中模板(freemarker)方式導出Word后文件巨大,及xml word打開提示轉換的解決辦法


兩種解決方式:

Aspose 方式優點是速度快。缺點是收費的 格式不一定很好

jacob  方式優點是免費且樣式保持的相當好。缺點是特別慢而且只支持windows環境下

 

首先freemarker 導出word文檔直接參考:

https://juejin.im/post/6844903766970335246

 

jacob 集成參考:

https://blog.csdn.net/dangerous_fire/article/details/61922656

jacob 1.8下載地址

鏈接:https://pan.baidu.com/s/1rfymOlEKptyedtyDDVipqg   提取碼:50jp 

Jacob的包pom引入

 

<dependency>
		  <!-- jsoup HTML parser library @ https://jsoup.org/ -->
		  <groupId>org.jsoup</groupId>
		  <artifactId>jsoup</artifactId>
		  <version>1.13.1</version>
		</dependency>

 

aspose方式直接引入(aspose-words-19.5-jdk.jarjar包,由於是收費的我就不放出jar包了。(CSDN一堆,我也不是坑大家分畢竟我也沒放下載鏈接不是)

 

工具類JacobVariant

 

package com.tpcp.topic.utils;

public enum JacobVariant {
//	Variant(0):doc
//    *Variant(1):dot
//    *Variant(2-5),Variant(7):txt
//    *Variant(6):rft
//    *Variant(8),Variant(10):htm
//    *Variant(9):mht
//    *Variant(11),Variant(19-22):xml
//    *Variant(12):docx
//    *Variant(13):docm
//    *Variant(14):dotx
//    *Variant(15):dotm
//    *Variant(16)、Variant(24):docx
//    *Variant(17):pdf
//    *Variant(18):xps
//    *Variant(23):odt
//    *Variant(25):與Office2003與2007的轉換程序相關,執行本程序后彈出一個警告框說是需要更高版本的 Microsoft Works Converter
	/**
	 * DOC
	 */
	DOC(0), 
	/**
	 * TXT
	 */
	TXT(7), 
	/**
	 * XML
	 */
	XML(11), 
	/**
	 * DOCX
	 */
	DOCX(12), 
	/**
	 * PDF
	 */
	PDF(17);
	
	private JacobVariant(int code) {
		this.code=code;
	}
	
	private int code;

	public int getCode() {
		return code;
	}

	public void setCode(int code) {
		this.code = code;
	}
}

 

工具類JacobUtil

 

package com.tpcp.topic.utils;

import java.io.File;

import com.aspose.words.Document;
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;

public class JacobUtil {
	
	/**
	 * (jacob)將目標路徑文件轉換為指定的文件類型
	 * @param oldFilePath 要轉換的文件路徑
	 * @param newFileName 轉換后的文件名
	 * @param jacobVariant 要轉換的目標類型
	 * @param oldFileDel 轉換完成后轉換前的文件需要刪除嗎
	 * @return 轉換后的文件全路徑
	 */
	public static String convertXMLWordToBaseWord(String oldFilePath,String newFileName,JacobVariant jacobVariant,Boolean oldFileDel) {
		long startTime = System.currentTimeMillis();    //獲取開始時間
		
		//指定被轉換文件的完整路徑
		String path = new String(oldFilePath);
		//根據路徑創建文件對象
		File docFile=new File(path);
		//獲取文件名(包含擴展名)
		String filename=docFile.getName();
		//設置輸出路徑,一定要包含輸出文件名(不含輸出文件的擴展名)
		String savepath = new String (System.getProperty("java.io.tmpdir")+File.separator+newFileName);
		//啟動Word程序
		ActiveXComponent app = new ActiveXComponent("Word.Application");
		//接收輸入文件和輸出文件的路徑
		String inFile = path;
		String tpFile = savepath;
		//設置word不可見
		app.setProperty("Visible", new Variant(false));
		//這句不懂
		Object docs = app.getProperty("Documents").toDispatch();
		//打開輸入的doc文檔
		Object doc = Dispatch.invoke((Dispatch) docs,"Open", Dispatch.Method, new Object[]{inFile,new Variant(false), new Variant(true)}, new int[1]).toDispatch();
		//另存文件, 其中Variant(n)參數指定另存為的文件類型,詳見代碼結束后的文字
		Dispatch.invoke((Dispatch) doc,"SaveAs", Dispatch.Method, new Object[]{tpFile,new Variant(jacobVariant.getCode())}, new int[1]);
		//這句也不懂
		Variant f = new Variant(false);
		//關閉並退出
		Dispatch.call((Dispatch) doc, "Close", f);
		app.invoke("Quit", new Variant[] {});
		
		if(oldFileDel){
			docFile.delete();
		}
		
		System.out.println(tpFile+"."+jacobVariant+"轉換完畢。");
		long endTime = System.currentTimeMillis();    //獲取結束時間
		System.out.println("轉換用時:" + (endTime - startTime) + "ms");
		return tpFile+"."+jacobVariant;
	}
	
	/**
	 * 將目標路徑DOC 文件轉換為 指定路徑指定后綴文件
	 * @param oldFilePath 源文件路徑
	 * @param newFileName 新文件路徑
	 * @param oldFileDel 轉換完成后需要刪除源文件嗎
	 */
	public static void convertXMLWordToBaseWord(String oldFilePath,String newFilePath,Boolean oldFileDel) {
		long startTime = System.currentTimeMillis();    //獲取開始時間
		try {
			Document doc = new Document(oldFilePath); 
			doc.save(newFilePath);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		if(oldFileDel){
			new File(oldFilePath).delete();
		}
		
		long endTime = System.currentTimeMillis();    //獲取結束時間
		System.out.println("轉換用時:" + (endTime - startTime) + "ms");
	}
	
	public static void main(String[] args) {
		long startTime = System.currentTimeMillis();    //獲取開始時間
		try {
			Document doc = new Document("E:\\upFiles\\123.doc"); 
			doc.save("E:\\upFiles\\456.doc");
		} catch (Exception e) {
			e.printStackTrace();
		}
		long endTime = System.currentTimeMillis();    //獲取結束時間
		System.out.println("轉換用時:" + (endTime - startTime) + "ms");
	}
}

 

工具類ExportWordUtil

 

package com.tpcp.topic.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
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.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import freemarker.template.Configuration;
import freemarker.template.TemplateException;

/**
 * 導出Word
 * @author ll
 *
 */
public class ExportWordUtil {
	
	/**
	 * 導出Word並使用aspose.words 轉換為正常word
	 * @param map 數據源
	 * @param ftlFloder  模板所在文件夾  例:   request.getServletContext().getRealPath("/")+"export/template/"
	 * @param ftlName 模板名稱 例:    ZZBAB.ftl
	 * @param exportWordName 要導出的文件名  例 :	課程備案表.doc
	 * @param response HttpServletResponse
	 * @param aspose   true aspose方式(aspose方式耗時短 但是格式不一定能保持的很好)  false Jacob方式(Jacob方式耗時長格式保持的相當好)
	 */
	public static void exportWordDataForMap(Map<String,Object> map,String ftlFloder,String ftlName,String exportWordName,HttpServletResponse response,boolean aspose) {
		try {
			String outFilePath = System.getProperty("java.io.tmpdir")+File.separator+UUIDGenerator.generate()+exportWordName;
			//創建配置實例 
			Configuration configuration = new Configuration();
			configuration.setDefaultEncoding("UTF-8");
			configuration.setDirectoryForTemplateLoading(new File(ftlFloder));
			//獲取模板 
			freemarker.template.Template template = configuration.getTemplate(ftlName);
			//輸出文件
			File outFile = new File(outFilePath);
			//將模板和數據模型合並生成文件 
			Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8"));
			//生成文件
			template.process(map, out);
			//關閉流
			out.flush();
			out.close();
	        
			exportWord(outFilePath,exportWordName,response,aspose);
		} catch (TemplateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 導出Word
	 * @param map 數據源
	 * @param ftlFloder  模板所在文件夾  例:   request.getServletContext().getRealPath("/")+"export/template/"
	 * @param ftlName 模板名稱 例:    ZZBAB.ftl
	 * @param exportWordName 要導出的文件名  例 :	課程備案表.doc
	 * @param response HttpServletResponse
	 * @param aspose   true aspose方式(aspose方式耗時短 但是格式不一定能保持的很好)  false Jacob方式(Jacob方式耗時長格式保持的相當好)
	 */
	public static void exportWordDataForList(List<Map<String,Object>> list,String ftlFloder,String ftlName,String exportWordName,HttpServletResponse response,boolean aspose) {
		try {
			String outFilePath = System.getProperty("java.io.tmpdir")+File.separator+UUIDGenerator.generate()+exportWordName;
			//創建配置實例 
			Configuration configuration = new Configuration();
			configuration.setDefaultEncoding("UTF-8");
			configuration.setDirectoryForTemplateLoading(new File(ftlFloder));
			//獲取模板 
			freemarker.template.Template template = configuration.getTemplate(ftlName);
			//輸出文件
			File outFile = new File(outFilePath);
			//將模板和數據模型合並生成文件 
			Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8"));
			//生成文件
			template.process(list, out);
			//關閉流
			out.flush();
			out.close();
	        
			exportWord(outFilePath,exportWordName,response,aspose);
		} catch (TemplateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static void exportWord(String outFilePath,String filename,HttpServletResponse response,boolean aspose) {
			try{
				String newFilePath = System.getProperty("java.io.tmpdir")+File.separator+UUIDGenerator.generate()+".doc";
				if(aspose){ //aspose 轉換
					JacobUtil.convertXMLWordToBaseWord(outFilePath, newFilePath, true);
				}else{//Jacob轉換
					newFilePath = JacobUtil.convertXMLWordToBaseWord(outFilePath, UUIDGenerator.generate(), JacobVariant.DOC,true);
				}
				 // 以流的形式下載文件。
				File file = new File(newFilePath);
		        InputStream fis = new BufferedInputStream(new FileInputStream(newFilePath));
		        byte[] buffer = new byte[fis.available()];
		        fis.read(buffer);
		        fis.close();
		        // 清空response
		        response.reset();
		        // 設置response的Header
		        response.setHeader("Content-Disposition", "attachment;fileName=" + new String((filename).getBytes(), "iso-8859-1"));
		        response.addHeader("Content-Length", "" + file.length());
		        OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
		        response.setContentType("application/octet-stream");
		        toClient.write(buffer);
		        toClient.flush();
		        toClient.close();
		 	        
		        file.delete();
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		
	}
	
}

 

使用數據源為map的方法

 

ExportWordUtil.exportWordDataForMap(map, request.getServletContext().getRealPath("/")+"export/template/", "ZZBAB.ftl", "xxx.doc", response, false);

 

Map數據源是單獨數據,list方式則是需要循環生成,這都取決於你的ftl模板。

 

還有一點需要注意的是你的ftl模板把它格式化成一行,這也有助於你的xml word文件大小減小。

 

最后附一張xml word轉為正常word文件后的文件大小對比:

 

 

可以看到xml word大小35M左右  轉換后只有6M左右。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM