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;

/**

* @ClassName WordUtil

* @Description 描述:easypoi导出工具类

* @Author xuan

* @Date 2023/8/22

* @Version 2.0

**/

@Component

public 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);

}

/**

* 导出PDF

*

* @param templatePath word模板地址

* @param params 替换的参数

* @return pdf的完全路径

*/

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;

}

/**

* 导出word

* 模版变量中变量格式:{{foo}}

*

* @param templatePath word模板地址

* @param saveDir word文档保存的路径

* @param fileName 文件名

* @param params 替换的参数

*/

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();

}

/**

* @param wordPath word文件路径

* @param pdfPath pdf输出路径

*/

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();

}

}

}

/**

* @param path 图片路径

* @return

* @throws IOException

*/

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模板完全路径(业务 需求)

2.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中写了,也不会报错

目前就这些问题了,什么时候遇到新问题了在补充一下,有什么不懂的,或者有问题的可以留言

明天周末,周末愉快!!!!

相关链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: