JAVAWEB使用FreeMarker利用ftl把含有图片的word模板生成word文档,然后打包成压缩包进行下载
这是写的另一个导出word方法:https://www.cnblogs.com/pxblog/p/13072711.html
引入jar包,freemarker.jar、apache-ant-zip-1.8.0.jar(制作压缩包使用)
下载地址: https://yvioo.lanzous.com/b00njhxoh 密码:2mcs
或者maven
<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker --> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.23</version> </dependency>
<!-- https://mvnrepository.com/artifact/org.apache.ant/ant --> <dependency> <groupId>org.apache.ant</groupId> <artifactId>ant</artifactId> <version>1.8.0</version> </dependency>
1、准备ftl模板,先在一个word中模板排版好,然后另存为-保存成“Word 2003 XML文档” 后缀名是.xml的文件
注:模板中的值要使用占位符进行填充 ,如下图所示,“name”名称是根据后台代码来的,这里可以换成自己的
然后生成.xml文件后,可以利用网上格式化工具格式化看下 生成的模板文件是否正确,占位符“${name}”必须是完整的,中间不能含有其他字符
如果word模板中含有图片,图片在xml文件中展现的形式是Base64格式的 ,包含在<w:binData>和</w:binData>中,把Base64删掉,替换成占位符,我这里使用的是“${photo}”(<w:binData>和</w:binData>中除了占位符不能有其他代码,也不能换行,主要是下面两个标签内都不能有其他标签)
如果没有<w:binData>和</w:binData>标签的话,就是在模板中没有把图片放进去,需要把图片也放进去模板中,然后生成xml文件
<w:binData w:name="wordml://03000001.png" xml:space="preserve">${photo}</w:binData> <v:shape id="图片 2" o:spid="_x0000_i1025" type="#_x0000_t75" style="width:56.5pt;height:93pt;visibility:visible;mso-wrap-style:square"><v:imagedata src="wordml://03000001.png" o:title="touxiangm"/></v:shape>
如果是多张图片的时候,就在模板文档里面放多张图片,然后看生成的模板样子,内容都是可以循环的,把共同部分拿出来,然后使用<#list>标签进行循环遍历,有些字段循环也是不一样,如下图所示,每个人可能模板不一样。
2、然后把保存的wordExport.xml文件 后缀名改成.ftl文件
3、后台代码
导出word工具类
WordUtils.javapackage testword;
import java.io.*; import java.util.Map; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import freemarker.template.Configuration; import freemarker.template.Template; import sun.misc.BASE64Encoder; public class WordUtils { //配置信息,代码本身写的还是很可读的,就不过多注解了 private static Configuration configuration = null; //这里注意的是利用WordUtils的类加载器动态获得模板文件的位置 // private static final String templateFolder = WordUtils.class.getClassLoader().getResource("../../").getPath() + "WEB-INF/templetes/"; public File exportMillCertificateWord(HttpServletRequest request, HttpServletResponse response, Map map,String title,String templateFolder,String toDirFloder) throws IOException { configuration = new Configuration(); configuration.setDefaultEncoding("utf-8"); //模板所在文件夹 configuration.setDirectoryForTemplateLoading(new File(templateFolder)); //wordExport.ftl为模板文件名称 Template freemarkerTemplate = configuration.getTemplate("wordExport.ftl"); File file = null; InputStream fin = null; ServletOutputStream out = null; // 调用工具类的createDoc方法生成Word文档 file = createDoc(map,freemarkerTemplate,title,toDirFloder); return file; } private static File createDoc(Map<?, ?> dataMap, Template template,String filename,String toDirFloder) {
File f = new File(toDirFloder+"/"+filename+".doc"); Template t = template; try { // 这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开 Writer w = new OutputStreamWriter(new FileOutputStream(f), "utf-8"); t.process(dataMap, w); w.close(); } catch (Exception ex) { ex.printStackTrace(); throw new RuntimeException(ex); } return f; } public String getImageBase(String src) { if(src==null||src==""){ return ""; } File file = new File(src); if(!file.exists()) { return ""; } InputStream in = null; byte[] data = null; try { in = new FileInputStream(file); } catch (FileNotFoundException e1) { e1.printStackTrace(); } try { data = new byte[in.available()]; in.read(data); in.close(); } catch (IOException e) { e.printStackTrace(); } BASE64Encoder encoder = new BASE64Encoder(); return encoder.encode(data); } }
导出压缩包工具类
Zipper.java
import org.apache.commons.lang.StringUtils; import org.apache.tools.zip.ZipEntry; import org.apache.tools.zip.ZipOutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.Assert; import java.io.*; import java.util.List; /** * 用于制作zip压缩包 */ public class Zipper { private static final Logger log = LoggerFactory.getLogger(Zipper.class); /** * 制作压缩包 * */ public static void zip(OutputStream out, List<FileEntry> fileEntrys, String encoding) { new Zipper(out, fileEntrys, encoding); } /** * 制作压缩包 * */ public static void zip(OutputStream out, List<FileEntry> fileEntrys) { new Zipper(out, fileEntrys, null); } /** * 创建Zipper对象 * * @param out * 输出流 * @param filter * 文件过滤,不过滤可以为null。 * @param srcFilename * 源文件名。可以有多个源文件,如果源文件是目录,那么所有子目录都将被包含。 */ protected Zipper(OutputStream out, List<FileEntry> fileEntrys, String encoding) { Assert.notEmpty(fileEntrys); long begin = System.currentTimeMillis(); log.debug("开始制作压缩包"); try { try { zipOut = new ZipOutputStream(out); if (!StringUtils.isBlank(encoding)) { log.debug("using encoding: {}", encoding); zipOut.setEncoding(encoding); } else { log.debug("using default encoding"); } for (FileEntry fe : fileEntrys) { zip(fe.getFile(), fe.getFilter(), fe.getZipEntry(), fe .getPrefix()); } } finally { zipOut.close(); } } catch (IOException e) { throw new RuntimeException("制作压缩包时,出现IO异常!", e); } long end = System.currentTimeMillis(); log.info("制作压缩包成功。耗时:{}ms。", end - begin); } /** * 压缩文件 * * @param srcFile * 源文件 * @param pentry * 父ZipEntry * @throws IOException */ private void zip(File srcFile, FilenameFilter filter, ZipEntry pentry, String prefix) throws IOException { ZipEntry entry; if (srcFile.isDirectory()) { if (pentry == null) { entry = new ZipEntry(srcFile.getName()); } else { entry = new ZipEntry(pentry.getName() + "/" + srcFile.getName()); } File[] files = srcFile.listFiles(filter); for (File f : files) { zip(f, filter, entry, prefix); } } else { if (pentry == null) { entry = new ZipEntry(prefix + srcFile.getName()); } else { entry = new ZipEntry(pentry.getName() + "/" + prefix + srcFile.getName()); } FileInputStream in; try { log.debug("读取文件:{}", srcFile.getAbsolutePath()); in = new FileInputStream(srcFile); try { zipOut.putNextEntry(entry); int len; while ((len = in.read(buf)) > 0) { zipOut.write(buf, 0, len); } zipOut.closeEntry(); } finally { in.close(); } } catch (FileNotFoundException e) { throw new RuntimeException("制作压缩包时,源文件不存在:" + srcFile.getAbsolutePath(), e); } } } private byte[] buf = new byte[1024]; private ZipOutputStream zipOut; public static class FileEntry { private FilenameFilter filter; private String parent; private File file; private String prefix; public FileEntry(String parent, String prefix, File file, FilenameFilter filter) { this.parent = parent; this.prefix = prefix; this.file = file; this.filter = filter; } public FileEntry(String parent, File file) { this.parent = parent; this.file = file; } public FileEntry(String parent, String prefix, File file) { this(parent, prefix, file, null); } public ZipEntry getZipEntry() { if (StringUtils.isBlank(parent)) { return null; } else { return new ZipEntry(parent); } } public FilenameFilter getFilter() { return filter; } public void setFilter(FilenameFilter filter) { this.filter = filter; } public String getParent() { return parent; } public void setParent(String parent) { this.parent = parent; } public File getFile() { return file; } public void setFile(File file) { this.file = file; } public String getPrefix() { if (prefix == null) { return ""; } else { return prefix; } } public void setPrefix(String prefix) { this.prefix = prefix; } } }
使用控制器类
import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class TestWord { @RequestMapping("/o_export") public void export(HttpServletRequest request, HttpServletResponse response) { WordUtils wordUtils = new WordUtils(); List<Zipper.FileEntry> flist = new ArrayList<Zipper.FileEntry>(); //这里要获取要导出的数据列表集合 List list = null; //模板所在文件夹路径 String tplDir = null;
//模板word临时存储的位置
String toDirFloder=null
//文件夹不存在,创建文件夹
File dirFile=new File(toDirFloder);
if (!dirFile.exists()){
dirFile.mkdirs();
}
//要循环遍历的数据 for (Object e : list) { //导出的word文件名称 String filename = null; try { File file = wordUtils.exportMillCertificateWord(request, response, enrollToMap(e, wordUtils), filename, tplDir, toDirFloder); //这里表示压缩包下会有一个文件夹,名称是“学生信息表”,所有的word文件会放到这个文件夹底下 Zipper.FileEntry entry = new Zipper.FileEntry("学生信息表", file); //把文件放到压缩包中 flist.add(entry); } catch (IOException e1) { e1.printStackTrace(); } } response.setContentType("application/x-download;charset=UTF-8"); try { //这里的“学生信息表”是压缩包文件名 response.addHeader("Content-disposition", "filename=" + new String("学生信息表".getBytes("gb2312"), "iso8859-1") + ".zip"); Zipper.zip(response.getOutputStream(), flist, "GBK");
//删除word临时保存的文件和文件夹
File[] files=dirFile.listFiles();
for (File f:files){
f.delete();
}
dirFile.delete();
} catch (IOException e) { e.printStackTrace(); } } public Map enrollToMap(Student s, WordUtils wordUtils) { Map map = new HashMap(); //这里的name和sex为模板中占位符的名称 我模板中用的占位符是“${name}”,所以这里map集合的key是name map.put("name", s.getName()); map.put("sex", s.getSex()); //获取图片URL地址后,调用方法生成BASE64格式 String photoBase64 = wordUtils.getImageBase("图片URL绝对地址"); map.put("photo", photoBase64); return map; } }