java使用itext 直接生成pdf

news2024/11/14 15:21:07

itext 使用

  • 需求背景
  • itext 的使用
    • 依赖
    • 简单示例
    • 基础设置(页面大小、边距、字体等)
    • 段落内部,特殊设置关键字 字体或颜色
    • 生成动态表格
    • 页脚展示页数
    • 其他
      • 设置密码
      • 添加水印(背景图)
      • 目录
      • Header, Footer
      • 分割 PDF
      • 合并 PDF

需求背景

在工作中经常会有生成pdf文件的需求,大多数情况下,我们只需要使用pdf模版添加表单域,就足以胜任了。但是有一些特殊的需求,需要生成较为复杂的文件,如动态数据表格、插入图像等。
这时候,我们就可以使用拼接的方式,将pdf文件内容一段段拼上去,组合成一个pdf文件,来灵活的操纵文件的排版与内存形式。

itext 的使用

依赖

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.itextpdf/itext-asian -->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext-asian</artifactId>
    <version>5.2.0</version>
</dependency>

简单示例

生成一个内容为“Hello World”的pdf文件

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.PdfWriter;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 生成一个内容为“Hello World”的pdf文件
 * @author ym
 */
public class HelloWorld {

    public static void main(String[] args) {
        String FILE_DIR = "./"; // 项目根目录:盘符:/.../.../项目名称,注意:点号并不表示当前类文件所在的目录,而是项目目录下
        //Step 1—Create a Document.  
        Document document = new Document();
        try {
            //Step 2—Get a PdfWriter instance.
            PdfWriter.getInstance(document, new FileOutputStream(FILE_DIR + "createSamplePDF.pdf"));
            //Step 3—Open the Document.  
            document.open();
            //Step 4—Add content.  
            document.add(new Paragraph("Hello World"));
            //Step 5—Close the Document.  
            document.close();
        } catch (DocumentException ex) {
            Logger.getLogger(HelloWorld.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(HelloWorld.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

基础设置(页面大小、边距、字体等)

      //页面大小  
      Rectangle rect = new Rectangle(PageSize.A4.rotate());
      //页面背景色  
      rect.setBackgroundColor(BaseColor.ORANGE);
      //  page , 外边距 marginLeft marginRight marginTop marginBottom
      Document doc = new Document(rect,90, 90, 30, 40);  
      // 新开一页
      doc.newPage();
		

      /**
      * 段落设置
      */
     Paragraph titleParagraph = new Paragraph("hello world!", getChineseTitleFont());
     titleParagraph.setAlignment(Element.ALIGN_CENTER);// 居中
     titleParagraph.setFirstLineIndent(24);// 首行缩进
     titleParagraph.setLeading(35f);// 行间距
     titleParagraph.setSpacingBefore(5f);// 设置上空白
     titleParagraph.setSpacingAfter(10f);// 设置段落下空白



    //支持中文 设置字体,字体颜色、大小等
    public Font getChineseTitleFont() throws RuntimeException {
        Font ChineseFont = null;
        try {
        	/**
             *  name – the name of the font or its location on file 
             *  encoding – the encoding to be applied to this font 
             *  embedded – true if the font is to be embedded in the PDF
             */
            BaseFont simpChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            ChineseFont = new Font(simpChinese, 15, Font.BOLD, BaseColor.BLACK);
        } catch (DocumentException e) {
            log.error("getChineseFont" ,"字体异常",e);
            throw new RuntimeException("getChineseFont字体异常",e);
        } catch (IOException e) {
            log.error("getChineseFont" ,"字体异常",e);
            throw new RuntimeException("getChineseFont字体异常",e);
        }
        return ChineseFont;
    }

段落内部,特殊设置关键字 字体或颜色

// 文本内容
String content = "This is a sample text with different colors.";
String[] words = content.split(" "); // 将文本拆分为单词

for (String word : words) {
    Chunk chunk = new Chunk(word); // 创建一个新的 Chunk

    // 如果单词是 "different",则设置为红色
    if (word.equals("different")) {
        chunk.setForegroundColor(BaseColor.RED);
    }

    // 如果单词是 "colors.",则设置为蓝色
    if (word.equals("colors.")) {
        chunk.setForegroundColor(BaseColor.BLUE);
    }

    contentParagraph.add(chunk); // 将 Chunk 添加到段落中
    contentParagraph.add(" "); // 添加单词之间的空格
}

document.add(contentParagraph); // 将段落添加到文档中

生成动态表格


            // 创建一个包含5列的表格
            PdfPTable table = new PdfPTable(5);

            // 添加表头
            table.addCell("Header 1");
            table.addCell("Header 2");
            table.addCell("Header 3");
            table.addCell("Header 4");
            table.addCell("Header 5");

            // 添加动态数据到表格
            for (int i = 0; i < 10; i++) {
                table.addCell("Data " + i + ", 1");
                table.addCell("Data " + i + ", 2");
                table.addCell("Data " + i + ", 3");
                table.addCell("Data " + i + ", 4");
                table.addCell("Data " + i + ", 5");
            }

            document.add(table);





		/**
         * 如果需要更精细的控制属性
         */
        cell = new PdfPCell(new Phrase("title1",fontChinese));
        cell.setColspan(1);//设置所占列数
        cell.setRowspan(1);//合并行
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);//设置水平居中
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);//设置垂直居中
        cell.setFixedHeight(30);//设置高度
        table.addCell(cell);

页脚展示页数

PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(FILE_DIR + "createSamplePDF.pdf"));
            writer.setPageEvent(new FooterEvent());









    public  class FooterEvent extends PdfPageEventHelper {
        //总页数
        PdfTemplate totalPage;
        //字体
        Font font;

        {
            try {
                BaseFont chinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
                font = new Font(chinese,10);
            } catch (DocumentException | IOException e) {
                e.printStackTrace();
            }
        }

        //打开文档时,创建一个总页数的模版
        @Override

        public void onOpenDocument(PdfWriter writer, Document document) {
            PdfContentByte cb = writer.getDirectContent();
            totalPage = cb.createTemplate(50, 9);
        }

        @Override
        public void onEndPage(PdfWriter writer, Document document) {
            //创建一个两列的表格
            PdfPTable table = new PdfPTable(2);
            try {
                table.setTotalWidth(PageSize.A4.getWidth());//总宽度为A4纸张宽度
                table.setLockedWidth(true);//锁定列宽
                table.setWidths(new int[]{50, 50});//设置每列宽度
                PdfPCell cell = new PdfPCell(new Phrase("第"+document.getPageNumber() + " 页,共", font));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);//设置水平右对齐
                cell.setVerticalAlignment(Element.ALIGN_MIDDLE);//设置垂直居中
                cell.disableBorderSide(15);//隐藏全部边框
                table.addCell(cell);
                PdfPCell cell1 = new PdfPCell(Image.getInstance(totalPage));//共 页
                cell1.setHorizontalAlignment(Element.ALIGN_LEFT);//设置水平左对齐
                cell1.setVerticalAlignment(Element.ALIGN_MIDDLE);//设置垂直居中
                cell1.disableBorderSide(15);//隐藏全部边框
                table.addCell(cell1);
                table.writeSelectedRows(0, -1, 0, 30, writer.getDirectContent());
            } catch (Exception e) {
                throw new ExceptionConverter(e);
            }
        }
        @Override
        public void onCloseDocument(PdfWriter writer, Document document) {
            String text = "" +String.valueOf(writer.getPageNumber()-1) +"页";
            ColumnText.showTextAligned(totalPage, Element.ALIGN_MIDDLE, new Paragraph(text, font), 0, 0, 0);
        }
    }

其他

设置密码

PdfWriter writer = PdfWriter.getInstance(doc, out);  
  
// 设置密码为:"World"  
writer.setEncryption("Hello".getBytes(), "World".getBytes(),  
        PdfWriter.ALLOW_SCREENREADERS,  
        PdfWriter.STANDARD_ENCRYPTION_128);  
  
doc.open();  
doc.add(new Paragraph("Hello World"));  

添加水印(背景图)

//图片水印
PdfReader reader = new PdfReader(FILE_DIR + "setWatermark.pdf");  
PdfStamper stamp = new PdfStamper(reader, new FileOutputStream(FILE_DIR  
        + "setWatermark2.pdf"));  
  
Image img = Image.getInstance("resource/watermark.jpg");  
img.setAbsolutePosition(200, 400);  
PdfContentByte under = stamp.getUnderContent(1);  
under.addImage(img);  
  
//文字水印  
PdfContentByte over = stamp.getOverContent(2);  
over.beginText();  
BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI,  
        BaseFont.EMBEDDED);  
over.setFontAndSize(bf, 18);  
over.setTextMatrix(30, 30);  
over.showTextAligned(Element.ALIGN_LEFT, "DUPLICATE", 230, 430, 45);  
over.endText();  
  
//背景图  
Image img2 = Image.getInstance("resource/test.jpg");  
img2.setAbsolutePosition(0, 0);  
PdfContentByte under2 = stamp.getUnderContent(3);  
under2.addImage(img2);  
  
stamp.close();  
reader.close();  

目录

// Code 1  
document.add(new Chunk("Chapter 1").setLocalDestination("1"));  
  
document.newPage();  
document.add(new Chunk("Chapter 2").setLocalDestination("2"));  
document.add(new Paragraph(new Chunk("Sub 2.1").setLocalDestination("2.1")));  
document.add(new Paragraph(new Chunk("Sub 2.2").setLocalDestination("2.2")));  
  
document.newPage();  
document.add(new Chunk("Chapter 3").setLocalDestination("3"));  
  
// Code 2  
PdfContentByte cb = writer.getDirectContent();  
PdfOutline root = cb.getRootOutline();  
  
// Code 3  
@SuppressWarnings("unused")  
PdfOutline oline1 = new PdfOutline(root, PdfAction.gotoLocalPage("1", false), "Chapter 1");  
  
PdfOutline oline2 = new PdfOutline(root, PdfAction.gotoLocalPage("2", false), "Chapter 2");  
oline2.setOpen(false);  
  
@SuppressWarnings("unused")  
PdfOutline oline2_1 = new PdfOutline(oline2, PdfAction.gotoLocalPage("2.1", false), "Sub 2.1");  
@SuppressWarnings("unused")  
PdfOutline oline2_2 = new PdfOutline(oline2, PdfAction.gotoLocalPage("2.2", false), "Sub 2.2");  
  
@SuppressWarnings("unused")  
PdfOutline oline3 = new PdfOutline(root, PdfAction.gotoLocalPage("3", false), "Chapter 3"); 

Header, Footer

PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(FILE_DIR + "setHeaderFooter.pdf"));  
  
writer.setPageEvent(new PdfPageEventHelper() {  
  
    public void onEndPage(PdfWriter writer, Document document) {  
          
        PdfContentByte cb = writer.getDirectContent();  
        cb.saveState();  
  
        cb.beginText();  
        BaseFont bf = null;  
        try {  
            bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.EMBEDDED);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        cb.setFontAndSize(bf, 10);  
          
        //Header  
        float x = document.top(-20);  
          
        //左  
        cb.showTextAligned(PdfContentByte.ALIGN_LEFT,  
                           "H-Left",  
                           document.left(), x, 0);  
        //中  
        cb.showTextAligned(PdfContentByte.ALIGN_CENTER,  
                            writer.getPageNumber()+ " page",  
                           (document.right() + document.left())/2,  
                           x, 0);  
        //右  
        cb.showTextAligned(PdfContentByte.ALIGN_RIGHT,  
                           "H-Right",  
                           document.right(), x, 0);  
  
        //Footer  
        float y = document.bottom(-20);  
  
        //左  
        cb.showTextAligned(PdfContentByte.ALIGN_LEFT,  
                           "F-Left",  
                           document.left(), y, 0);  
        //中  
        cb.showTextAligned(PdfContentByte.ALIGN_CENTER,  
                            writer.getPageNumber()+" page",  
                           (document.right() + document.left())/2,  
                           y, 0);  
        //右  
        cb.showTextAligned(PdfContentByte.ALIGN_RIGHT,  
                           "F-Right",  
                           document.right(), y, 0);  
  
        cb.endText();  
          
        cb.restoreState();  
    }  
});  
  
doc.open();  
doc.add(new Paragraph("1 page"));          
doc.newPage();  
doc.add(new Paragraph("2 page"));          
doc.newPage();  
doc.add(new Paragraph("3 page"));          
doc.newPage();  
doc.add(new Paragraph("4 page"));  

分割 PDF

FileOutputStream out = new FileOutputStream(FILE_DIR + "splitPDF.pdf");  
  
Document document = new Document();  
  
PdfWriter.getInstance(document, out);  
  
document.open();  
document.add(new Paragraph("1 page"));  
  
document.newPage();  
document.add(new Paragraph("2 page"));  
  
document.newPage();  
document.add(new Paragraph("3 page"));  
  
document.newPage();  
document.add(new Paragraph("4 page"));  
  
document.close();  
  
PdfReader reader = new PdfReader(FILE_DIR + "splitPDF.pdf");  
  
Document dd = new Document();  
PdfWriter writer = PdfWriter.getInstance(dd, new FileOutputStream(FILE_DIR + "splitPDF1.pdf"));  
dd.open();  
PdfContentByte cb = writer.getDirectContent();  
dd.newPage();  
cb.addTemplate(writer.getImportedPage(reader, 1), 0, 0);  
dd.newPage();  
cb.addTemplate(writer.getImportedPage(reader, 2), 0, 0);  
dd.close();  
writer.close();  
  
Document dd2 = new Document();  
PdfWriter writer2 = PdfWriter.getInstance(dd2, new FileOutputStream(FILE_DIR + "splitPDF2.pdf"));  
dd2.open();  
PdfContentByte cb2 = writer2.getDirectContent();  
dd2.newPage();  
cb2.addTemplate(writer2.getImportedPage(reader, 3), 0, 0);  
dd2.newPage();  
cb2.addTemplate(writer2.getImportedPage(reader, 4), 0, 0);  
dd2.close();  
writer2.close();  

合并 PDF

PdfReader reader1 = new PdfReader(FILE_DIR + "splitPDF1.pdf");  
PdfReader reader2 = new PdfReader(FILE_DIR + "splitPDF2.pdf");  
  
FileOutputStream out = new FileOutputStream(FILE_DIR + "mergePDF.pdf");  
  
Document document = new Document();  
PdfWriter writer = PdfWriter.getInstance(document, out);  
  
document.open();  
PdfContentByte cb = writer.getDirectContent();  
  
int totalPages = 0;  
totalPages += reader1.getNumberOfPages();  
totalPages += reader2.getNumberOfPages();  
  
java.util.List<PdfReader> readers = new ArrayList<PdfReader>();  
readers.add(reader1);  
readers.add(reader2);  
  
int pageOfCurrentReaderPDF = 0;  
Iterator<PdfReader> iteratorPDFReader = readers.iterator();  
  
// Loop through the PDF files and add to the output.  
while (iteratorPDFReader.hasNext()) {  
    PdfReader pdfReader = iteratorPDFReader.next();  
  
    // Create a new page in the target for each source page.  
    while (pageOfCurrentReaderPDF < pdfReader.getNumberOfPages()) {  
        document.newPage();  
        pageOfCurrentReaderPDF++;  
        PdfImportedPage page = writer.getImportedPage(pdfReader, pageOfCurrentReaderPDF);  
        cb.addTemplate(page, 0, 0);  
    }  
    pageOfCurrentReaderPDF = 0;  
}  
out.flush();  
document.close();  
out.close();  

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

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

相关文章

动态路由//

静态路由的缺点 1.配置量大 2.不能基于拓扑的变化进行实时更新 总结:只能在简单的小型网络中进行配置 动态路由的优点 实时基于拓扑的变化而进行路由表的收敛 动态路由的缺点 1.额外的占用链路资源:动态路由协议需要路由器之间不断交换路由信息&#xff0c;这会占用网络…

在PasteSpider中使用gitee的webhook实现类似Jenkins的CI/CD持续部署

准备事宜 1.已经在PasteSpider中配置好了相关的项目和服务 2.在gitee中有创建对应的代码仓库 实现原理 1.webhook是时下非常流行的一个推送模式&#xff0c;webhook其实就是往某一个特定的地址推送消息&#xff0c;这样可以避免频繁的轮询&#xff0c;在事件发生后的第一时间告…

Microsoft Edge 使用方法与秘诀概览

目录 ​编辑引言 Microsoft Edge 功能与技巧概览 掌握这些设置技巧&#xff0c;让 Edge 浏览器的体验更干净 1. 使用阅读视图 2. 开启广告过滤 3. 管理扩展 4. 个性化新标签页 5. 使用网页截图 6. 清理浏览器缓存 7. 管理启动设置 8. 自定义地址栏建议 9. 使用内置笔…

OLAP引擎之Druid

Apache Druid 简介 Apache Druid 是一个开源的、分布式的实时分析数据库&#xff0c;专为大规模数据的快速查询和实时分析而设计。Druid 将数据存储、索引和查询处理功能结合在一起&#xff0c;支持对流数据和批量数据进行快速的、低延迟的分析查询。它特别适用于需要高并发、…

C语言内存操作函数

目录 一. C语言内存操作函数 1. memcpy的使用和模拟实现 2. memmove函数 3. memset函数 4. memcmp函数 一. C语言内存操作函数 随着知识的不断积累&#xff0c;我们所想要实现的目标程序就会更加复杂&#xff0c;今天我们来学习一个新的知识叫做C语言内存操作函数&#x…

eNSP 华为交换机生成树协议

华为交换机生成树协议 生成树协议原理与作用 选举一个交换机作为根网桥&#xff08;生成树的根&#xff09;&#xff0c;计算出到其他所有交换机的最佳路径&#xff0c;把备用路径的端口设为堵塞状态&#xff08;逻辑上关闭备用路径&#xff09;&#xff0c;当最佳路径故障再…

制造企业为什么要数字化转型?面临哪些困难?

如何界定制造企业 制造业&#xff08;Manufacturing Industry&#xff09;是指机械工业时代利用某种资源&#xff08;物料、能源、设备、工具、资金、技术、信息和人力等&#xff09;&#xff0c;按照市场要求&#xff0c;通过制造过程&#xff0c;转化为可供人们使用和利用的…

01:电容的什么,各类电容的优缺点

1.电容是什么&#xff1f; 电容是由两块不连通的导体&#xff0c;已经中间的不导电材料组成 电容结构&#xff1a; 1.2电容的容量计算公式 C ε s d \displaystyle\frac{εs}{d} dεs​ 1.3常见电容的种类 1.4各类电容的特点

【大模型从入门到精通31】开源库框架LangChain RAG 系统中的问答技术1

这里写目录标题 引言问答与语言模型一般流程整合方法 通过高级问答技术增强 RAG 系统利用 VectorDB 进行文档检索实现问答链初始化语言模型配置 RetrievalQA 链 问答实战 引言 检索增强生成 (RAG) 系统已经革新了我们与大型数据集互动的方式&#xff0c;使得开发高度复杂的聊天…

深入探索MyBatis的动态代理模式

文章目录 深入探索MyBatis的动态代理模式引言一、 MyBatis动态代理概述动态代理的优势 二、准备工作文件存放结构视图1、Mybatis的主配置文件 mybatis-config.xml2、db.properties文件:3、mybatis-config.xml引用properties文件: 三、MyBatis动态代理的实现原理1. Mapper接口定…

基于STM32F103的FreeRTOS系列(十)·消息队列的使用详细介绍以及代码编写

目录 1. 消息队列简介 1.1 概念 1.2 数据存储 1.3 阻塞机制 1.3.1 出队阻塞 1.3.2 入队阻塞 1.4 操作示意图 1.4.1 创建队列 1.4.2 向队列发送第一个消息 1.4.3 向队列发送第二个消息 1.4.4 从队列读取消息 1.5 消息队列的控制块 2. 常用API函数介绍…

android13顶部状态栏里面调节背光,不隐藏状态栏面板

总纲 android13 rom 开发总纲说明 目录 1.前言 2.代码分析 3.修改方法 4.编译运行 5.彩蛋 1.前言 android13顶部状态栏里面调节背光,这个时候状态栏面板会被隐藏掉,有些需求就需要不隐藏这个面板。 2.代码分析 查找亮度条属性 id/brightness_slider ./frameworks/b…

Vue 3 + 天地图 + D3.js 绘制行政区划

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;组件封装篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来组件封装篇专栏内容:组件封装-天地图 目录 引入天地图 API 初始化地图 引入 D3.js 加载行政区划数据 添…

k8s高版本(1,28)部署NodePort模式下的ingress-nginx的详细过程及应用案例

文章目录 前言环境ingress安装应用案例(ingress-http案例&#xff1a; 基于名称的负载均衡) 前言 这个是nodeport模式下的&#xff0c;如果需要loadbalancer模式下的&#xff0c;看看博主下面以前的博客 链接: k8s学习–负载均衡器matelLB的详细解释与安装 链接: k8s学习–ing…

机器学习 之 使用逻辑回归 进行银行贷款预测(请帮忙点点赞谢谢,这对我很重要)

目录 一、逻辑回归简介 逻辑回归的基本原理 线性组合&#xff1a; Sigmoid函数&#xff1a; 二、实战案例 1.导入数据 2.准备环境 混淆矩阵的基本概念 混淆矩阵的作用 3.加载数据 4.数据预处理 什么是标准化&#xff1f; 标准化的计算公式 划分数据集 5.逻辑回归模…

19.缓存的认识和基本使用

缓存介绍 缓存是数据交换的缓冲区Cache&#xff0c;是临时存储数据的地方&#xff0c;一般读写性能较高。 数据库的缓存就是建立索引。 缓存的作用 1.降低后端负载。 2.提高读写效率&#xff0c;降低响应时间。 缓存的问题 1.保证数据的一致性。 2.增加代码维护成本。解…

Kafka运行机制(二):消息确认,消息日志的存储和回收

前置知识 Kafka基本概念https://blog.csdn.net/dxh9231028/article/details/141270920?spm1001.2014.3001.5501Kafka运行机制&#xff08;一&#xff09;&#xff1a;Kafka集群启动&#xff0c;controller选举&#xff0c;生产消费流程https://blog.csdn.net/dxh9231028/arti…

Qt 0816作业

一、思维导图 二、将day1做的登录界面升级优化【资源文件的添加】 三、在登录界面的登录取消按钮进行一下设置 使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 将登录按钮使用qt5版本的连接到…

C++ | Leetcode C++题解之第350题两个数组的交集II

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {sort(nums1.begin(), nums1.end());sort(nums2.begin(), nums2.end());int length1 nums1.size(), length2 nums2…

函数递归VS操作符深入?

1>>前言 函数递归函数递归&#xff0c;当小白听到这样的词会感到无比陌生&#xff0c;请不要惊慌&#xff0c;这是正常的&#xff0c;以至于都不是很经常用到&#xff0c;但是它的算法&#xff0c;它的思想是值得我们深入思考的。还有一些复杂操作符&#xff0c;如按位与…