之前使用XWPFDocument动态写入word,XWPFDocument不支持2003,word2003需要用HWPFDocument,HWPFDocument对于动态生成行效果不是很好,所以使用freemarker动态生成,生成的支持所有格式。

一、使用officeword建一个需要的表格,需要动态替换的可以先写上字母

二、另存为word2003xml格式

三、把后缀修改为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 2019年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 com.enter.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,合并单元格,单元格内换行