先将word文档整合,为单个循环的样子,然后将该word文档另存为xml文档,在文件所在位置将其改为ftl后缀文件,然后拖入到idea中进行格式化并修改。
先导入freemarker包
<properties>
<freemarker>2.3.30</freemarker>
</properties>
<!-- PDF生成组件start -->
<!-- freemarker,生成 html -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>${freemarker}</version>
</dependency>
工具类
package com.jkr.utils;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.Version;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
public class WordUtil {
private static final String BASE_PATH = "/templates/";
private static Map<String, String> TEMPLATE_MAP = new HashMap<String, String>();
public static String getTemplate(String id) throws IOException {
String template = TEMPLATE_MAP.get(id);
if (StringUtils.isBlank(template)) {
StringBuffer path = new StringBuffer();
path.append(BASE_PATH).append(id);
template = inputStream2String(WordUtil.class.getResourceAsStream(path.toString()));
TEMPLATE_MAP.put(id, template);
}
return template;
}
/**
* 将stream 转成字符串
*
* @param is
* @return
* @throws IOException
*/
private static String inputStream2String(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int i = -1;
while ((i = is.read()) != -1) {
baos.write(i);
}
return baos.toString();
}
/**
* 导出excel
* @param map word文档中参数
* @param wordName 为模板的名字 例如xxx.ftl
* @param name 是临时的文件夹米名称 string类型 可随意定义
* @throws IOException
*/
public static File getFileExportMillCertificateWord(Map map, String wordName, String name)throws IOException{
String source = getTemplate(wordName);
Configuration cfg = new Configuration(new Version("2.3.23"));
StringTemplateLoader loader = new StringTemplateLoader();
loader.putTemplate("", source);
cfg.setTemplateLoader(loader);
cfg.setDefaultEncoding("UTF-8");
Template freemarkerTemplate = cfg.getTemplate("");
File file = null;
try {
// 调用工具类的createDoc方法生成Word文档
file = createDoc(map,freemarkerTemplate,name);
} finally {
}
return file;
}
/**
* 导出excel
* @param response 响应对象
* @param map word文档中参数
* @param wordName 为模板的名字 例如xxx.ftl
* @param fileName 是word 文件的名字 格式为:"xxxx.doc"
* @param name 是临时的文件夹米名称 string类型 可随意定义
* @throws IOException
*/
public static void exportMillCertificateWord(HttpServletResponse response, Map map, String wordName, String fileName, String name) throws IOException {
String source = getTemplate(wordName);
Configuration cfg = new Configuration(new Version("2.3.23"));
StringTemplateLoader loader = new StringTemplateLoader();
loader.putTemplate("", source);
cfg.setTemplateLoader(loader);
cfg.setDefaultEncoding("UTF-8");
Template freemarkerTemplate = cfg.getTemplate("");
File file = null;
InputStream fin = null;
ServletOutputStream out = null;
try {
// 调用工具类的createDoc方法生成Word文档
file = createDoc(map,freemarkerTemplate,name);
fin = new FileInputStream(file);
response.setCharacterEncoding("utf-8");
response.setContentType("application/x-download");
response.setHeader("Content-Disposition", "attachment;filename=" + new String(java.net.URLEncoder.encode(fileName, "UTF-8")));
out = response.getOutputStream();
byte[] buffer = new byte[512];// 缓冲区
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();// 删除临时文件
}
}
}
private static File createDoc(Map<?, ?> dataMap, Template template, String name) {
File f = new File(name);
Template t = template;
try {
// 这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开
Writer w = new OutputStreamWriter(new FileOutputStream(f), "utf-8");
t.process(dataMap, w);
w.close();
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
return f;
}
}
controller层
@PostMapping(value = "/checkExport")
public void checkExport(HttpServletResponse response, @RequestParam String checkId , @RequestParam Integer dataSources) {
baseService.checkExport(response, checkId, dataSources);
}
service层
@Override
public void checkExport(HttpServletResponse response, String checkId, Integer dataSources) {
try {
// 获取检查记录
Map<String, Object> exportMap = new HashMap<>();
// 获取要导出的记录信息
Check check = baseMapper.selectById(checkId);
// 将获取的记录放入map中
exportMap.put("check", check);
// 处理循环数据的方法(根据需求自己修改,这里不写了)
exportMap = checkDataProcessing(exportMap, checkId);
String wordName;
// 根据传来的字段,判断导出哪个模版
if(ObjectUtils.isNotEmpty(dataSources) && dataSources.equals(CommonConstant.DATA_SOURCES_2)){
wordName = "societyRenovate.ftl";
}else{
wordName = "superviseInspect.ftl";
}
// jdk8中比较安全的时间格式化
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(check.getCheckTime().toInstant(), ZoneId.systemDefault());
LocalDate localDate = zonedDateTime.toLocalDate();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
String checkDate = localDate.format(formatter);
// 导出的文件命名(根据自己需求获取字段进行处理)
String fileName = checkDate+"_"+check.getEntName()+"_"+check.getEntTypeAll()+".doc"; //命名
// 将信息放进工具类处理导出
WordUtil.exportMillCertificateWord(response, exportMap, wordName, fileName , "name");
} catch (Exception e) {
e.printStackTrace();
}
}
在ftl中:
使用:
1. <w:t>${ check.userName! }</w:t>
时间格式化为:<w:t>${(check.checkTime)?string('yyyy-MM-dd')}</w:t>
来进行map中的变量引入(因为上面map传递的名字叫做check),‘!’的作用是判空,如果没有就在word中导出空格(如果可能为空必须写,不然报错)
2.<#if detailList?? && (detailList?size > 0)>
<#list detailList! as item>
</#list>
</#if>
if语句,其中变量后的‘??’作用是判断是否存在, ‘&&’ 是并且, as 是将集合起别名,之后的detailList为item
3.<w:t>${item_index + 1}</w:t>
这样是索引,是排序的 1 - list.size()