Web项目中生成Word文档的操作屡见不鲜,基于Java的解决方案也是很多的,包括使用Jacob、Apache POI、Java2Word、iText等各种方式,其实在从Office 2003开始,就可以将Office文档转换成XML文件,这样只要将需要填入的内容放上${}占位符,就可以使用像FreeMarker这样的模板引擎将出现占位符的地方替换成真实数据,这种方式较之其他的方案要更为简单。这个功能就是由XML+FreeMarker来实现的,Word从2003开始支持XML格式,大致的步骤:用office2003或者以上的版本编辑好word的样式,然后另存为xml,将xml翻译为FreeMarker模板,最后用java来解析FreeMarker模板并输出Doc。使用Freemarker其实就只准备模板和数据。
打开XML文件看看,如果刚才你写的${qno}、${title}等被xml文件给拆散了,修改一下XML文件就OK了
修改过后另存为resume.ftl模板文件,如下所示:
接下来修改图片,搜索w:binData 或者 png可以快速定位图片的位置,图片已经是0-F的字符串了,换成一个占位符,在将要插入Word文档的图片对象转换成BASE64编码的字符串,用该字符串替换掉占位符就可以了,示意图如下所示:
接下来就可以编码啦:
服务的代码:
@RequestMapping(value = "/demo/word", method = RequestMethod.POST)
public void word(@RequestParam(value = "image", required = false) MultipartFile image, ModelMap model, HttpServletRequest req, HttpServletResponse resp) throws IOException {
req.setCharacterEncoding("utf-8");
Map map = null;
Enumeration paramNames = req.getParameterNames();
// 通过循环将表单参数放入键值对映射中
/*while (paramNames.hasMoreElements()) {
String key = paramNames.nextElement();
String value = req.getParameter(key);
map.put(key, value);
}*/
InputStream in = image.getInputStream();
String reportImage = WordGenerator.getImageString(in);
String jsonStr = "{\"exam\": [{\"ecnt\": 4,\"eid\": \"25\",\"options\": [{\"choice\": \"3\",\"option\": \"男\",\"rowratio\": \"75.00%\"}, {\"choice\": \"1\",\"option\": \"女\",\"rowratio\": \"25.00%\"}],\"qno\": \"3\",\"title\": \"你的性别是\",\"types\": \"单选题\"}]}";
JSONObject jsonObject = JSONObject.parseObject(jsonStr);
List exams = jsonObject.getJSONArray("exam");
List
工具类的代码:
package cn.comm.util;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import freemarker.template.Configuration;
import freemarker.template.Template;
import sun.misc.BASE64Encoder;
public class WordGenerator {
private static Configuration configuration = null;
private static Map allTemplates = null;
static {
configuration = new Configuration();
configuration.setDefaultEncoding("utf-8");
configuration.setClassForTemplateLoading(WordGenerator.class, "/cn/comm/ftl");
allTemplates = new HashMap<>(); // Java 7 钻石语法
try {
allTemplates.put("resume", configuration.getTemplate("resume.ftl"));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
private WordGenerator() {
throw new AssertionError();
}
public static File createDoc(Map dataMap, String type) {
String name = "temp" + (int) (Math.random() * 100000) + ".doc";
File f = new File(name);
Template t = allTemplates.get(type);
try {
// 这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开
Writer w = new OutputStreamWriter(new FileOutputStream(f), "utf-8");
t.process(dataMap, w);
w.flush();
w.close();
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
return f;
}
//将图片转换成BASE64字符串
public static String getImageString(InputStream in) throws IOException {
//InputStream in = null;
byte[] data = null;
try {
// in = new FileInputStream(filename);
data = new byte[in.available()];
in.read(data);
in.close();
} catch (IOException e) {
throw e;
} finally {
if (in != null)
in.close();
}
BASE64Encoder encoder = new BASE64Encoder();
return data != null ? encoder.encode(data) : "";
}
}
jsp代码:
<%@ page pageEncoding="UTF-8"%>
Document
注意:这里使用的BASE64Encoder类在sun.misc包下,rt.jar中有这个类,但是却无法直接使用,需要修改访问权限,在Eclipse中可以这样修改。
在项目上点右键选择Properties菜单项进入如下图所示的界面:
到这里就可以导出一个复杂的带表格,图片的wors文档啦。导出来就是这样的,如下图: