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

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作