1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 使用freemarker生成word文档(包含遍历多条数据 图片)

使用freemarker生成word文档(包含遍历多条数据 图片)

时间:2020-10-31 07:40:43

相关推荐

使用freemarker生成word文档(包含遍历多条数据 图片)

在做项目的过程中,有时候需要把数据生成word文档,常用的有POI、ITEXT等,在这篇文章中我们使用freemarker模板来生成我们想要的word文档。

首先我们需要使用office word来编辑一个word模板文档:

上面的图片中,我们把字段字写成${XXX}的格式,这对应这我们实体类的字段,下面的图片可以任意上传两张图片,因为我们会生成base64格式的一段编码。

接下来我们另存word文档为xml文件,打开后如下所示:

图中选中的部分如果发现被发开了,不是${XXX}的格式,只需把中间的标签删除即可,接下来是图片部分,我们能看到它生成了一段base64位的编码,我们只需要先删除这段编码,然后把图片对应的字段名以上述的格式写进去即可:

接下来是java后台代码,建了一个包放我们编辑好的ftl文件:

下面的代码是图片编码转换器,这里写的是固定路径,实际项目中可以从数据库查询保存的路径放入imgFile即可:

/图片编码转换public String getImgStr() throws Exception{//System.out.println("realpath=================:::::::::::"+realpath);//System.out.println("photo=================:::::::::::"+photo);String imgFile = "D:\timg.png";InputStream in = null;byte[] data = null;in = new FileInputStream(imgFile);data = new byte[in.available()];in.read(data);in.close();BASE64Encoder ecoder = new BASE64Encoder();return ecoder.encode(data);}

下面是主要代码,它主要用来读取到ftl文件,然后放入我们对应字段的值:

private Configuration configuration = null;public WordTest() {configuration = new Configuration();configuration.setDefaultEncoding("UTF-8");}public void createWord() {Map<String, Object> dataMap = new HashMap<String, Object>();try {dataMap.put("name", "张三");dataMap.put("sex", "男");dataMap.put("age", "22");dataMap.put("school", "清华大学");dataMap.put("age", "22");dataMap.put("sfzzm", getImgStr());dataMap.put("sfzfm", getImgStr2());configuration.setClassForTemplateLoading(this.getClass(), "/template"); //Template template = configuration.getTemplate("demo.ftl");File outFile = new File("D:/wordTest.doc");//Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "UTF-8"));template.process(dataMap, out);out.close();} catch (Exception e) {e.printStackTrace();}}

Template类是主要使用的模板引擎类。接下来写个测试方法,就会在我们指定的d盘下面生成一个叫wordTest.doc的word。

public static void main(String[] args) {WordTest test = new WordTest();test.createWord();}

打开后生成word文档如下:

到此使用freemarker生成word就结束了,由于我们再实际的项目中,下载word会调用浏览器的下载功能进行下载,所以下面贴下处理方法:

// 提示:在调用工具类生成Word文档之前应当检查所有字段是否完整 // 否则Freemarker的模板引擎在处理时可能会因为找不到值而报错 这里暂时忽略这个步骤了 File file = null; InputStream fin = null; ServletOutputStream out = null; try { // 调用工具类WordUtil的createDoc方法生成Word文档 file = WordUtil.createDoc(map, "userDoc"); fin = new FileInputStream(file); String fileName = gagl.getSname()+"的沙盘档案报告.doc";response.setCharacterEncoding("utf-8"); response.setContentType("application/msword"); // 设置浏览器以下载的方式处理该文件默认名为resume.doc //response.addHeader("Content-Disposition", "attachment;filename=userDoc.doc"); response.setHeader("Content-Disposition", "attachment;filename=" .concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8")))); out = response.getOutputStream(); byte[] buffer = new byte[1024]; // 缓冲区 int bytesToRead = -1; // 通过循环将读入的Word文件的内容输出到浏览器中 while((bytesToRead = fin.read(buffer)) != -1) { out.write(buffer, 0, bytesToRead); } } finally { if(fin != null) fin.close(); if(out != null) out.close(); if(file != null) file.delete(); // 删除临时文件 }return null;

接下来就是遍历,如果我们的图片路径放在一个字段里,我们肯定需要分割然后再显示图片,数据也是一样,如果我们的数据有多条,需要遍历之后都显示在word中,那么该怎么做呢,下面简单的介绍下,这部分就不做实例了,直接贴代码:

//已完成技能培训String skillStrs2 ="";List<String> skillList = new ArrayList<String>();String[] skillStrs = teacher.getSkillTheme().split(",");for(int i=0;i<skillStrs.length;i++){skillStrs2 = skillStrs[i];skillList.add(skillStrs2);}map.put("skillThemeList", skillList);//技能主题String hourStrs2 = "";List<String> hourList = new ArrayList<String>();String[] hourStrs = teacher.getSkillHours().split(",");for(int i=0;i<hourStrs.length;i++){hourStrs2 = hourStrs[i];hourList.add(hourStrs2);}map.put("skillHoursList", hourList); //技能总计小时数//技能培训证书照try {String simgStrs2 ="";List<String> skillImgList = new ArrayList<String>();String[] simgStrs = teacher.getSkillImg().split(",");for(int i=0;i<simgStrs.length;i++){simgStrs2 = simgStrs[i].substring(14, simgStrs[i].length());try {skillImgList.add(getImgStr(simgStrs2));} catch (Exception e) {e.printStackTrace();}}map.put("skillImgList", skillImgList);} catch (Exception e) {e.printStackTrace();}

上面的代码中,第一部分是数据的集合,下面是图片集合,我们先进行分割,然后遍历后放入集合里,最后再放入我们需要的map里,这个map对应的key就是ftl里对应的${}字段。

然后我们需要去修改我们的ftl文件:

<#list supervisorTypeList as sups><#list supervisorHoursList as shours><#list supervisorImgList as supim><#assign a=sups_index /> <#assign b=shours_index /> <#assign c=supim_index /> <#if (a=b) ><#if (b=c) ><w:p wsp:rsidR="00551926" wsp:rsidRDefault="00551926" wsp:rsidP="003D2B62"><w:pPr><w:jc w:val="left"/><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体"/><wx:font wx:val="宋体"/><w:sz w:val="28"/><w:sz-cs w:val="28"/></w:rPr></w:pPr><w:r><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:hint="fareast"/><wx:font wx:val="宋体"/><w:sz w:val="28"/><w:sz-cs w:val="28"/></w:rPr><w:t>心理督导</w:t></w:r><w:r wsp:rsidR="00E90F59"><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:hint="fareast"/><wx:font wx:val="宋体"/><w:sz w:val="28"/><w:sz-cs w:val="28"/></w:rPr><w:t>:</w:t></w:r></w:p><w:p wsp:rsidR="00A57CB2" wsp:rsidRDefault="00551926" wsp:rsidP="003D2B62"><w:pPr><w:jc w:val="left"/><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体"/><wx:font wx:val="宋体"/><w:sz w:val="28"/><w:sz-cs w:val="28"/></w:rPr></w:pPr><w:r><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:hint="fareast"/><wx:font wx:val="宋体"/><w:sz w:val="28"/><w:sz-cs w:val="28"/></w:rPr><w:t>1.</w:t></w:r><w:r wsp:rsidR="00DE7BE6"><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:hint="fareast"/><wx:font wx:val="宋体"/><w:sz w:val="28"/><w:sz-cs w:val="28"/></w:rPr><w:t>督导类型:${sups}</w:t></w:r></w:p><w:p wsp:rsidR="00DE7BE6" wsp:rsidRDefault="00551926" wsp:rsidP="003D2B62"><w:pPr><w:jc w:val="left"/><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体"/><wx:font wx:val="宋体"/><w:sz w:val="28"/><w:sz-cs w:val="28"/></w:rPr></w:pPr><w:r><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:hint="fareast"/><wx:font wx:val="宋体"/><w:sz w:val="28"/><w:sz-cs w:val="28"/></w:rPr><w:t>2.</w:t></w:r><w:r wsp:rsidR="002B42DF" wsp:rsidRPr="002B42DF"><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:hint="fareast"/><wx:font wx:val="宋体"/><w:sz w:val="28"/><w:sz-cs w:val="28"/></w:rPr><w:t>总计小时数</w:t></w:r><w:r wsp:rsidR="002B42DF"><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:hint="fareast"/><wx:font wx:val="宋体"/><w:sz w:val="28"/><w:sz-cs w:val="28"/></w:rPr><w:t>:${shours}</w:t></w:r></w:p><w:p wsp:rsidR="002B42DF" wsp:rsidRDefault="00551926" wsp:rsidP="003D2B62"><w:pPr><w:jc w:val="left"/><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体"/><wx:font wx:val="宋体"/><w:sz w:val="28"/><w:sz-cs w:val="28"/></w:rPr></w:pPr><w:r><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:hint="fareast"/><wx:font wx:val="宋体"/><w:sz w:val="28"/><w:sz-cs w:val="28"/></w:rPr><w:t>3.</w:t></w:r><w:r wsp:rsidR="00A97706"><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:hint="fareast"/><wx:font wx:val="宋体"/><w:sz w:val="28"/><w:sz-cs w:val="28"/></w:rPr><w:t>证书</w:t></w:r><w:r><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:hint="fareast"/><wx:font wx:val="宋体"/><w:sz w:val="28"/><w:sz-cs w:val="28"/></w:rPr><w:t>照片</w:t></w:r><w:r wsp:rsidR="00A97706"><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:hint="fareast"/><wx:font wx:val="宋体"/><w:sz w:val="28"/><w:sz-cs w:val="28"/></w:rPr><w:t>:</w:t></w:r></w:p><w:p wsp:rsidR="00A97706" wsp:rsidRDefault="00A86982" wsp:rsidP="003D2B62"><w:pPr><w:jc w:val="left"/><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体"/><wx:font wx:val="宋体"/><w:sz w:val="28"/><w:sz-cs w:val="28"/></w:rPr></w:pPr><w:r wsp:rsidRPr="00A86982"><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体"/><wx:font wx:val="宋体"/><w:noProof/><w:sz w:val="28"/><w:sz-cs w:val="28"/></w:rPr><w:pict><v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><v:stroke joinstyle="miter"/><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"/><v:f eqn="sum @0 1 0"/><v:f eqn="sum 0 0 @1"/><v:f eqn="prod @2 1 2"/><v:f eqn="prod @3 21600 pixelWidth"/><v:f eqn="prod @3 21600 pixelHeight"/><v:f eqn="sum @0 0 1"/><v:f eqn="prod @6 1 2"/><v:f eqn="prod @7 21600 pixelWidth"/><v:f eqn="sum @8 21600 0"/><v:f eqn="prod @7 21600 pixelHeight"/><v:f eqn="sum @10 21600 0"/></v:formulas><v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"/><o:lock v:ext="edit" aspectratio="t"/></v:shapetype><w:binData w:name="${"wordml://0200001"+supim_index+1+".jpg"}" xml:space="preserve">${supim}</w:binData><v:shape id="图片" o:spid="_x0000_i1025" type="#_x0000_t75" style="width:414.75pt;height:207.75pt;visibility:visible;mso-wrap-style:square"><v:imagedata src="${"wordml://0200001"+supim_index+1+".jpg"}" o:title="菜单"/></v:shape></w:pict></w:r></w:p></#if></#if></#list></#list></#list>

上述的代码就是在ftl中使用遍历了,便签都是固定的,有兴趣的可以尝试下遍历,然后显示在word中。

由于需要生成ftl文件,如果字段过多的话,写起来就会很麻烦,看到那么多标签,改起来也是个大工程。这应该是一个弊端。

好了,至此freemarker生成word的代码就结束了。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。