之前使用XWPFDocument动态写入word,XWPFDocument不支持,word需要用HWPFDocument,HWPFDocument对于动态生成行效果不是很好,所以使用freemarker动态生成,生成的支持所有格式。
一、使用officeword建一个需要的表格,需要动态替换的可以先写上字母
二、另存为wordxml格式
三、把后缀修改为ftl
四、把word xml格式化,可以使用notepad++的xml tool插件,或者使用在线格式化
格式化前
格式化后
五、把之前所有要替换的字母加${}
改为
六、需要动态添加的找到<w:tr>,在<w:tr>上加<#list postdutyNormList as postdutyNormObj>
循环里面的字母加上${postdutyNormObj.}
七、合并单元格
例合并5行的第一列,第一行的第一列有值,增加<w:vmerge w:val="restart"/>;第二、三、四、五行的第一列没值把<w:r></w:r>去掉,增加<w:vmerge/>
第一行:
第二、三、四、五行:
动态判断如下:其中index是行号
八、内容相同的上下行合并,其中preContent是上一行的值,可以在java里添加需要判断列的值
九、单元格内换行
在java里循环,trs就是替换的count
for (int i = 0; i < count; i++) {VPersonalWorkDailyChild tr = list_p.get(i);VPersonalWorkDaily parent = baseInfoService.getObjectById(VPersonalWorkDaily.class, tr.getId_personal_work_daily());String data = i+1+". "+gfnull(tr.getTime())+" "+gfnull(parent.getName_place())+gfnull(tr.getPlace())+" "+gfnull(tr.getContent());trs += "<w:p wsp:rsidR=\"00000000\" wsp:rsidRDefault=\"008F1A6A\">"+"<w:pPr>"+"<w:jc w:val=\"left\"/>"+"<w:rPr>"+"<w:sz w:val=\"20\"/>"+"</w:rPr>"+"</w:pPr>"+"<w:r>"+"<w:rPr>"+"<w:rFonts w:hint=\"fareast\"/>"+"<w:sz w:val=\"20\"/>"+"</w:rPr>"+"<w:t>"+data+"</w:t>"+"</w:r>"+"</w:p>";}
十、Controller代码,map是所有要替换的内容
/**** @Date 2月25日 下午17:30:23* @Description 考核成绩汇总导出考核表具体条目* @Fcunction exportWordForSpecific* @param response* @return ReturnDatas**/@ResponseBody@SystemControllerLog(description="考核成绩汇总导出考核表具体条目")@RequestMapping(value="exportWordForSpecific")public ReturnDatas exportWordForSpecific(HttpServletResponse response, String id){ReturnDatas returnDatas = ReturnDatas.getSuccessReturnDatas();try {Map<String, Object> map = assessGradeSumService.exportWordForSpecific(id);String org_name = (String) map.get("org_name");String user_name = (String) map.get("user_name");String month_ = (String) map.get("month_");response.setCharacterEncoding("UTF-8");response.setContentType("application/msexcle");response.setHeader("content-disposition", "attachment;filename="+new String((org_name+"-"+user_name+month_+"履职考核表").getBytes("utf-8"),"ISO8859-1")+".doc");OutputStream outputStream = response.getOutputStream();WordGenerator.createDoc(map, "AssessMonthTable2.ftl", outputStream);outputStream.flush();outputStream.close();returnDatas.setStatus(ReturnDatas.SUCCESS);return returnDatas;} catch (Exception e) {e.printStackTrace();LogUtil.error("考核成绩汇总导出考核表具体条目异常:"+e.getMessage(),e);returnDatas.setStatus(ReturnDatas.ERROR);returnDatas.setMessage("考核成绩汇总导出考核表具体条目异常。");}return returnDatas;}
十一、WordGenerator 工具类
package .util;import java.io.BufferedWriter;import java.io.IOException;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.io.Writer;import java.util.Map;import freemarker.template.Configuration;import freemarker.template.Template;import freemarker.template.TemplateException;public class WordGenerator {/*** 生成doc文件* @param dataMap word中需要展示的动态数据* @param templateName word模板名称* @param output 输出流* @return* @throws IOException * @throws TemplateException */public static void createDoc(Map<?, ?> dataMap,String templateName,OutputStream output) throws TemplateException, IOException {//创建配置实例 Configuration configuration = new Configuration(Configuration.VERSION_2_3_23);//设置编码configuration.setDefaultEncoding("UTF-8");//空值configuration.setClassicCompatible(true);//ftl模板文件统一放至 com.fh.template 包下面configuration.setClassForTemplateLoading(WordGenerator.class,"/templates/");//获取模板 Template template = configuration.getTemplate(templateName);//将模板和数据模型合并生成文件 Writer out = new BufferedWriter(new OutputStreamWriter(output,"UTF-8"));// 这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开 //Writer w = new OutputStreamWriter(new FileOutputStream(f), "utf-8"); //生成文件template.process(dataMap, out);//关闭流out.flush();out.close();} }
十二、参考
注:若动态替换的内容里有特殊符号,如"<>",可以是用?html转义。在freemarker模板里把${content}改成${content?html}
标签相关
<w:tr></w:tr>:每一行;
<w:tc></w:tc>:是每一列;
<w:p></w:p>:控制单元格内换行;
<w:tcPr></w:tcPr>:里面添加合并;
<w:r></w:r>:里面是内容样式及内容;
<w:t></w:t>:里面是内容;
${assessAllObj.content?html}:如果替换的内容里有<>会报错,可以加上?html进行转义
常用到的语句
<#list postdutyNormList as postdutyNormObj></#if><#if postdutyNormObj.index==1><w:vmerge w:val="restart"/><#else><w:vmerge/></#if>
如果觉得《java使用freemarker模板导出word 合并单元格 单元格内换行》对你有帮助,请点赞、收藏,并留下你的观点哦!