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

SpringMVC源码-AbstractHandlerMethodMapping处理器映射器将@Controller修饰类方法存储到处理器映射器

SpringMVC九大内置组件之HandlerMapping处理器映射器-AbstractHandlerMethodMapping类以及子类RequestMappingHandlerMapping如何将@Controller修饰的注解类以及类下被注解RequestMapping修饰的方法存储到处理器映射器中。

在这里插入图片描述
从RequestMappingHandlerMapping寻找:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
AbstractHandlerMethodMapping类的mappingRegistry什么时候赋值的呢?

AbstractHandlerMethodMapping类以及子类RequestMappingHandlerMapping的类关系图如下,实现了InitializingBean接口,那么该映射器在SpringMVC容器中进行9大组件初始化的时候肯定会调用该afterPropertiesSet方法。

在这里插入图片描述
调用链路如下,在启动项目的时候,先进行Spring父容器的刷新,然后进行SpringMVC子容器的刷新,在子容器中监听器会进行调用9大组件初始化代码(initStrategies)。初始化 HandlerMapping:映射器(initHandlerMappings),配置文件没有配置就获取默认的,实例化属性填充之后进行初始化的设置,调用InitializingBean接口。开始完成@Controller注解进行方法和controller的映射关系,便于在后续进行http接口调用的时候,根据请求路径找到方法名从而获取到对行的controller类去执行方法

InitializingBean接口的afterPropertiesSet方法:200, RequestMappingHandlerMapping (org.springframework.web.servlet.mvc.method.annotation)
invokeInitMethods:2352, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
调用初始化方法,先调用bean的InitializingBean接口方法,后调用bean的自定义初始化方法 initializeBean:2261, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
doCreateBean:736, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBean:630, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBean:361, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createDefaultStrategy:957, DispatcherServlet (org.springframework.web.servlet)
getDefaultStrategies:925, DispatcherServlet (org.springframework.web.servlet)
初始化 HandlerMapping:映射器,用来将对应的request跟controller进行对应initHandlerMappings:657, DispatcherServlet (org.springframework.web.servlet)
initStrategies:529, DispatcherServlet (org.springframework.web.servlet)
onRefresh:514, DispatcherServlet (org.springframework.web.servlet)
onApplicationEvent:901, FrameworkServlet (org.springframework.web.servlet)
onApplicationEvent:1277, FrameworkServlet$ContextRefreshListener (org.springframework.web.servlet)
onApplicationEvent:1273, FrameworkServlet$ContextRefreshListener (org.springframework.web.servlet)
onApplicationEvent:64, GenericApplicationListenerAdapter (org.springframework.context.event)
onApplicationEventInternal:109, SourceFilteringListener (org.springframework.context.event)
onApplicationEvent:73, SourceFilteringListener (org.springframework.context.event)
doInvokeListener:215, SimpleApplicationEventMulticaster (org.springframework.context.event)
invokeListener:202, SimpleApplicationEventMulticaster (org.springframework.context.event)
multicastEvent:164, SimpleApplicationEventMulticaster (org.springframework.context.event)
publishEvent:440, AbstractApplicationContext (org.springframework.context.support)
publishEvent:379, AbstractApplicationContext (org.springframework.context.support)
finishRefresh:1053, AbstractApplicationContext (org.springframework.context.support)
refresh:618, AbstractApplicationContext (org.springframework.context.support)
configureAndRefreshWebApplicationContext:759, FrameworkServlet (org.springframework.web.servlet)
createWebApplicationContext:715, FrameworkServlet (org.springframework.web.servlet)
createWebApplicationContext:773, FrameworkServlet (org.springframework.web.servlet)
initWebApplicationContext:625, FrameworkServlet (org.springframework.web.servlet)
initServletBean:536, FrameworkServlet (org.springframework.web.servlet)
init:185, HttpServletBean (org.springframework.web.servlet)
init:158, GenericServlet (javax.servlet)
initServlet:1164, StandardWrapper (org.apache.catalina.core)
loadServlet:1117, StandardWrapper (org.apache.catalina.core)
load:1010, StandardWrapper (org.apache.catalina.core)
loadOnStartup:4957, StandardContext (org.apache.catalina.core)
startInternal:5264, StandardContext (org.apache.catalina.core)
start:183, LifecycleBase (org.apache.catalina.util)
addChildInternal:726, ContainerBase (org.apache.catalina.core)
addChild:698, ContainerBase (org.apache.catalina.core)
addChild:696, StandardHost (org.apache.catalina.core)
manageApp:1783, HostConfig (org.apache.catalina.startup)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invoke:293, BaseModelMBean (org.apache.tomcat.util.modeler)
invoke:819, DefaultMBeanServerInterceptor (com.sun.jmx.interceptor)
invoke:801, JmxMBeanServer (com.sun.jmx.mbeanserver)
createStandardContext:460, MBeanFactory (org.apache.catalina.mbeans)
createStandardContext:408, MBeanFactory (org.apache.catalina.mbeans)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invoke:293, BaseModelMBean (org.apache.tomcat.util.modeler)
invoke:819, DefaultMBeanServerInterceptor (com.sun.jmx.interceptor)
invoke:801, JmxMBeanServer (com.sun.jmx.mbeanserver)
invoke:468, MBeanServerAccessController (com.sun.jmx.remote.security)
doOperation:1468, RMIConnectionImpl (javax.management.remote.rmi)
access$300:76, RMIConnectionImpl (javax.management.remote.rmi)
run:1309, RMIConnectionImpl$PrivilegedOperation (javax.management.remote.rmi)
doPrivileged:-1, AccessController (java.security)
doPrivilegedOperation:1408, RMIConnectionImpl (javax.management.remote.rmi)
invoke:829, RMIConnectionImpl (javax.management.remote.rmi)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
dispatch:346, UnicastServerRef (sun.rmi.server)
run:200, Transport$1 (sun.rmi.transport)
run:197, Transport$1 (sun.rmi.transport)
doPrivileged:-1, AccessController (java.security)
serviceCall:196, Transport (sun.rmi.transport)
handleMessages:568, TCPTransport (sun.rmi.transport.tcp)
run0:826, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
lambda$run$0:683, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
run:-1, 1316528462 (sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$25)
doPrivileged:-1, AccessController (java.security)
run:682, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
runWorker:1142, ThreadPoolExecutor (java.util.concurrent)
run:617, ThreadPoolExecutor$Worker (java.util.concurrent)
run:748, Thread (java.lang)

去父类AbstractHandlerMethodMapping类中去调用
在这里插入图片描述
在初始化时检测处理程序方法。
在这里插入图片描述
扫描ApplicationContext中的bean,检测和注册处理程序方法
在这里插入图片描述
判断 Bean 是否为处理器(例如有 @Controller 或者 @RequestMapping 注解)
在这里插入图片描述

	@Overrideprotected boolean isHandler(Class<?> beanType) {// 判断是否有 @Controller 或者 @RequestMapping 的注解return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));}

找到controller类上的方法去存储到处理器映射器中:
在这里插入图片描述

	/*** Uses method and type-level @{@link RequestMapping} annotations to create* the RequestMappingInfo.* @return the created RequestMappingInfo, or {@code null} if the method* does not have a {@code @RequestMapping} annotation.* @see #getCustomMethodCondition(Method)* @see #getCustomTypeCondition(Class)*/@Override@Nullableprotected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {// 基于方法上的 @RequestMapping 注解,创建 RequestMappingInfo 对象RequestMappingInfo info = createRequestMappingInfo(method);if (info != null) {// 基于类上的 @RequestMapping 注解,合并进去RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);if (typeInfo != null) {info = typeInfo.combine(info);}// 如果有前缀,则设置到 info 中String prefix = getPathPrefix(handlerType);if (prefix != null) {info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);}}return info;}
	/*** Delegates to {@link #createRequestMappingInfo(RequestMapping, RequestCondition)},* supplying the appropriate custom {@link RequestCondition} depending on whether* the supplied {@code annotatedElement} is a class or method.* @see #getCustomTypeCondition(Class)* @see #getCustomMethodCondition(Method)*/@Nullableprivate RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {// 获得 @RequestMapping 注解RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);// 获得自定义的条件。目前都是空方法,可以无视RequestCondition<?> condition = (element instanceof Class ?getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));// 基于 @RequestMapping 注解,创建 RequestMappingInfo 对象return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);}

getMappingForMethod方法中调用createRequestMappingInfo方法,完成从类中筛选有RequestMapping注解修饰的方法存储到处理器映射器中

RequestMappingHandlerMapping的registerHandlerMethod

protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {super.registerHandlerMethod(handler, method, mapping);updateConsumesCondition(mapping, method);}

AbstractHandlerMethodMapping的registerHandlerMethod

protected void registerHandlerMethod(Object handler, Method method, T mapping) {this.mappingRegistry.register(mapping, handler, method);}

AbstractHandlerMethodMapping的register

		/*** 释放读锁** Release the read lock after using getMappings and getMappingsByUrl.*/public void releaseReadLock() {this.readWriteLock.readLock().unlock();}public void register(T mapping, Object handler, Method method) {// Assert that the handler method is not a suspending one.if (KotlinDetector.isKotlinType(method.getDeclaringClass())) {Class<?>[] parameterTypes = method.getParameterTypes();if ((parameterTypes.length > 0) && "kotlin.coroutines.Continuation".equals(parameterTypes[parameterTypes.length - 1].getName())) {throw new IllegalStateException("Unsupported suspending handler method detected: " + method);}}// 获得写锁this.readWriteLock.writeLock().lock();try {// 创建HandlerMethod对象HandlerMethod handlerMethod = createHandlerMethod(handler, method);// 校验当前mapping是否存在对应的HandlerMethod对象,如果已存在但不是当前的handlerMethod对象则抛出异常validateMethodMapping(handlerMethod, mapping);// 将mapping与handlerMethod的映射关系保存至this.mappingLookupthis.mappingLookup.put(mapping, handlerMethod);// 获得mapping对应的普通URL数组List<String> directUrls = getDirectUrls(mapping);// 将url和mapping的映射关系保存至this.urlLookupfor (String url : directUrls) {this.urlLookup.add(url, mapping);}// 初始化nameLookupString name = null;if (getNamingStrategy() != null) {// 获得Mapping的名字name = getNamingStrategy().getName(handlerMethod, mapping);// 将mapping的名字与HandlerMethod的映射关系保存至this.nameLookupaddMappingName(name, handlerMethod);}// 初始化CorsConfiguration配置对象CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);if (corsConfig != null) {this.corsLookup.put(handlerMethod, corsConfig);}// 创建MappingRegistration对象// 并与mapping映射添加到registry注册表中this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));}finally {// 释放写锁this.readWriteLock.writeLock().unlock();}}

在这里插入图片描述
submit方法对应的FlashMapController存在映射器了,其他@Controller修饰的注解处理过程一样。
在这里插入图片描述

相关文章:

SpringMVC源码-AbstractHandlerMethodMapping处理器映射器将@Controller修饰类方法存储到处理器映射器

SpringMVC九大内置组件之HandlerMapping处理器映射器-AbstractHandlerMethodMapping类以及子类RequestMappingHandlerMapping如何将Controller修饰的注解类以及类下被注解RequestMapping修饰的方法存储到处理器映射器中。 从RequestMappingHandlerMapping寻找: AbstractHandle…...

毕业设计选题:基于ssm+vue+uniapp的购物系统小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…...

【动态规划-最长公共子序列(LCS)】力扣583. 两个字符串的删除操作

给定两个单词 word1 和 word2 &#xff0c;返回使得 word1 和 word2 相同所需的最小步数。 每步 可以删除任意一个字符串中的一个字符。 示例 1&#xff1a; 输入: word1 “sea”, word2 “eat” 输出: 2 解释: 第一步将 “sea” 变为 “ea” &#xff0c;第二步将 "e…...

【分布式微服务云原生】8分钟探索RPC:远程过程调用的奥秘与技术实现

摘要 在分布式系统中&#xff0c;RPC&#xff08;Remote Procedure Call&#xff0c;远程过程调用&#xff09;技术是连接各个组件的桥梁。本文将深入探讨RPC的概念、技术实现原理、以及请求处理的详细过程。通过清晰的结构、流程图、代码片段和图表&#xff0c;我们将一起揭开…...

Linux操作系统中Redis

1、什么是Redis Redis&#xff08;Remote Dictionary Server &#xff09;&#xff0c;即远程字典服务&#xff0c;是一个开源的使用ANSIC语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库&#xff0c;并提供多种语言的API。 可以理解成一个大容量的map。…...

每日论文5—06TCAS2锁相环电流匹配的gain-boosting电荷泵

《Gain-Boosting Charge Pump for Current Matching in Phase-Locked Loop》 06TCAS2 本质上和cascode来增加输出电阻&#xff0c;从而减小电流变化的思路是一样的。这里用了放大器来增加输出电阻。具体做法如下图&#xff1a; 如图1(a)&#xff0c;A3把Vb和Vx拉平&#xff0…...

接口隔离原则(学习笔记)

客户端不应该被迫依赖于它不使用的方法&#xff1a;一个类对另一个类的依赖应该建立在最小的接口上。 上面的设计我们发现他存在的问题&#xff0c;黑马品牌的安全门具有防盗&#xff0c;防水&#xff0c;防火的功能。现在如果我们还需要再创建一盒传智品牌的安全门&#xff0c…...

基于ESP8266—AT指令连接阿里云+MQTT透传数据(1)

在阿里云创建MQTT产品的过程涉及几个关键步骤,主要包括注册阿里云账号、实名认证、开通MQTT服务实例、创建产品与设备等。以下是详细的步骤说明: 一、准备工作 访问阿里云官网,点击注册按钮,填写相关信息(如账号、密码、手机号等)完成注册。注册完成后,需要对账号进行实…...

强化学习-python案例

强化学习是一种机器学习方法&#xff0c;旨在通过与环境的交互来学习最优策略。它的核心概念是智能体&#xff08;agent&#xff09;在环境中采取动作&#xff0c;从而获得奖励或惩罚。智能体的目标是最大化长期奖励&#xff0c;通过试错的方式不断改进其决策策略。 在强化学习…...

Element UI教程:如何将Radio单选框的圆框改为方框

大家好&#xff0c;今天给大家带来一篇关于Element UI的使用技巧。在项目中&#xff0c;我们经常会用到Radio单选框组件&#xff0c;默认情况下&#xff0c;Radio单选框的样式是圆框。但有时候&#xff0c;为了满足设计需求&#xff0c;我们需要将圆框改为方框&#xff0c;如下…...

vue3结合 vue-router和keepalive实现路由跳转保持滚动位置不改变(超级简易清晰)

1.首先我们在路由跳转页面设置keepalive(Seeall是我想实现结果的页面) 2. 想实现结果的页面中如果不是全屏实现滚动而是有单独的标签实现滚动效果...

PostgreSQL 字段使用pglz压缩测试

PostgreSQL 字段使用pglz压缩测试 测试一&#xff1a; 创建测试表 yewu1.test1&#xff0c;并插入1000w行数据 创建测试表 yewu1.test2&#xff0c;使用 pglz压缩字段&#xff0c;并插入1000w行数据–创建测试表1&#xff0c;并插入1000w行数据 white# create table yewu1.t…...

基于大数据的学生体质健康信息系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…...

【STM32】 TCP/IP通信协议(1)--LwIP介绍

一、前言 TCP/IP是干啥的&#xff1f;它跟SPI、IIC、CAN有什么区别&#xff1f;它如何实现stm32的通讯&#xff1f;如何去配置&#xff1f;为了搞懂这些问题&#xff0c;查询资料可解决如下疑问&#xff1a; 1.为什么要用以太网通信? 以太网(Ethernet) 是指遵守 IEEE 802.3 …...

828华为云征文|部署音乐流媒体服务器 mStream

828华为云征文&#xff5c;部署音乐流媒体服务器 mStream 一、Flexus云服务器X实例介绍二、Flexus云服务器X实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置2.4 Docker 环境搭建 三、Flexus云服务器X实例部署 mStream3.1 mStream 介绍3.2 mStream 部署3.3 mStream 使用 四、…...

【动态规划-最长公共子序列(LCS)】力扣712. 两个字符串的最小ASCII删除和

给定两个字符串s1 和 s2&#xff0c;返回 使两个字符串相等所需删除字符的 ASCII 值的最小和 。 示例 1: 输入: s1 “sea”, s2 “eat” 输出: 231 解释: 在 “sea” 中删除 “s” 并将 “s” 的值(115)加入总和。 在 “eat” 中删除 “t” 并将 116 加入总和。 结束时&…...

override

override 是 C11 引入的一个关键字&#xff0c;override 的作用是在派生类中显式地声明某个函数是用于重写基类的虚函数。它不仅仅是一个语法标记&#xff0c;更重要的是提供了编译时的错误检查功能&#xff0c;确保程序员确实按照预期在派生类中重写了基类的函数。如果没有正确…...

万象奥科工业平板上线,邀您体验与众不同!

Vanxoak推出的全新品类——ARM工业平板电脑&#xff01;该系列工业平板具有防护等级高、接口丰富、易开发等特点&#xff0c;专为工业HMI&#xff08;人机界面&#xff09;和工业控制领域设计。整机采用高性能工业级ARM处理器&#xff0c;适配全贴合电容触摸屏&#xff0c;可选…...

java将word转pdf

总结 建议使用aspose-words转pdf,poi的容易出问题还丑… poi的(多行的下边框就不对了) aspose-words的(基本和word一样) poi工具转换 <!-- 处理PDF --><dependency><groupId>fr.opensagres.xdocreport</groupId><artifactId>fr.opensagres…...

Golang | Leetcode Golang题解之第449题序列化和反序列化二叉搜索树

题目&#xff1a; 题解&#xff1a; type Codec struct{}func Constructor() (_ Codec) { return }func (Codec) serialize(root *TreeNode) string {arr : []string{}var postOrder func(*TreeNode)postOrder func(node *TreeNode) {if node nil {return}postOrder(node.Le…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

Linux-07 ubuntu 的 chrome 启动不了

文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了&#xff0c;报错如下四、启动不了&#xff0c;解决如下 总结 问题原因 在应用中可以看到chrome&#xff0c;但是打不开(说明&#xff1a;原来的ubuntu系统出问题了&#xff0c;这个是备用的硬盘&a…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

9-Oracle 23 ai Vector Search 特性 知识准备

很多小伙伴是不是参加了 免费认证课程&#xff08;限时至2025/5/15&#xff09; Oracle AI Vector Search 1Z0-184-25考试&#xff0c;都顺利拿到certified了没。 各行各业的AI 大模型的到来&#xff0c;传统的数据库中的SQL还能不能打&#xff0c;结构化和非结构的话数据如何和…...

ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]

报错信息&#xff1a;libc.so.6: cannot open shared object file: No such file or directory&#xff1a; #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...

沙箱虚拟化技术虚拟机容器之间的关系详解

问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西&#xff0c;但是如果把三者放在一起&#xff0c;它们之间到底什么关系&#xff1f;又有什么联系呢&#xff1f;我不是很明白&#xff01;&#xff01;&#xff01; 就比如说&#xff1a; 沙箱&#…...

第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)

第一篇&#xff1a;Liunx环境下搭建PaddlePaddle 3.0基础环境&#xff08;Liunx Centos8.5安装Python3.10pip3.10&#xff09; 一&#xff1a;前言二&#xff1a;安装编译依赖二&#xff1a;安装Python3.10三&#xff1a;安装PIP3.10四&#xff1a;安装Paddlepaddle基础框架4.1…...

uni-app学习笔记三十五--扩展组件的安装和使用

由于内置组件不能满足日常开发需要&#xff0c;uniapp官方也提供了众多的扩展组件供我们使用。由于不是内置组件&#xff0c;需要安装才能使用。 一、安装扩展插件 安装方法&#xff1a; 1.访问uniapp官方文档组件部分&#xff1a;组件使用的入门教程 | uni-app官网 点击左侧…...