为什么用freemaker呢,因为用freemarker的模板来搞比较方便,比较快捷也让人更好的可以接受
主要还是因为简单,具体的步骤如下
1.首先你要添加freemaker的相关依赖,还需要在配置类application.yml中添加配置
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
#################################### Freemarker start #################################
# 设置freemarker
#设置是否允许HttpServletRequest属性覆盖(隐藏)控制器生成的同名模型属性
freemarker:
allow-request-override: false
# 开发过程建议关闭缓存
#启用模板缓存
cache: false
#检查模板位置是否存在
check-template-location: false
#设置编码格式
charset: UTF-8
content-type: text/html; charset=utf-8
#设置是否应该在与模板合并之前将所有请求属性添加到模型中。
expose-request-attributes: false
#设置是否在与模板合并之前将所有HttpSession属性添加到模型中。
expose-session-attributes: false
#设置是否公开RequestContext供Spring宏库使用,名称为“SpringMacroRequestContext”。
expose-spring-macro-helpers: false
#所有视图的RequestContext属性的名称。
request-context-attribute:
# 默认后缀就是.ftl
suffix: .ftl
template-loader-path: classPath:/code/
#################################### Freemarker end ###################################
具体含义请点击这个大佬的链接
springboot集成freemarker 配置application.properties详解 - 冰~橙 - 博客园 (cnblogs.com)
2.你要找到你需要的这个word文档的具体样子
比如,如下图,看着比较简单,没有做表格,但是用到了循环
比如这就是你的表格,之后你要去数据库中找到其对应的字段经行更改
如下图所示
之后进行另存,切记这时保存时要改文件格式
保存完毕之后更改其后缀名为 .ftl 文件
打开之后Ctrl+A Ctrl+C然后找到xml在线格式化
XML 在线格式化 | 菜鸟工具 ,直接复制上去,点格式化,这样你就得到了一份很整齐的代码,之后打开我们的idea,找到你的项目把他放下在如下图所示的位置上
打开.ftl有的应该会报错,要修改成正确的格式比如
<w:r>
<w:rPr>
<w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:fareast="宋体" w:cs="宋体" w:hint="fareast"/>
<w:sz w:val="24"/>
<w:sz-cs w:val="24"/>
<w:lang w:val="EN-US" w:fareast="ZH-CN"/>
</w:rPr>
<w:t>${name}</w:t>
</w:r>
应为加了遍历所以要加一个list,把它加在你遍历表里的第一个之前,结尾加在遍历的最后
Controller
@PostMapping("user/doc") @ResponseBody @ApiOperation(value="导出用户doc", httpMethod = "POST",produces="application/json",notes = "导出用户doc") public ApiResult exportDoc(Integer pid,Integer id) throws IOException { //这是我自己写的两个查询方法 List<BulletinDzh> list = bulletinDzhMapper.selectByPid(pid,id); Bulletin bulletin = bulletinMapper.findByName(pid); Configuration configuration = new Configuration(); configuration.setDefaultEncoding("utf-8"); //这是模板的位置 configuration.setClassForTemplateLoading(this.getClass(), "/code"); //这是引用的模板 Template template = configuration.getTemplate("name.ftl"); //把数据存入到map中,也就是放到了word文档中 Map<String,Object> dataMap = new HashMap<String,Object>(); dataMap.put("name",bulletin.getName()); dataMap.put("newlist",list); //这是年月日 Calendar rightNow = Calendar.getInstance(); Integer year = rightNow.get(Calendar.YEAR); Integer month = rightNow.get(Calendar.MONTH)+1; //第一个月从0开始,所以得到月份+1 Integer day = rightNow.get(Calendar.DAY_OF_MONTH); File outFile = new File("文件导出的名字"+ +year+"-"+month+"-"+day+ ".doc"); Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8")); try { template.process(dataMap,out); out.flush(); out.close(); } catch (TemplateException e) { e.printStackTrace(); } return ApiResult.ok(); }
可能会遇到的问题
- If you need a particular format only once, use ?string(pattern), like ?string('dd.MM.yyyy HH:mm:ss'), to specify which fields to display
- 如果出现时间报错问题 如上
-
把ftl中的 <w:t>${new.dutyDate}</w:t>
- 改为 ${new.dutyDate?string('yyyy-MM-dd HH:mm:ss')} 就可以了
- Ftl文件导出为空的解决办法:
- ${template.headImg}//如果值为空那么页面便会报错
- ${template.headImg ! "default"}
- //如果值为空 那么就默认为 ! 感叹号后面引号内的内容 ,切记需要使用双引号
如果你可以通过上面做出导出了,你就直接用下面得代买就好,也就是try后面的,记得要修改文件路径哦,记得看看代码中得注释,有问题可以及时留言
@SneakyThrows
@GetMapping("/doc/{id}")
@ResponseBody
@SysLog(value = "导出简报信息", type = LogTypeEnum.DOWNLOAD)
@ApiOperation(value = "导出用户doc", httpMethod = "Get", produces = "application/json", notes = "导出用户doc")
public void exportDoc(@PathVariable("id") Integer pid,HttpServletResponse response, HttpServletRequest request) {
//此方法是我自己写的查询方法
List<BulletinDzh> list = bulletinDzhMapper.selectByPid(pid);
//此方法是我自己写的查询方法
String bulletin = bulletinMapper.findByName(pid);
Configuration configuration = new Configuration(Configuration.VERSION_2_3_23);
configuration.setDefaultEncoding("utf-8");
configuration.setClassForTemplateLoading(this.getClass(), "/code");
Template template = configuration.getTemplate("dzh3.ftl");
Map<String, Object> dataMap = new HashMap<>(16);
dataMap.put("name",bulletin);
dataMap.put("newlist", list);
Calendar rightNow = Calendar.getInstance();
int year = rightNow.get(Calendar.YEAR);
//第一个月从0开始,所以得到月份+1
int month = rightNow.get(Calendar.MONTH) + 1;
int day = rightNow.get(Calendar.DAY_OF_MONTH);
File outFile = new File("简报导出" + +year + "-" + month + "-" + day + ".doc");
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), StandardCharsets.UTF_8));
template.process(dataMap, out);
//以上为导出到服务器
//但这么说不是很准确
//以下为做成链接可以在浏览器中下载
try {
//关键点,需要获取的文件所在文件系统的目录,定位准确才可以顺利下载文件
//部署的服务器地址
String filePath = "/yjya/" + "简报导出" + year + "-" + month + "-" + day + ".doc";
File file = new File(filePath);
String str = "简报导出";
//创建一个输入流,将读取到的文件保存到输入流
InputStream fis = new BufferedInputStream(new FileInputStream(filePath));
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
fis.close();
// 清空response
response.reset();
// 重要,设置response的Header
response.setHeader("Content-Disposition", "attachment;filename=" + new String(str.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1) + year + "-" + month + "-" + day + ".doc");
response.setHeader("Content-Length", "" + file.length());
//octet-stream是二进制流传输,当不知文件类型时都可以用此属性
response.setContentType("application/octet-stream");
//跨域请求,*代表允许全部类型
response.setHeader("Access-Control-Allow-Origin", "*");
//允许请求方式
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
//用来指定本次预检请求的有效期,单位为秒,在此期间不用发出另一条预检请求
response.setHeader("Access-Control-Max-Age", "3600");
//请求包含的字段内容,如有多个可用哪个逗号分隔如下
response.setHeader("Access-Control-Allow-Headers", "content-type,x-requested-with,Authorization, x-ui-request,lang");
//访问控制允许凭据,true为允许
response.setHeader("Access-Control-Allow-Credentials", "true");
//创建一个输出流,用于输出文件
OutputStream oStream = new BufferedOutputStream(response.getOutputStream());
//写入输出文件
oStream.write(buffer);
oStream.flush();
oStream.close();
System.out.println("下载日志文件:" + str + year + "-" + month + "-" + day + ".doc" + "成功");
out.flush();
out.close();
} catch (IOException ioe) {
ioe.printStackTrace();
System.out.println("下载日志文件出错,错误原因:" + ioe);
}
}