赞
踩
- <dependency>
- <groupId>com.deepoove</groupId>
- <artifactId>poi-tl</artifactId>
- <version>1.12.1</version>
- </dependency>
可能会出现poi jar包冲突 如出现 将老版本的poi排掉就好 ,也可能出现 log4j 版本低 用下面这个就行
- <dependency>
- <groupId>org.apache.logging.log4j</groupId>
- <artifactId>log4j-api</artifactId>
- <version>2.17.1</version>
- </dependency>
- package com.util;
-
- import com.deepoove.poi.XWPFTemplate;
- import com.deepoove.poi.config.Configure;
- import com.deepoove.poi.config.ConfigureBuilder;
- import com.deepoove.poi.data.HyperlinkTextRenderData;
- import com.deepoove.poi.data.PictureRenderData;
- import com.deepoove.poi.data.Pictures;
- import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
- import com.deepoove.poi.util.PoitlIOUtils;
- import com.zjjw.platform.core.exception.BusinessRuntimeException;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.commons.collections.CollectionUtils;
- import org.apache.poi.xwpf.usermodel.XWPFDocument;
- import org.apache.poi.xwpf.usermodel.XWPFTable;
- import org.apache.poi.xwpf.usermodel.XWPFTableCell;
- import org.apache.poi.xwpf.usermodel.XWPFTableRow;
- import org.springframework.core.io.ClassPathResource;
-
- import javax.servlet.http.HttpServletResponse;
- import java.io.BufferedOutputStream;
- import java.io.ByteArrayInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.Closeable;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.io.UnsupportedEncodingException;
- import java.net.HttpURLConnection;
- import java.net.URL;
- import java.net.URLConnection;
- import java.net.URLEncoder;
- import java.nio.file.Files;
- import java.nio.file.Paths;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.HashMap;
- import java.util.LinkedHashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.Objects;
- import java.util.UUID;
- import java.util.stream.Collectors;
-
- /**
- * POI-TL 进行转换 支持多图片及循环增加表格
- * <p>
- * 使用方式:
- * 参数传入类型 Map<String,Object>
- * 模版 纯文本 为:
- * {{name}} 则map.put("name",params) name 是自己定义的名字 下面的都是自己定义名字,只是示例
- * <p>
- * 图片为:
- * {{@imgUrl}} 只要是 图片的 都需在参数前 加 @ 符号 这个只支持单张图片!!! map.put("imgUrl",params)
- * <p>
- * 循环表格:表格示例:
- * {{list}} 用户名称 | 年龄 | 图片
- * [user] | [age] | [?img1][@#this][/img1]
- * list 为表格定义配置 需在配置文件配置,已提供默认表格配置 和 自定义配置方法 如一个文档中有 多处 需要循环表格 {{list}} 不可重复
- * 示例:
- * String avatar = "http://deepoove.com/images/icecream.png,http://deepoove.com/images/icecream.png,http://deepoove.com/images/icecream.png";
- * List<PictureRenderData> imgList = Arrays.stream(avatar.split(",")).map(s -> Pictures.ofStream(getInputStream(s))
- * .size(50, 50).create()).collect(Collectors.toList());
- * List<Map<String, Object>> par = new ArrayList<>();
- * for (int i = 0; i <= 1; i++) {
- * Map<String, Object> map1 = new HashMap<>(16);
- * map1.put("user", "测试一下吧");
- * map1.put("age", "123");
- * map1.put("img1", imgList);
- * par.add(map1);
- * }
- * map.put("list", par);
- * 其中 getInputStream(s) 方法是 获取url文件流方法,这里也可填入文件流 或 Pictures. 按自己需求来
- * <p>
- * 空白处循环添加图片:
- * {{?imga}}
- * {{@#this}}
- * {{#table}}
- * {{/imga}}
- * <p>
- * {{#table}} 占位符
- * <p>
- * 放入map方式如上
- * <p>
- * 支持 删除表格的 第一行 也就是表头 removeTags 需要去处的表格第一行的标签 word中定义为 {{xxx}} 集合中传入 xxx
- *
- * @author: chenjiaxiang
- * @create: 2023/9/12 10:47
- **/
- @Slf4j
- public class PoiTlToWordUtils {
-
-
- /**
- * 导出文件到本地
- *
- * @param map 数据集合
- * @param nameList 循环增加表格的标识名称集合
- * @param filePath 模版地址
- * @param outPath 输出地址及文件名称 需要后缀 ,如 /xx/xx/xx.docx
- * @param removeTags 需要去处的表格第一行的标签 word中定义为 {{xxx}} 集合中传入 xxx
- */
- public static void exportWordToLocality(Map<String, Object> map, List<String> nameList, String filePath, String outPath, List<String> removeTags) {
- exportFile(map, nameList, filePath, outPath, null, removeTags);
- }
-
- /**
- * 导出文件到本地,无循环表格
- *
- * @param map 数据集合
- * @param filePath 模版地址
- * @param outPath 输出地址及文件名称 需要后缀 ,如 /xx/xx/xx.docx
- * @param removeTags 需要去处的表格第一行的标签 word中定义为 {{xxx}} 集合中传入 xxx
- */
- public static void exportWordToLocality(Map<String, Object> map, String filePath, String outPath, List<String> removeTags) {
- exportFile(map, null, filePath, outPath, null, removeTags);
- }
-
- /**
- * 导出文件到本地
- *
- * @param map 数据集合
- * @param nameList 循环增加表格的标识名称集合
- * @param filePath 模版地址
- * @param outPath 输出地址及文件名称 需要后缀 ,如 /xx/xx/xx.docx
- * @param configure 自定义配置文件
- * @param removeTags 需要去处的表格第一行的标签 word中定义为 {{xxx}} 集合中传入 xxx
- */
- public static void exportWordToLocality(Map<String, Object> map, List<String> nameList, String filePath, String outPath, Configure configure, List<String> removeTags) {
- exportFile(map, nameList, filePath, outPath, configure, removeTags);
- }
-
- /**
- * 导出文件到本地,无循环表格
- *
- * @param map 数据集合
- * @param filePath 模版地址
- * @param outPath 输出地址及文件名称 需要后缀 ,如 /xx/xx/xx.docx
- * @param configure 自定义配置文件
- * @param removeTags 需要去处的表格第一行的标签 word中定义为 {{xxx}} 集合中传入 xxx
- */
- public static void exportWordToLocality(Map<String, Object> map, String filePath, String outPath, Configure configure, List<String> removeTags) {
- exportFile(map, null, filePath, outPath, configure, removeTags);
- }
-
- /**
- * 浏览器下载
- *
- * @param response response
- * @param map 数据信息
- * @param nameList 循环增加表格的标识名称集合
- * @param filePath 模版文件地址
- * @param fileName 文件名称
- * @param removeTags 需要去处的表格第一行的标签 word中定义为 {{xxx}} 集合中传入 xxx
- */
- public static void exportBrowser(HttpServletResponse response, Map<String, Object> map, List<String> nameList, String filePath, String fileName, List<String> removeTags) {
- exportFile(response, map, nameList, filePath, fileName, null, removeTags);
- }
-
- /**
- * 浏览器下载,无循环表格
- *
- * @param response response
- * @param map 数据信息
- * @param filePath 模版文件地址
- * @param fileName 文件名称
- * @param removeTags 需要去处的表格第一行的标签 word中定义为 {{xxx}} 集合中传入 xxx
- */
- public static void exportBrowser(HttpServletResponse response, Map<String, Object> map, String filePath, String fileName, List<String> removeTags) {
- exportFile(response, map, null, filePath, fileName, null, removeTags);
- }
-
- /**
- * 浏览器下载 支持自定义配置文件
- *
- * @param response response
- * @param map 数据信息
- * @param nameList 循环增加表格的标识名称集合
- * @param filePath 模版文件地址
- * @param fileName 文件名称
- * @param configure 自定义配置文件
- * @param removeTags 需要去处的表格第一行的标签 word中定义为 {{xxx}} 集合中传入 xxx
- */
- public static void exportBrowser(HttpServletResponse response, Map<String, Object> map, List<String> nameList, String filePath, String fileName, Configure configure, List<String> removeTags) {
- exportFile(response, map, nameList, filePath, fileName, configure, removeTags);
- }
-
- /**
- * 浏览器下载,无循环表格,支持自定义配置文件
- *
- * @param response response
- * @param map 数据信息
- * @param filePath 模版文件地址
- * @param fileName 文件名称
- * @param configure 自定义配置文件
- * @param removeTags 需要去处的表格第一行的标签 word中定义为 {{xxx}} 集合中传入 xxx
- */
- public static void exportBrowser(HttpServletResponse response, Map<String, Object> map, String filePath, String fileName, Configure configure, List<String> removeTags) {
- exportFile(response, map, null, filePath, fileName, configure, removeTags);
- }
-
- /**
- * 文件生成返回 InputStream
- *
- * @param map 数据集合
- * @param nameList 循环增加表格的标识名称集合
- * @param filePath 模版地址
- * @param removeTags 需要去处的表格第一行的标签 word中定义为 {{xxx}} 集合中传入 xxx
- */
- public static InputStream exportFileInputStream(Map<String, Object> map, List<String> nameList, String filePath, List<String> removeTags) {
- return exportFile(map, nameList, filePath, null, removeTags);
- }
-
- /**
- * 文件生成返回 InputStream ,无循环表格
- *
- * @param map 数据集合
- * @param filePath 模版地址
- * @param removeTags 需要去处的表格第一行的标签 word中定义为 {{xxx}} 集合中传入 xxx
- */
- public static InputStream exportFileInputStream(Map<String, Object> map, String filePath, List<String> removeTags) {
- return exportFile(map, null, filePath, null, removeTags);
- }
-
-
- /**
- * 文件生成返回 InputStream
- *
- * @param map 数据集合
- * @param nameList 循环增加表格的标识名称集合
- * @param filePath 模版地址
- * @param configure 自定义配置文件
- * @param removeTags 需要去处的表格第一行的标签 word中定义为 {{xxx}} 集合中传入 xxx
- */
- public static InputStream exportFileInputStream(Map<String, Object> map, List<String> nameList, String filePath, Configure configure, List<String> removeTags) {
- return exportFile(map, nameList, filePath, configure, removeTags);
- }
-
- /**
- * 文件生成返回 InputStream ,无循环表格
- *
- * @param map 数据集合
- * @param filePath 模版地址
- * @param configure 自定义配置文件
- * @param removeTags 需要去处的表格第一行的标签 word中定义为 {{xxx}} 集合中传入 xxx
- */
- public static InputStream exportFileInputStream(Map<String, Object> map, String filePath, Configure configure, List<String> removeTags) {
- return exportFile(map, null, filePath, configure, removeTags);
- }
-
- /**
- * 导出文件到本地
- *
- * @param map 数据集合
- * @param nameList 循环增加表格的标识名称集合
- * @param filePath 模版地址
- * @param outPath 输出地址及文件名称 需要后缀 ,如 /xx/xx/xx.docx
- * @param removeTags 需要去处的表格第一行的标签 word中定义为 {{xxx}} 集合中传入 xxx
- */
- private static void exportFile(Map<String, Object> map, List<String> nameList, String filePath, String outPath, Configure configure, List<String> removeTags) {
- XWPFTemplate template = null;
- BufferedOutputStream bos = null;
- OutputStream out = null;
- try {
- // 获取Word模板,模板存放路径在项目的resources目录下
- template = common(filePath, map, nameList, configure);
- out = new ByteArrayOutputStream();
- bos = new BufferedOutputStream(out);
- template.write(bos);
- bos.flush();
- out.flush();
- removeTags(template, removeTags);
- template.writeAndClose(Files.newOutputStream(Paths.get(outPath)));
- } catch (Exception e) {
- log.info("[生成word文件]-失败,{}", e.getMessage());
- throw new BusinessRuntimeException(e.getMessage());
- } finally {
- closeStream(template);
- closeStream(bos);
- closeStream(out);
- }
- }
-
-
- /**
- * 浏览器下载
- *
- * @param response response
- * @param map 数据信息
- * @param nameList 循环增加表格的标识名称集合
- * @param filePath 模版文件地址
- * @param fileName 文件名称
- * @param removeTags 需要去处的表格第一行的标签 word中定义为 {{xxx}} 集合中传入 xxx
- */
- private static void exportFile(HttpServletResponse response, Map<String, Object> map, List<String> nameList, String filePath, String fileName, Configure configure, List<String> removeTags) {
- XWPFTemplate template = null;
- BufferedOutputStream bos = null;
- OutputStream out = null;
- try {
- // 获取Word模板,模板存放路径在项目的resources目录下
- template = common(filePath, map, nameList, configure);
- // 浏览器端下载 设置响应
- setResponse(response, fileName);
- out = response.getOutputStream();
- bos = new BufferedOutputStream(out);
- removeTags(template, removeTags);
- template.write(bos);
- bos.flush();
- out.flush();
- PoitlIOUtils.closeQuietlyMulti(template, bos, out);
- } catch (Exception e) {
- log.info("[生成word文件]-失败,{}", e.getMessage());
- throw new BusinessRuntimeException(e.getMessage());
- } finally {
- closeStream(template);
- closeStream(bos);
- closeStream(out);
- }
- }
-
- /**
- * 文件生成返回 InputStream
- *
- * @param map 数据集合
- * @param nameList 循环增加表格的标识名称集合
- * @param filePath 模版地址
- * @param removeTags 需要去处的表格第一行的标签 word中定义为 {{xxx}} 集合中传入 xxx
- */
- private static InputStream exportFile(Map<String, Object> map, List<String> nameList, String filePath, Configure configure, List<String> removeTags) {
- XWPFTemplate template = null;
- ByteArrayOutputStream bos = null;
- try {
- // 获取Word模板,模板存放路径在项目的resources目录下
- template = common(filePath, map, nameList, configure);
- bos = new ByteArrayOutputStream();
- removeTags(template, removeTags);
- template.write(bos);
- return new ByteArrayInputStream(bos.toByteArray());
- } catch (Exception e) {
- log.info("[生成word文件]-失败,{}", e.getMessage());
- throw new BusinessRuntimeException(e.getMessage());
- } finally {
- closeStream(template);
- closeStream(bos);
- }
- }
-
- private static XWPFTemplate common(String filePath, Map<String, Object> map, List<String> nameList, Configure configure) {
- //获取模版文件的文件流
- XWPFTemplate template;
- InputStream ins = null;
- try {
- ins = getTemplate(filePath);
- //如果有循环添加的数据表格的话 则绑定
- template = CollectionUtils.isNotEmpty(nameList) ? XWPFTemplate.compile(ins, Objects.nonNull(configure) ? configure : getConfig(nameList)).render(map)
- : XWPFTemplate.compile(ins).render(map);
- } finally {
- closeStream(ins);
- }
- return template;
- }
-
- private static <T extends Closeable> void closeStream(T ins) {
- if (ins != null) {
- try {
- ins.close();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- }
-
-
- /**
- * 绑定循环表格标识
- *
- * @param nameList 标识集合
- * @return 配置
- */
- private static Configure getConfig(List<String> nameList) {
- //使用行循环插件
- LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
- ConfigureBuilder builder = Configure.builder();
- nameList.forEach(name -> builder.bind(name, policy));
- return builder.build();
- }
-
-
- /**
- * 【获取网络文件的输入流】
- *
- * @param filePath: 网络文件路径
- * @return java.io.InputStream
- */
- public static InputStream getInputStream(String filePath) {
- InputStream inputStream = null;
- //创建URL
- try {
- URL url = new URL(filePath);
- //试图连接并取得返回状态码
- URLConnection urlconn = url.openConnection();
- urlconn.connect();
- HttpURLConnection httpconn = (HttpURLConnection) urlconn;
- int httpResult = httpconn.getResponseCode();
- if (httpResult == HttpURLConnection.HTTP_OK) {
- inputStream = urlconn.getInputStream();
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
-
- return inputStream;
- }
-
- /**
- * 获取模版文件流信息
- *
- * @param filePath 模版路径
- * @return 流
- */
- public static InputStream getTemplate(String filePath) {
- // 获取Word模板,模板存放路径在项目的resources目录下
- ClassPathResource classPathResource = new ClassPathResource(filePath);
- try {
- return classPathResource.getInputStream();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * 放入 response
- *
- * @param response 响应
- * @param fileName 文件名称
- */
- private static void setResponse(HttpServletResponse response, String fileName) {
- response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
- response.setCharacterEncoding("utf-8");
- String filePoiName;
- try {
- filePoiName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException(e);
- }
- response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + filePoiName + ".docx");
- }
-
- /**
- * 去处表格标签
- *
- * @param template word
- * @param removeTags 标签集合
- */
- private static void removeTags(XWPFTemplate template, List<String> removeTags) {
- if (CollectionUtils.isNotEmpty(removeTags)) {
- traverseTables(template.getXWPFDocument(), removeTags);
- }
- }
-
- /**
- * 根据标签去除该表格的 第一行
- *
- * @param document 文件
- * @param removeTags 标签集合
- */
- private static void traverseTables(XWPFDocument document, List<String> removeTags) {
- List<XWPFTable> tables = document.getTables();
- // 递归处理嵌套表格
- tables.forEach(table -> {
- containsMarkerInFirstRow(table, removeTags);
- traverseNestedTables(table, removeTags);
- });
- }
-
- /**
- * 递归处理嵌套表格
- *
- * @param table 表格
- * @param removeTags 需要去处的表格标签
- */
- private static void traverseNestedTables(XWPFTable table, List<String> removeTags) {
- table.getRows().forEach(row -> row.getTableCells().forEach(cell -> traverseTables(cell, removeTags)));
- }
-
- /**
- * 传入cell 进行判断当前行是否包含
- */
- private static void traverseTables(XWPFTableCell cell, List<String> removeTags) {
- cell.getTables().forEach(table -> {
- // 判断是否包含标签 是的话则去除表格表头
- containsMarkerInFirstRow(table, removeTags);
- traverseNestedTables(table, removeTags);
- });
- }
-
- /**
- * 判断是否包含标签 是的话则去除表格表头
- *
- * @param table 表格
- * @param removeTags 需要去处的表格信息
- */
- private static void containsMarkerInFirstRow(XWPFTable table, List<String> removeTags) {
- List<XWPFTableRow> rows = table.getRows();
- int a = 0;
- if (!rows.isEmpty()) {
- for (XWPFTableRow row : rows) {
- if (removeTags.stream().anyMatch(removeTag -> row.getTable().getText().contains(String.format("{{%s}}", removeTag)) && rows.indexOf(row) == 0)) {
- table.removeRow(0);
- a = 1;
- }
- if (a > 0) {
- break;
- }
- }
- }
- }
-
-
- private static final String OUT_PATH = "/Users/chenjx/Downloads/zipceshi/0911/";
-
- private static final String FOP = "/file/elTest123.docx";
-
-
- public static void main(String[] args) {
- Map<String, Object> m = new HashMap<>();
- m.put("baseName", "爱就是打卡上");
- m.put("imgUrl", Pictures.ofStream(getInputStream("http://img.crcz.com/allimg/202003/27/1585280268112506.jpg"))
- .size(50, 50).create());
- //try {
- String avatar = "http://img.crcz.com/allimg/202003/27/1585280268105939.jpg," +
- "http://img.crcz.com/allimg/202003/27/1585280268458675.jpg," +
- "http://img.crcz.com/allimg/202003/26/1585192258743890-lp.jpg";
- List<PictureRenderData> imgList = Arrays.stream(avatar.split(",")).map(s -> Pictures.ofStream(getInputStream(s))
- .size(50, 50).create()).collect(Collectors.toList());
- List<Map<String, Object>> par = new ArrayList<>();
- for (int i = 0; i <= 1; i++) {
- Map<String, Object> map = new HashMap<>(16);
- map.put("user", "测试一下吧");
- map.put("pag", "123");
- map.put("img1", imgList);
- par.add(map);
- }
-
- m.put("imgs", imgList);
- m.put("img", imgList);
- m.put("list", par);
- m.put("list1", par);
- m.put("list3", par);
- m.put("imga", imgList);
- m.put("mo", new HyperlinkTextRenderData("测试超链接", "http://www.baidu.com"));
-
- List<Map<String, Object>> par1 = new ArrayList<>();
- for (int i = 0; i <= 2; i++) {
- Map<String, Object> map = new LinkedHashMap<>(16);
- map.put("test1", "测试一下吧");
- map.put("test2", "123");
- map.put("test3", imgList);
- par1.add(map);
- }
- exportWordToLocality(m, Arrays.asList("list", "list1", "list3"), FOP, OUT_PATH + UUID.randomUUID() + ".docx", Arrays.asList("remove_tit", "remove_tit1"));
-
- }
-
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。