1 引入jar包 包括以下几个jar包
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-core</artifactId>
<version>8.3.2</version>
</dependency>
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-ImportXHTML</artifactId>
<version>8.3.11</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.3</version>
</dependency>
<dependency>
<groupId>net.sf.jtidy</groupId>
<artifactId>jtidy</artifactId>
<version> r938</version>
</dependency>
2. 工具类转化 html 转化成word
大坑 html和word 一些编码规则 不同 如 空格  
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.tidy.Tidy;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
@Slf4j
public class FileUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(FileUtil.class);
private final static String wordPath = "src/main/resources/export/word/";
public static void exportWord(String htmlContent, HttpServletResponse response) throws IOException {
log.info("开始导出word",htmlContent);
HtmlToDocxConverter.convertHtmlToDocxAndWriteToResponse(htmlContent, response,wordPath);
LOGGER.info("导出word成功");
}
public static String cleanHtml(String html) {
// 清理 html
Tidy tidy = new Tidy();
tidy.setXHTML(true); // 输出 XHTML
tidy.setInputEncoding("UTF-8");
tidy.setOutputEncoding("UTF-8");
StringReader reader = new StringReader(html);
StringWriter writer = new StringWriter();
tidy.parse(reader, writer);
// 转移
String exprotContent = writer.toString()
.replace("&", "&")
.replace("<", "<")
.replace(">", ">")
.replace(""", "\"")
.replace("'", "'")
.replace(" ", "\u00A0");
return exprotContent;
}
}
3html 转word转化器
import org.docx4j.convert.in.xhtml.XHTMLImporterImpl;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
public class HtmlToDocxConverter {
/**
* 将 HTML 文本转换为 DOCX 文件并写入 HTTP 响应流中。
*
* @param htmlContent HTML 文本内容
* @param response HTTP 响应对象
* @param cacheDir 文件缓存目录
*/
public static void convertHtmlToDocxAndWriteToResponse(String htmlContent, HttpServletResponse response, String cacheDir) {
try {
// 创建 WordMLPackage 对象
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
// 使用 XHTMLImporterImpl 进行转换
XHTMLImporterImpl htmlImporter = new XHTMLImporterImpl(wordMLPackage);
documentPart.getContent().addAll(htmlImporter.convert(htmlContent, null));
// 生成临时文件路径
Path cachePath = Paths.get(cacheDir);
if (!Files.exists(cachePath)) {
Files.createDirectories(cachePath);
}
String tempFileName = UUID.randomUUID().toString() + ".docx";
Path tempFilePath = cachePath.resolve(tempFileName);
// 保存文件
wordMLPackage.save(tempFilePath.toFile());
// 设置响应头
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
response.setHeader("Content-Disposition", "attachment; filename=converted_file.docx");
// 将文件内容写入响应流
try (FileInputStream fis = new FileInputStream(tempFilePath.toFile());
OutputStream os = response.getOutputStream()) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
}
// 删除临时文件
Files.delete(tempFilePath);
} catch (Exception e) {
e.printStackTrace();
// 处理异常,例如返回错误信息
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
try {
response.getWriter().write("Error converting HTML to DOCX: " + e.getMessage());
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
4 controller直接导出
public void exportHrSpeak(@RequestBody TCompetitionHrSpeakParams params, HttpServletResponse response) {
// TCompetitionHrSpeakDto tCompetitionHrSpeak = iTCompetitionHrSpeakService.exportWord(params).getData();
String content = params.getContent();
log.info("导出 竞聘 讲稿 params:" + params);
// 转义 加格式校验。
String s = FileUtil.cleanHtml(content);
log.info("导出 竞聘 讲稿 清理完 之后 :" + s);
try {
FileUtil.exportWord(s, response);
} catch (IOException e) {
log.info("导出 竞聘 讲稿 异常 e:" + e.getMessage());
}
}
5 html内容
<html><p style="text-align: center;"><span style="font-size: 24pt;"><strong>竞聘述职口述环节讲稿</strong></span></p>
<p style="text-align: left;"><span style="font-size: 14pt;"><span style="font-size: 12pt;">尊敬的各位评委、各位领导,大家好!</span></span></p>
<p style="text-align: left; padding-left: 40px;"><span style="font-size: 14pt;"><span style="font-size: 12pt;">欢迎大家参与今天的<strong><span style="color: #0000ff;">风扇外销销</span></strong>竞聘</span></span></p>
<p style="text-align: left; padding-left: 40px;"><span style="font-size: 14pt;"><span style="font-size: 12pt;">在正式开始之前请大家将手机调为静音或振动模式</span></span></p>
<p style="text-align: left; padding-left: 40px;">本次竞聘流程分为人力口述-PPT述职-评委提问三个环节</p>
<p style="text-align: left; padding-left: 40px;">下面由我对大家的口碑、业绩、政府案测试结果进行口述</p>
<p style="text-align: left; padding-left: 40px;">第一位AA,第二位BB,请做好准备</p>
<p style="text-align: left; padding-left: 40px;">姓名:AA</p>
<p style="text-align: left; padding-left: 40px;">司龄:80年,工龄:80年</p>
<p style="text-align: left; padding-left: 40px;">口碑:80</p>
<p style="text-align: left; padding-left: 40px;">政府案测试:达标</p>
<p style="text-align: left; padding-left: 40px;">业绩:KP1100潜能/历能模型:合格</p>
<p style="text-align: left; padding-left: 40px;">优点:全是优点</p>
<p style="text-align: left; padding-left: 40px;">缺点:没有缺点</p>
<p style="text-align: left; padding-left: 40px;">接下来开始PPT述职,时间为7分钟,6分钟响铃一次,7分钟响铃二次,超时一票否决</p>
<p></p>
<p style="text-align: left; padding-left: 40px;">第二位BB</p>
<p style="text-align: left; padding-left: 40px;">姓名:BB</p>
<p style="text-align: left; padding-left: 40px;">司龄:80年,工龄:80年</p>
<p style="text-align: left; padding-left: 40px;">口碑:80</p>
<p style="text-align: left; padding-left: 40px;">政府案测试:达标</p>
<p style="text-align: left; padding-left: 40px;">业绩:KP1100潜能/历能模型:合格</p>
<p style="text-align: left; padding-left: 40px;">优点:全是优点</p>
<p style="text-align: left; padding-left: 40px;">缺点:没有缺点</p>
<p style="text-align: left; padding-left: 40px;">接下来开始PPT述职,时间为7分钟,6分钟响铃一次,7分钟响铃二次,超时一票否决</p>
<p style="text-align: left; padding-left: 40px;"></p>
<p style="text-align: left; padding-left: 40px;">没有第三位了</p></html>
前端界面
导出文档样式 ,