关于用java编写生成word文档,动态添加数据到word文档的一些心得,经过翻阅了无数的有用的和无用的资料以后,总算找到了一种靠谱的方法
1.概述
经过反反复复的查阅资料,总算找到了一个靠谱的生成word的方案,这里分享给大家.
2.需求
首先我们的需求是通过一个指定的word模板来生成新的word并且填充内容,内容是我们在布局页面上面就写好的,比如说EditText,TextView,或者是图片ImageView,填充完内容之后,在页面上进行点击操作,生成新的word,可以指定路径,内容自动填充到新生成word文档中
3.方案
3.1 概述
上面所讲到的几种方案。
3.1.1 jadoc
3.1.2 apache poi
3.1.3 java2word
3.1.4 iText
3.1.5 jsp
3.1.6 xml的方式
最终得出结论,这几种方法 要么就是操作太简陋,没有实现我们这样复杂的需求,要么就是不太好用。期间还去研究过一个名为Jword的一个第三方,除去试用期只有30天,不是免费的之外,本身Jword自带的jar包内含方法太多,导致出现 65536的问题,需要我们分 dex,分jar,去除没用的方法,这里这种大费周章的搞,不是我们的目的。
4.实现
4.1使用freemarker实现我们的需求
4.4.1 自己新建一个 word的模板 模板中指定需要填写的内容的字段 如 name, type等
4.2.2.新建word文档模板之后,保存为xml格式的文件,保存之后打开编辑,在xml中修改我们的字段为${name}等,修改之后可以通过代码的方式来写入内容到wrod中
4.2.3.利用freemarker 来实现 生成word、动态添加数据到word中
5.demo运行项目
5.1 这里我们以 java项目为例,Android项目类似,只需要添加文件读写权限即可。
5.2 这里新建的模板为 doc格式。
这里我们指定每一项的字段,有图片或者文件时不需要处理。
5.3 模板有了之后我们保存为*xml 文件 ,打开编辑xml文件,用crtl+f 的方法 去找我们对应的NAME、SEX 并且将其改为
${NAME}、${SEX}...
这里我们需要找到类似这样的标签
<w:t>.......</w:t>
,然后将其修改为
</w:t>${NAME}</w:t>
所有的字符串字段均作为修改,这里需要注意,当我们有图片时,我们需要找的标签是这样的
w:binData w:name="wordml://02000001.jpg" xml:space="preserve">${image}</w:binData>
//这里 ${image} 已经是修改之后的值,没修改之前为 一串很长的值,我们替换掉
这里我已经修改过,原来的里面是一堆很长很长的乱码,我们直接用我给的这个给替换掉,代码中用image去写一张新的图片进去。
5.4 至此,我们的xml修改成功,修改完成之后,我们需要修改生成的 xml后缀名 为 ftl 格式,生成之后放到我们的项目之下,这个模板就当做我们word的模板,下面的事情就是写代码进去,将我们的内容填充进去,main函数中申明我们的模板
public static void main(String[] args){
Freemark freemark = new Freemark("template/");//这里如果放在了具体的包名下,需要修改为 "/com/test/template/"
freemark.setTemplateName("简历-朱老师.ftl");
freemark.setFileName("doc_"+new SimpleDateFormat("yyyy-MM-dd hh-mm-ss").format(new Date())+".doc");//生成的word名称
freemark.setFilePath("D:/");//生成word存储路径
freemark.createWord();//生成方法
}
创建word的方法
private void createWord(){
Template t = null;
try {
t = configuration.getTemplate(templateName);
} catch (IOException e) {
e.printStackTrace();
}
File outFile = new File(filePath+fileName);
Writer out = null;
try {
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Map map = new HashMap<String, Object>();
map.put("NAME", "韩满义");
map.put("image", getImageStr());
map.put("SEX", "男");
map.put("BIRTH", "1987-08");
map.put("ZZMM", "党员");
map.put("MZ", "汉");
map.put("JG", "河北省");
map.put("JKZK", "良好");
map.put("SG", "173cm");
map.put("HYZK", "已婚");
map.put("XL", "本科");
map.put("BYYX", "河北工业大学");
map.put("ZY", "软件工程");
map.put("ZP", "照片//todo");
map.put("QZYX", "软件方向工作薪资1w上下");
map.put("JYSH1", "06-09-01~10-06-20");
map.put("JYYZ1", "河北工业大学 软件工程");
map.put("JYXW1", "学士学位");
map.put("JYKC1", "软件工程、微积分、软件过程管理、数据库原理等等");
map.put("JYSH2", "10-07-01~至今");
map.put("JYYZ2", "ABCDE大学");
map.put("JYXW2", "XYZ学位");
map.put("JYKC2", "POI课程");
map.put("ZYJN", "软件开发、软件管理");
map.put("GZSH1", "10-07-01~11-12-09");
map.put("GZDZ1", "华信软件");
map.put("GZGY1", "初级软件工程师");
map.put("GZSH2", "11-12-15~14-4-05");
map.put("GZDZ2", "北京久其");
map.put("GZGY2", "高级软件工程师");
map.put("JLQK", "二三等奖学金、富士通奖学金等");
map.put("ZWPJ", "兴趣丰富、好奇心强、有研究精神。");
map.put("DH", "0312-3132098");
map.put("SJ", "15033768387");
map.put("YJ", "hanmanyifengyi@163.com");
map.put("DZ", "河北省保定市");
map.put("YB", "071000");
try {
t.process(map, out);
out.close();
} catch (TemplateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
下面是类里面的其余方法:
/**
* freemark初始化
* @param templatePath 模板文件位置
*/
public Freemark(String templatePath) {
configuration = new Configuration();
configuration.setDefaultEncoding("utf-8");
configuration.setClassForTemplateLoading(this.getClass(),templatePath);
}
/**
* 得到图片
* @return
*/
private String getImageStr() {
String imgFile = "D:/hanmanyi/pic/111.jpg";//需要在D盘下指定的目录下放一张图片
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);
}
/**
* freemark模板配置
*/
private Configuration configuration;
/**
* freemark模板的名字
*/
private String templateName;
/**
* 生成文件名
*/
private String fileName;
/**
* 生成文件路径
*/
private String filePath;
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public String getTemplateName() {
return templateName;
}
public void setTemplateName(String templateName) {
this.templateName = templateName;
}
6.需要注意的问题
6.1 word模板如果有图片或者是文件,需要有一张默认的图片,即要赋值,不能为空 ,如果不写,则编译不成功
6.2 BASE64ENCODE 出现的错误,这里需要修改我们的编译环境,以eclipse为例,我们需要 windows->preference-> java->compiler->Error/warning->
这里需要修改为warning,不要弄成error
6.4 如果我们想在安卓客户端实现此处功能,建议后台服务器写一个接口,客户端传递参数生成word文档,之后返回客户端,本项目为web应用的项目,尝试将项目改为Android项目,运行报错,Configration 在初始化过程中出错,无法执行下去。