效果图
由于源码标签太长不方便全部展示,这里仅展示部分
首先,要先准备好初始Word模板,一定要确保档能在Offce的Word中打开,因为Office是不兼容WPS的某些格式。
然后再另存为xml格式的文件,这里建议使用Word软件中的另存为xml方式,直接更改后缀名可能会乱码,确保没有乱码然后再将后缀更改为.ftl。
接下来导入工具类所需依赖
<!-- 引入Freemarker的依赖 -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
工具类引入到项目即可
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.*;
/**
* 检查导出word使用的模板文件
* 若无则创建
*/
@Component
public class ExportTemplateUtil {
private static final String TEMPLATE_PATH = "/template";
private String path;
// 初始化模板存放路径,因为项目打包后可能放在服务器不同的文件夹里
@PostConstruct
public void init() throws IOException {
File directory = new File("需更换成自己的包名/src/main/resources/template");
String reportPath = directory.getCanonicalPath();
path = reportPath.replace("\\", "/") + "/";
}
/**
* 项目中的模板文件输入流
*/
private InputStream templateIs = null;
private Configuration cfg = null;
/**
* 检查导出word功能模板文件并返回模板文件
*/
public Template localTemplate(String name) {
Template template = null;
//系统中路径
File localPathDir = new File(path);
if (!localPathDir.exists()) {
try {
localPathDir.mkdirs();
} catch (Exception e) {
e.printStackTrace();
}
}
File file = new File(path + name + ".ftl");
InputStream fileIs = null;
try {
ClassPathResource resource = new ClassPathResource(TEMPLATE_PATH + File.separator + name + ".ftl");
templateIs = resource.getInputStream();
if (file.exists()) {
fileIs = new FileInputStream(file);
if (fileIs.available() != templateIs.available()) {
writeTemplate(file);
initConfig(path);
}
} else {//文件不存在
writeTemplate(file);
initConfig(path);
}
if (cfg == null) {
initConfig(path);
}
template = cfg.getTemplate(name + ".ftl", "UTF-8");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (templateIs != null) {
templateIs.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fileIs != null) {
fileIs.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return template;
}
/**
* 初始化freemaker模板配置
*
* @param filePath 本地模板文件路径
*/
private void initConfig(String filePath) {
cfg = new Configuration(
Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
cfg.setDefaultEncoding("UTF-8");
File templateFile = new File(filePath);
try {
cfg.setDirectoryForTemplateLoading(templateFile);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 写入模板文件到运行环境本地
*
* @param file 模板文件
* @throws IOException
*/
private void writeTemplate(File file) throws IOException {
OutputStream os = new FileOutputStream(file);
byte[] bs = new byte[1024];
int length = 0;
while ((length = templateIs.read(bs)) != -1) {
os.write(bs, 0, length);
os.flush();
}
os.close();
}
}
如何使用工具类?
@Autowired
ExportTemplateUtil exportTemplateUtil;
public void exportWord(HttpServletResponse response) {
// 所有需要渲染到Word中的数据都需要put到此map中
Map<String, Object> params = new HashMap<>();
Calendar calendar = Calendar.getInstance();
try {
// wordVO 为需要填入模板的对象
WordVO wordVO = new WordVO();
// 生成报表年月日
wordVO.setYear(calendar.get(Calendar.YEAR) + "");
wordVO.setMonth(calendar.get(Calendar.MONTH) + 1);
wordVO.setDataDay(calendar.get(Calendar.DAY_OF_MONTH));
// 全年至数据日期共计天数
wordVO.setTotalDays(calendar.get(Calendar.DAY_OF_YEAR));
// 尽量将所需数据都封装到一个对象中方便日后修改
params.put("data", wordVO);
Template pointWork = exportTemplateUtil.localTemplate("存放在template目录下的模板名,不带后缀!(例如:demo.ftl,此处填demo即可,多级目录加/即可)");
response.setContentType("application/msword; charset=utf-8");
response.setHeader("Content-Disposition", "attachment;filename=" + Encodes.urlEncode("xxx数据报表") + ".doc");
pointWork.process(params, new OutputStreamWriter(response.getOutputStream()));
} catch (Exception e) {
e.printStackTrace();
}
}
最后在模板中按文章开头的格式去取对应的数据,${map中put的键.根据map中的键获取到的对象去取对应的属性值}。
PS:对于引用类型的数据一定要做非空判断,否则模板无法正常渲染,例如:<#if data.dataYear??>${data.dataYear}</#if>
常用的list集合:(此处省略标签)
<#if data.yearRankList??>
<#list data.yearRankList as item>
${item.excellentPercentRank}
</#list>
</#if>
Freemarker还有很多标签语法,大家可以自行百度搜索FTL语法