java导出word文档

准备模板:

  1. 先预填写好word文档,比如字体,文字居中,动态扩展表格啥子的。然后选择另存为->选其他格式->保存为xml格式。保存后最好再修改后缀为doc,打开看看是否乱码了

  1. 把xml格式文件美化输出后,找出预填充的内容,预填充内容可能被分隔了,需要合并,合并后需要替换为freemarker中的表达式${year}

    合并前

合并后

全部用表达式替换后再把xml改为doc打开看看是这种内容

  1. 最后把文件改为freemarke支持的ftl格式即可

有个小坑。若数据库没有查询到对应内容就往模板里面保存会报错不能为空或null,在xml文档中使用一个条件判断就可。或者在service层中提前做判空判断塞入值

1
<#if tenant_name?has_content >${tenant_name}<#else >无</#if>

controller层代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@ApiOperation(value = "据id导出销号表")
@GetMapping("/exportToWord/{id}")
public void maintainExportToWord(HttpServletResponse response, @PathVariable(name = "id", required = true) String id) {
QuestionRemove questionRemove = questionRemoveService.getById(id);
if (questionRemove == null) {
throw new RuntimeException("给的id不对啦!");
}
//文档生成
File file = questionRemoveService.exportToWord(questionRemove);
InputStream fin = null;
OutputStream out = null;
try {
fin = new FileInputStream(file);
response.setCharacterEncoding("utf-8");
response.setContentType("application/msword");
String filename = "企业问题销号表"+ DateUtils.gettimestamp();
String filenameEncoder = "";
filenameEncoder = URLEncoder.encode(filename, "utf-8");
response.setHeader("Access-Control-Allow-Origin", "*");//前后端分离
response.setHeader("Content-Type", "application/octet-stream;charset=UTF-8");//二进制 流文件
response.setHeader("Content-Disposition", "attachment;filename=" + filenameEncoder + ".doc");//下载及其文件名
response.setHeader("Connection", "close");//关闭请求头连接
response.setContentType("application/x-download"); //设置文件在浏览器打开还是下载
out = response.getOutputStream();
byte[] buffer = new byte[512];
int bytesToRead = -1;
while ((bytesToRead = fin.read(buffer)) != -1) {
out.write(buffer, 0, bytesToRead);
}
} catch (Exception e) {
new RuntimeException("导出异常");
} finally {
try {
if (fin != null) {
fin.close();
}
if (out != null) {
out.close();
}
if (file != null) {
file.delete();
}
} catch (IOException e) {
new RuntimeException("关闭流异常");
//return ResultVO.error(500,"导出失败!");
}
}
// return ResultVO.ok("生成成功",file.length());
}

service层代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public File exportToWord(QuestionRemove questionRemove) {
Map<String, String> datas = new HashMap();
Date fillInDate = questionRemove.getFillInDate();
SimpleDateFormat sim = new SimpleDateFormat("yyyy年MM月dd日");
Questions questions = questionsMapper.selectById(questionRemove.getQuestionId());
if(questions==null){
throw new RuntimeException("销号表中的问题id在问题表中查找不到");
}
String enpterpriseName = questions.getEnterpriseName()==null?"无": questions.getEnterpriseName();
String linkDeptName = questions.getLinkDeptName()==null?"无":questions.getLinkDeptName();
String fillFormDate = DateUtils.date2Str(fillInDate==null?new Date():fillInDate, sim);
String principalPhone = questionRemove.getPrincipal()+": "+questionRemove.getPrincipalPhone();
String linkDeptPeoplePhone = questionRemove.getLinkedDeptContacts()+": "+questionRemove.getLinkedDeptContactsPhone();
String tel = questionRemove.getContacts()+": "+questionRemove.getContactsPhone();
String solveInfo = questionRemove.getHandleInfo()==null ? "无":questionRemove.getHandleInfo();
String activeDeptName =questionRemove.getReferDepts()==null?"无":questionRemove.getReferDepts(); //双签办加不?
String completeDate = questionRemove.getFinishTime()==null?fillFormDate:questionRemove.getFinishTime();

datas.put("year", DateUtil.year(new Date())+"");
datas.put("linkDeptName",linkDeptName );
datas.put("enpterpriseName", enpterpriseName);
datas.put("fillFormDate", fillFormDate);
datas.put("principal_phone",principalPhone);
datas.put("tel", tel);
datas.put("linkDeptPeoplePhone", linkDeptPeoplePhone);
datas.put("solve_info",solveInfo);
datas.put("active_deptName", activeDeptName);
datas.put("completeDate",completeDate);
File maintainFile = WordGeneratorUtil.createDoc(WordGeneratorUtil.FreemarkerTemplate.maintain, "企业问题销号表", datas);
return maintainFile;
}

word生成工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import freemarker.template.Configuration;
import freemarker.template.Template;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
* <p>
* 主要以freemarker 为核心的模板生成word文档的工具类
* 这里默认配置了固定路径
* 需要根据路径取到对应模板
* 请求参数需要设置对应的模板名称
* @className: WordGeneratorUtils
* @description: 文档生成工具类
* </p>
* version: V1.0.0
*/
public final class WordGeneratorUtil {
private static Configuration configuration = null;
private static Map<String, Template> allTemplates = null;
private static final String TEMPLATE_URL = "/templates";

/**
* 模板常量类配置
*/
public static final class FreemarkerTemplate {
public static final String Test = "test";
public static final String maintain = "整改通知单";
public static final String REC_RECOMMEND = "recRecommend";
}

static {
configuration = new Configuration(Configuration.VERSION_2_3_28);
configuration.setDefaultEncoding("utf-8");
configuration.setClassForTemplateLoading(WordGeneratorUtil.class, TEMPLATE_URL);
allTemplates = new HashMap(4);
try {
// 注意初始化要载入对应模板
//allTemplates.put(FreemarkerTemplate.Test, configuration.getTemplate(FreemarkerTemplate.Test + ".ftl"));
allTemplates.put(FreemarkerTemplate.maintain, configuration.getTemplate(FreemarkerTemplate.maintain + ".ftl"));
// allTemplates.put(FreemarkerTemplate.REC_RECOMMEND, configuration.getTemplate(FreemarkerTemplate.REC_RECOMMEND + ".ftl"));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}

private WordGeneratorUtil() {
throw new AssertionError();
}

/**
* 创建doc 文档
* dataMap 数据,需要对应模板的占位符,否则会出错
* @param dataMap 数据
* @param wordName word 报表的名称
* @param freemarkerTemplateName 指定需要使用哪个freemarker模板
* @return
*/
public static File createDoc(String freemarkerTemplateName, String wordName, Map<String, String> dataMap) {
try {
File f = new File(wordName);
Template t = allTemplates.get(freemarkerTemplateName);
// 这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开
Writer w = new OutputStreamWriter(new FileOutputStream(f), StandardCharsets.UTF_8);
t.process(dataMap, w);
w.close();
return f;
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException("生成word文档失败");
}
}
}

模板位置


java导出word文档
https://lililib.github.io/java导出word文档/
作者
煨酒小童
发布于
2022年10月25日
许可协议