使用ftl生成word

x33g5p2x  于2022-05-24 转载在 其他  
字(3.6k)|赞(0)|评价(0)|浏览(382)

背景:根据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);模板要这样

相关文章