该方法借助freemarker的JAR包即可。
参考:
Java Web项目中使用Freemarker生成Word文档(带图片)
所需工具:
步骤:
1、在word中编辑好模版样式,设置好占位符,注意图片最好先黏上去
2、在word中,文件-另存为-XML格式
3、使用工具格式化上图的XML文件
a.在表格数据的TR中加入<#list myListData as tmp> 和</#list>
b.将XML文件中图片的BASE64转换为相应的占位符
4、在Eclipse中新建文件teample-pic.ftl,将XML的数据粘贴进去
5、使用工具类WordUtil.java生成word文件
代码:
package com.test; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.Map; import sun.misc.BASE64Encoder; import freemarker.template.Configuration; import freemarker.template.Template; public class WordUtil { /** * @param dataMap * word中需要展示的动态数据,用map集合来保存 * @param templateName * word模板名称,例如:teample.ftl * @param filePath * 文件生成的目标路径,例如:D:/ * @param fileName * 生成的文件名称 */ @SuppressWarnings("unchecked") public static void createWord(Map dataMap, String templateName, String filePath, String fileName) { try { // 创建配置实例 Configuration configuration = new Configuration(); // 设置编码 configuration.setDefaultEncoding("UTF-8"); // ftl模板文件 configuration.setClassForTemplateLoading(WordUtil.class, "/com/test/"); // 获取模板 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(); } catch (Exception e) { e.printStackTrace(); } } /** * 将图片转换为BASE64为字符串 * @param filename * @return * @throws IOException */ public static String getImageString(String filename) 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) : ""; } }
package com.test; 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; public class TestJava2Word { public static void main(String[] args) throws IOException { createWord(); //String BASE64 = WordUtil.getImageString("D://doc//friend.jpg"); //System.out.println(BASE64); } public static void createWord() { Map<String, Object> dataMap = new HashMap<String, Object>(); /** 组装数据 */ dataMap.put("username","张三"); dataMap.put("address","深圳市南山区西丽镇"); dataMap.put("num", Math.floor(Math.random()*10)); SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日"); dataMap.put("date",sdf.format(new Date())); dataMap.put("content","华语天王周杰伦在北京召开周杰伦战略发布会。在发布会上,推出时尚与专业结合的:引起了广泛的关注和讨论。现在终于正式与大家见面,天猫、官网同时上线,首卖期间还有好礼相赠!买就送,就是这么任性!"); List<Map<String, Object>> newsList=new ArrayList<Map<String,Object>>(); for(int i=1;i<=10;i++){ Map<String, Object> map=new HashMap<String, Object>(); map.put("name", "王"+i); map.put("tel", "137"+i); map.put("age", "年龄"+i); map.put("address", System.currentTimeMillis()); newsList.add(map); } dataMap.put("myListData",newsList); String myPic = ""; String myPic2 = ""; try { myPic = WordUtil.getImageString("D://doc//ganen.jpg"); myPic2 = WordUtil.getImageString("D://doc//friend.jpg"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } dataMap.put("myPic", myPic); dataMap.put("myPic2", myPic2); //文件路径 String filePath= "D://doc"; //文件名称 String fileName = System.currentTimeMillis()+".doc"; /** 生成word */ WordUtil.createWord(dataMap, "teample-pic.ftl", filePath, fileName); } }
模版文件:
teample.ftl等见附件。
注意两个问题:
1、如果图片是网络图片时,getImageString() 方法中不可使用本地new FileInputStream处理图片,应该使用new URL()获取链接,然后openConnection(),最后connection.getInputStream()获取流
2、InputStream流转Byte[]时,使用new byte[in.available]可能会有问题,推荐使用IOUtils.toByteArray(in) 转换为byte数组。
在commons-io包中org.apache.commons.io.IOUtils类的toByteArray(InputStream input)已经有实现了,我们可以参考下思路,完成我们的方法,我们可以用类似下面的代码实现inputStream转化为byte[]数组
public static byte[] toByteArray(InputStream input) throws IOException { ByteArrayOutputStream output = new ByteArrayOutputStream(); byte[] buffer = new byte[4096]; int n = 0; while (-1 != (n = input.read(buffer))) { output.write(buffer, 0, n); } return output.toByteArray(); }
下面是IOUtils中摘录出与toByteArray相关的方法
org.apache.commons.io.IOUtils.toByteArray 方法如下: public static byte[] toByteArray(InputStream input) throws IOException { ByteArrayOutputStream output = new ByteArrayOutputStream(); copy(input, output); return output.toByteArray(); } public static int copy(InputStream input, OutputStream output) throws IOException { long count = copyLarge(input, output); if (count > 2147483647L) { return -1; } return (int)count; } public static long copyLarge(InputStream input, OutputStream output) throws IOException { byte[] buffer = new byte[4096]; long count = 0L; int n = 0; while (-1 != (n = input.read(buffer))) { output.write(buffer, 0, n); count += n; } return count; }
。。。