文章目录
准备 Freemarker 的 .ftl 模板文件
① 先编写好 Word 模板
② 编写实体类
根据需要导出的 Word 模板编写对应的实体类。
public class TaskNotice{
private Integer id;
private Integer projectId;
private String number;
private String projectName;
//省略.....
}
③ 将实体类中的属性填写到对应的位置。
比如:项目名称后面填写projectName。
④ 另存为 XML 格式,并修改属性。修改完成后将文件尾缀修改为 .ftl
注意:另存为 Word XML 文档(.xml) 格式,不要存 Word 2003 XML 文档(.xml) 或其它格式的 XML。
接下来就是在 xml 中找到我们第二步填写的那些参数,并将那些参数用占位符 ${参数} 替换掉。
保存,修改文件名尾缀为ftl。
Freemarker 模板设置常见问题
-
日期问题
解决方法有很多,介绍一个常用的。
将参数 ${endTime} 中的变量名后面添加 ?string('你指定的日期格式') ,例:${endTime?string('yyy-MM-dd')}
Freemarker文档说明: 日期格式处理. -
空值问题
解决方法一:
将参数 ${user} 中的变量名后面添加一个 !和默认值。例: ${user!"匿名用户"} ,此时如果参数 user 传入为 null 时,将会显示 “匿名用户”。
解决方法二:
使用 if 指令。例:<#if user??>${user}</#if> ,此时如果参数 user 传入为 null 时,将什么都不显示。
Freemarker文档说明: 处理不存在的变量.
导出 word 带图片(比如加印章)
步骤如上,同样是先把印章插入到 word 预定位置,然后另存为 xml 文件,然后用占位符 ${参数} 替换掉 xml 中被编码成 base64 字符串的图片,保存,修改文件尾缀为 .ftl 即可。
至此,Freemarker模板文件准备完毕。
java代码实现下载
pom.xml
<!-- 引入freeMarker的依赖包. -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
exportTaskNotice方法
@RestController
@RequestMapping(value = "/export",produces = "application/json;charset=utf-8")
public class ExportController{
@Autowired
private TaskNoticeService taskNoticeService;
@Autowired
private ZipUtils zipUtils;
// 导出任务通知单
@PostMapping("/exportTaskNotice")
public String exportTaskNotice(HttpServletResponse response, @RequestParam(value = "id")Integer[] id) {
try {
String ftlname = "taskNotice.ftl";
String filenamePrefix = "福建省台湾县生产任务通知单";
//HACK
List<TaskNotice> list = new ArrayList<>();
for (Integer taskNoticeId : id) {
TaskNotice taskNotice;
try {
taskNotice= taskNoticeService.select(taskNoticeId );
} catch (Exception e) {
e.printStackTrace();
return "操作失败!";
}
if (taskNotice != null) {
list.add(taskNotice);
}
}
if(list.size() < 1){
return "操作失败!";
}
exportWordUtil(response, ftlname, filenamePrefix, list);
return "操作成功!";
} catch (Exception e) {
e.printStackTrace();
return "操作失败!";
}
}
}
exportWordUtil 方法
/**
* 提取公共代码 简化代码
* @param response response
* @param ftlName ftlName
* @param filenamePrefix 存储文件名前缀
* @param list list——根据id查询出的表单数据实体类的集合
* @param <T> 泛型
* @throws Exception 异常
*/
private <T> void exportWordUtil(HttpServletResponse response, String ftlName, String filenamePrefix, List<T> list) throws Exception{
//Configuration 用于读取ftl文件
Configuration configuration = new Configuration(new Version("2.3.0"));
configuration.setDefaultEncoding("utf-8");
//路径分隔符修改 TODO 这里使用类加载器获取 ftl 文件路径(根据自己实际的文件位置来获取)
String path = StringUtils.replace(ExportController.class.getClassLoader().getResource("word-model"+File.separator+ftlName).getPath(),"%5c",File.separator);
path = StringUtils.substring(path,1,path.length()-ftlName.length()-1);
//得到临时文件存放路径
String tempPath = path+File.separator+"temp";
/**
* 以下是三种指定ftl文件所在目录路径的方式
* 指定ftl文件所在目录的路径,而不是ftl文件的路径
*/
//指定路径的第一种方式(适合加载Jar包内的资源)
// configuration.setClassForTemplateLoading(this.getClass(), basePackagePath);
// configuration.setClassLoaderForTemplateLoading(classLoader, basePackagePath);
//指定路径的第二种方式(适合加载文件路径)
configuration.setDirectoryForTemplateLoading(new File(path));
//指定路径的第三种方式(基于Servlet Context,指的是基于WebRoot下的template下的framemaker.ftl文件)
// configuration.setServletContextForTemplateLoading(request.getSession().getServletContext(), "/word-model");
//以utf-8的编码读取ftl文件
Template template = configuration.getTemplate(ftlName);
if(list.size()==1){//单个直接下载
String saveName = null;
//根据不同的实体类型去获取其存储名saveName TODO 根据实际情况修改下列关于saveName的代码
if(list.get(0) instanceof TaskNotice){
saveName = "《"+filenamePrefix+"》"+".doc";
}
//if(list.get(0) instanceof QualityTrackingCardVO){
// saveName = "《"+filenamePrefix+"-"+((QualityTrackingCardVO) list.get(0)).getName()+"》"+".doc";
//}
//输出文档路径及名称
ServletOutputStream outputStream = null;
BufferedWriter bufferedWriter = null;
try {
//设置输出流
response.reset();
response.setContentType("application/msword");
response.setCharacterEncoding("utf-8");
response.addHeader("Content-Disposition" ,"attachment;filename=" + URLEncoder.encode(saveName,"utf-8"));
outputStream = response.getOutputStream();
bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream,"UTF-8"));
template.process(list.get(0), bufferedWriter);
} finally {
if(bufferedWriter!=null){
bufferedWriter.flush();
bufferedWriter.close();
}
if(outputStream!=null){
outputStream.flush();
outputStream.close();
}
}
}else if(list.size() > 1) {//多个压缩后返回zip文件
//创建临时资源文件夹 和 zip文件全路径
String tempFolderPath = tempPath + File.separator + "temp-word-folder";
String tempZipFilePath = tempPath + File.separator + filenamePrefix + "Batch.zip";
File file = new File(tempFolderPath);
if(!file.exists()){//创建临时文件夹
file.mkdirs();
}
//批量生成word
for (Object entity : list) {
String saveName = null;
//TODO 这里的saveName可能会重复,到时候问清楚
//根据不同的实体类型去获取其存储名 saveName TODO 根据实际情况修改下列获取 saveName 的代码
if(entity instanceof TaskNotice){
saveName = "《"+filenamePrefix+"-"+((TaskNotice) entity).getId()+"》"+".doc";
}
//if(entity instanceof QualityTrackingCardVO){
// saveName = "《"+filenamePrefix+"-"+((QualityTrackingCardVO) entity).getName()+"》"+".doc";
//}
FileOutputStream fileOutputStream = null;
BufferedWriter bufferedWriter = null;
try {
fileOutputStream = new FileOutputStream(tempFolderPath + File.separator + saveName);
bufferedWriter = new BufferedWriter(new OutputStreamWriter(fileOutputStream,"UTF-8"));
template.process(entity, bufferedWriter);
}finally {
if(bufferedWriter != null){
bufferedWriter.close();
}
if(fileOutputStream != null){
fileOutputStream.close();
}
}
}
//打包成zip
zipUtils.createZip(tempFolderPath,tempZipFilePath);
//返回输出流
ServletOutputStream outputStream = null;
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(tempZipFilePath);
//设置输出流
response.reset();
response.setContentType("application/x-download");
response.setCharacterEncoding("utf-8");
response.addHeader("Content-Disposition" ,"attachment;filename=" + URLEncoder.encode(filenamePrefix + "Batch.zip","utf-8"));
outputStream = response.getOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = fileInputStream.read(buffer)) != -1) {
outputStream.write(buffer,0,len);
}
} finally {//关闭流
if(outputStream != null){
outputStream.flush();
outputStream.close();
}
if(fileInputStream != null){
fileInputStream.close();
}
zipUtils.deleteFile(new File(tempPath));//删除临时文件夹
}
}
}
zipUtils 方法
链接: ZipUtils