springboot+poi-tl根据模板导出word(含动态表格和图片),并将导出的文档压缩zip导出

本文主要是介绍springboot+poi-tl根据模板导出word(含动态表格和图片),并将导出的文档压缩zip导出,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

springboot+poi-tl根据模板导出word(含动态表格和图片)

官网:http://deepoove.com/poi-tl/
参考网站:https://blog.csdn.net/M625387195/article/details/124855854

  • pom导入的maven依赖
<dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.12.1</version>
</dependency>
  • 准备模板
    在这里插入图片描述
    文本标签用{{ }},动态表格的字段标签用[]。

  • 代码实现
    3.1 控制器

    package io.renren.modules.sys.controller;
    import io.renren.common.utils.R;
    import io.renren.modules.sys.service.POIService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;/*** @Author: Administrator* @Date: 2024/3/14* @Description:*/
    @RestController
    @RequestMapping("/anli")
    public class AnliController {@Autowiredprivate POIService poiService;@GetMapping("/daochu/{renwuId}")public R daochu(@PathVariable("renwuId") Long renwuId) {String zipUrl = poiService.anlidaochu(renwuId);return new R().put("zipUrl", zipUrl);}
    }
    

    3.2 实现类

    package io.renren.modules.sys.service;/*** @Author: Administrator* @Date: 2024/3/4* @Description:*/
    public interface POIService {/*** 案例导出* @param renwuId*/String anlidaochu(Long renwuId);
    }
    
    package io.renren.modules.sys.service.impl;import io.renren.common.utils.word.WordUtils;
    import io.renren.modules.sys.dto.RenwuTemplateDTO;
    import io.renren.modules.sys.service.POIService;
    import io.renren.modules.sys.service.SysRenwuService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.List;
    import java.util.UUID;
    import java.util.concurrent.CompletableFuture;
    import java.util.zip.ZipOutputStream;/*** @Author: Administrator* @Date: 2024/3/4* @Description:*/
    @Service
    public class POIServiceImpl implements POIService {@Autowiredprivate SysRenwuService renwuService;@Value("${upload.url}")private String UPLOAD_URL;@Value("${upload.path}")private String UPLOAD_SUFFIX_URL;public String getUPLOAD_URL() {return UPLOAD_URL + getUploadSuffixURL();}public String getUploadSuffixURL() {SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");String dateString = sdf.format(new Date());return UPLOAD_SUFFIX_URL + dateString + "/";}/*** 案例导出* @param renwuId*/@Overridepublic String anlidaochu(Long renwuId) {// 将要生成文档的数据查询出来RenwuTemplateDTO renwuTemplateDTO = renwuService.daochuByRenwuId(renwuId);String url = null;if (renwuTemplateDTO != null) {try {List<String> urlList = WordUtils.piliangDaochu(renwuTemplateDTO);if (urlList != null && urlList.size() > 0) {String name = renwuTemplateDTO.getRenwuName()+"_"+ UUID.randomUUID() +".zip";url =  this.getUploadSuffixURL() + name;FileOutputStream fos = new FileOutputStream(this.getUPLOAD_URL() + name);ZipOutputStream zos = new ZipOutputStream(fos);for (String file : urlList) {WordUtils.addToZipFile(file, zos);}zos.close();fos.close();// 使用异步线程删除文件deleteFilesAsync(urlList);}} catch (Exception e) {throw new RuntimeException(e);}}return url;}@Asyncpublic CompletableFuture<Void> deleteFilesAsync(List<String> urlList) {for (String file : urlList) {File fileToDelete = new File(file);if (fileToDelete.exists()) {if (fileToDelete.delete()) {System.out.println("Deleted file: " + file);} else {System.out.println("Failed to delete file: " + file);}}}return CompletableFuture.completedFuture(null);}
    }
    

    3.3 配置文件

    upload:url: H:/GoTionBackends/2023/resourcespath: /u/cms/www/outPath: H:/GoTionBackends/2023/resources/docprefix: http://xxx.xxx.xxx:8087
    

    3.4 工具类

    package io.renren.common.utils.word;import com.alibaba.fastjson.JSON;
    import com.deepoove.poi.XWPFTemplate;
    import com.deepoove.poi.config.Configure;
    import com.deepoove.poi.data.*;
    import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
    import com.deepoove.poi.policy.PictureRenderPolicy;
    import io.renren.common.utils.word.dto.WordQingdanDetailsDTO;
    import io.renren.modules.sys.dto.RenwuTemplateDTO;
    import io.renren.modules.sys.entity.SysQingdanExtEntity;
    import org.apache.commons.lang.StringUtils;import java.io.*;
    import java.nio.file.Files;
    import java.nio.file.Paths;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.UUID;
    import java.util.zip.ZipEntry;
    import java.util.zip.ZipOutputStream;/*** @Author: Administrator* @Date: 2024/3/1* @Description:*/
    public class WordUtils {public static List<String> piliangDaochu(RenwuTemplateDTO renwuTemplate) throws IOException {List<String> urlList = new ArrayList<>();if (renwuTemplate.getQingdanDTOList() != null && renwuTemplate.getQingdanDTOList().size() > 0) {for (int i = 0; i < renwuTemplate.getQingdanDTOList().size(); i++) {renwuTemplate.setQingdanDTO(renwuTemplate.getQingdanDTOList().get(i));String daochuUrl = daochumoban(renwuTemplate);urlList.add(daochuUrl);}} else {String daochuUrl =daochumoban(renwuTemplate);urlList.add(daochuUrl);}return urlList;}public static String daochumoban(RenwuTemplateDTO renwuTemplate) throws IOException {// 为表格的显示绑定行循环LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();// 将bz设置为行循环绑定的数据源的key,即key是bz的value会在模板中的{{bz}}处进行解析Configure configure = Configure.builder().bind("bz", policy).build();// 图片标签集合List<String> pictureTag = new ArrayList<>();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");HashMap<String, Object> dataMap = new HashMap<String, Object>() {{//添加文本put("xiangmuName", renwuTemplate.getXiangmuName());put("xiangmuzhouqi", renwuTemplate.getXiangmuzhouqi());put("renwuName", renwuTemplate.getRenwuName());put("renwuzhouqi", sdf.format(renwuTemplate.getStartTime()) + " 至 " + sdf.format(renwuTemplate.getEndTime()));put("description", renwuTemplate.getDescription());String xiangmuLink = "";if (renwuTemplate.getRenwuResourceUrlList() != null && renwuTemplate.getRenwuResourceUrlList().size() > 0) {for (int i = 0; i < renwuTemplate.getRenwuResourceUrlList().size(); i++) {if (i != renwuTemplate.getRenwuResourceUrlList().size()-1) {xiangmuLink += PeizhiConfig.getUploadPrefix() + renwuTemplate.getRenwuResourceUrlList().get(i) + "\n";} else {xiangmuLink += PeizhiConfig.getUploadPrefix() + renwuTemplate.getRenwuResourceUrlList().get(i);}}}put("xiangmulink", xiangmuLink );put("biaoqianName", renwuTemplate.getQingdanDTO() != null ? renwuTemplate.getQingdanDTO().getBiaoqianName() : "");String diliurk = PeizhiConfig.getUploadUrl() + renwuTemplate.getQingdanDTO().getResourceUrl();PictureRenderData pictureRenderData = Pictures.ofStream(Files.newInputStream(Paths.get(diliurk)), PictureType.PNG).size(200, 150).create();put("dililink", pictureRenderData);put("resourceDescription", renwuTemplate.getQingdanDTO() != null ? renwuTemplate.getQingdanDTO().getDescription() : "");put("startYear", renwuTemplate.getQingdanDTO() != null ? renwuTemplate.getQingdanDTO().getStartYear() : "");put("endYear", renwuTemplate.getQingdanDTO() != null ? renwuTemplate.getQingdanDTO().getEndYear(): "");put("area", renwuTemplate.getQingdanDTO() != null ? renwuTemplate.getQingdanDTO().getArea() : "");// 其他业务获取到数据源String testTable = null;if (renwuTemplate.getQingdanDTO() != null && renwuTemplate.getQingdanDTO().getQingdanExtList() != null &&  renwuTemplate.getQingdanDTO().getQingdanExtList().size() > 0) {String str = "";for (int i = 0; i < renwuTemplate.getQingdanDTO().getQingdanExtList().size(); i++) {SysQingdanExtEntity ext = renwuTemplate.getQingdanDTO().getQingdanExtList().get(i);String templateType = null, data = PeizhiConfig.getUploadPrefix() + ext.getResourceUrl();// PictureRenderData pictureRenderData1 = null;if (ext.getTemplateType() == 1) {templateType = "图片";//String dataUrl = PeizhiConfig.getUploadUrl() + ext.getResourceUrl();//pictureRenderData1 = Pictures.ofStream(Files.newInputStream(Paths.get(dataUrl)), PictureType.PNG)//        .size(200, 150).create();} else if (ext.getTemplateType() == 2) {templateType = "附件";} else if (ext.getTemplateType() == 3) {templateType = "音视频";} else if (ext.getTemplateType() == 4) {templateType = "文本";data = ext.getExtText();} else if (ext.getTemplateType() == 5) {templateType = "文档";}String source = StringUtils.isNotBlank(ext.getSource()) ? ext.getSource() : "";data = StringUtils.isNotBlank(data) ? data : "";str += "{\n" +"        \"index\": \"" + (i + 1) + "\",\n" +"        \"templateName\": \"" + ext.getTemplateName() + "\",\n" +"        \"templateType\": \"" + templateType + "\",\n" +"        \"source\": \"" + source + "\",\n" +"        \"data\": \"" + data + "\",\n" +"    },\n";}testTable = "[" + str + "]";}// 内容在表格里循环// JSON使用,需要导入fastjson依赖List<WordQingdanDetailsDTO> forms = JSON.parseArray(testTable, WordQingdanDetailsDTO.class);if (forms != null && forms.size() > 0) {for (int i = 0; i < forms.size(); i++) {put("index" + i, forms.get(i).getIndex());put("templateName" + i, forms.get(i).getTemplateName());put("templateType" + i, forms.get(i).getTemplateType());put("source" + i, forms.get(i).getSource());put("data" + i, forms.get(i).getData());}}put("bz", forms);pictureTag.add("dililink");}};for (String tag : pictureTag ) {//设置图片,不然保存的是一串字符configure.customPolicy(tag, new PictureRenderPolicy());}if (!new File(PeizhiConfig.getUploadOutPath()).exists()) {new File(PeizhiConfig.getUploadOutPath()).mkdirs();}String outPath = PeizhiConfig.getUploadOutPath() + "/"+ UUID.randomUUID() +".docx";// 读取模板、数据并渲染XWPFTemplate template = XWPFTemplate.compile(new FileInputStream(PeizhiConfig.getUploadOutPath() + "/任务数据.docx"), configure).render(dataMap);//  文件是否已存在,则删除File file = new File(outPath);if (file.exists()) {file.delete();}// 生成word保存在指定目录//template.writeToFile(outPath);template.writeAndClose(Files.newOutputStream(Paths.get(outPath)));template.close();return outPath;}public static void addToZipFile(String filePath, ZipOutputStream zos) throws IOException {File file = new File(filePath);FileInputStream fis = new FileInputStream(file);ZipEntry zipEntry = new ZipEntry(file.getName());zos.putNextEntry(zipEntry);byte[] bytes = new byte[1024];int length;while ((length = fis.read(bytes)) >= 0) {zos.write(bytes, 0, length);}zos.closeEntry();fis.close();}public static void createDoc() throws Exception {// 为表格的显示绑定行循环LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();// 将bz设置为行循环绑定的数据源的key,即key是bz的value会在模板中的{{bz}}处进行解析Configure configure = Configure.builder().bind("bz", policy).build();List<String> pictureTag = new ArrayList<>();// 将需要解析的数据放到dataMap中HashMap<String, Object> dataMap = new HashMap<String, Object>() {{//添加文本put("xiangmuName", "项目名称");put("xiangmuzhouqi", "2024-03-01 至 2024-04-02");put("renwuName", "任务名称");put("renwuzhouqi", "2024-03-05 至 2024-03-26");put("description", "项目描述");put("xiangmulink", "http://www.baidu.com");put("biaoqianName", "标签名称");PictureRenderData pictureRenderData = Pictures.ofStream(Files.newInputStream(Paths.get("D:\\template\\picture\\其他\\yiyan-NewYear.png")), PictureType.PNG).size(200, 150).create();put("dililink", pictureRenderData);put("resourceDescription", "资源描述");put("startYear", "1997");put("endYear", "2018");put("area", "100.5");// 其他业务获取到数据源String testTable = null;{testTable = "[\n" +"    {\n" +"        \"index\": \"1\",\n" +"        \"templateName\": \"模板内容1\",\n" +"        \"templateType\": \"模板类型1\",\n" +"        \"source\": \"来源1\",\n" +"        \"data\": \"http://www.baidu.com\"\n" +"    },\n" +"    {\n" +"        \"index\": \"2\",\n" +"        \"templateName\": \"模板内容2\",\n" +"        \"templateType\": \"模板类型2\",\n" +"        \"source\": \"来源2\",\n" +"        \"data\": \"http://www.baidu.com111\"\n" +"    },\n" +"    {\n" +"        \"index\": \"3\",\n" +"        \"templateName\": \"模板内容3\",\n" +"        \"templateType\": \"模板类型3\",\n" +"        \"source\": \"来源3\",\n" +"        \"data\": \"http://www.baidu.com222\"\n" +"    }\n" +"]";}// 内容在表格里循环// JSON使用,需要导入fastjson依赖List<WordQingdanDetailsDTO> forms = JSON.parseArray(testTable, WordQingdanDetailsDTO.class);for (int i = 0; i < forms.size(); i++) {put("index" + i, forms.get(i).getIndex());put("templateName" + i, forms.get(i).getTemplateName());put("templateType" + i, forms.get(i).getTemplateType());put("source" + i, forms.get(i).getSource());put("data" + i, forms.get(i).getData());}put("bz", forms);pictureTag.add("dililink");}};for (String tag : pictureTag ) {//设置图片,不然保存的是一串字符configure.customPolicy(tag, new PictureRenderPolicy());}String outPath = "D:\\生成数据.docx";// 读取模板、数据并渲染XWPFTemplate template = XWPFTemplate.compile(new FileInputStream("D:\\任务数据.docx"), configure).render(dataMap);//  文件是否已存在,则删除File file = new File(outPath);if (file.exists()) {file.delete();}// 生成word保存在指定目录//template.writeToFile(outPath);template.writeAndClose(Files.newOutputStream(Paths.get(outPath)));template.close();}public static void main(String[] args) throws Exception {createDoc();}}
    

    3.5 用到的实体类

  • RenwuTemplateDTO

    package io.renren.modules.sys.dto;import com.fasterxml.jackson.annotation.JsonFormat;
    import io.renren.common.validator.group.AddGroup;
    import io.renren.common.validator.group.UpdateGroup;
    import io.renren.modules.sys.entity.SysRenwuTemplateEntity;
    import io.renren.modules.sys.entity.SysResourceEntity;
    import io.renren.modules.sys.entity.SysXiangmuEntity;
    import lombok.Data;
    import org.springframework.format.annotation.DateTimeFormat;import javax.validation.constraints.NotBlank;
    import javax.validation.constraints.NotNull;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;/*** @Author: Administrator* @Date: 2023/12/8* @Description:*/
    @Data
    public class RenwuTemplateDTO {private Long renwuId;private Long xiangmuId;private String renwuName;@DateTimeFormat(pattern = "yyyy-MM-dd")@JsonFormat(pattern = "yyyy-MM-dd")private Date startTime;@DateTimeFormat(pattern = "yyyy-MM-dd")@JsonFormat(pattern = "yyyy-MM-dd")private Date endTime;private String description;private String xiangmuName;private String xiangmuzhouqi;private List<SysXiangmuEntity> xiangmuList;private List<SysResourceEntity> fileList = new ArrayList<>();private QingdanDTO qingdanDTO;/*** 用于导出*/private List<QingdanDTO> qingdanDTOList;private List<String> renwuResourceUrlList;
    }
    
  • QingdanDTO

    import com.fasterxml.jackson.annotation.JsonFormat;
    import io.renren.common.validator.group.AddGroup;
    import io.renren.common.validator.group.UpdateGroup;
    import io.renren.modules.sys.entity.SysQingdanExtEntity;
    import lombok.Data;
    import org.springframework.format.annotation.DateTimeFormat;import javax.validation.constraints.NotNull;
    import java.util.Date;
    import java.util.List;/*** @Author: Administrator* @Date: 2023/12/11* @Description:*/
    @Data
    public class QingdanDTO {private Long qingdanId;private Long renwuId;private Long userId;private String biaoqianName;@DateTimeFormat(pattern = "yyyy")@JsonFormat(timezone = "GMT+8", pattern = "yyyy")private String startYear;@DateTimeFormat(pattern = "yyyy")@JsonFormat(timezone = "GMT+8", pattern = "yyyy")private String endYear;private String area;private String resourceUrl;/*** 资源描述*/private String description;private String xiangmuName;private String renwuName;/*** 清单详情*/private List<SysQingdanExtEntity> qingdanExtList;/*** 任务周期*/private String renwuzhouqi;/*** 项目周期*/private String xiangmuzhouqi;}
    
  • SysQingdanExtEntity

    import com.baomidou.mybatisplus.annotation.TableField;
    import com.baomidou.mybatisplus.annotation.TableLogic;
    import lombok.Data;import java.io.Serializable;/*** @Author: Administrator* @Date: 2023/12/11* @Description:*/
    @Data
    public class SysQingdanExtEntity implements Serializable {private static final long serialVersionUID = 1L;private Long qingdanExtId;private Long qingdanId;private String templateName;private Long resourceId;private String source;private String extText;private Integer templateType;private String resourceUrl;
    }
    
  • WordQingdanDetailsDTO

    import lombok.Data;/*** @Author: Administrator* @Date: 2024/3/1* @Description:*/
    @Data
    public class WordQingdanDetailsDTO {/*** 下标序号*/private Integer index;/*** 名称*/private String templateName;/*** 类型*/private String templateType;/*** 来源*/private String source;/*** 数据*/private String data;
    }
  1. 工具类ConvertUtils

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.BeanUtils;import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;/*** 转换工具类** @author Mark sunlightcs@gmail.com*/
    public class ConvertUtils {private static Logger logger = LoggerFactory.getLogger(ConvertUtils.class);public static <T> T sourceToTarget(Object source, Class<T> target){if(source == null){return null;}T targetObject = null;try {targetObject = target.newInstance();BeanUtils.copyProperties(source, targetObject);} catch (Exception e) {logger.error("convert error ", e);}return targetObject;}public static <T> List<T> sourceToTarget(Collection<?> sourceList, Class<T> target){if(sourceList == null){return null;}List targetList = new ArrayList<>(sourceList.size());try {for(Object source : sourceList){T targetObject = target.newInstance();BeanUtils.copyProperties(source, targetObject);targetList.add(targetObject);}}catch (Exception e){logger.error("convert error ", e);}return targetList;}
    }
    
  2. 导出效果
    在这里插入图片描述

这篇关于springboot+poi-tl根据模板导出word(含动态表格和图片),并将导出的文档压缩zip导出的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/814359

相关文章

Java实现Excel与HTML互转

《Java实现Excel与HTML互转》Excel是一种电子表格格式,而HTM则是一种用于创建网页的标记语言,虽然两者在用途上存在差异,但有时我们需要将数据从一种格式转换为另一种格式,下面我们就来看看... Excel是一种电子表格格式,广泛用于数据处理和分析,而HTM则是一种用于创建网页的标记语言。虽然两

java图像识别工具类(ImageRecognitionUtils)使用实例详解

《java图像识别工具类(ImageRecognitionUtils)使用实例详解》:本文主要介绍如何在Java中使用OpenCV进行图像识别,包括图像加载、预处理、分类、人脸检测和特征提取等步骤... 目录前言1. 图像识别的背景与作用2. 设计目标3. 项目依赖4. 设计与实现 ImageRecogni

Java中Springboot集成Kafka实现消息发送和接收功能

《Java中Springboot集成Kafka实现消息发送和接收功能》Kafka是一个高吞吐量的分布式发布-订阅消息系统,主要用于处理大规模数据流,它由生产者、消费者、主题、分区和代理等组件构成,Ka... 目录一、Kafka 简介二、Kafka 功能三、POM依赖四、配置文件五、生产者六、消费者一、Kaf

Java访问修饰符public、private、protected及默认访问权限详解

《Java访问修饰符public、private、protected及默认访问权限详解》:本文主要介绍Java访问修饰符public、private、protected及默认访问权限的相关资料,每... 目录前言1. public 访问修饰符特点:示例:适用场景:2. private 访问修饰符特点:示例:

详解Java如何向http/https接口发出请求

《详解Java如何向http/https接口发出请求》这篇文章主要为大家详细介绍了Java如何实现向http/https接口发出请求,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用Java发送web请求所用到的包都在java.net下,在具体使用时可以用如下代码,你可以把它封装成一

使用Python实现在Word中添加或删除超链接

《使用Python实现在Word中添加或删除超链接》在Word文档中,超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能,本文将为大家介绍一下Python如何实现在Word中添加或... 在Word文档中,超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能。通过添加超

SpringBoot使用Apache Tika检测敏感信息

《SpringBoot使用ApacheTika检测敏感信息》ApacheTika是一个功能强大的内容分析工具,它能够从多种文件格式中提取文本、元数据以及其他结构化信息,下面我们来看看如何使用Ap... 目录Tika 主要特性1. 多格式支持2. 自动文件类型检测3. 文本和元数据提取4. 支持 OCR(光学

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

JAVA系统中Spring Boot应用程序的配置文件application.yml使用详解

《JAVA系统中SpringBoot应用程序的配置文件application.yml使用详解》:本文主要介绍JAVA系统中SpringBoot应用程序的配置文件application.yml的... 目录文件路径文件内容解释1. Server 配置2. Spring 配置3. Logging 配置4. Ma

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu