当前位置: 首页 > article >正文

flutter: table calendar笔记

pub dev:table_calendar 3.2.0
我来详细解释 TableCalendar 是如何根据不同的 CalendarFormat 来显示界面的。主要逻辑在 CalendarCore 中实现。
核心逻辑分为以下几个部分:

  1. 页面数量计算 - _getPageCount 方法根据不同格式计算总页数:
int _getPageCount(CalendarFormat format, DateTime first, DateTime last) {switch (format) {case CalendarFormat.month:return _getMonthCount(first, last) + 1;case CalendarFormat.twoWeeks:return _getTwoWeekCount(first, last) + 1;case CalendarFormat.week:return _getWeekCount(first, last) + 1;}
}
  1. 可见日期范围计算 - _getVisibleRange 方法决定每种格式显示多少天:
DateTimeRange _getVisibleRange(CalendarFormat format, DateTime focusedDay) {switch (format) {case CalendarFormat.month:return _daysInMonth(focusedDay);  // 显示整月case CalendarFormat.twoWeeks:return _daysInTwoWeeks(focusedDay);  // 显示两周case CalendarFormat.week:return _daysInWeek(focusedDay);  // 显示一周}
}
  1. 行数计算 - _getRowCount 方法决定显示多少行:
int _getRowCount(CalendarFormat format, DateTime focusedDay) {if (format == CalendarFormat.twoWeeks) {return 2;  // 两周显示2行} else if (format == CalendarFormat.week) {return 1;  // 一周显示1行} else if (sixWeekMonthsEnforced) {return 6;  // 月视图强制6行}// 月视图动态计算行数final first = _firstDayOfMonth(focusedDay);final daysBefore = _getDaysBefore(first);final firstToDisplay = first.subtract(Duration(days: daysBefore));final last = _lastDayOfMonth(focusedDay);final daysAfter = _getDaysAfter(last);final lastToDisplay = last.add(Duration(days: daysAfter));return (lastToDisplay.difference(firstToDisplay).inDays + 1) ~/ 7;
}
  1. 日期生成 - 根据不同格式生成要显示的日期:
// 生成一周的日期
DateTimeRange _daysInWeek(DateTime focusedDay) {final daysBefore = _getDaysBefore(focusedDay);final firstToDisplay = focusedDay.subtract(Duration(days: daysBefore));final lastToDisplay = firstToDisplay.add(const Duration(days: 7));return DateTimeRange(start: firstToDisplay, end: lastToDisplay);
}// 生成两周的日期
DateTimeRange _daysInTwoWeeks(DateTime focusedDay) {final daysBefore = _getDaysBefore(focusedDay);final firstToDisplay = focusedDay.subtract(Duration(days: daysBefore));final lastToDisplay = firstToDisplay.add(const Duration(days: 14));return DateTimeRange(start: firstToDisplay, end: lastToDisplay);
}// 生成一个月的日期
DateTimeRange _daysInMonth(DateTime focusedDay) {final first = _firstDayOfMonth(focusedDay);final daysBefore = _getDaysBefore(first);final firstToDisplay = first.subtract(Duration(days: daysBefore));if (sixWeekMonthsEnforced) {// 强制显示6周final end = firstToDisplay.add(const Duration(days: 42));return DateTimeRange(start: firstToDisplay, end: end);}// 根据实际天数显示final last = _lastDayOfMonth(focusedDay);final daysAfter = _getDaysAfter(last);final lastToDisplay = last.add(Duration(days: daysAfter));return DateTimeRange(start: firstToDisplay, end: lastToDisplay);
}
  1. 页面切换逻辑 - _getFocusedDay 方法处理不同格式下的页面切换:
DateTime _getFocusedDay(CalendarFormat format,DateTime prevFocusedDay,int pageIndex,
) {if (pageIndex == previousIndex) {return prevFocusedDay;}final pageDif = pageIndex - previousIndex!;DateTime day;switch (format) {case CalendarFormat.month:// 月视图按月切换day = DateTime.utc(prevFocusedDay.year, prevFocusedDay.month + pageDif);case CalendarFormat.twoWeeks:// 两周视图每次移动14天day = DateTime.utc(prevFocusedDay.year,prevFocusedDay.month,prevFocusedDay.day + pageDif * 14,);case CalendarFormat.week:// 周视图每次移动7天day = DateTime.utc(prevFocusedDay.year,prevFocusedDay.month,prevFocusedDay.day + pageDif * 7,);}// 确保不超出范围if (day.isBefore(firstDay)) {day = firstDay;} else if (day.isAfter(lastDay)) {day = lastDay;}return day;
}

如果你想添加新的 CalendarFormat(比如 threeWeeks),需要:

  • 在 utils.dart 中的 CalendarFormat 枚举中添加新格式
  • 在上述所有 switch 语句中添加新的 case 处理
  • 实现对应的日期范围计算方法
  • 添加行数计算逻辑

例如添加 threeWeeks 格式

// 1. 在 CalendarFormat 中添加
enum CalendarFormat { month, twoWeeks, week, threeWeeks }// 2. 在 switch 语句中添加处理
case CalendarFormat.threeWeeks:return _daysInThreeWeeks(focusedDay);// 3. 实现日期范围计算
DateTimeRange _daysInThreeWeeks(DateTime focusedDay) {final daysBefore = _getDaysBefore(focusedDay);final firstToDisplay = focusedDay.subtract(Duration(days: daysBefore));final lastToDisplay = firstToDisplay.add(const Duration(days: 21));return DateTimeRange(start: firstToDisplay, end: lastToDisplay);
}// 4. 添加行数计算
if (format == CalendarFormat.threeWeeks) {return 3;  // 三周显示3行
}

TableCalendar 的界面绘制流程

让我详细解释 TableCalendar 的界面绘制流程。整个日历界面的绘制主要涉及以下组件的配合:
TableCalendar (主组件) -> CalendarCore (核心布局) -> CalendarPage (单页渲染)
让我们从最内层的 CalendarPage 开始解释:

  1. CalendarPage - 单个日历页面的渲染
class CalendarPage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Row(children: [// 1. 可选的周数显示列if (weekNumberVisible) _buildWeekNumbers(context),// 2. 主日历表格Expanded(child: Table(border: tableBorder,children: [// 2.1 星期头部行 (Mon, Tue, Wed...)if (dowVisible) _buildDaysOfWeek(context),// 2.2 日期行..._buildCalendarDays(context),],),),],);}
}

日历页面使用 Table widget 来布局,包含:
可选的周数列
星期头部行
日期网格
2. CalendarCore - 页面管理与切换

class CalendarCore extends StatelessWidget {@overrideWidget build(BuildContext context) {return PageView.builder(controller: pageController,itemCount: _getPageCount(calendarFormat, firstDay, lastDay),itemBuilder: (context, index) {// 1. 计算这一页要显示的基准日期final baseDay = _getBaseDay(calendarFormat, index);// 2. 计算这一页要显示的日期范围final visibleRange = _getVisibleRange(calendarFormat, baseDay);// 3. 生成要显示的所有日期final visibleDays = _daysInRange(visibleRange.start, visibleRange.end);// 4. 计算行高final actualDowHeight = dowVisible ? dowHeight! : 0.0;final constrainedRowHeight = constraints.hasBoundedHeight? (constraints.maxHeight - actualDowHeight) / _getRowCount(calendarFormat, baseDay): null;// 5. 渲染日历页面return CalendarPage(visibleDays: visibleDays,// ... 其他配置);},);}
}
  1. 实际的渲染过程
    以月视图为例,完整的渲染流程:
// 1. 确定要显示的日期范围
DateTimeRange _daysInMonth(DateTime focusedDay) {// 获取月份第一天final first = _firstDayOfMonth(focusedDay);  // 例如:2024-03-01// 计算需要显示的上月剩余天数final daysBefore = _getDaysBefore(first);    // 如果3月1日是周五,需要显示前4天// 计算本月第一个显示的日期final firstToDisplay = first.subtract(Duration(days: daysBefore));  // 2024-02-26if (sixWeekMonthsEnforced) {// 强制显示6周final end = firstToDisplay.add(const Duration(days: 42));  // 显示42天return DateTimeRange(start: firstToDisplay, end: end);}// 获取月份最后一天final last = _lastDayOfMonth(focusedDay);    // 2024-03-31// 计算需要显示的下月天数final daysAfter = _getDaysAfter(last);       // 补充到完整的周// 计算最后一个显示的日期final lastToDisplay = last.add(Duration(days: daysAfter));  // 2024-04-06return DateTimeRange(start: firstToDisplay, end: lastToDisplay);
}// 2. 生成所有要显示的日期
List<DateTime> _daysInRange(DateTime first, DateTime last) {final dayCount = last.difference(first).inDays + 1;return List.generate(dayCount,(index) => DateTime.utc(first.year, first.month, first.day + index),);
}// 3. 渲染表格
List<TableRow> _buildCalendarDays(BuildContext context) {final rowAmount = visibleDays.length ~/ 7;  // 计算行数return List.generate(rowAmount,(row) => TableRow(decoration: rowDecoration,children: List.generate(7,(column) => dayBuilder(context, visibleDays[row * 7 + column]),),),);
}

视觉效果示意:

     March 2024
Mo Tu We Th Fr Sa Su
26 27 28 29  1  2  3  <- 上月日期4  5  6  7  8  9 10  <- 本月第一周
11 12 13 14 15 16 17  <- 本月第二周
18 19 20 21 22 23 24  <- 本月第三周
25 26 27 28 29 30 31  <- 本月第四周1  2  3  4  5  6  7  <- 下月日期

不同的 CalendarFormat 只是改变了显示的行数:

  • CalendarFormat.month: 显示整月(4-6行)
  • CalendarFormat.twoWeeks: 显示2行
  • CalendarFormat.week: 显示1行
    每个日期单元格的具体样式由 dayBuilder 控制,可以通过 CalendarBuilders 和 CalendarStyle 来自定义外观。
    这就是整个 TableCalendar 的界面渲染流程。它通过 PageView 实现翻页,通过 Table 实现网格布局,通过精确的日期计算确保日历的正确显示

其中函数_buildCalendarDays的解释如下:
让我们一步步解析:

  1. 函数声明:
    • List 表示返回一个 TableRow 类型的列表
      List.generate(count, (index) => value)
      下划线 _ 开头表示这是一个私有方法
      BuildContext context 是 Flutter 中用于构建 Widget 的上下文参数
  2. 行数计算:
   final rowAmount = visibleDays.length ~/ 7;
- ~/ 是整数除法运算符
比如如果 visibleDays.length 是 35,那么 rowAmount 就是 5
  1. List.generate: List.generate(count, (index) => value)
    这是 Dart 的列表生成方法
    count 指定要生成多少个元素
    (index) => value 是一个函数,用于生成每个元素
  2. TableRow:
    • Flutter 中表格的一行
      decoration 用于设置行的样式(比如背景色)
      children 包含这一行的所有单元格
  3. 嵌套的 List.generate:
    • 生成每行的 7 个单元格
      index * 7 + id 计算当前单元格对应的日期索引
      dayBuilder 用于构建每个日期的显示内容

举个例子,如果你要显示一个月的日历:
假设有 35 天要显示(5 周)
rowAmount 将是 5(35/7)
外层 List.generate 会生成 5 行
每行内部的 List.generate 会生成 7 个单元格
最终生成一个 5×7 的表格
这就像在创建一个 Excel 表格:
每个单元格的具体显示内容由 dayBuilder 决定,这就是为什么它是一个可自定义的函数。

生成视图的流程

  1. 初始化阶段:
// 在测试代码中初始化 TableCalendarBase
TableCalendarBase(dayBuilder: (context, day, focusedDay) {return Text('${day.day}',key: dateToKey(day),);},// ... 其他参数
)
  1. CalendarCore 中的包装:
// CalendarCore 给每个日期添加固定高度的容器
dayBuilder: (context, day) {// ... 计算 baseDay ...return SizedBox(height: constrainedRowHeight ?? rowHeight,child: dayBuilder(context, day, baseDay),  // 调用原始的 dayBuilder);
}
  1. CalendarPage 中的布局:
// CalendarPage 将日期排列成表格
List<TableRow> _buildCalendarDays(BuildContext context) {return List.generate(rowAmount,  // 行数(index) => TableRow(children: List.generate(7,  // 每行7列(id) => dayBuilder(context, visibleDays[index * 7 + id]),  // 调用包装后的 dayBuilder),),);
}

所以完整流程是:
用户提供基础的日期显示方式(Text组件)
CalendarCore 添加大小控制(SizedBox)
CalendarPage 将所有日期组织成表格形式(Table和TableRow)
最终形成一个完整的日历视图
这就像搭积木:
Text(显示日期)
→ SizedBox(控制大小)
→ TableRow(排成一行)
→ Table(组成表格)
→ 完整日历

相关文章:

flutter: table calendar笔记

pub dev&#xff1a;table_calendar 3.2.0 我来详细解释 TableCalendar 是如何根据不同的 CalendarFormat 来显示界面的。主要逻辑在 CalendarCore 中实现。 核心逻辑分为以下几个部分&#xff1a; 页面数量计算 - _getPageCount 方法根据不同格式计算总页数&#xff1a; in…...

smolagents学习笔记系列(五)Tools-in-depth-guide

这篇文章锁定官网教程中的 Tools-in-depth-guide 章节&#xff0c;主要介绍了如何详细构造自己的Tools&#xff0c;在之前的博文 smolagents学习笔记系列&#xff08;二&#xff09;Agents - Guided tour 中我初步介绍了下如何将一个函数或一个类声明成 smolagents 的工具&…...

axios几种请求类型的格式

Axios 是一个基于 Promise 的 HTTP 客户端&#xff0c;广泛用于浏览器和 Node.js 中发送 HTTP 请求。它支持多种请求格式&#xff0c;包括 GET、POST、PUT、DELETE 等。也叫RESTful 目录 一、axios几种请求类型的格式 1、get请求 2、post请求 3、put请求 4、delete请求 二…...

架构设计系列(六):缓存

一、概述 在应用对外提供服务的时候其稳定性&#xff0c;性能会受到诸多因素的影响。缓存的作用是将频繁访问的数据缓存起来&#xff0c;避免资源重复消耗&#xff0c;提升系统服务的吞吐量。 二、缓存的应用场景 2.1 客户端 HTTP响应可以被浏览器缓存。我们第一次通过HTTP请…...

个人电脑小参数GPT预训练、SFT、RLHF、蒸馏、CoT、Lora过程实践——MiniMind图文版教程

最近看到Github上开源了一个小模型的repo&#xff0c;是真正拉低LLM的学习门槛&#xff0c;让每个人都能从理解每一行代码&#xff0c; 从零开始亲手训练一个极小的语言模型。开源地址&#xff1a; GitHub - jingyaogong/minimind: &#x1f680;&#x1f680; 「大模型」2小时…...

MySQL 中的事务隔离级别有哪些?MySQL 默认的事务隔离级别是什么?为什么选择这个级别?数据库的脏读、不可重复读和幻读分别是什么?

MySQL 中的事务隔离级别有哪些&#xff1f; 1. 读未提交&#xff08;Read Uncommitted&#xff09; 特点&#xff1a;一个事务可以读取另一个事务未提交的数据。如果一个事务对数据进行了修改但尚未提交&#xff0c;其他事务仍能读取到这些未提交的修改。优缺点&#xff1a; …...

格式工厂 FormatFactory v5.18.便携版 ——多功能媒体文件转换工具

格式工厂 FormatFactory v5.18.便携版 ——多功能媒体文件转换工具 功能&#xff1a;视频 音频 图片 文档PDF格式 各种转换&#xff0c;同格式调整压缩比例&#xff0c;调整大小 特色&#xff1a;果风图标 好看; 支持多任务队列&#xff0c;完成自动关机 下载地址&#xff1…...

python爬虫学习第十一篇爬取指定类型数据

最近在学习Python爬虫的过程中&#xff0c;尝试用爬虫获取指定类型的数据。今天&#xff0c;我想和大家分享一下我的实践过程和遇到的问题。 一、实现目标 目标是从一个网站的API接口获取不同类型的食品数据。 比如&#xff0c;第一步我想获取汉堡、小食、甜品等不同类型的数…...

Android 实现 RTMP 推流:快速集成指南

简介 在 Android 设备上实现 RTMP 推流,可以用于直播、远程监控等应用场景。本文将基于 rtmp-rtsp-stream-client-java 库,介绍如何在 Android 端快速集成 RTMP 推流,包括权限管理、相机预览、推流控制等关键步骤。 步骤 1. 配置 Maven 仓库 在 settings.gradle.kts 中添…...

KafkaTool

Offset Explorer 第一次打开需要配置kafka相关配置连接 随便先启动一个Kafka(先启动zookeeper) 设置key value 记得刷新...

基于C++“简单且有效”的“数据库连接池”

前言 数据库连接池在开发中应该是很常用的一个组件&#xff0c;他可以很好的节省连接数据库的时间开销&#xff1b;本文基使用C实现了一个简单的数据库连接池&#xff0c;代码量只有400行只有&#xff0c;但是压力测试效果很好&#xff1b;欢迎收藏 关注&#xff0c;本人将会…...

简单易懂,解析Go语言中的struct结构体

目录 4. struct 结构体4.1 初始化4.2 内嵌字段4.3 可见性4.4 方法与函数4.4.1 区别4.4.2 闭包 4.5 Tag 字段标签4.5.1定义4.5.2 Tag规范4.5.3 Tag意义 4. struct 结构体 go的结构体类似于其他语言中的class&#xff0c;主要区别就是go的结构体没有继承这一概念&#xff0c;但可…...

爬虫第九篇-结束爬虫循环

最近在学习Python爬虫的过程中&#xff0c;遇到了一个很有趣的问题&#xff1a;如何优雅地结束爬虫循环&#xff1f;今天&#xff0c;我想和大家分享一下我的发现和心得。 一、爬虫循环结束的常见问题 在写爬虫时&#xff0c;我们经常会遇到这样的情况&#xff1a;当爬取到的…...

国产编辑器EverEdit - 洞察秋毫!文件比较功能!

1 文件比较 1.1 应用场景 项目开发过程中&#xff0c;可能不同的部分会由不同的人在负责&#xff0c;存在一个文件多人编辑的情况&#xff0c;用户需要寻找差异&#xff0c;并将文档进行合并&#xff0c;比较专业的文本比较工具为BeyondCompare&#xff0c;WinMerge等。   如…...

QARepVGG--含demo实现

文章目录 前言引入Demo实现总结 前言 在上一篇博文RepVGG中&#xff0c;介绍了RepVGG网络。RepVGG 作为一种高效的重参数化网络&#xff0c;通过训练时的多分支结构&#xff08;3x3卷积、1x1卷积、恒等映射&#xff09;和推理时的单分支合并&#xff0c;在精度与速度间取得了优…...

五、 Spring Framework基础:Spring Data JPA基本用法与 Repository 接口

深入解析 Spring Data JPA&#xff1a;基本用法与 Repository 接口 Spring Data JPA 是 Spring 框架中用于简化数据访问层开发的核心模块。它基于 JPA 规范&#xff0c;底层使用 Hibernate 实现&#xff0c;通过接口继承和方法命名规则&#xff0c;自动实现增删改查等常见操作…...

如何实现在Redis集群情况下,同一类数据固定保存在同一个Redis实例中

1. 使用哈希标签&#xff08;Hash Tags&#xff09; 概述 Redis Cluster使用一致性哈希算法来分配数据到不同的节点上。为了确保相同类型的数据被分配到同一个Redis实例上&#xff0c;可以利用哈希标签&#xff08;Hash Tags&#xff09;。哈希标签是指在键名中用花括号 {} 包…...

kotlin 知识点 七 泛型的高级特性

对泛型进行实化 泛型实化这个功能对于绝大多数Java 程序员来讲是非常陌生的&#xff0c;因为Java 中完全没有这个概 念。而如果我们想要深刻地理解泛型实化&#xff0c;就要先解释一下Java 的泛型擦除机制才行。 在JDK 1.5之前&#xff0c;Java 是没有泛型功能的&#xff0c;…...

Transformer LLaMA

一、Transformer Transformer&#xff1a;一种基于自注意力机制的神经网络结构&#xff0c;通过并行计算和多层特征抽取&#xff0c;有效解决了长序列依赖问题&#xff0c;实现了在自然语言处理等领域的突破。 Transformer 架构摆脱了RNNs&#xff0c;完全依靠 Attention的优…...

Qt学习 网络编程 TPC通信

一 基本网络端口 1 网络编程基本概念 通讯方式&#xff1a;信息的通讯时通过网络来进行&#xff0c;通讯方式有两种&#xff0c;TCP和UDP通信&#xff0c;TCP通讯是专用通道&#xff0c;指定某个信息只能走某个通道&#xff0c;UDP则是非专用通道&#xff0c;比如一个车队&am…...

ESP32-S3 实战指南:BOOT-KEY 按键驱动开发全解析

一、基础知识 本篇我们使用 BOOT 按键来学习一下 GPIO 功能&#xff0c;首先补充一下相关术语介绍。 1、GPIO&#xff08;General Purpose Input/Output&#xff09; GPIO 是微控制器上的通用引脚&#xff0c;既可以作为输入&#xff08;读取外部信号&#xff09;&#xff0…...

ssh配置 远程控制 远程协作 github本地配置

0.设备版本 windows11 ubuntu24.0.4 1.1 在 Linux 上启用 SSH 服务 首先&#xff0c;确保 Linux 计算机上安装并启用了 SSH 服务。 安装和启动 OpenSSH 服务&#xff08;如果未安装&#xff09; # 在终端安装 OpenSSH 服务&#xff08;如果尚未安装&#xff09; sudo apt …...

C++知识整理day9——继承(基类与派生类之间的转换、派生类的默认成员函数、多继承问题)

文章目录 1.继承的概念和定义2.基类与派生类之间的转换3.继承中的作用域4.派生类的默认成员函数5.实现一个不能被继承的类6.继承与友元7.继承与静态成员8.多继承和菱形继承问题8.1 继承分类及菱形继承8.2 虚继承 1.继承的概念和定义 概念&#xff1a; 继承(inheritance)机制是⾯…...

2024年国赛高教杯数学建模A题板凳龙闹元宵解题全过程文档及程序

2024年国赛高教杯数学建模 A题 板凳龙闹元宵 原题再现 “板凳龙”&#xff0c;又称“盘龙”&#xff0c;是浙闽地区的传统地方民俗文化活动。人们将少则几十条&#xff0c;多则上百条的板凳首尾相连&#xff0c;形成蜿蜒曲折的板凳龙。盘龙时&#xff0c;龙头在前领头&#x…...

华为认证考试证书下载步骤(纸质+电子版)

华为考试证书可以通过官方渠道下载相应的电子证书&#xff0c;部分高级认证如HCIE还支持申请纸质证书。 一、华为电子版证书申请步骤如下&#xff1a; ①访问华为培训与认证网站 打开浏览器&#xff0c;登录华为培训与认证官方网站 ②登录个人账号 在网站首页&#xff0c;点…...

[杂学笔记]工厂模式、多态、内存空间区域划分、cp指令破坏软连接问题、UDP如何实现可靠传输、滑动窗口的原理、进程与线程、线程之间的通信

目录 1.工厂模式 2.多态 3.内存空间区域划分 4.cp指令破坏软连接问题 5.UDP实现可靠传输 6.滑动窗口的原理 7.进程与线程 8.线程之间的通信 1.工厂模式 工厂模式是一种创建对象的设计模式。它提供了一种创建对象的方式&#xff0c;将对象的创建和使用分离&#xff0c;通…...

开源RAG主流框架有哪些?如何选型?

开源RAG主流框架有哪些?如何选型? 一、开源RAG框架全景图 (一)核心框架类型对比 类型典型工具技术特征适用场景传统RAGLangChain, Haystack线性流程(检索→生成)通用问答、知识库检索增强型RAGRAGFlow, AutoRAG支持重排序、多路召回优化高精度问答、复杂文档处理轻量级…...

【Android】用 chrome://inspect/#devices 调试H5页面

通常做Android开发的过程中&#xff0c;不可避免的需要遇到去与H5交互&#xff0c;甚至有时候需要去调试H5的信息。 这里分享一下Android工程里如何调试H5页面信息&#xff1a; 直接在浏览器地址栏输入 &#xff1a; chrome://inspect/#devices 直接连接手机usb,打开开发者模式…...

贪心算法精品题

1.找钱问题 本题的贪心策略在于我们希望就可能的保留作用大的5元 class Solution { public:bool lemonadeChange(vector<int>& bills) {std::map<int ,int> _map;for(auto ch:bills){if(ch 5) _map[ch];else if(ch 10){if(_map[5] 0) return false;else{_m…...

七、Spring Boot:初识与项目搭建

深入解析 Spring Boot&#xff1a;初识与项目搭建 Spring Boot 是基于 Spring Framework 的开源 Java 基础框架&#xff0c;旨在简化 Spring 应用的开发过程。它通过“约定优于配置”的理念&#xff0c;极大地减少了开发中的配置工作&#xff0c;同时提供了“开箱即用”的功能…...