赞
踩
- 基于Freemarker模版动态生成并导出word文档存在弊端,生成的word文档格式是xml类型(通过生成word文档然后点击另存为可以查看是xml类型);但我们当前的需求是对生成的word文档提供预览功能,在公司提供的接口中,如果word格式不是doc格式就不能正确展示数据;同时对于频繁修改模板,Freemarker不好维护等问题;于是就有了此篇文章。
- 调研市面上java导出word文档主流的方案以及弊端(借鉴以下文章):https://zhuanlan.zhihu.com/p/672525861
<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>
/** * @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","员工统计"); } }
/** * @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()); } }
同生成基本word的工具类
@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","简介"); }
需要在单元格换行,只需要添加“//---------------------单元格换行----------------------”内的代码即可。然后根据索引获取对应的单元格
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()); } }
@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","简介");
}
1、模板文件读取不到(容易出现错误-需及时更换文件读取方式)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。