【期末复习】JavaEE(下)

1. MVC开发模式

1.1. 运行流程

1.2. SpringMVC 核心组件

1.3. 注解解释

2. ORM与MyBatis

2.1. ORM—对象关系映射

2.2. MyBatis

2.2.1. 创建步骤

会话是单例的,不能跨方法。(单例的原因主要是从数据安全角度出发)

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;
import java.io.Reader;
import java.util.List;public class MyBatisExample {public static void main(String[] args) {SqlSessionFactory sqlSessionFactory = null;try (Reader reader = Resources.getResourceAsReader("mybatis-config.xml")) {sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);} catch (IOException e) {e.printStackTrace();}try (SqlSession session = sqlSessionFactory.openSession()) {// 获取 Mapper 接口的代理对象UserMapper userMapper = session.getMapper(UserMapper.class);// 使用 Mapper 接口的方法执行 SQL 操作1User user = userMapper.selectUserById(1);System.out.println(user);User newUser = new User();newUser.setName("John");newUser.setAge(30);// 使用 Mapper 接口的方法执行 SQL 操作2userMapper.insertUser(newUser);session.commit(); // 提交事务// 使用 Mapper 接口的方法执行 SQL 操作3List<User> users = userMapper.selectAllUsers();for (User u : users) {System.out.println(u);}} catch (Exception e) {e.printStackTrace();}}
}

2.2.2. mybatis-config.xml 配置

UserDao 是接口,在 namespace 必须是完整的路径。

2.2.3. sql 注入

2.2.4. 动态 SQL

if 和 where 是最重要的。

2.2.4.1. if

2.2.4.2. where

where 可以自动选择去掉多余的 and

2.2.4.3. set

set 可以自动去掉多余的 ,

2.2.4.4. foreach 语句

collection 是集合的变量名

2.2.4.5. trim 标签

2.2.4.6. choose、when、otherwise

2.2.5. Mybatis 的结果类型(使用 resultMap 和 resultType)

2.2.5.1. resultMap 的详细使用

在 MyBatis 中,resultMap 是一个非常重要的标签,它主要用于复杂的结果映射,特别是当数据库表的列名和 Java 对象的属性名不一致,或者需要映射关联关系(如一对一、一对多等)时。以下是 resultMap 的详细使用方法:

一、基本使用步骤

  1. 定义 resultMap
    在 Mapper XML 文件中,首先定义一个 resultMap,指定 id(用于在 SQL 语句中引用该结果映射)和 type(映射结果的 Java 类型)。
<resultMap id="userResultMap" type="com.example.User"><id property="id" column="user_id"/><result property="userName" column="user_name"/><result property="age" column="user_age"/>
</resultMap>

在上述 resultMap 中:

  • id="userResultMap":是结果映射的唯一标识符,后续会在 select 语句中使用。
  • type="com.example.User":表示映射的 Java 类型是 com.example.User 类。
  • <id> 标签:用于映射主键,property 是 Java 对象的属性名,column 是数据库表的列名。
  • <result> 标签:用于映射非主键的普通列,property 是 Java 对象的属性名,column 是数据库表的列名。

  1. select 语句中使用 resultMap
    resultMap 应用于 select 语句中,而不是 resultType
<select id="selectUserById" resultMap="userResultMap">select user_id, user_name, user_age from users where user_id = #{id}
</select>

二、处理复杂对象映射

当处理对象之间的关联关系时,resultMap 变得更加重要。

2.2.5.1.1. 一对一关联映射

假设 User 类中有一个 Address 对象作为属性,并且 Address 存储在另一个表中,需要进行一对一关联映射。

  1. 首先,在 User 类中添加 Address 属性:
public class User {private int id;private String userName;private int age;private Address address;// getters and setters
}
  1. 然后,在 Mapper XML 文件中定义 resultMap 包含 association 元素:
<resultMap id="userWithAddressResultMap" type="com.example.User"><id property="id" column="user_id"/><result property="userName" column="user_name"/><result property="age" column="user_age"/><association property="address" javaType="com.example.Address"><id property="id" column="address_id"/><result property="street" column="address_street"/><result property="city" column="address_city"/><result property="zipcode" column="address_zipcode"/></association></resultMap>
  1. select 语句中使用该 resultMap
<select id="selectUserWithAddressById" resultMap="userWithAddressResultMap">select u.user_id, u.user_name, u.user_age, a.address_id, a.address_street, a.address_city, a.address_zipcodefrom users ujoin addresses a on u.user_id = a.user_idwhere u.user_id = #{id}
</select>

2.2.5.1.2. 一对多关联映射

假设 User 类中有一个 List<Order> 表示用户的多个订单,需要进行一对多关联映射。

  1. User 类中添加 List<Order> 属性:
public class User {private int id;private String userName;private int age;private List<Order> orders;// getters and setters
}
  1. 在 Mapper XML 文件中定义 resultMap 包含 collection 元素:
<resultMap id="userWithOrdersResultMap" type="com.example.User"><id property="id" column="user_id"/><result property="userName" column="user_name"/><result property="age" column="user_age"/><collection property="orders" ofType="com.example.Order"><id property="id" column="order_id"/><result property="orderName" column="order_name"/><result property="amount" column="order_amount"/></collection></resultMap>
  1. select 语句中使用该 resultMap
<select id="selectUserWithOrdersById" resultMap="userWithOrdersResultMap">select u.user_id, u.user_name, u.user_age, o.order_id, o.order_name, o.order_amountfrom users ujoin orders o on u.user_id = o.user_idwhere u.user_id = #{id}
</select>

三、继承和扩展 resultMap

可以使用 extends 属性扩展已有的 resultMap,以避免重复定义。

<resultMap id="extendedUserResultMap" type="com.example.User" extends="userResultMap"><result property="email" column="user_email"/>
</resultMap>

四、使用 resultMap 的好处

  • 灵活映射:可以处理各种复杂的映射情况,包括列名和属性名不匹配、关联对象映射等。
  • 代码清晰:将结果映射的逻辑集中在 XML 文件中,使得 SQL 语句和结果映射逻辑清晰,易于维护。

五、注意事项

  • 列名和属性名:确保 resultMap 中的 column 与 SQL 语句中的列名一致,property 与 Java 对象的属性名一致。
  • 关联关系:使用 association 处理一对一关系,使用 collection 处理一对多关系,确保关联的对象和集合类型正确。

使用 resultMap 可以让 MyBatis 更好地处理复杂的结果映射,使数据库结果能够准确地映射到 Java 对象及其关联对象或集合,提供了强大而灵活的结果映射机制,特别是在处理对象之间的复杂关系时,它是 MyBatis 实现对象关系映射的关键元素。

2.2.5.2. typeAliases

2.2.6. 查询的 resultType

2.2.7. sql 抽取

3. Spring MVC

SpringMVC 中有默认的编码拦截器,所以不用管乱码的问题。

3.1. Spring MVC工作原理

3.2. 控制器编写

3.3. 拦截器

3.3.1. 拦截器配置

3.3.1.1. 编写拦截器

3.3.1.2. 配置拦截器
3.3.1.2.1. 基于代码

3.3.1.2.2. 基于 xml

3.3.2. 单个拦截器

3.3.3. 多个拦截器

4. Spring

4.1. Spring 体系结构

4.2. 核心容器

4.3. web

4.4. 数据访问

4.5. 其他模块

4.6. Spring 特征

4.7. IOC

4.8. DI

4.9. Bean配置(重点)

使用ApplicationContext 对象获取 bean:

bean 的配置文件:

4.9.1. xml 的四种方式配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--    1.使用property标签--><bean id="book" class="com.bean.Book"><!--        如果类中有显示构造函数,则必须加上这两行--><constructor-arg index="0" value=""/><constructor-arg index="1" value=""/><property name="name" value="书名0"></property><property name="price" value="2022.12"></property></bean><!--    2.使用 构造器+index 标签--><bean id="book" class="com.bean.Book"><constructor-arg index="0" value="书名1"/><constructor-arg index="1" value="2024.12"/></bean><!--    3.使用 构造器+name 标签--><bean id="book" class="com.bean.Book"><constructor-arg name="name" value="书名2"></constructor-arg><constructor-arg name="price" value="2023.12"></constructor-arg></bean><!--    4.使用 p标签--><bean id="book" class="com.bean.Book" p:name="书名3" p:price="2025.12"><!--        如果类中有显示构造函数,则必须加上这两行--><constructor-arg index="0" value=""/><constructor-arg index="1" value=""/></bean>
</beans>

4.9.2. 注解配置(重点)

4.9.3. ApplicationContext 的构造方式

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("D:\\code\\4Spring\\ssm_st" +

ClassPathXmlApplicationContext:使用文件名

FileSystemXmlApplicationContext:使用绝对路径

4.9.4. Bean的作用域

4.9.4.1. 多例模式
<bean id="book" class="com.bean.Book" p:name="书名3" p:price="2025.12" scope="prototype"><!--        如果类中有显示构造函数,则必须加上这两行--><constructor-arg index="0" value=""/><constructor-arg index="1" value=""/></bean>
4.9.4.2. 单例模式
<bean id="book" class="com.bean.Book" p:name="书名3" p:price="2025.12" scope="singleton"><!--        如果类中有显示构造函数,则必须加上这两行--><constructor-arg index="0" value=""/><constructor-arg index="1" value=""/></bean>

4.9.5. bean 的 xml 装配

4.9.5.1. 手动-ref 标签

<!--    bean的装配--><!--    1.手动装配--><bean id="cat" class="com.bean.Cat"></bean><bean id="dog" class="com.bean.Dog"></bean><bean id="animal" class="com.bean.Animal"><property name="cat" ref="cat"/><property name="dog" ref="dog"/></bean>
4.9.5.2. 自动-autowire
  1. 通过名字
    <!--    2.自动装配--><bean id="cat" class="com.bean.Cat"></bean><bean id="dog" class="com.bean.Dog"></bean><bean id="animal" class="com.bean.Animal" autowire="byName"></bean>
  1. 通过类型
    <!--    2.自动装配--><bean id="cat" class="com.bean.Cat"></bean><bean id="dog" class="com.bean.Dog"></bean><bean id="animal" class="com.bean.Animal" autowire="byType"></bean>
4.9.5.2.1. autowire 属性取值

4.9.5.3. 总结
  1. 手动需要使用 ref 标签进行引用
  2. 自动需要通过 名字 或者 类型 ,间接使用 setter 方法进行装配

4.10. bean 的注解装配

4.10.1. Autowired

  1. 匹配流程:
    1. 根据类型
    2. 类型相同,根据名称
  1. 不用 setter 方法

4.10.2. Qualifier

  1. 按照名字查
  2. 不能单独使用

4.10.3. Resource

  1. 匹配流程:
    1. 根据名称
    2. 名称相同,根据类型

4.10.4. 注解包扫描装配

4.11. AOP

4.11.1. 相关概念

4.11.2. 基于 xml

        <!--    注册bean--><bean id="userService" class="com.bean.service.UserService"></bean><!--    注册切面bean--><bean id="myPoint" class="com.pointCut.MyPointCut"></bean><!--    配置切面--><aop:config><aop:aspect ref="myPoint"><!--        配置切点--><aop:pointcut id="point" expression="execution(String com.bean.service.UserService.show())"/><!--        配置通知--><aop:before method="before" pointcut-ref="point"></aop:before><aop:after method="after" pointcut-ref="point"></aop:after></aop:aspect></aop:config>

切点和通知不需要注册 bean。

4.11.3. 基于注解

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;import java.util.Arrays;// 配置类,启用 AOP 支持
@Configuration
@EnableAspectJAutoProxy
@SpringBootApplication
public class AopExampleApplication {public static void main(String[] args) {SpringApplication.run(AopExampleApplication.class, args);}// 定义一个简单的业务服务@Servicepublic static class UserService {public String getUserById(int id) {System.out.println("Executing getUserById with id: " + id);return "User " + id;}public void updateUser(int id, String name) {System.out.println("Updating user with id: " + id + " and name: " + name);}}// 定义自定义注解@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Loggable {}// 切面类,包含各种通知@Aspect@Componentpublic static class LoggingAspect {// 定义切点,拦截 UserService 类的所有方法@Pointcut("execution(* com.example.AopExampleApplication.UserService.*(..))")public void userServicePointcut() {}// 前置通知@Before("userServicePointcut()")public void beforeAdvice(JoinPoint joinPoint) {System.out.println("Before method execution: " + joinPoint.getSignature().getName());System.out.println("Arguments: " + Arrays.toString(joinPoint.getArgs()));}// 后置通知@After("userServicePointcut()")public void afterAdvice(JoinPoint joinPoint) {System.out.println("After method execution: " + joinPoint.getSignature().getName());}// 环绕通知@Around("userServicePointcut()")public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("Before around advice: " + joinPoint.getSignature().getName());Object result = joinPoint.proceed();System.out.println("After around advice: " + joinPoint.getSignature().getName());return result;}// 返回通知,获取方法返回值@AfterReturning(pointcut = "userServicePointcut()", returning = "result")public void afterReturningAdvice(JoinPoint joinPoint, Object result) {System.out.println("Method returned: " + result);}// 异常通知,处理方法抛出的异常@AfterThrowing(pointcut = "userServicePointcut()", throwing = "e")public void afterThrowingAdvice(JoinPoint joinPoint, Exception e) {System.out.println("Method threw exception: " + e.getMessage());}// 自定义注解作为切点@Pointcut("@annotation(Loggable)")public void loggablePointcut() {}@Before("loggablePointcut()")public void loggableBeforeAdvice(JoinPoint joinPoint) {System.out.println("Before annotated method execution: " + joinPoint.getSignature().getName());}}
}

还需要在 xml 开启配置:

  <!--    基于注解配置切面的xml--><context:component-scan base-package="com.*"></context:component-scan><aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

4.11.4. 环绕通知

@Around("execution(String com.bean.service.UserService.show())")public void around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("====around->执行方法之前的处理====");Object res = pjp.proceed();System.out.println("====around->执行方法之后的处理====");System.out.println("方法执行的返回结果:"+res);}

4.11.5. 返回结果后的通知

@AfterReturning("execution(String com.bean.service.UserService.show())")public void afterReturning() {System.out.println("====afterReturning->执行方法之后的处理====");}

4.11.6. 抛异常后的通知

@AfterThrowing("execution(String com.bean.service.UserService.show())")public void afterThrowing() {System.out.println("====afterThrowing->执行异常之后的处理====");}

4.11.7. 切点表达式

4.12. 事务管理

4.12.1. 编程式事务

4.12.2. 声明式事务

4.12.3. 例子

4.12.4. 注解实现

4.12.5. 传播方式

4.12.6. 隔离级别

5. SSM整合

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

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

相关文章

作业帮基于 Apache DolphinScheduler 3_0_0 的缺陷修复与优化

文|作业帮大数据团队&#xff08;阮文俊、孙建业&#xff09; 背 景 基于 Apache DolphinScheduler &#xff08;以下简称DolphinScheduler&#xff09;搭建的 UDA 任务调度平台有效支撑了公司的业务数据开发需求&#xff0c;处理着日均百万级别的任务量。 整个 UDA 的架构如…

电脑缺失sxs.dll文件要怎么解决?

一、文件丢失问题&#xff1a;以sxs.dll文件缺失为例 当你在运行某个程序时&#xff0c;如果系统提示“找不到sxs.dll文件”&#xff0c;这意味着你的系统中缺少了一个名为sxs.dll的动态链接库文件。sxs.dll文件通常与Microsoft的.NET Framework相关&#xff0c;是许多应用程序…

Web开发:ORM框架之使用Freesql的分表分页写法

一、自动分表&#xff08;高版本可用&#xff09; 特性写法 //假如是按月分表&#xff1a;[Table(Name "log_{yyyyMM}", AsTable "createtime2022-1-1(1 month)")]注意&#xff1a;①需包含log_202201这张表 ②递增规律是一个月一次&#xff0c;确保他们…

【数据结构与算法】单向链表

一、什么是链表 链表由一系列节点组成&#xff0c;每个节点都包含一个 data 域&#xff08;存放数据&#xff09;和一个 next 域&#xff08;指向下一节点&#xff09;。链表中的节点可以按照任意顺序存放在内存中&#xff0c;它们之间并不连续。每个节点都记录了下一个节点的地…

【ACCSS】2024年亚信安全云认证专家题库

文件包含&#xff1a; 亚信安全ACCSS认证2019年真题&#xff08;1&#xff09; 亚信安全ACCSS认证2019年真题&#xff08;2&#xff09; 亚信安全ACCSS认证2019年真题&#xff08;3&#xff09; 亚信安全ACCSS认证2020年真题&#xff08;1&#xff09; 亚信安全ACCSS认证2020年…

OpenCV-Python实战(10)——形态学

1、腐蚀 cv2.erode() 可以删除图像中的噪音点。 可以删除毛边。 分割图像&#xff08;当图像连接的不够紧密时&#xff09; 。 img cv2.erode(src*,kernel*,anchor*,iterations*,borderType*,borderValue*)img&#xff1a;目标图像。 src&#xff1a;原始图像。 kernel&…

用VBA将word文档处理成支持弹出式注释的epub文档可用的html内容

有一种epub文件&#xff0c;其中的注释以弹窗形式显示&#xff0c;如下图&#xff1a; 点击注释引用后&#xff0c;对应的注释内容会弹出在页面中显示&#xff0c;再次点击弹窗外的任意位置该弹窗即关闭&#xff0c;关闭后点击任意注释引用&#xff0c;对应的注释内容会弹窗显示…

Ngnix介绍、安装、实战及用法!!!

一、Nginx简介 1、Nginx概述 Nginx (“engine x”) 是一个高性能的 HTTP 和 反向代理服务器&#xff0c;特点是占有内存少&#xff0c;并发能力强&#xff0c;能经受高负载的考验,有报告表明能支持高达 50,000 个并发连接数 。 2、正向代理 正向代理&#xff1a;如果把局…

【超详细】Git的基本概念和基本使用方式

Git是程序开发中非常重要的工具&#xff0c;是一种分布式版本控制系统&#xff0c;可用于管理和追踪软件开发过程中的变化。那么关于Git的基本操作你知道吗&#xff1f;下面是Git的基本概念和使用方式的解释&#xff1a; 仓库&#xff08;Repository&#xff09;&#xff1a;Gi…

springboot503基于Sringboot+Vue个人驾校预约管理系统(论文+源码)_kaic

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装个人驾校预约管理系统软件来发挥其高效地信息处理的作用&am…

【Rust自学】7.4. use关键字 Pt.2 :重导入与换国内镜像源教程

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 7.4.1. 使用pub use重新导入名称 使用use将路径导入作用域内后。该名称在词作用域内是私有的。 以上一篇文章的代码为例&#xff1a; m…

Pandas03

Pandas01 Pandas02 文章目录 内容回顾1 排序和统计函数2 缺失值处理2.1 认识缺失值2.2 缺失值处理- 删除2.3 缺失值处理- 填充非时序数据时序数据 3 Pandas数据类型3.1 数值类型和字符串类型之间的转换3.2 日期时间类型3.3 日期时间索引 4 分组聚合4.1 分组聚合的API使用4.2 分…

平凉一窝丝:丝丝缕缕的舌尖风情

在平凉的美食版图中&#xff0c;食家巷一窝丝以其独特的工艺和诱人的口感&#xff0c;占据着重要的一席之地&#xff0c;成为了平凉人心目中的经典美食之一。从外观上看&#xff0c;平凉食家巷一窝丝如同一盘精心雕琢的金丝&#xff0c;根根细丝紧密盘绕&#xff0c;整齐而美观…

Wordly Wise 3000 国际背单词01 介绍 + 测词汇量

&#x1f4da; Wordly Wise 3000 国际背单词01 介绍 测词汇量 &#x1f31f; 大家好&#xff01;我们正式启动背Wordly Wise 3000单词&#xff0c;旨在利用国际资源和科学的学练方法&#xff0c;帮助大家更得效地坚持学练单词。我们将通过图文和Video等多种形式与大家分享经验…

C++进阶重点知识(一)|智能指针|右值|lambda|STL|正则表达式

目录 1智能指针1.shared_ptr1.1 shared_ptr的基本用法使用shared_ptr要注意的问题运用 2.unique_ptr独占的智能指针示例&#xff1a;管理动态内存 3.weak_ptr弱引用的智能指针weak_ptr的基本用法lock 的作用&#xff1a;weak_ptr返回this指针weak_ptr解决循环引用问题weak_ptr使…

计算机网络 (9)数据链路层

前言 计算机网络中的数据链路层&#xff08;Data Link Layer&#xff09;是OSI&#xff08;开放系统互连&#xff09;参考模型中的第二层&#xff0c;位于物理层和网络层之间。它在物理层提供的服务基础上&#xff0c;负责在相邻节点之间建立、维护和终止链路&#xff0c;确保数…

【Elasticsearch】DSL查询文档

目录 1.DSL查询文档 1.1.DSL查询分类 1.2.全文检索查询 1.2.1.使用场景 1.2.2.基本语法 1.2.3.示例 1.2.4.总结 1.3.精准查询 1.3.1.term查询 1.3.2.range查询 1.3.3.总结 1.4.地理坐标查询 1.4.1.矩形范围查询 1.4.2.附近查询 1.5.复合查询 1.5.1.相关性算分 …

国内独立开发者案例及免费送独立开发蓝图书

独立开发者在国内越来越受到关注&#xff0c;他们追求的是一种自由且自给自足的工作状态。 送这个&#xff1a; 少楠light&#xff08;Flomo、小报童、如果相机&#xff09;&#xff1a;他们是独立开发者的典范&#xff0c;不仅开发了多款产品&#xff0c;还坚信“剩者为王”…

Browser Use:AI智能体自动化操作浏览器的开源工具

Browser Use:AI智能体自动化操作浏览器的开源工具 Browser Use 简介1. 安装所需依赖2. 生成openai密钥3. 编写代码4. 运行代码5. 部署与优化5.1 部署AI代理5.2 优化与扩展总结Browser Use 简介 browser-use是一个Python库,它能够帮助我们将AI代理与浏览器自动化操作结合起来;…

园区网综合拓扑实验

一、实验要求 实验拓扑图如上图所示 1、按照图示的VLAN及IP地址需求&#xff0c;完成相关配置 2、要求SW1为VLAN 2/3的主根及主网关 SW2为vlan 20/30的主根及主网关 SW1和SW2互为备份 3、可以使用super vlan&#xff08;本实验未使用&#xff09; 4、上层…