1.介绍easypoi
EasyPoi是一款基于POI的Java快速导出/导入Excel工具。它在POI的基础上进行了封装,提供了更加简洁易用的API,使得生成Excel文件更加容易和高效。
使用EasyPoi可以轻松地生成Excel文件,并支持多种格式,如xlsx、xls、csv等。同时,EasyPoi也支持读取Excel文件,可以方便地获取其中的数据,并进行相应的处理。
EasyPoi具有以下特点:
-
简单易用:EasyPoi提供了简洁易用的API,使用起来非常方便。
-
支持多种格式:EasyPoi支持多种格式的Excel文件,如xlsx、xls、csv等。
-
灵活性高:EasyPoi支持多种数据格式,包括文本、数字、日期等,同时也支持复杂数据结构,如嵌套表格等。
-
导入导出高效:EasyPoi在性能上进行了优化,导入导出速度快,使用起来非常高效。
总之,EasyPoi是一个非常实用的Java导入导出Excel工具,它可以帮助开发者轻松地生成和处理Excel文件。
easypoi网站:悟耘科技 - Powered by MinDoc
2.改善的word工具类
在百度上面搜索了很多类似的文章,因为自己的业务需求,然后将其他博主的工具类进行了完善,最后还会说一些我做这个工具类 遇到的一些坑,
2.1导入相关依赖
如果是需要 jar包的话可以在下面给我留言
cn.afterturn easypoi-base 4.3.0 cn.afterturn easypoi-web 4.3.0 cn.afterturn easypoi-annotation 4.3.0 org.docx4j docx4j-export-fo 6.1.0 org.slf4j slf4j-log4j12
2.2准备好word模板放在resources项目下
我自己放在这个目录下,因为项目打包的原因,规范一点
2.3word模板样式
里面包含了最简单的一些参数注入
如果需要打印遍历集合,模板可以参考其他博主:java使用easypoi导出word文档,包含图片,表格,文字;_easypoi导出word list图片_一点博客的博客-CSDN博客
大概是这个样子,比较简单(其他 博主 的 模板)
模板指令:
2.4.工具类
这个工具类可以直接拿去用,我把这个工具 类封装成一个bean,需要调用的时候在业务层注入
import cn.afterturn.easypoi.word.WordExportUtil;import org.apache.poi.xwpf.usermodel.XWPFDocument;import org.docx4j.Docx4J;import org.docx4j.convert.out.FOSettings;import org.docx4j.fonts.IdentityPlusMapper;import org.docx4j.fonts.Mapper;import org.docx4j.fonts.PhysicalFonts;import org.docx4j.openpackaging.packages.WordprocessingMLPackage;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.core.io.ResourceLoader;import org.springframework.stereotype.Component;import org.springframework.util.Assert;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.*;import java.net.URLEncoder;import java.nio.charset.StandardCharsets;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Map;@Componentpublic class WordUtil { @Value(value = "${jeecg.path.upload}") private String uploadpath; //从yml文件读取文件下载路径 @Autowired private ResourceLoader resourceLoader; public String exportPdf(WordTemplateEnum templateType, Map params) throws IOException { String temPath = templateType.getPath(); String absolutePath = resourceLoader.getResource("classpath:" + temPath).getFile().getAbsolutePath(); //String absolutePath = ResourceUtils.getFile("classpath:static\\template\\1.docx").getAbsolutePath(); return exportPdf(absolutePath,params); } public String exportPdf(String templatePath, Map params) { // 生成的wold文档文件名 String woldFileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".docx"; //保存的文件路径名 String saveDir = uploadpath + File.separator + "pdf"; // 生成的pdf文件名 String pdfFileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".pdf"; // 导出wold文档 返回值为生成的wold文档全路径 String word = exportWord(templatePath, saveDir, woldFileName, params); cn.hutool.core.lang.Assert.notNull(word, "word路径不能为空"); // 自定义生成的pdf全路径 String pdfPath = saveDir + File.separator + pdfFileName; // 导出pdf,同时删除生成的wold文档 convertDocx2Pdf(word, pdfPath); return pdfPath; } public String exportWord(String templatePath, String saveDir, String fileName, Map params) { Assert.notNull(templatePath, "模板路径不能为空"); Assert.notNull(saveDir, "临时文件路径不能为空"); Assert.notNull(fileName, "导出文件名不能为空"); Assert.isTrue(fileName.endsWith(".docx"), "word导出请使用docx格式"); if (!saveDir.endsWith("/")) { saveDir = saveDir + File.separator; } File dir = new File(saveDir); if (!dir.exists()) { dir.mkdirs(); } String savePath = saveDir + fileName; try { XWPFDocument doc = WordExportUtil.exportWord07(templatePath, params); FileOutputStream fos = new FileOutputStream(savePath); doc.write(fos); fos.flush(); fos.close(); } catch (Exception e) { e.printStackTrace(); } return savePath; } public String exportWord(String templatePath, String temDir, String fileName, Map params, HttpServletRequest request, HttpServletResponse response) { Assert.notNull(templatePath,"模板路径不能为空"); Assert.notNull(temDir,"临时文件路径不能为空"); Assert.notNull(fileName,"导出文件名不能为空"); Assert.isTrue(fileName.endsWith(".docx"),"word导出请使用docx格式"); if (!temDir.endsWith("/")){ temDir = temDir + File.separator; } File dir = new File(temDir); if (!dir.exists()) { dir.mkdirs(); } try { String userAgent = request.getHeader("user-agent").toLowerCase(); if (userAgent.contains("msie") || userAgent.contains("like gecko")) { fileName = URLEncoder.encode(fileName, "UTF-8"); } else { fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1); } XWPFDocument doc = WordExportUtil.exportWord07(templatePath, params); String tmpPath = temDir + fileName; FileOutputStream fos = new FileOutputStream(tmpPath); doc.write(fos); // 设置强制下载不打开 response.setContentType("application/force-download"); // 设置文件名 response.addHeader("Content-Disposition", "attachment;fileName=" + fileName); OutputStream out = response.getOutputStream(); doc.write(out); out.close(); } catch (Exception e) { e.printStackTrace(); } finally { //这一步看具体需求,要不要删 //delFileWord(temDir,fileName); } return temDir + fileName; } public void delFileWord(String filePath, String fileName) { File file = new File(filePath + fileName); File file1 = new File(filePath); file.delete(); file1.delete(); } public void convertDocx2Pdf(String wordPath, String pdfPath) { OutputStream os = null; InputStream is = null; if (pdfPath.endsWith("/")) { pdfPath = pdfPath + File.separator; } try { is = new FileInputStream(new File(wordPath)); WordprocessingMLPackage mlPackage = WordprocessingMLPackage.load(is); Mapper fontMapper = new IdentityPlusMapper(); fontMapper.put("隶书", PhysicalFonts.get("LiSu")); fontMapper.put("宋体", PhysicalFonts.get("SimSun")); fontMapper.put("微软雅黑", PhysicalFonts.get("Microsoft Yahei")); fontMapper.put("黑体", PhysicalFonts.get("SimHei")); fontMapper.put("楷体", PhysicalFonts.get("KaiTi")); fontMapper.put("新宋体", PhysicalFonts.get("NSimSun")); fontMapper.put("华文行楷", PhysicalFonts.get("STXingkai")); fontMapper.put("华文仿宋", PhysicalFonts.get("STFangsong")); fontMapper.put("宋体扩展", PhysicalFonts.get("simsun-extB")); fontMapper.put("仿宋", PhysicalFonts.get("FangSong")); fontMapper.put("仿宋_GB2312", PhysicalFonts.get("FangSong_GB2312")); fontMapper.put("幼圆", PhysicalFonts.get("YouYuan")); fontMapper.put("华文宋体", PhysicalFonts.get("STSong")); fontMapper.put("华文中宋", PhysicalFonts.get("STZhongsong")); mlPackage.setFontMapper(fontMapper); os = new java.io.FileOutputStream(pdfPath); //docx4j docx转pdf FOSettings foSettings = Docx4J.createFOSettings(); foSettings.setWmlPackage(mlPackage); Docx4J.toFO(foSettings, os, Docx4J.FLAG_EXPORT_PREFER_XSL); is.close();//关闭输入流 os.close();//关闭输出流 } catch (Exception e) { e.printStackTrace(); try { if (is != null) { is.close(); } if (os != null) { os.close(); } } catch (Exception ex) { ex.printStackTrace(); } } finally { // 删除word文档的地址 File file = new File(wordPath); if (file != null && file.isFile() && file.exists()) { file.delete(); } } } public byte[] getImageBase64(String path) throws IOException { InputStream input = new FileInputStream(path); ByteArrayOutputStream output = new ByteArrayOutputStream(); byte[] buf = new byte[1024]; int numBytesRead = 0; while ((numBytesRead = input.read(buf)) != -1) { output.write(buf, 0, numBytesRead); } byte[] data = output.toByteArray(); output.close(); input.close(); return data; }}
其中exportpdf方法调用,第一个参数是模板路径,第二参数是 注入的参数,返回是导出的pdf模板完全路径(业务 需求)
5调用工具类
我就简单的在测试类中写一下,肯定是没有问题的,
import cn.afterturn.easypoi.entity.ImageEntity;@Autowired private WordUtil wordUtil; @Test public void testPostDoctor() throws IOException { Map params = new HashMap<>(); params.put("enterpriseName","张三"); params.put("contactsName","李四"); params.put("contactsPhone","12345678"); ImageEntity image = new ImageEntity(); image.setHeight(50); image.setWidth(50); image.setUrl("https://lmg.jj20.com/up/allimg/4k/s/02/2109250006343S5-0-lp.jpg"); params.put("testCode", image); String exportPdf = wordUtil.exportPdf("static\\template\\1.docx", params); System.out.println("exportPdf = " + exportPdf); }
下面的在application.yml文件写的文件下载路径
jeecg : path : #文件上传根目录 设置 upload: D://opt//upFiles
这个根据自己的需求来写,因为我考虑 到项目打包发服务器的,我想想应该没有其他的了把
3.1坑
自己遇到了很多坑在导出模板的,我是先将 wold模板导为wold文件,然后在将wold文件转为pdf
第一个坑:因为自己的模板放在resources目录下面,项目完整启动会将模板加载进target目录里面,会 默认的对docx文件进行压缩,一压缩就乱码, 我找了半个小时才找出问题
大概是这个样子,我们需要在pom.xml文件指明不压缩docx文件
org.apache.maven.plugins maven-resources-plugin woff woff2 eot ttf svg docx
这样就不会压缩一些 文件
第二个坑:
当一些属性你没有在map找到的时候,运行 会报空指针
解决方案:
在map中写满,如果没有值,可以写空字符串都可以,不能不写,
还有一种方案,将工具类底层调用的poiUtil中重写,运行的时候就会先调用 重写的这个类
然后将代码的这部分修改
private static Boolean isTrue(String[] keys, Map map) throws Exception { if (keys.length == 1) { String constant = null; if ((constant = isConstant(keys[0])) != null) { return Boolean.valueOf(constant); } Object paramsValue = PoiPublicUtil.getParamsValue(keys[0], map); if (Objects.isNull(paramsValue)){ return false; } return Boolean.valueOf(paramsValue.toString()); } if (keys.length == 3) { Object first = evalNoParse(keys[0], map); Object second = evalNoParse(keys[2], map); return PoiFunctionUtil.isTrue(first, keys[1], second); } throw new ExcelExportException("判断参数不对"); }
这样即使忘记在map中写了,也不会报错
目前就这些问题了,什么时候遇到新问题了在补充一下,有什么不懂的,或者有问题的可以留言
明天周末,周末愉快!!!!
来源地址:https://blog.csdn.net/xuanzihhh/article/details/132497575