使用ftl生成word

背景:根据word模板下载word。word里面需要填充数据,格式是固定的。首先在word中给数据起个变量名称
在这里插入图片描述需要更换的数据改成${变量名!},必须是英文的,加感叹号是为了防止null,如果数据是null,文档下载下来后会直接显示null,加上感叹号就不会,没数据就是空。也可以不加感叹号,在代码设置下属性即可,后面会说到。变量名结束后把word另存为xml
在这里插入图片描述
然后复制到项目中,我用的是idea,打开后会发现就几行,后面老长了
在这里插入图片描述
然后format下ctrl+alt+L(快捷键仅供参考,本人是这样的),就会
在这里插入图片描述

这些红色不影响,不用管它。在文件中搜索${,被搜到的都是起变量的地方,有的地方是会分离的
在这里插入图片描述
这就需要手动帮他们破镜重圆了,剪切下即可
在这里插入图片描述
这种应该比较多,手动改下就行。改完后保存,改为.ftl文件。下面是代码

import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

import java.io.*;
import java.util.Map;

public class ExportController {
    
    

    public void download(WeeklyTask weeklyTask, HttpServletResponse response) {
    
    
        try {
    
    
            //加入模板的数据
            Map<String, Object> data = new HashMap<>();
            data.put("key", value);
            String outFileName = "测试.docx";
            //模板相对路径
            String path = Thread.currentThread().getContextClassLoader().getResource("").getPath();
            path = path + "templates/";
            //linux
            if ("/".equals(File.separator)) {
    
    
                path = path.replaceAll("\\\\", "/");
            }
            File outFile = createDoc(data, outFileName, path, "模板.ftl");
            if (null != outFile) {
    
    
                response.reset();
                response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(outFile.getName(), "UTF-8"));
                //获取文件输入流
                InputStream in = new FileInputStream(outFile);
                byte[] buffer = new byte[1024];
                OutputStream out = response.getOutputStream();
                int len = 0;
                while ((len = in.read(buffer)) > 0) {
    
    
                    //将缓冲区的数据输出到客户端浏览器
                    out.write(buffer, 0, len);
                }
                in.close();
                out.close();
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
 public static File createDoc(Map<String, Object> dataMap, String outFileName, String templatePath, String templateFileName) throws IOException {
    
    
        //设置模本装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载,
        Configuration configuration = new Configuration();
        //设置null转为空串
        configuration.setClassicCompatible(true);

        configuration.setDefaultEncoding("UTF-8");
        configuration.setDirectoryForTemplateLoading(new File(templatePath));
        Template t = null;
        try {
    
    
            //test.ftl为要装载的模板
            t = configuration.getTemplate(templateFileName, "UTF-8");
            t.setOutputEncoding("UTF-8");
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
        //输出文档路径及名称
        File outFile = new File(outFileName);
        if (!outFile.exists()) {
    
    
            outFile.createNewFile();
        }
        Writer out = null;
        FileOutputStream fos = null;
        try {
    
    
            fos = new FileOutputStream(outFile);
            OutputStreamWriter oWriter = new OutputStreamWriter(fos, "UTF-8");
            //这个地方对流的编码不可或缺,使用main()单独调用时,应该可以,但是如果是web请求导出时导出后word文档就会打不开,并且包XML文件错误。主要是编码格式不正确,无法解析。
            // out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile)));
            out = new BufferedWriter(oWriter);
        } catch (FileNotFoundException e1) {
    
    
            e1.printStackTrace();
        }

        try {
    
    
            t.process(dataMap, out);
            out.close();
            fos.close();
            return outFile;
        } catch (TemplateException e) {
    
    
            e.printStackTrace();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
        return null;
    }
}

我的模板文件放在
在这里插入图片描述
下,我是springBoot,前后端分离的maven。获取模板路径视情况而定。

//设置null转为空串
configuration.setClassicCompatible(true);

这个设置下就可以不加感叹号了。然后模板获取数据是根据你起的变量名称和Map的key对应来获取值的,即使模板里面的变量名称加了感叹号,key也不用加感叹号。然后就可以下载了。如果下载后发现有错位现象,多了空格或者换行,比如这种
在这里插入图片描述
下载的文件前面肯定多了很多空格或者回车,把多余的删除即可
在这里插入图片描述
还有是循环,塞数据的map要put成
List<Map<String, String>> list = new ArrayList<>();
Map<String, String> m = new HashMap<>();
m.put(“anzlsz01”,value);
list .add(m);
data.put(“TABLE1”, list);模板要这样在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_43842093/article/details/124940139