大致的思路是先用office2003或者2007编辑好word的样式,然后另存为xml,将xml翻译为FreeMarker模板,最后用java来解析FreeMarker模板并输出Doc。经测试这样方式生成的word文档完全符合office标准,样式、内容控制非常便利,打印也不会变形,生成的文档和office中编辑文档完全一样。

用xml做导出方案。

先创建一个word文档,按照需求在word中填好一个模板,然后把对应的数据换成变量${},然后将文档保存为xml文档格式,使用文档编辑器打开这个xml格式的文档,去掉多余的xml符号,使用Freemarker读取这个文档然后替换掉变量,输出word文档即可

需要freemarker jar包

/**
Project Name:exam-services
File Name:DownloadService.java
Package Name:com.wt.service.download
Date:2016年9月28日下午4:44:37
Copyright (c) 2016, chenzhou1025@126.com All Rights Reserved.
*/
package com.wt.service.download;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
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.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.http.HttpServletResponse;
import net.paoding.rose.web.Invocation;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
/**
ClassName:DownloadService 
Function: 文件下载. 
Reason: ADD REASON. 
Date: 2016年9月28日 下午4:44:37 
@author wpengfei
@version
@since JDK 1.6
@see
*/
@Service
public class DownloadService {
private Logger logger = Logger.getLogger(this.getClass());
/**
* downLoad:(文件下载). 
*
* @author wpengfei
* @param inv
* @param fileName
* @param path
* @throws IOException
* @since JDK 1.6
*/
public void downLoad(Invocation inv, String fileName, String path) throws IOException {
File file = new File(path);// 构造要下载的文件
if (file.exists()) {
InputStream ins = null;
BufferedInputStream bins = null;
OutputStream outs = null;
BufferedOutputStream bouts = null;
try {
ins = new FileInputStream(path);// 构造一个读取文件的IO流对象
bins = new BufferedInputStream(ins);// 放到缓冲流里面
outs = inv.getResponse().getOutputStream();// 获取文件输出IO流
bouts = new BufferedOutputStream(outs);
String path1 = inv.getRequest().getSession().
getServletContext().getRealPath("/WEB-INF/downloads");
logger.info(path1);
inv.getResponse().setContentType("application/x-download");// 设置response内容的类型
inv.getResponse().setHeader("Content-disposition",
"attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));// 设置头部信息
// inv.getResponse().setContentLength((int)file.length());
int bytesRead = 0;
byte[] buffer = new byte[8192];
// 开始向网络传输文件流
while ((bytesRead = bins.read(buffer, 0, 8192)) != -1) {
bouts.write(buffer, 0, bytesRead);
}
bouts.flush();// 这里一定要调用flush()方法
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bouts != null) {
bouts.close();
}
if (outs != null) {
outs.close();
}
if (bins != null) {
bins.close();
}
if (ins != null) {
ins.close();
}
}
} else {
logger.info("导出的文件不存在");
}
}
}
package com.wt.common.util;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Map;
import freemarker.template.Configuration;
import freemarker.template.Template;
/**
@Desc:word操作工具类
@Author:
@Date:2014-1-22下午05:03:19
*/
public class WordUtil {
@SuppressWarnings("rawtypes")
public static String createWord2(Map dataMap, String templateName, String filePath, String fileName) {
try {
// 创建配置实例
Configuration configuration = new Configuration();
// 设置编码
configuration.setDefaultEncoding("UTF-8");
// ftl模板文件统一放至 com.lun.template 包下面
configuration.setClassForTemplateLoading(WordUtil.class, "\\com\\wt\\common\\util\\");
// 获取模板
Template template = configuration.getTemplate(templateName);
// 输出文件
File outFile = new File(filePath + File.separator + fileName);
// 如果输出目标文件夹不存在,则创建
if (!outFile.getParentFile().exists()) {
outFile.getParentFile().mkdirs();
}
// 将模板和数据模型合并生成文件
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "UTF-8"));
// 生成文件
template.process(dataMap, out);
// 关闭流
out.flush();
out.close();
return filePath + File.separator + fileName;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
package com.wt.controllers.test1;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import net.paoding.rose.web.Invocation;
import net.paoding.rose.web.annotation.Path;
import net.paoding.rose.web.annotation.rest.Get;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import com.wt.common.util.CommonsUtil;
import com.wt.common.util.Constants;
import com.wt.common.util.ResponseObject;
import com.wt.common.util.WordUtil;
import com.wt.service.download.DownloadService;
/**
@Desc:生成word
@Author:
@Date:2014-1-22下午04:52:03
*/
@Path("/word")
public class WordController {
@Autowired
private DownloadService downloadService;
private String filePath; //文件路径
// private String fileName; //文件名称
private String fileOnlyName; //文件唯一名称
/**
* createWord2:(这里用一句话描述这个方法的作用). 
* localhost:8080/test1/word/createWord2
*
* @author wpengfei
* @param inv
* @return
* @throws IOException
* @since JDK 1.6
*/
@Get("/createWord2")
public String createWord2(Invocation inv) throws IOException {
/** 用于组装word页面需要的数据 */
Map dataMap = new HashMap();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日");
dataMap.put("startTime", sdf.format(new Date()));
dataMap.put("endTime", sdf.format(new Date()));
dataMap.put("count", 1);
dataMap.put("username", "Tom");
dataMap.put("courseName", "物理");
dataMap.put("className", "1班");
dataMap.put("materialName", "体育学");
dataMap.put("materialVer", 1.0);

dataMap.put("teachAim", "诺克尔12421价是否可骄傲了空间阿凡达捡垃圾覅文件附件安防奇偶万佛诺克尔12421价是否可骄傲了空间阿凡达捡垃圾覅文件附件安防奇偶万佛诺克尔12421价是否可骄傲了空间阿凡达捡垃圾覅文件附件安防奇偶万佛诺克尔12421价是否可骄傲了空间阿凡达捡垃圾覅文件附件安防奇偶万佛诺克尔12421价是否可骄傲了空间阿凡达捡垃圾覅文件附件安防奇偶万佛");

//文件导出的目标路径
filePath=Constants.UPLOAD_BASE_FOLD;
StringBuffer sb=new StringBuffer();
sb.append(sdf.format(new Date()));
sb.append("_");
Random r=new Random();
sb.append(r.nextInt(100));
//文件唯一名称
fileOnlyName = "testDoc11_"+sb+".doc";
/** 生成word */
String result = WordUtil.createWord2(dataMap, "testDoc11.ftl", filePath, fileOnlyName);
if(StringUtils.isNotBlank(result)){
downloadService.downLoad(inv, fileOnlyName, result);
}
return "@";
}
}