JAVA使用Apache POI动态导出Word文档

懒惰的小白521 2024-07-01 16:07:02 阅读 59

文章目录

一、文章背景二、实现步骤2.1 普通篇-需要的依赖2.2 普通篇-创建模板2.3 普通篇-书写java类2.3.1 模板目录2.3.2 Controller类2.3.2 Util类

2.4 普通篇-测试2.4.1 浏览器请求接口2.4.2 下载word

2.5 额外篇-list集合遍历2.5.1 模板2.5.2 工具类2.5.3 Controller类2.5.4 生成的案例

2.6 额外篇-单元格中换行2.6.1 模板2.6.2 工具类2.6.3 Controller类2.6.4 生成的案例

三、注意事项四、其他导出word实现方式

一、文章背景

基于Freemarker模版动态生成并导出word文档存在弊端,生成的word文档格式是xml类型(通过生成word文档然后点击另存为可以查看是xml类型);但我们当前的需求是对生成的word文档提供预览功能,在公司提供的接口中,如果word格式不是doc格式就不能正确展示数据;同时对于频繁修改模板,Freemarker不好维护等问题;于是就有了此篇文章。调研市面上java导出word文档主流的方案以及弊端(借鉴以下文章):https://zhuanlan.zhihu.com/p/672525861

在这里插入图片描述

二、实现步骤

2.1 普通篇-需要的依赖

<dependency>

<groupId>cn.afterturn</groupId>

<artifactId>easypoi-base</artifactId>

<version>4.4.0</version>

</dependency>

<dependency>

<groupId>cn.afterturn</groupId>

<artifactId>easypoi-web</artifactId>

<version>4.4.0</version>

</dependency>

<dependency>

<groupId>cn.afterturn</groupId>

<artifactId>easypoi-annotation</artifactId>

<version>4.4.0</version>

</dependency>

<dependency>

<groupId>org.apache.poi</groupId>

<artifactId>poi</artifactId>

<version>4.1.1</version>

</dependency>

<dependency>

<groupId>org.apache.poi</groupId>

<artifactId>poi-ooxml</artifactId>

<version>4.1.1</version>

</dependency>

2.2 普通篇-创建模板

请添加图片描述

2.3 普通篇-书写java类

2.3.1 模板目录

在这里插入图片描述

2.3.2 Controller类

/**

* @author henry

* @version 1.0

* @describe todo

* @data 2024/5/10 09:44

*/

@Api("测试poi导出word")

@RestController

@RequestMapping("/poiExport")

@Slf4j

public class Controller {

@ApiOperation("word模板下载")

@GetMapping("/poiExport")

public void exportWordByModel(HttpServletResponse response, String path){

Map<String,Object> map = new HashMap<>();

map.put("startTime","2023");

map.put("endTime","2024");

map.put("name","tom");

map.put("age","23");

map.put("sex","男");

List<String> list = new ArrayList<>();

list.add("2019就读A学校");

list.add("2022就读B学校");

list.add("2023上岸研究生");

map.put("list",list);

ImageEntity imageEntity = new ImageEntity();

imageEntity.setUrl(FileUtil.filePath("templates/cute.png").getPath());

imageEntity.setWidth(80);

imageEntity.setHeight(100);

map.put("photo",imageEntity);

FileUtil.exportWordByModel(response,map,"templates/word.docx","员工统计");

}

}

2.3.2 Util类

/**

* @author henry

* @version 1.0

* @describe todo

* @data 2024/5/10 09:48

*/

public class FileUtil {

/**

* 根据模板导出Word

* @param response

* @param map

* @param modelFileName

* @param outFileName

*/

public static void exportWordByModel(HttpServletResponse response, Map<String, Object> map, String modelFileName, String outFileName) {

try {

// 1.获取模板文件路径 - 重点

//XWPFDocument word = WordExportUtil.exportWord07(modelFileName, map);有时候这种方式可以找到有时候找不到(不太清楚)

String templatePath = filePath(modelFileName).getAbsolutePath();

// 打印出模板文件的完整路径 - 校验路径是否存在

File templateFile = new File(templatePath);

if (templateFile.exists()) {

System.out.println("模板文件存在: " + templateFile.getAbsolutePath());

} else {

System.out.println("模板文件不存在: " + templateFile.getAbsolutePath());

}

// 2.映射模板,替换数据

XWPFDocument word = WordExportUtil.exportWord07(templatePath, map);

// 3.设置返回参数的字符集

response.reset();

response.setHeader("Access-Control-Allow-Origin", "*");

response.setContentType("application/msexcel");

response.setContentType("text/html; charset=UTF-8");

// 4.设置响应类型为Word文档

response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");

// 5.中文文件名处理,否则报错

String encodedFileName = URLEncoder.encode(outFileName, "UTF-8");

response.setHeader("Content-Disposition", "attachment;filename=" + encodedFileName + ".docx");

// 6.将Word文档发送到浏览器

word.write(response.getOutputStream());

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* 根据文件名获取文件对象

* @param modelFileName

* @return

*/

public static File filePath(String modelFileName) {

// 获取类加载器

ClassLoader classLoader = FileUtil.class.getClassLoader();

// 尝试从类路径中加载资源

URL resource = classLoader.getResource(modelFileName);

return new File(resource.getFile());

}

}

2.4 普通篇-测试

2.4.1 浏览器请求接口

在这里插入图片描述

2.4.2 下载word

在这里插入图片描述

2.5 额外篇-list集合遍历

2.5.1 模板

请添加图片描述

2.5.2 工具类

同生成基本word的工具类

2.5.3 Controller类

@ApiOperation("word模板下载(主要测试遍历)")

@GetMapping("/poiExportList")

public void exportWordByModelList(HttpServletResponse response, String path) throws Exception {

Map<String, Object> map = new HashMap<>();

Course chineseCourse = new Course("语文", 90.00);

Course mathCourse = new Course("数学", 92.00);

Course englistCourse = new Course("英语", 94.00);

List<Course> courseList = new ArrayList<>();

courseList.add(chineseCourse);

courseList.add(mathCourse);

courseList.add(englistCourse);

map.put("courseList", courseList);

FileUtil.exportWordByModel(response,map,"templates/wordList.docx","简介");

}

2.5.4 生成的案例

请添加图片描述

2.6 额外篇-单元格中换行

2.6.1 模板

请添加图片描述

2.6.2 工具类

需要在单元格换行,只需要添加“//---------------------单元格换行----------------------”内的代码即可。然后根据索引获取对应的单元格

public class FileUtil {

/**

* 根据模板导出Word

* @param response

* @param map

* @param modelFileName

* @param outFileName

*/

public static void exportWordByModel(HttpServletResponse response, Map<String, Object> map, String modelFileName, String outFileName) {

try {

// 1.获取模板文件路径 - 重点

// XWPFDocument word = WordExportUtil.exportWord07(modelFileName, map);

String templatePath = filePath(modelFileName).getAbsolutePath();

// 打印出模板文件的完整路径 - 校验路径是否存在

File templateFile = new File(templatePath);

if (templateFile.exists()) {

System.out.println("模板文件存在: " + templateFile.getAbsolutePath());

} else {

System.out.println("模板文件不存在: " + templateFile.getAbsolutePath());

}

// 2.映射模板,替换数据

XWPFDocument word = WordExportUtil.exportWord07(templatePath, map);

// ---------------------单元格换行----------------------

// 获取表格

XWPFTable table = word.getTables().get(0); // 假设表格是第一个

// 根据行列索引获取单元格并设置样式

int rowIndex = 0; // 假设单元格在第一行

int colIndex = 1; // 假设单元格在第二列

XWPFTableCell cell = table.getRow(rowIndex).getCell(colIndex);

cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);

// 创建段落和运行实例

XWPFParagraph para = cell.addParagraph();

para.setWordWrapped(true); // 允许段落内的文本换行

XWPFRun run = para.createRun();

// 设置文本和换行符

String text = (String) map.get("name");

String[] lines = text.split("\n");

run.setText(lines[0], 0);

for (int i = 1; i < lines.length; i++) {

run.addBreak(BreakType.TEXT_WRAPPING);

run.setText(lines[i]);

}

// ---------------------单元格换行----------------------

// 3.设置返回参数的字符集

response.reset();

response.setHeader("Access-Control-Allow-Origin", "*");

response.setContentType("application/msexcel");

response.setContentType("text/html; charset=UTF-8");

// 4.设置响应类型为Word文档

response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");

// 5.中文文件名处理,否则报错

String encodedFileName = URLEncoder.encode(outFileName, "UTF-8");

response.setHeader("Content-Disposition", "attachment;filename=" + encodedFileName + ".docx");

// 6.将Word文档发送到浏览器

word.write(response.getOutputStream());

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* 根据文件名获取文件对象

* @param modelFileName

* @return

*/

public static File filePath(String modelFileName) {

// 获取类加载器

ClassLoader classLoader = FileUtil.class.getClassLoader();

// 尝试从类路径中加载资源

URL resource = classLoader.getResource(modelFileName);

return new File(resource.getFile());

}

}

2.6.3 Controller类

@ApiOperation("word模板下载(主要测试遍历)")

@GetMapping("/poiExportList")

public void exportWordByModelList(HttpServletResponse response, String path) throws Exception {

Map<String, Object> map = new HashMap<>();

map.put("name","lisi\nzhangsan");

map.put("sex","男");

map.put("nation","中国北京");

map.put("age",12);

FileUtil.exportWordByModel(response,map,"templates/wordList.docx","简介");

}

2.6.4 生成的案例

请添加图片描述

三、注意事项

1、模板文件读取不到(容易出现错误-需及时更换文件读取方式)

四、其他导出word实现方式

JAVA利用Freemarker模版动态生成并导出word文档



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。