freemarker生成pdf,同时pdf插入页脚,以及数据量大时批量处理

最近公司有个需求,就是想根据一个模板生成一个pdf文档,当即我就想到了freemarker这个远古老东西,毕竟freemarker在模板渲染方面还是非常有优势的。

准备依赖:

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><dependency><groupId>com.itextpdf</groupId><artifactId>html2pdf</artifactId><version>3.0.5</version></dependency><!--pdf 支持中文(默认不支持)--><dependency><groupId>com.itextpdf</groupId><artifactId>itext-asian</artifactId><version>5.2.0</version></dependency><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13</version></dependency>

我这里不想选freemarker版本,直接用spring集成的省事。
配置一下freemarker的配置

import freemarker.template.Configuration;
import freemarker.template.TemplateExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;import java.io.IOException;@Component
@org.springframework.context.annotation.Configuration
public class FreemarkerConfig {// 我这里为了省事,不想创建那么多的Configuration,而且创建Configuration太多不好@Bean(name = "cfg")public Configuration freemarkerConfigurer() throws IOException {// 选择版本,不同版本对不同的模板语法或者模板转换也会有差异,如果你css 样式比较新,建议选高版本准没错Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);// 选择你存放模板的位置final ClassPathResource classPathResource = new ClassPathResource("templates");cfg.setDirectoryForTemplateLoading(classPathResource.getFile());cfg.setDefaultEncoding("UTF-8");// 模板异常处理cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);return cfg;}
}

然后我们准备下我们的ftl模板【freemarker的模板文件】----pdf.ftl
freemarker框架类似于beetlthymeleafjspVelocity等模板引擎
JSP就不用说了吧,基本上开发Java的基本上都会了解开发过

<!doctype html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title>
</head>
<style>.logo {width: 320px;height: 80px;}.user-info {padding: 10px 10px;background: RGB(221, 235, 247);}.label {width: 150px;padding: 0 20px 0 0;text-align: left;}.time {width: 100px;margin-right: 10px;text-align: center;}.label, .time {display: inline-block;}.range-time {margin: 20px 0;}.table-data {width: 100%;}table{border-collapse: collapse;}.header > th {text-align: left;height: 50px;}.divider-line {margin: 20px 0;height: 3px;background: #000;}.desc {padding: 15px 10px;}.date {width: 100px;}.fee {width: 50px;}.name {width: 140px;}.name, .fee, .date {padding: 0 10px;}.download-date {text-align: right;}.bottom-footer-tip {width: 100%;margin-top: 300px;font-size: 12px;transform: scale(.9);}
</style>
<body><div class="download-date">Download on 2022/2/2</div>
<div class="range-time"><span class="time">${startTime}</span><span>to</span><span class="time">${endTime}</span>
</div><table class="table-data"><tr class="header"><th>Date</th><th>Name</th><th>desc</th><th>fee</th></tr><tr class="divider-line"><th></th><th></th><th></th><th></th></tr><#list list as item><tr><td class="date">${item.date}</td><td class="name">${item.name}</td><td class="desc"><div>${item.desc}</div></td><td class="fee">${item.fee}</td></tr></#list><tr class="divider-line"><th></th><th></th><th></th><th></th></tr>
</table>
</body>
</html>

这里ftl的语法,我就不多做解释了,我这里附上freemarker的官方文档,感兴趣的自己去学习一下。

然后准备下我们的代码处理逻辑

首先是PDF实体数据

import lombok.Data;import java.util.List;@Data
public class PDFData {private String logo;private String name;private String address;private String startTime;private String endTime;private List<TableData> list;
}

然后是关联(table)数据


import lombok.Data;@Data
public class TableData {private String date;private String desc;private String name;private String fee;
}

然后我们处理我们处理逻辑的代码

import com.alibaba.fastjson.JSONObject;
import com.example.web.pojo.TableData;
import com.example.web.pojo.PDFData;
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.html2pdf.resolver.font.DefaultFontProvider;
import com.itextpdf.kernel.colors.DeviceRgb;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.font.FontProvider;
import com.itextpdf.layout.property.TextAlignment;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;@Component
public class FreemarkerExecution {// 准备下字体文件private static String FONT = "./src/main/resources/templates/AlibabaPuHuiTi-3-65-Medium.ttf";// 后续转pdf时的配置private static ConverterProperties converterProperties = new ConverterProperties();private static String base64LogoData = null;{FontProvider dfp = new DefaultFontProvider();//添加字体库dfp.addFont(FONT);//设置解析属性converterProperties.setFontProvider(dfp);converterProperties.setCharset("utf-8");try {// 有一个logo处理,因为一般服务器渲染的话一般建议将部分图片处理成base64然后放进来,或者大家看看其他的方式base64LogoData = imgToBase64(new FileInputStream("./src/main/resources/templates/logo.png"));} catch (FileNotFoundException e) {e.printStackTrace();}}@Resource(name = "cfg")private Configuration configuration;// 普通处理逻辑public void converterHTML() {// 这个会将处理后的html语法输出至 命令行窗口,可以手动创建一个html文件,然后把结果复制进去直接打开查看try (Writer out = new OutputStreamWriter(System.out)) {// 获取数据final PDFData pdfData = getData();Template temp = configuration.getTemplate("pdf.ftl");// 直接写出文件temp.process(pdfData, out);} catch (IOException e) {e.printStackTrace();} finally {}}private void writeToPDF(Template template, Map<String, Object> dataModel) {try {final File file = new File("D:/pdf/test.html");template.process(dataModel, new OutputStreamWriter(new FileOutputStream(file)));final File pdfFile = new File("D:/pdf/test.pdf");HtmlConverter.convertToPdf(file, pdfFile, converterProperties);PdfReader reader = new PdfReader(new File("D:/pdf/test.pdf"));PdfWriter writer = new PdfWriter(new FileOutputStream("D:/pdf/test_1.pdf"));PdfDocument pdfDocument = new PdfDocument(reader, writer);// 页大小final PageSize pageSize = pdfDocument.getDefaultPageSize();// 页数final int numberOfPages = pdfDocument.getNumberOfPages();for (int i = 1; i <= numberOfPages; i++) {PdfPage page = pdfDocument.getPage(i);final PdfDocument pdfDoc = page.getDocument();final Document document = new Document(pdfDoc);final Paragraph paragraph = new Paragraph("Page" + i).setFont(PdfFontFactory.createFont(FONT)).setFontColor(new DeviceRgb(0, 0, 0)).setFixedPosition(i, 0, 10, pageSize.getWidth()).setFontSize(10).setTextAlignment(TextAlignment.CENTER);document.add(paragraph);}pdfDocument.close();reader.close();writer.close();} catch (Exception e) {e.printStackTrace();}}private PDFData getData() throws FileNotFoundException {PDFData data = new PDFData();data.setName("重生之我是蔡徐坤");data.setAddress("蔡徐坤蔡徐坤喜欢唱跳rap篮球");data.setStartTime("01-Feb-22");data.setEndTime("28-Feb-22");data.setLogo("data:image/png;base64," + base64LogoData);final LocalDateTime nowTime = LocalDateTime.now();final List<TableData> arr = new ArrayList<>();for (int i = 0; i < 10; i++) {final TableData tableData = new TableData();tableData .setDesc(i % 2 == 0 ? "交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大" : "交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大");tableData .setName("蔡徐坤" + i);tableData .setFee(1000 + i + "");tableData .setDate(nowTime.plusDays(-i).format(DateTimeFormatter.ofPattern("YYYY/MM/dd")));arr.add(tableData);}data.setList(arr);return data;}private String imgToBase64(InputStream inputStream) {byte[] data = null;try {data = new byte[inputStream.available()];inputStream.read(data);inputStream.close();} catch (IOException e) {e.printStackTrace();}return Base64.getEncoder().encodeToString(data);}
}

这里会又有一个问题出现,就是我们一般处理PDF的时候,数据不可能一次性处理到内存中,因为我们服务器内存等问题,假如我们有100w数据,肯定不能一次性查出来,由此我们就需要批量处理,这里我们可以将模板拆分开,重复的数据放一个模板文件,然后后续进行模板的组装。

首先,我将一个ftl模板文件拆成了三个 👉 header.ftl,content.ftl,footer.ftl,然后再由一个主的核心ftl模板来组装这几个模板。
思路:准备上述模板文件,然后渲染模板后继续解析成ftl模板文件,然后读取选然后的ftl模板文件,然后转成html,最后通过html文件处理成pdf文件。

这里content.ftl是批量的数据,因为不能一次读取大量数据,所以这里content.ftl要单独处理一下。

Main.ftl
<!doctype html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title>
</head>
<style>.logo {width: 320px;height: 80px;}.user-info {padding: 10px 10px;background: RGB(221, 235, 247);}.label {width: 150px;padding: 0 20px 0 0;text-align: left;}.time {width: 100px;margin-right: 10px;text-align: center;}.label, .time {display: inline-block;}.range-time {margin: 20px 0;}.table-data {width: 100%;}table {border-collapse: collapse;}.header > th {text-align: left;height: 50px;}.divider-line {margin: 20px 0;height: 3px;background: #000;}.desc {padding: 15px 10px;}.date {width: 100px;}.name {width: 50px;}.fee{width: 140px;}.fee, .name , .date {padding: 0 10px;}.download-date {text-align: right;}.bottom-footer-tip {width: 100%;margin-top: 300px;font-size: 12px;transform: scale(.9);}
</style>
<body>${headerPath}
<table class="table-data"><tr class="header"><th>Date</th><th>Desc</th><th>Name</th><th>Fee</th></tr><tr class="divider-line"><th></th><th></th><th></th><th></th></tr><#list contentPathList as content>${content}</#list><tr class="divider-line"><th></th><th></th><th></th><th></th></tr>
</table>
${footerPath}<#--<#include "header.ftl">-->
<#--<#include "content.ftl">-->
<#--<#include "footer.ftl">--></body>
</html>
header.ftl
<img src="${logo}" class="logo">
<div class="download-date">Download on 2022/2/2</div>
<div class="user-info"><div><div class="label">User:</div><span>${name}</span></div><div><div class="label">Address:</div><span>${address}</span></div>
</div><div class="range-time"><span class="time">${startTime}</span><span>to</span><span class="time">${endTime}</span>
</div>
content.ftl
<#list list as item><tr><td class="date">${item.date}</td><td class="desc"><div>${item.desc}</div></td><td class="fee">${item.fee}</td><td class="name">${item.name}</td></tr></#list>
footer.ftl
<#list list as item><tr><td class="date">${item.date}</td><td class="desc"><div>${item.desc}</div></td><td class="fee">${item.fee}</td><td class="name">${item.name}</td></tr></#list>
核心处理逻辑
    void allTemplatesWriteToPDF() {// 所有子模板final List<String> ftlNameList = new ArrayList<>();try {// 读取对应的模板文件final Template template = getTemplate("content.ftl");final Template headerTemplate = getTemplate("header.ftl");final Template footerTemplate = getTemplate("footer.ftl");final PDFData data = getData();// 先处理头部和尾部headerTemplate.process(data, new FileWriter("D:/pdf/content/header.ftl"));footerTemplate.process(data, new FileWriter("D:/pdf/content/footer.ftl"));// mock 模拟数据库查询10次for (int i = 0; i < 10; i++) {// 组装10条数据,算上10次循环一共100条数据final PDFData pdfData = getData();String fileName = "D:/pdf/content/content" + i + ".ftl";final FileWriter writer = new FileWriter(fileName);// 存储最后框架模板的数据,这里是存储了freemarker include 语法连接所有的需要组装的数据模板名称ftlNameList.add("<#include \"" + fileName.substring(fileName.lastIndexOf("/") + 1, fileName.lastIndexOf(".")) + ".ftl \"/>");// 生成对应的模板文档template.process(pdfData, writer);writer.flush();writer.close();}// 获取所有子模板final Configuration cdf = new Configuration(Configuration.VERSION_2_3_22);cdf.setDirectoryForTemplateLoading(new File("D:/pdf/content"));cdf.setDefaultEncoding("UTF-8");cdf.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);final Template mainTemplate = getTemplate("main.ftl");final HashMap<Object, Object> map = new HashMap<>();map.put("headerPath", "<#include \"" + "header.ftl\"/>");map.put("contentPathList", ftlNameList);map.put("footerPath", "<#include \"" + "footer.ftl\"/>");mainTemplate.process(map, new FileWriter("D:/pdf/content/main.ftl"));final Template cdfTemplate = cdf.getTemplate("main.ftl");cdfTemplate.process(null, new FileWriter("D:/pdf/content/main.html"));final File pdfFile = new File("D:/pdf/test_new.pdf");HtmlConverter.convertToPdf(new File("D:/pdf/content/main.html"), pdfFile, converterProperties);PdfReader reader = new PdfReader(pdfFile);PdfWriter writer = new PdfWriter(new FileOutputStream("D:/pdf/test_new_1.pdf"));PdfDocument pdfDocument = new PdfDocument(reader, writer);// 页大小final PageSize pageSize = pdfDocument.getDefaultPageSize();// 页数final int numberOfPages = pdfDocument.getNumberOfPages();// 这里是处理页脚数据for (int i = 1; i <= numberOfPages; i++) {PdfPage page = pdfDocument.getPage(i);final PdfDocument pdfDoc = page.getDocument();final Document document = new Document(pdfDoc);final Paragraph paragraph = new Paragraph("Page" + i).setFont(PdfFontFactory.createFont(FONT)).setFontColor(new DeviceRgb(0, 0, 0)).setFixedPosition(i, 0, 10, pageSize.getWidth()).setFontSize(10).setTextAlignment(TextAlignment.CENTER);document.add(paragraph);}pdfDocument.close();reader.close();writer.close();} catch (IOException | TemplateException e) {e.printStackTrace();}}private Template getTemplate(String name) throws IOException {return configuration.getTemplate(name);}

在这里插入图片描述

在这里插入图片描述

OK,大概就这样,剩下的大家自己去玩吧, 解散!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/40994.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【IDEA】maven如何进行文件导入,配置并打包

一&#xff0c;介绍、安装 1、maven介绍 maven是一个Java世界中&#xff0c;构建工具。 核心功能&#xff1a; (1) 管理依赖&#xff1a; 管理文件运行的顺序逻辑依赖关系。对配置文件&#xff0c;进行构建和编译。其也是在调用jdk&#xff0c;来进行编译打包工作。 (2) 打…

JavaScript中的原型和原型链

一、原型&#xff1a;每个函数都有prototype属性&#xff0c;称之为原型&#xff0c;这个属性也是个对象所以也称之为原型对象。 1.原型可以放一些属性和方法&#xff0c;供实例对象使用。 <body><script>const arr new Array(1,3,5,7,6)document.getElementByI…

Go语言--延迟调用defer、获取命令行参数、局部变量以及全局变量

延迟调用defer 关键字 defer 用于延迟一个函数或者方法(或者当前所创建的匿名函数)的执行。注意&#xff0c;defer语句只能出现在函数或方法的内部。 defer 语句经常被用于处理成对的操作&#xff0c;如打开、关闭、连接、断开连接、加锁、释放锁。通过defer 机制&#xff0…

NASA——quarius(水瓶座) L3 网格化 1 度年土壤湿度,第 5 版

Aquarius L3 Gridded 1-Degree Annual Soil Moisture V005 水瓶座 L3 网格化 1 度年土壤湿度&#xff0c;第 5 版 简介 该数据集包含美国国家航空航天局&#xff08;NASA&#xff09;科学应用卫星&#xff08;SAC-D&#xff09;上的宝瓶座被动微波辐射计得出的第 3 级网格化…

SLAM 精度评估

SLAM 精度的评估有两个最重要的指标&#xff0c;即绝对轨迹误差&#xff08;ATE&#xff09;和相对位姿误差&#xff08;RPE&#xff09;的 均方根误差&#xff08;RMSE&#xff09;: 绝对轨迹误差:直接计算相机位姿的真实值与 SLAM 系统的估计值之间的差值&#xff0c;首先将…

交换机基本原理

文章目录 前言一、交换机的转发行为二、交换机的转发原理1.MAC地址表2.交换机初始状态3.学习MAC地址4.ARP协议5.交换机转发数据帧6.目标主机回复 三、华为交换机基本命令1.VRP视图分层2.命令行补全3.命令行帮助4.配置设备名称5.命令等级6.用户界面7.配置console认证8.配置用户界…

python-Django项目:图书后台管理系统

具体操作&#xff1a;请参考 Django项目&#xff1a;图书后台管理系统

运维锅总详解计算机缓存

本文从OSI模型中的每一层缓存介绍、常见开源中间件缓存举例、TCP/IP协议栈中的缓存机制、操作系统中的缓存、访问缓存数据的时间范围统计等方面对计算机中的缓存进行详细介绍。希望对您有所帮助&#xff01; 一、OSI模型中的每一层缓存 1. 物理层&#xff08;Physical Layer&…

自动化立体仓库出入库能力及堆垛机节拍

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》人俱乐部 完整版文件和更多学习资料&#xff0c;请球友到知识星球【智能仓储物流技术研习社】自行下载 自动化立体仓库的出入库能力、堆垛机节拍以…

掌握电路交换与分组交换:计算机网络的核心技术

计算机网络是现代信息社会的基石&#xff0c;而交换技术是实现网络通信的核心。本文将详细介绍两种典型的交换方式&#xff1a;电路交换和分组交换&#xff0c;帮助基础小白快速掌握这两种技术的基本概念和区别。 什么是电路交换&#xff1f; 电路交换&#xff08;Circuit Swi…

Centos系统迁移

目前&#xff0c;CentOS 全系列版本已经于l六月底正式停止维护&#xff0c;这意味着 CentOS 时代彻底终结&#xff0c;也意味着部署在 CentOS 7 上的业务系统将面临前所未有的安全挑战。 本文推荐由红帽衍生出来的且可以做到真正无缝替代的linux版本Open Euler 注&#xff1a…

科普文:Linux服务器性能调优概叙

概叙 Java web应用性能分析之服务端慢和优化概叙_cpu飙高java-CSDN博客 Java web应用性能分析之【CPU飙升分析概述】_web页面性能分析cpu占满是因为死循环,还是循环过多-CSDN博客 在我们的软件服务中&#xff0c;软件部署的服务器&#xff0c;一般都是linux服务器&#xff0c…

rtsp地址 + 测试网站 + java(免环境、免插件、零编码转换http播放)

目录 1、创建rtsp网站 2、测试rtsp网站 3、Java实现rtsp播放 ①maven添加依赖 ②访问http地址即可展示视频内容 1、创建rtsp网站 填写邮箱即可获得两个可用的rtsp网站&#xff08;每月可免费用2G&#xff09;&#xff1a; https://rtsp.stream/ 2、测试rtsp网站 测试网络…

基于SpringBoot的地方废物回收机构管理系统

本系统主要包括管理员和员工两个角色组成&#xff1b;主要包括&#xff1a;首页、个人中心、员工管理、员工请假管理、销假申请管理、工作日志管理、员工工资管理、员工任务管理、任务汇报管理、设备信息管理、设备借用管理、设备归还管理、设备保修管理、维修入库管理、员工打…

Python酷库之旅-第三方库Pandas(002)

目录 一、用法精讲 1、pandas.read_pickle函数 1-1、语法 1-2、参数 1-3、功能 1-4、返回值 1-5、说明 1-6、用法 1-6-1、代码示例 1-6-2、结果输出 2、pandas.DataFrame.to_pickle方法 2-1、语法 2-2、参数 2-3、功能 2-4、返回值 2-5、说明 2-5-1、文件路径…

数据结构(3.8)——栈的应用

栈在括号匹配中的应用 流程图 代码 #include <stdio.h> #include <stdlib.h> #define MaxSize 10typedef struct {char data[MaxSize];int top; } SqStack;// 初始化栈 void InitStack(SqStack* S) {S->top -1; // 初始化栈顶指针 }// 判空 bool StackEmpty(…

《米小圈日记魔法》边看边学,轻松掌握写日记的魔法!

在当今充满数字化娱乐和信息快速变迁的时代&#xff0c;如何创新引导孩子们学习&#xff0c;特别是如何培养他们的写作能力&#xff0c;一直是家长和教育者们关注的焦点。今天就向大家推荐一部寓教于乐的动画片《米小圈日记魔法》&#xff0c;该系列动画通过其独特的故事情节和…

vue通过后台返回的数字显示不同的文字内容,多个内容用、隔开

后台返回的数据 显示效果&#xff1a; html&#xff1a; <el-table-columnalign"center"label"使用过的小程序"width"124"v-if"activeTab 0"><template #default"scope"><divv-for"(item, index) in s…

数据结构(3.5)——队列的顺序实现

队列的顺序实现 #define MaxSize 10//定义队列中元素的最大个数 typedef struct {int data[MaxSize];//用静态数组存放队列元素int front, rear;//队头指针和队尾指针 } SqQueue;void testQueue() {SqQueue Q;//声明一个队列(顺序存储) } 队列的初始化操作和判空 //初始化队…