官网:http://deepoove.com/poi-tl/
参考网站:https://blog.csdn.net/M625387195/article/details/124855854
<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 {
@Autowired
private 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 {
@Autowired
private 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
*/
@Override
public 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;
}
@Async
public 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/resources
path: /u/cms/www/
outPath: H:/GoTionBackends/2023/resources/doc
prefix: 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;
}
工具类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;
}
}
导出效果
更多【c#-springboot+poi-tl根据模板导出word(含动态表格和图片),并将导出的文档压缩zip导出】相关视频教程:www.yxfzedu.com