生成word思路
用WPS或者office编辑好word的样式,然后另存为word xml文档,将xml翻译为FreeMarker模板,最后用java来解析FreeMarker模板并输出Docx
配置变量
把需要注入的信息换成变量名称,比如几年几月用${d1}表示,全部替换后的格式如下图所示
word另存为xml文档
替换完成后另存为word xml格式的文档,如下图
将xml文件格式化
选定表格的动态生成范围,添加 list 标签,记得保存
动态表头
动态表格
把改好的XML文件存放到项目的resources文件夹下,(我这里模板比较多,就自己建了一个word文件夹)
导入依赖
<!-- 导出word -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
编写代码
control类
/**
* 基于模板生成 Word 文档
*
* @param response response
*/
@RequestMapping( value = "/wordExport", method = RequestMethod.POST )
@ResponseBody
@ApiOperation( value = "生成通知单", notes = "生成通知单", code = 200, produces = "application/json" )
public void wordExport(@RequestBody List<JSONObject> jsonObjects,HttpServletResponse response) {
wordService.wordExport(jsonObjects,response);
}
WordService
void wordExport(List<JSONObject> jsonObjects, HttpServletResponse response);
WordServiceImpl
package com.cnpc.epai.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.cnpc.epai.common.util.SpringManager;
import com.cnpc.epai.dto.WordInfo;
import com.cnpc.epai.service.WordService;
import com.cnpc.epai.utils.ObjectUtils;
import com.cnpc.epai.utils.WordUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.*;
@Service
public class WordServiceImpl implements WordService {
@Resource
private WordUtil wordUtil;
@Override
public void wordExport(List<JSONObject> jsonObjects, HttpServletResponse response) {
List<WordInfo> userList = new ArrayList<>();
int i = 0;
Map<String, Object> templateParam = new HashMap<>(7);
if (ObjectUtils.isNotEmpty(jsonObjects)) {
templateParam.put("orgName", StringUtils.isBlank(jsonObjects.get(0).getString("orgName")) ? "" : jsonObjects.get(0).getString("orgName"));
for (JSONObject jsonObject : jsonObjects) {
userList.add(new WordInfo(++i,
StringUtils.isBlank(jsonObject.getString("orgName")) ? "" : jsonObject.getString("orgName"),
StringUtils.isBlank(jsonObject.getString("wellCommonName")) ? "" : jsonObject.getString("wellCommonName"),
"4",
"5",
"6",
"7",
"8",
"9",
StringUtils.isBlank(jsonObject.getString("reasonsInefficiency")) ? "" : jsonObject.getString("reasonsInefficiency"),
StringUtils.isBlank(jsonObject.getString("measureContent")) ? "" : jsonObject.getString("measureContent"),
StringUtils.isBlank(jsonObject.getString("measureObjective")) ? "" : jsonObject.getString("measureObjective"),
StringUtils.isBlank(jsonObject.getString("remark")) ? "" : jsonObject.getString("remark")));
}
}
Calendar calendar = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
String year = sdf.format(new Date());
templateParam.put("date", LocalDate.now());
templateParam.put("total", userList.size());
templateParam.put("userList", userList);
templateParam.put("year", year);
templateParam.put("month", calendar.get(Calendar.MONTH));
templateParam.put("userName", SpringManager.getCurrentUser().getDisplayName());
wordUtil.generate(response, "/word", "通知单.xml", templateParam, "通知单Word");
}
}
导出word工具类
package com.cnpc.epai.utils;
import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
/**
* Word 工具类
*
* @author sunyujie
* 2024/9/20 11:48
*/
@Slf4j
@Component
public class WordUtil {
/**
* 基于模板生成 Word 文档
*
* @param response response
* @param basePackagePath resources 目录下模板所在包路径
* @param templateFileName 模板文件名
* @param templateParam 模板参数
* @param fileName 文件名
*/
public void generate(HttpServletResponse response, String basePackagePath, String templateFileName, Object templateParam, String fileName) {
try {
// 设置 HTTP 响应的内容类型为 Microsoft Word 文档
response.setContentType("application/msword");
// 设置响应字符编码为 UTF-8
response.setCharacterEncoding("utf-8");
// 使用 URLEncoder 对文件名进行编码,以防止中文文件名在不同浏览器和操作系统下出现乱码问题
String filename = URLEncoder.encode(fileName + "_" + System.currentTimeMillis(), "utf-8");
// 设置响应头,指定文档将以附件的形式下载,并定义文件名
response.setHeader("Content-disposition", "attachment;filename=" + filename + ".doc");
// 创建 Freemarker 的 Configuration 对象,设置默认的不兼容改进选项
Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
configuration.setDefaultEncoding("utf-8");
// 设置模板加载器,加载模板文件
configuration.setTemplateLoader(new ClassTemplateLoader(getClass(), basePackagePath));
Template t = configuration.getTemplate(templateFileName, "utf-8");
// 创建 Writer 对象,用于将生成的文档写到输出流中,缓存区大小设为 10KB
Writer out = new BufferedWriter(new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8), 10240);
// 将模型数据与模板结合生成 Word 文档,写入到 Writer 对象中
t.process(templateParam, out);
out.close();
} catch (Exception e) {
log.info("基于模板{}生成Word文档异常,异常原因:{}", templateFileName, e.getMessage(), e);
throw new RuntimeException("生成Word文档异常,异常原因:" + e.getMessage());
}
}
/**
* 基于模板生成 Word 文档到指定文件夹
*
* @param outputDir 输出文件夹
* @param basePackagePath resources 目录下模板所在包路径
* @param templateFileName 模板文件名
* @param templateParam 模板参数
* @param fileName 文件名
*/
public void generate(String outputDir, String basePackagePath, String templateFileName, Object templateParam, String fileName) {
try {
// 创建 Freemarker 的 Configuration 对象,设置默认的不兼容改进选项
Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
configuration.setDefaultEncoding("utf-8");
// 设置模板加载器,加载模板文件
configuration.setTemplateLoader(new ClassTemplateLoader(getClass(), basePackagePath));
Template t = configuration.getTemplate(templateFileName, "utf-8");
// 构建输出文件的完整路径
File outputFile = new File(outputDir, fileName + "_" + System.currentTimeMillis() + ".doc");
// 创建 Writer 对象,用于将生成的文档写到输出流中,缓存区大小设为 10KB
Writer out = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(outputFile.toPath()), StandardCharsets.UTF_8), 10240);
// 将模型数据与模板结合生成 Word 文档,写入到 Writer 对象中
t.process(templateParam, out);
out.close();
} catch (Exception e) {
log.info("基于模板{}生成Word文档异常,异常原因:{}", templateFileName, e.getMessage(), e);
throw new RuntimeException("生成Word文档异常,异常原因:" + e.getMessage());
}
}
}