导出到excel功能会常做,但是导出到word功能很少做,项目遇到,在这里做一下标记。
导出到excel比较容易,excel都有固定格式也模板,但是word需要自己写模板,这里用了freemarker做模板。
具体代码如下
import freemarker.template.Configuration;import freemarker.template.Template;import sun.misc.BASE64Encoder;import javax.servlet.ServletOutputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.*;import java.net.URLEncoder;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Map;public class WordUtils { //配置信息,代码本身写的还是很可读的,就不过多注解了 private static Configuration configuration = null; //这里注意的是利用WordUtils的类加载器动态获得模板文件的位置 // private static final String templateFolder = WordUtils.class.getClassLoader().getResource("../../").getPath() + "WEB-INF/templetes/";// private static final String templateFolder = "d:/我的项目/lm/lm/web/src/main/webapp/WEB-INF/templates";// private static final String templateFolder = static { configuration = new Configuration(); configuration.setDefaultEncoding("utf-8"); try {// configuration.setDirectoryForTemplateLoading(new File(templateFolder)); configuration.setClassForTemplateLoading(WordUtils.class, "/template/");//模板文件所在路径 } catch (Exception e) { e.printStackTrace(); } } private WordUtils() { throw new AssertionError(); } /** * 具体导出功能 * @param request * @param response * @param map 具体数据 * @param title 导出的文件名 * @param ftlFile word模板ftl名称,对应静态代码快中:模板文件所在路径下的ftl文件 * @throws IOException */ public static void exportMillCertificateWord(HttpServletRequest request, HttpServletResponse response, Map map, String title, String ftlFile) throws IOException { Template freemarkerTemplate = configuration.getTemplate(ftlFile); File file = null; InputStream fin = null; ServletOutputStream out = null; try { // 调用工具类的createDoc方法生成Word文档 file = createDoc(map, freemarkerTemplate); fin = new FileInputStream(file); response.setCharacterEncoding("utf-8"); response.setContentType("application/msword"); // 设置浏览器以下载的方式处理该文件名 Calendar cal = Calendar.getInstance(); SimpleDateFormat f = new SimpleDateFormat("yyyyMMddhhmmss"); String fileName = title + f.format(cal.getTime()) + ".doc"; response.setHeader("Content-Disposition", "attachment;filename=" .concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8")))); out = response.getOutputStream(); byte[] buffer = new byte[512]; // 缓冲区 int bytesToRead = -1; // 通过循环将读入的Word文件的内容输出到浏览器中 while((bytesToRead = fin.read(buffer)) != -1) { out.write(buffer, 0, bytesToRead); } } catch(Exception e){ e.printStackTrace(); }finally { if(fin != null) fin.close(); if(out != null) out.close(); if(file != null) file.delete(); // 删除临时文件 } } private static File createDoc(Map dataMap, Template template) { String name = "sellPlan.doc"; File f = new File(name); 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; } //获得图片的base64码 @SuppressWarnings("deprecation") private static String getImageBase(String src, HttpServletRequest request, HttpServletResponse response) { if(src==null||src==""){ return ""; } File file = new File(request.getRealPath("/")+src.replace(request.getContextPath(), "")); 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); }}
作为一个工具类,调用还是很简单的,自己构建数据后,在控制器端一行代码就可以了。
WordUtils.exportMillCertificateWord(request, response, outMap, testpager.getTPNAME(), "exportword.ftl");
其中outMap就是自己的数据,map键值对,在模板中通过${key}显示,其中判断语句,循环语句等需要参考freemarker的具体写法。
需要说明的是:
1、工具类中直接写入了response对象,所以在controller中调用需要返回void。
2、注意引入模板时的路径问题。
configuration.setDirectoryForTemplateLoading(new File(templateFolder));configuration.setClassForTemplateLoading(WordUtils.class, "/template/");//模板文件所在路径
都可以引入路径,第一种是绝对路径,第二种是相对路径,代码中用了第二种。找到静态资源的template文件夹下的模板文件。
总的说没技术含量,但是ftl模板没有预览,调试很麻烦,网上查也灭有好的方法,希望看官能够提供更好的方式。