Spring Boot 凭借其 "约定大于配置" 的理念,极大简化了 Java 应用开发流程。本文将从 Spring Boot 核心特性出发,详细解析静态资源映射规则、Thymeleaf 模板引擎的使用,并结合完整实战案例,帮助开发者快速上手 Spring Boot web 开发。

一、Spring Boot 简介:简化开发的核心优势

Spring Boot 是 Spring 生态的 "开箱即用" 框架,其核心优势在于自动配置—— 通过预设场景化配置,让开发者无需手动整合各种框架,专注于业务逻辑实现。

1.1 Spring Boot 开发流程

使用 Spring Boot 开发应用的典型步骤:

  1. 创建应用:通过 Spring Initializr(或 IDE 插件)选择所需模块(如 web、thymeleaf 等);
  2. 极简配置:仅需在application.properties/yml中指定少量个性化配置(如端口、缓存时间等);
  3. 编写业务:直接开发控制器、服务层等业务代码,无需关心框架整合细节。

1.2 自动配置的核心疑问

使用 Spring Boot 时,我们常关心:

  • 框架默认配置了哪些组件?
  • 如何修改默认配置?
  • 能否扩展默认功能?

这些问题的答案,藏在 Spring Boot 的自动配置原理中 —— 通过@Conditional系列注解,根据类路径下的依赖、配置参数动态激活配置类,开发者可通过自定义配置类或配置文件覆盖默认行为。

二、静态资源映射规则:Spring Boot 如何处理静态资源?

Web 应用中,静态资源(JS、CSS、图片等)的访问是基础需求。Spring Boot 通过WebMvcAutoConfiguration自动配置了静态资源映射规则,无需手动配置即可访问。

2.1 核心配置类解析

静态资源映射的核心逻辑在WebMvcAutoConfigurationaddResourceHandlers方法中,主要处理以下场景:

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {// 若关闭默认映射(spring.resources.add-mappings=false),则不生效if (!this.resourceProperties.isAddMappings()) {logger.debug("Default resource handling disabled");return;}// 处理webjars资源if (!registry.hasMappingForPattern("/webjars/**")) {customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/").setCachePeriod(cachePeriod));}// 处理静态资源文件夹String staticPathPattern = this.mvcProperties.getStaticPathPattern();if (!registry.hasMappingForPattern(staticPathPattern)) {customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern).addResourceLocations(this.resourceProperties.getStaticLocations()).setCachePeriod(cachePeriod));}
}

2.2 四大静态资源访问规则

(1)WebJars:以 Jar 包形式管理静态资源

WebJars 将常用前端库(如 jQuery、Bootstrap)打包成 Jar 包,方便 Maven/Gradle 管理。Spring Boot 默认映射规则:
访问路径/webjars/**
资源位置classpath:/META-INF/resources/webjars/

使用示例

  1. 引入 jQuery 的 WebJar 依赖(pom.xml):
<dependency><groupId>org.webjars</groupId><artifactId>jquery</artifactId><version>3.5.0</version>
</dependency>
  1. 访问 jQuery:通过http://localhost:8080/webjars/jquery/3.5.0/jquery.js即可访问。

(2)静态资源文件夹:直接访问本地资源

Spring Boot 默认将以下路径作为静态资源文件夹,通过/**路径直接访问:

  • classpath:/META-INF/resources/
  • classpath:/resources/
  • classpath:/static/(推荐)
  • classpath:/public/
  • 项目根路径/(不推荐,易与控制器路径冲突)

示例:在src/main/resources/static/下放置img/logo.png,可通过http://localhost:8080/img/logo.png访问。

(3)欢迎页:默认首页自动映射

静态资源文件夹下的index.html会被自动识别为欢迎页,访问http://localhost:8080/时直接返回该页面。

实现逻辑WebMvcAutoConfiguration中的WelcomePageHandlerMapping会映射/**到静态资源文件夹下的index.html

(4)Favicon:网站图标自动配置

浏览器会自动请求**/favicon.ico作为网站图标,Spring Boot 默认从静态资源文件夹中查找该文件。

关闭方式:在配置文件中设置spring.mvc.favicon.enabled=false即可禁用默认图标。

配置后重启后没有显示可能是浏览器缓存问题。可以通过 Ctrl+Shift+R清理缓存

2.3 静态资源配置扩展

可通过application.properties修改静态资源行为:

# 关闭默认静态资源映射(谨慎使用)
spring.resources.add-mappings=false
# 设置静态资源缓存时间(单位:秒)
spring.resources.cache.period=3600
# 自定义静态资源文件夹路径(默认值不变,追加新路径)
spring.resources.static-locations=classpath:/static/,classpath:/my-resources/

三、Thymeleaf 模板引擎:Spring Boot 推荐的视图层方案

JSP 因依赖 Servlet 容器、无法嵌入 Jar 包等问题,逐渐被现代模板引擎替代。Spring Boot 推荐使用Thymeleaf—— 一款基于 HTML 的服务器端模板引擎,支持自然模板(模板即静态原型)、强大的表达式语法和 Spring 生态深度整合。

3.1 引入与基础配置

(1)引入依赖

pom.xml中添加 Thymeleaf Starter:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
(2)核心配置属性

Thymeleaf 的默认配置由ThymeleafProperties类定义,可通过application.properties修改:

public class ThymeleafProperties {// 默认模板前缀:classpath:/templates/(模板文件存放位置)private String prefix = "classpath:/templates/";// 默认模板后缀:.html(模板文件扩展名)private String suffix = ".html";// 编码:UTF-8private Charset encoding = StandardCharsets.UTF_8;// 开发环境建议关闭缓存(默认true)private boolean cache = true;// 模板模式:HTML(支持HTML5、XML等)private String mode = "HTML";
}

开发环境配置(推荐):

# 关闭模板缓存(修改后无需重启)
spring.thymeleaf.cache=false
# 自定义模板前缀(默认不变)
spring.thymeleaf.prefix=classpath:/templates/

 出现 Error resolving template [demo] 错误的核心原因是:Thymeleaf 无法找到名为 demo 的模板文件,通常是由于模板路径、文件名错误或配置问题导致的。

3.2 Thymeleaf 语法全解析

Thymeleaf 通过自定义属性(th:*)实现动态内容替换,核心语法包括四大表达式、丰富的操作符和常用标签。

(1)四大标准表达式
表达式类型语法作用
变量表达式${...}访问模型数据(Model/Request/Session 等)
选择表达式*{...}基于th:object的子属性访问
国际化表达式#{...}从国际化资源文件中获取内容
URL 表达式@{...}生成 URL(自动拼接上下文路径)

变量表达式示例
控制器传递数据:

@RequestMapping("/success")
public String hello(Model model) {model.addAttribute("user", new User("张三", "123456", 20, 88.5, 1));return "success"; // 对应templates/success.html
}

模板中使用:

<!-- 显示用户名 -->
<p th:text="${user.username}">默认用户名</p>
<!-- 显示年龄+1 -->
<p th:text="${user.age + 1}">默认年龄</p>

选择表达式示例
通过th:object指定对象后,用*{...}简化属性访问:

<div th:object="${user}"><p>用户名:<span th:text="*{username}"></span></p><p>年龄:<span th:text="*{age}"></span></p>
</div>
<!-- 等价于 ${user.username}、${user.age} -->

国际化表达式示例

  1. 创建国际化资源文件(src/main/resources/i18n/messages.properties):
welcome.cn=欢迎访问系统
welcome.en=Welcome to the system
  1. 模板中使用:
<p>中文:<span th:text="#{welcome.cn}"></span></p>
<p>英文:<span th:text="#{welcome.en}"></span></p>

URL 表达式示例
生成路径时自动拼接上下文路径,无需硬编码项目名:

<!-- 绝对路径 -->
<a th:href="@{/login}">登录页</a>
<!-- 带参数的路径 -->
<a th:href="@{/user/detail(name=${user.username})}">用户详情</a>
<!-- 表单提交路径 -->
<form th:action="@{/user/save}" method="post"><input type="submit" value="提交">
</form>
(2)表达式支持的语法操作

Thymeleaf 表达式支持丰富的操作,满足复杂业务场景:

  • 文本操作:字符串拼接(+)、文本替换(|...|

    <p th:text="'用户名:' + ${user.username}"></p>
    <p th:text="|用户${user.id}的名称是${user.username}|"></p>
    
  • 算术运算+-*/%

    <p>年龄+1:<span th:text="${user.age + 1}"></span></p>
    <p>分数8折:<span th:text="${user.score * 0.8}"></span></p>
    
  • 布尔与比较运算andor!>gt)、<lt)、==eq)等

    <p th:if="${user.age > 18 and user.score >= 60}">成年且及格</p>
    <p th:text="${user.gender eq 1 ? '男' : '女'}"></p>
    
  • 条件运算:三目运算符、默认值(?:

    <p>是否成年:<span th:text="${user.age > 18 ? '是' : '否'}"></span></p>
    <p>昵称:<span th:text="${user.nickname ?: '未知'}"></span></p>
    
(3)常用标签实战

Thymeleaf 提供了大量标签简化页面开发,核心标签及示例如下:

标签作用示例
th:text文本替换(转义 HTML)<p th:text="${user.username}">默认值</p>
th:utext文本替换(不转义 HTML)<p th:utext="${htmlContent}">默认HTML</p>
th:each循环遍历<tr th:each="u : ${userList}">...</tr>
th:if/th:unless条件判断(unless 为反向判断)<p th:if="${user.age > 18}">成年</p>
th:switch/th:case多条件分支<div th:switch="${user.role}">...</div>
th:href/th:src链接 / 资源路径<a th:href="@{/login}">登录</a>
th:value表单值绑定<input th:value="${user.username}">

th:each循环示例
控制器传递用户列表:

@RequestMapping("/all")
public String showAll(Model model) {List<User> userList = Arrays.asList(new User("李四", "654321", 17, 59.0, 2),new User("王五", "abcdef", 25, 92.5, 1));model.addAttribute("userList", userList);return "demo2";
}

模板中循环展示:

<table border="1"><tr><th>序号</th><th>用户名</th><th>年龄</th></tr><!-- stat为状态变量:index(索引)、count(计数)、even/odd(奇偶)等 --><tr th:each="u, stat : ${userList}"><td th:text="${stat.index + 1}"></td><td th:text="${u.username}"></td><td th:text="${u.age}"></td></tr>
</table>

th:switch多分支示例

<div th:switch="${user.gender}"><p th:case="1">性别:男</p><p th:case="2">性别:女</p><p th:case="*">性别:未知</p> <!-- default分支 -->
</div>

四、实战案例:完整代码与运行效果

结合以上知识点,我们通过一个完整案例展示 Spring Boot+Thymeleaf 开发流程。

4.1 项目结构

src/
├── main/
│   ├── java/
│   │   └── com/qcby/mavenspringboot/
│   │       ├── controller/
│   │       │   ├── ThymeleafDemo2Controller.java  // 数据展示控制器
│   │       │   ├── LoginController.java           // 登录控制器
│   │       │   └── UserController.java            // 用户详情控制器
│   │       ├── entity/
│   │       │   └── User.java                      // 用户实体类
│   │       └── MavenSpringbootApplication.java    // 启动类
│   └── resources/
│       ├── application.properties                // 配置文件
│       ├── static/                               // 静态资源
│       │   └── img/
│       │       └── logo.png
│       └── templates/                            // Thymeleaf模板
│           ├── demo2.html                         // 演示页
│           ├── login.html                         // 登录页
│           ├── hello.html                         // 登录成功页
│           └── user/
│               └── detail.html                    // 用户详情页
└── pom.xml                                        // 依赖配置

4.2 核心代码实现

(1)User 实体类
public class User {private String username;private String password;private int age;private double score;private int gender; // 1-男,2-女// 构造器、getter、setterpublic User(String username, String password, int age, double score, int gender) {this.username = username;this.password = password;this.age = age;this.score = score;this.gender = gender;}// getter和setter省略
}
(2)Thymeleaf 演示控制器
@Controller
@RequestMapping("/demo2")
public class ThymeleafDemo2Controller {@RequestMapping("/all")public String showAll(Model model) {// 传递基本数据model.addAttribute("hello", "欢迎使用Thymeleaf!");// 传递用户对象User user = new User("张三", "123456", 20, 88.5, 1);model.addAttribute("user", user);// 传递用户列表List<User> userList = Arrays.asList(new User("李四", "654321", 17, 59.0, 2),new User("王五", "abcdef", 25, 92.5, 1),new User("赵六", "fedcba", 30, 76.0, 2));model.addAttribute("userList", userList);return "demo2"; // 跳转至demo2.html}
}
(3)demo2.html 模板(核心语法演示)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Thymeleaf全语法演示</title>
</head>
<body><!-- 变量表达式 ${} --><h2>1. 变量表达式 ${}</h2><div th:text="${hello}">默认文本</div><!-- 选择表达式 *{} --><h2>2. 选择表达式 *{}</h2><div th:object="${user}"><p>用户名:<span th:text="*{username}"></span></p><p>年龄:<span th:text="*{age}"></span></p></div><!-- 国际化表达式 #{} --><h2>3. 国际化表达式 #{}</h2><p>中文欢迎:<span th:text="#{welcome.cn}"></span></p><!-- URL表达式 @{} --><h2>4. URL表达式 @{}</h2><a th:href="@{/login}">登录页</a><a th:href="@{/user/detail(name=${user.username})}">用户详情</a><!-- 表达式操作 --><h2>5. 表达式操作</h2><p>年龄+1:<span th:text="${user.age + 1}"></span></p><p>是否成年:<span th:text="${user.age > 18 ? '是' : '否'}"></span></p><!-- th:each循环 --><h2>6. th:each循环</h2><table border="1"><tr th:each="u, stat : ${userList}"><td th:text="${stat.index + 1}"></td><td th:text="${u.username}"></td><td th:text="${u.age}"></td></tr></table>
</body>
</html>
(3)登录功能实现

LoginController

@Controller
public class LoginController {// 跳转登录页@GetMapping("/login")public String toLogin() {return "login";}// 处理登录提交@PostMapping("/login")public String doLogin(@RequestParam("username") String username,@RequestParam("password") String password,Model model) {// 简单验证(实际项目需查数据库)if ("admin".equals(username) && "123456".equals(password)) {model.addAttribute("msg", username);return "hello"; // 登录成功页} else {return "redirect:/login?error"; // 登录失败重定向}}
}

login.html

<form th:action="@{/login}" method="post"><input type="text" name="username" placeholder="用户名"><br><input type="password" name="password" placeholder="密码"><br><input type="submit" value="登录">
</form>
<!-- 显示错误信息 -->
<p th:if="${param.error}" style="color: red;">用户名或密码错误</p>

4.3 依赖配置(pom.xml)

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.5.3</version>
</parent><dependencies><!-- Web依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Thymeleaf依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- WebJars(jQuery) --><dependency><groupId>org.webjars</groupId><artifactId>jquery</artifactId><version>3.5.0</version></dependency><!-- 热部署(开发用) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency>
</dependencies>

4.4 配置文件(application.properties)

# 端口配置
server.port=8082
# Thymeleaf配置
spring.thymeleaf.cache=false
# 静态资源缓存时间
spring.resources.cache.period=3600

4.5 运行效果

  1. 启动应用:运行MavenSpringbootApplication
  2. 访问演示页:http://localhost:8082/demo2/all,可看到 Thymeleaf 各种语法的展示效果;
  3. 测试登录:http://localhost:8082/login,输入admin/123456可跳转至成功页。

 

 

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

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

相关文章

docker的镜像与推送

docker build# 1. 基本构建命令&#xff08;使用当前目录的 Dockerfile&#xff09; docker build .# 2. 指定 Dockerfile 路径和构建上下文 docker build -f /path/to/Dockerfile /path/to/build/context# 3. 为镜像设置名称和标签 docker build -t my-image:latest .# 4. 设置…

计算机网络学习----域名解析

在互联网世界中&#xff0c;我们习惯通过域名&#xff08;如www.example.com&#xff09;访问网站&#xff0c;而非直接记忆复杂的 IP 地址&#xff08;如 192.168.1.1&#xff09;。域名与 IP 地址之间的转换过程&#xff0c;就是域名解析。它是互联网通信的基础环节&#xff…

构建高性能推荐系统:MixerService架构解析与核心实现

——深入剖析推荐服务的分层设计、工作流引擎与高可用策略 一、整体架构与分层设计 该推荐服务采用经典分层架构模式​7&#xff0c;各层职责清晰&#xff1a; ​HTTP接口层​ 支持 GET/POST 请求解析&#xff0c;自动映射参数到 RcmdReq 协议对象统一错误处理&#xff1a;参…

【安全漏洞】隐藏服务器指纹:Nginx隐藏版本号配置修改与重启全攻略

🚀 隐藏服务器指纹:Nginx配置修改与重启全攻略 你是否知道,默认情况下Nginx会在HTTP响应头中暴露版本号?这个看似无害的Server: nginx/1.x.x字段,实则可能成为黑客的"藏宝图"。今天我们就来揭秘如何通过简单配置提升服务器安全性,并手把手教你完成Windows环境…

构建RAG智能体(2):运行状态链

在现代AI应用开发中&#xff0c;如何让聊天机器人具备记忆能力和上下文理解是一个核心挑战。传统的无状态对话系统往往无法处理复杂的多轮对话场景&#xff0c;特别是当用户需要提供多种信息来完成特定任务时。 本文就来讨论一下如何利用runnable来编排更有趣的语言模型系统&a…

RPA认证考试全攻略:如何高效通过uipath、实在智能等厂商考试

rpa认证考试有什么作用&#xff1f;数字洪流席卷全球&#xff0c;企业效率之争已进入秒级战场。当重复性工作吞噬着创造力&#xff0c;RPA&#xff08;机器人流程自动化&#xff09;技术正以前所未有的速度重塑职场生态。财务对账、报表生成、跨系统数据搬运……这些曾经耗费人…

浅析MySQL事务隔离级别

MySQL 的事务隔离级别定义了多个并发事务在访问和修改相同数据时&#xff0c;彼此之间的可见性和影响程度。它解决了并发事务可能引发的三类核心问题&#xff1a; 脏读&#xff1a; 一个事务读取了另一个未提交事务修改的数据。不可重复读&#xff1a; 一个事务内多次读取同一行…

【Linux系统】基础IO(上)

1. 深入理解"文件"概念1.1 文件的狭义理解狭义上的“文件”主要指存储在磁盘上的数据集合。具体包括&#xff1a;文件在磁盘里&#xff1a;文件是磁盘上以特定结构&#xff08;如FAT、ext4文件系统&#xff09;保存的数据集合&#xff0c;由字节或字符序列构成。磁盘…

构建智能可视化分析系统:RTSP|RTMP播放器与AI行为识别的融合实践

技术背景 随着人工智能向边缘侧、实时化方向加速演进&#xff0c;视频已从传统的“记录媒介”跃升为支撑智能感知与自动决策的关键数据入口。在安防监控、工业安全、交通治理等复杂应用场景中&#xff0c;行为识别系统的准确性和响应效率&#xff0c;越来越依赖于视频源的时效…

AI入门学习-Python 最主流的机器学习库Scikit-learn

一、Scikit-learn 核心定位是什么&#xff1a;Python 最主流的机器学习库&#xff0c;涵盖从数据预处理到模型评估的全流程。 为什么测试工程师必学&#xff1a;✅ 80% 的测试机器学习问题可用它解决✅ 无需深厚数学基础&#xff0c;API 设计极简✅ 与 Pandas/Numpy 无缝集成&a…

apache-doris安装兼datax-web配置

Doris安装 官方快速开始链接 下载2.1.10&#xff0c;解压。我这边个人服务器CPU是J1900&#xff0c;是没有 avx2的&#xff0c;所以选no 配置JAVA_HOME&#xff0c;这里没有配置的要配置下&#xff0c;注意要Oracle的jdk&#xff0c;openjdk没有jps等工具集&#xff0c;后面跑…

问题实例:4G网络下语音呼叫失败

问题描述 测试机 拨号呼出后&#xff0c;一直在4G&#xff0c;超时后自动挂断。 对比机可以呼出成功&#xff0c;呼出时回落3G。 日志分析 测试机和对比机一样发起了CSFB 呼叫。 只是测试机后面没有回落3G。 03:44:40.373264 [0xB0ED] LTE NAS EMM Plain OTA Outgoing Message …

MATLAB 2024b深度学习新特性全面解析与DeepSeek大模型集成开发技术

随着人工智能技术向多学科交叉融合与工程实践领域纵深发展&#xff0c;MATLAB 2024b深度学习工具箱通过架构创新与功能强化&#xff0c;为科研创新和行业应用提供了全栈式解决方案。基于该版本工具链的三大革新方向展开&#xff1a;一是构建覆盖经典模型与前沿架构的体系化&…

Springboot美食分享平台

一、 绪论 1.1 研究意义 当今社会作为一个飞速的发展社会&#xff0c;网络已经完全渗入人们的生活&#xff0c; 网络信息已成为传播的第一大媒介&#xff0c; 可以毫不夸张说网络资源获取已逐步改变了人们以前的生活方式&#xff0c;网络已成为人们日常&#xff0c;休闲主要工…

微信小程序——世界天气小助手

哈喽&#xff0c;大家好&#xff01; 最近小编开发了一个简单的微信小程序——世界天气小助手&#xff0c;希望大家喜欢。 No.1: 为大家介绍下开发者工具下的页面结构。一共有三个界面{主页、搜索页、详情页}No.2&#xff1a; 具体页面展示&#xff1a;当前页面是主页&…

基于单片机的智能家居安防系统设计

摘 要 为了应对目前人们提出的对生活越来越智能的要求&#xff0c;在提高生活品质的同时降低意外事件发生对用户造成的经济损失或其他损失。针对日常生活中经常发生的火灾&#xff0c;失窃&#xff0c;电力资源浪费等生活问题&#xff0c;本设计正是在这种需求背景下展开研究…

腾讯研究院 | AI 浪潮中的中国品牌优势解码:华为、小米、大疆、科大讯飞等品牌从技术破壁到生态领跑的全维突围

当 DeepSeek-R1 模型在 2025 年掀起大众 AI 热潮&#xff0c;当腾讯混元大模型与京东言犀大模型在产业场景中落地生根&#xff0c;中国品牌正在 AI 技术革命的浪潮中完成从追随者到引领者的蜕变。腾讯营销洞察&#xff08;TMI&#xff09;联合京东消费及产业研究院、腾讯研究院…

FreeRTOS学习笔记——空闲任务prvIdleTask

文章目录任务创建任务的内容推荐阅读任务创建 prvIdleTask任务&#xff0c;是由任务调度函数vTaskStartScheduler创建的&#xff0c;任务优先级0&#xff0c;任务堆栈深度由配置选项configMINIMAL_STACK_SIZE定义。 void vTaskStartScheduler(void) {/* 其他代码*//* Add the…

初识卷积神经网络CNN

卷积神经网络CNN 全连接神经网络存在的问题: 输入的形式应该是列向量&#xff0c;但是卷积神经网络中的输入是图像(2D矩阵)&#xff0c;那么就需要对图片进行展平处理&#xff0c;原本图像中蕴含的空间等信息就被打乱了输入的特征多了&#xff0c;那么神经元的参数就会很多&…

高层功能架构详解 - openExo

高层功能架构详解1. 系统整体结构与模块化设计2. 两大核心类&#xff1a;ExoData 与 ExoA. ExoDataB. ExoC. 数据结构的层级关系3. 多微控制器协作与BLE通信4. 主控软件运行流程&#xff08;主循环伪代码&#xff09;5. 架构优点小结6. 与 Code Structure 的关系实用建议1. 系统…