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左右。

 

posted @ 2020-10-10 11:32  天线宝宝出来玩  阅读(2538)  评论(0编辑  收藏  举报