SpringCloud - Nacos注册/配置中心
前言
该博客为Nacos学习笔记,主要目的是为了帮助后期快速复习使用
 学习视频:7小快速通关SpringCloud
 辅助文档:SpringCloud快速通关
一、简介
Nacos官网:https://nacos.io/docs/next/quickstart/quick-start/
 Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
 
二、安装
2.1 Windows本地安装:
- 点击下载
 - 找到对应版本的二进制下载
 - 将压缩包解压到非中文无空格的目录
 - 找到并进入
bin目录,在地址栏输入cmd,打开黑窗口 - 输入
startup.cmd -m standalone启动,看到logo即启动成功【注意:黑窗口不能关闭】 - 在浏览器输入
http://localhost:8848/nacos/



 
2.2 Docker安装【推荐】
docker run -d -p 8848:8848 -p 9848:9848 -e MODE=standalone --name nacos nacos/nacos-server:v2.4.3
 
三、注册中心
3.1 整合配置
3.1.1 依赖引入
<!-- web场景 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><!-- 服务发现Nacos -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency> 
3.1.2 编写yml配置文件
# 服务端口
server:port: 8000spring:application:name: service-order # 服务名称cloud:nacos:server-addr: 127.0.0.1:8848 # nacos地址(默认)
 
3.1.3 编写主程序
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class OrderMainApplication {public static void main(String[] args) {SpringApplication.run(OrderMainApplication.class, args);}
}
 
3.1.4 运行主程序,查看注册中心效果
运行成功,可以在服务列表中查看到
 
3.2 单机模拟集群启动
- 点击
服务 - 找到
OrderMainApplication,右键,点击复制配置


 - 点击
修改选项,将程序参数勾选上

 - 重新指定运行端口 
--+ 配置,修改完成点击确定 
--server.port=8001
 

- 右键
运行,查看Nacos服务列表


 
3.3 服务发现
3.3.1 开启服务发现功能
在主程序上加上@EnableDiscoveryClient , 启用服务注册发现功能
3.3.2编写测试用例
3.3.2.1 依赖引入
<!-- 测试场景 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>
 
3.3.2.2 使用DiscoveryClient测试服务发现API
@SpringBootTest
public class DiscoveryTest {@Autowiredprivate DiscoveryClient discoveryClient; // 服务发现客户端@Testvoid discoveryClientTest() {for (String service : discoveryClient.getServices()) {System.out.println("service = " + service);// 获取服务实例 ip + portList<ServiceInstance> instances = discoveryClient.getInstances(service);for (ServiceInstance instance : instances) {System.out.println("ip:"+instance.getHost()+";"+"port = " + instance.getPort());}}}
}
 

3.3.2.3 使用NacosServiceDiscovery测试服务发现API
@SpringBootTest
public class DiscoveryTest {@Autowiredprivate NacosServiceDiscovery nacosServiceDiscovery; // nacos服务发现客户端@Testvoid  nacosServiceDiscoveryTest() throws NacosException {for (String service : nacosServiceDiscovery.getServices()) {System.out.println("service = " + service);List<ServiceInstance> instances = nacosServiceDiscovery.getInstances(service);for (ServiceInstance instance : instances) {System.out.println("ip:"+instance.getHost()+";"+"port = " + instance.getPort());}}}
}
 
DiscoveryClient和NacosServiceDiscovery区别:
- 抽象层次:
 
- DiscoveryClient 是一个通用接口,位于抽象层,不依赖于具体的服务注册中心。
 - NacosServiceDiscovery 是 DiscoveryClient 的具体实现,依赖于 Nacos。
 - 功能实现:
 
- DiscoveryClient 定义了服务发现的基本行为,但具体实现由各个服务注册中心提供。
 - NacosServiceDiscovery 提供了对 Nacos 的具体实现,包括与 Nacos 服务器的通信逻辑。
 - 使用方式:
 
- 在 Spring Cloud 应用程序中,通常通过
 @EnableDiscoveryClient注解启用服务发现功能,底层会自动选择合适的 DiscoveryClient 实现。- 如果使用 Nacos 作为服务注册中心,NacosServiceDiscovery 会被自动配置为 DiscoveryClient 的实现。
 
3.4 远程调用
3.4.1 服务之间调用的基本流程
以订单服务调用商品服务为例:
- 订单服务向注册中心获取商品服务可访问地址列表
 - 注册中返回商品服务地址列表
 - 订单服务从地址列表中选择一个地址
 - 订单服务向选中的商品服务地址发送请求
 - 商品服务处理请求并返回数据
 - 订单服务接收商品服务返回的数据

在上一篇博客中详细讲解:RestTemplate快速入门 
3.5 负载均衡
3.5.1 依赖引入
<!--loadbalancer-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
 
3.5.2 使用LoadBalancerClient开启负载均衡
3.5.2.1 测试
@SpringBootTest
public class LoadBalancerTest {@AutowiredLoadBalancerClient loadBalancerClient;@Testpublic void test() {ServiceInstance choose = loadBalancerClient.choose("service-product");System.out.println(choose.getHost() + ":" + choose.getPort());choose = loadBalancerClient.choose("service-product");System.out.println(choose.getHost() + ":" + choose.getPort());choose = loadBalancerClient.choose("service-product");System.out.println(choose.getHost() + ":" + choose.getPort());choose = loadBalancerClient.choose("service-product");System.out.println(choose.getHost() + ":" + choose.getPort());}
}
 

3.5.2.2 使用示例
定义远程调用客户端RestTemplateBean对象
@Configuration
public class OrderConfig {@Bean@LoadBalanced //注解式负载均衡public RestTemplate restTemplate() {return new RestTemplate();}
}
 
假设有一个服务名为service-product,通过RestTemplate调用其/product接口的代码如下
// 注入LoadBalancerClient对象
@Autowired
private LoadBalancerClient loadBalancerClient;// 负载均衡发送请求
private Product getProductFromRemoteWithLoadBalancer(Long productId) {// 1. 获取到商品服务所在的所有机器IP + portServiceInstance choose = loadBalancerClient.choose("service-product");// 2. 根据IP + port调用商品服务String url = "http://" + choose.getHost() + ":" + choose.getPort() + "/product/" + productId;log.info("调用商品服务: {}", url);// 调用商品服务return restTemplate.getForObject(url, Product.class);}
 
3.5.3 使用@LoadBalanced注解开启负载均衡
3.5.3.1 使用示例
在远程调用客户端RestTemplate的Bean对象上,加上@LoadBalanced注解,开启负载均衡
@Configuration
public class OrderConfig {@Bean@LoadBalanced //注解式负载均衡public RestTemplate restTemplate() {return new RestTemplate();}
}
 
假设有一个服务名为service-product,通过RestTemplate调用其/product接口的代码如下
// 基于注解的负载均衡发送请求
private Product getProductFromRemoteWithLoadBalancerAnnotation(Long productId) {String url = "http://service-product/product/" + productId;// 调用商品服务,service-product为服务名称, 会被动态替换return restTemplate.getForObject(url, Product.class);}
 
3.5.3.2 调用过程解析
当RestTemplate通过@LoadBalanced注解被标记为负载均衡客户端时,它会与服务发现机制集成。在调用http://service-product/product/时,
- RestTemplate会首先向服务注册中心查询
service-product服务的所有可用实例。 - 服务注册中心会返回一个实例列表
 - RestTemplate会根据配置的负载均衡策略(如轮询、随机等)从这些实例中选择一个进行调用
 
3.5.3.3 深入探索
经典面试题:如果注册中心宕机,远程调用是否可以成功?
- 从未调用过,如果宕机,调用会立即失败
 - 调用过,如果宕机,因为会缓存名单,调用会成功
 - 调用过,如果注册中心和对方服务宕机,因为会缓存名单,调用会阻塞后失败(Connection Refused)
 

四、配置中心
4.1 整合配置
4.1.1 依赖引入
<!-- 配置中心 -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
 
4.1.2 编写yml配置文件
spring:cloud:nacos:server-addr: 127.0.0.1:8848 # nacos地址(默认)config:import: nacos:service-order.properties
 
4.1.3 配置集-dataId
在浏览器中的Nacos可视化平台,找到配置管理,点击配置列表,新建一个配置
 注意:Data ID 要和 yml配置文件 中的完全一致
 
 注意:
 当我们在项目引入了Nacos的配置中心的依赖,在项目启动前没导入任何的配置,就会报如下错误:
17:28:47.552 [main] ERROR org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter -- ***************************
APPLICATION FAILED TO START
***************************Description:No spring.config.import property has been definedAction:Add a spring.config.import=nacos: property to your configuration.If configuration is not required add spring.config.import=optional:nacos: instead.To disable this check, set spring.cloud.nacos.config.import-check.enabled=false.
 
解决方法
- 添加可选配置
 
# properties文件
spring.config.import=optional:nacos: # 可选
 
- 在yml配置中禁用导入检查
 
spring:cloud:nacos:config:import-check:enabled: false # 禁用配置检查
 
4.2 动态刷新
4.2.1 @RefreshScope
@RefreshScope -> 激活配置中心的自动刷新功能
@RestController
@RequiredArgsConstructor
@RefreshScope//自动刷新
public class OrderController {private final OrderService orderService;@Value("${order.timeout}")String orderTimeout;@Value("${order.timeout}")String orderAutoConfirm;@GetMapping("/config")public String getConfig() {return "timeout:" + orderTimeout + ",autoConfirm:" + orderAutoConfirm;}
}
 
启动项目,可见如下日志
2025-02-07T17:11:12.391+08:00  INFO 8056 --- [service-order] [           main] c.a.c.n.c.NacosConfigDataLoader          : [Nacos Config] Load config[dataId=service-order.properties, group=DEFAULT_GROUP] success
2025-02-07T17:11:13.761+08:00  INFO 8056 --- [service-order] [           main] c.a.c.n.refresh.NacosContextRefresher    : [Nacos Config] Listening config: dataId=service-order.properties, group=DEFAULT_GROUP
 
在浏览器输入http://localhost:8000/config,即可得到配置内容,在配置中心修改也可同步修改
 
4.2.2 @ConfigurationProperties
在配置文件中的属性较多的时候,使用@Value注解就显得有点繁琐。可以使用 @ConfigurationProperties 进行批量属性绑定,并且无需 @RefreshScope ,自动绑定配置,动态更新
 抽取配置类,参考代码如下:
@Component
@ConfigurationProperties(prefix = "order") //配置批量绑定在nacos下,可以无需@RefreshScope就能实现自动刷新
@Data
public class OrderProperties {String timeout;String autoConfirm;String dbUrl;
}
 
@RestController
@RequiredArgsConstructor
public class OrderController {private final OrderProperties orderProperties; //注入订单配置类@GetMapping("/config")public String getConfig() {return "timeout:" + orderProperties.getTimeout() + ",autoConfirm:" + orderProperties.getAutoConfirm();}}
 
4.3 手动编写代码监听配置变化
 /*** 创建并配置ApplicationRunner bean* 该bean在应用启动后,执行指定的操作,这里用于监听Nacos配置变化** @param manager NacosConfigManager实例,用于与Nacos配置服务交互* @return ApplicationRunner实例,用于执行应用启动后的操作*/@BeanApplicationRunner applicationRunner(NacosConfigManager manager){return args -> {// 获取Nacos配置服务实例ConfigService configService = manager.getConfigService();// 为特定的配置文件添加监听器// 这里监听"service-order.properties"配置文件的变化configService.addListener("service-order.properties", "DEFAULT_GROUP", new Listener() {/*** 返回一个固定大小的线程池,用于异步处理配置变更** @return Executor实例,用于异步执行任务*/@Overridepublic Executor getExecutor() {// 创建一个包含4个线程的固定大小线程池return Executors.newFixedThreadPool(4);}/*** 当监听的配置信息发生变化时,该方法被调用** @param configInfo 变更后的配置信息*/@Overridepublic void receiveConfigInfo(String configInfo) {// 打印变更后的配置信息System.out.println("configInfo = " + configInfo);}});};}
 
思考:Nacos中的数据集 和 application.properties 有相同的 配置项,哪个生效?
参考答案:Nacos中的数据集的优先级高于本地application.properties,因此Nacos中的数据集的会生效。遵循先导入优先,外部优先,高优先级的配置会覆盖低优先级相同的配置。

4.4 数据隔离
4.4.1 namespace
**命名空间:**实现多环境隔离,如:开发、测试、预发、生产等
 创建方式如下图:
 
4.4.2 dataId
**数据集id:**就是以前配置文件的名字。完整写法:名字.后缀 如:common.properties
4.4.3 groupId
**分组id:**一般可以用微服务的名字作为自己的组。
 创建方式如下图:
 
 点击创建配置后,填写配置信息
 
 
 
4.4.4 推荐用法
namespace【命名空间】、dataId【数据集】、group【组】配合 spring.config.activate.on-profile实现配置环境隔离
 
 “通俗易懂”:多个命名空间,每个命名空间下有多个组,每个组就是一个微服务,每个微服务下又有多个配置文件即数据集,每个配置文件下又有多个配置项
4.4.4 按需加载
# 服务端口
server:port: 8000spring:profiles:active: dev # 指定环境application:name: service-order # 服务名称cloud:nacos:server-addr: 127.0.0.1:8848 # nacos地址(默认)config:import-check:enabled: false # 禁用配置检查 -> 记得开启不然会报错namespace: ${spring.profiles.active:public} # 指定命名空间 -> 采用 spring.profiles.active的值,默认为public---
spring:config:import:- nacos:common.properties?group=order # 配置文件地址  group->指定组名- nacos:database.properties?group=orderactivate:on-profile: dev # 指定dev环境启用---
spring:config:import:- nacos:common.properties?group=order # 配置文件地址  group->指定组名- nacos:database.properties?group=order- nacos:haha.properties?group=orderactivate:on-profile: test # 指定test环境启用---
spring:config:import:- nacos:common.properties?group=order # 配置文件地址  group->指定组名- nacos:database.properties?group=order- nacos:hehe.properties?group=orderactivate:on-profile: prod # 指定prod环境启用 
总结

相关文章:
SpringCloud - Nacos注册/配置中心
前言 该博客为Nacos学习笔记,主要目的是为了帮助后期快速复习使用 学习视频:7小快速通关SpringCloud 辅助文档:SpringCloud快速通关 一、简介 Nacos官网:https://nacos.io/docs/next/quickstart/quick-start/ Nacos /nɑ:kəʊ…...
面试准备——Java理论高级【笔试,面试的核心重点】
集合框架 Java集合框架是面试中的重中之重,尤其是对List、Set、Map的实现类及其底层原理的考察。 1. List ArrayList: 底层是动态数组,支持随机访问(通过索引),时间复杂度为O(1)。插入和删除元素时&#…...
AI伴读-清华大学104页《DeepSeek:从入门到精通》
辅助工具:deepseek、豆包AI伴读 官网:DeepSeekDeepSeek, unravel the mystery of AGI with curiosity. Answer the essential question with long-termism.https://www.deepseek.com/https://www.deepseek.com/清华大学104页《DeepSeek:从入…...
unity学习34:角色相关3,触发器trigger,铰链 hingejoint 等 spring joint, fixed joint
目录 1 触发的实现条件 1.1 碰撞的的实现条件 1.2 触发的实现条件 1.3 触发器trigger,直接拿 碰撞器collider修改下配置即可 2 触发器相关实验:触发开门效果 2.0 目标 2.1 player物体的属性 2.2 新建一个trigger 物体 2.3 新建一个被trigger 控…...
HarmonyOS Next 方舟字节码文件格式介绍
在开发中,可读的编程语言要编译成二进制的字节码格式才能被机器识别。在HarmonyOS Next开发中,arkts会编译成方舟字节码。方舟字节码长什么样呢?我们以一个demo编译出的abc文件: 二进制就是长这样,怎么去理解呢&…...
计算机视觉语义分割——Attention U-Net(Learning Where to Look for the Pancreas)
计算机视觉语义分割——Attention U-Net(Learning Where to Look for the Pancreas) 文章目录 计算机视觉语义分割——Attention U-Net(Learning Where to Look for the Pancreas)摘要Abstract一、Attention U-Net1. 基本思想2. Attention Gate模块3. 软注意力与硬注意力4. 实验…...
html 列动态布局
样式说明: /* 列动态布局,列之间以空格填充 */ li {display: flex;/* flex-direction: column; */justify-content: space-between; }...
DeepSeek开源多模态大模型Janus-Pro部署
DeepSeek多模态大模型部署 请自行根据电脑配置选择合适环境配置安装conda以及gitJanus 项目以及依赖安装运行cpu运行gpu运行 进入ui界面 请自行根据电脑配置选择合适 本人家用电脑为1060,因此部署的7B模型。配置高的可以考虑更大参数的模型。 环境配置 安装conda…...
DeepSeek结合Langchain的基本用法
DeepSeek结合Langchain的基本用法 DeepSeek 基于Openai接口规范的Prompt应答Deepseek结合LangchainDeepSeek 基于langchain的结构化返回 DeepSeek 基于Openai接口规范的Prompt应答 首先我们需要先基于pip 安装 pip install openai最开始我们先熟悉如何使用openai的接口规范&a…...
Redis持久化的两种方式:RDB和AOF
redis中的数据存储在缓存中,如果没有持久化的策略,Redis一旦宕机,那么将会导致数据丢失;因此redis提供了以下两种持久化方式:RDB和AOF 一般来说,大部分公司对这两种方式都是同时开启的 一、RDB RDB策略全…...
每日一题——131.分割回文串
题目链接:131. 分割回文串 - 力扣(LeetCode) 代码: class Solution { private:vector<vector<string>> result;vector<string> path;void backtracking (const string& s,int startindex){if(startindex …...
内容中台赋能人工智能技术提升业务创新能力
内容概要 在当今快速变化的市场环境中,企业需要不断寻求创新以保持竞争力。内容中台作为一种新型的内容管理架构,能够极大地提升企业在内容创建、管理和分发方面的效率。通过与人工智能技术的深度融合,企业能够将海量的数据和信息转化为有价…...
第七节 文件与流
基本的输入输出(iostream) C标准库提供了一组丰富的输入/输出功能,C的I/O发生在流中,流是字节序列。如果字节流是从设备(键盘、磁盘驱动器、网络连接等)流向内存,叫做输入操作。如果字节流是从…...
软件工程 项目管理
软件项目管理中可以分成两部分: 软件创新 软件项目管理项目是定义明确的任务,这是为了实现某个目标(例如,软件开发和交付)进行的一系列操作的集合。一个项目可以表征为: 每个项目都可以有一个独特而鲜明的目标。 项目不是日常活…...
通过类加载和初始化的一些题目理解Java类加载过程
通过题目重点理解:Class加载流程和运行时区域 目录 子类和父类static变量父子类加载顺序2class.forName初始化 子类和父类static变量 class Parent {static int a 1;static int b 2;static int c;static {c 3;System.out.println("parent static block&quo…...
LLMs之DeepSeek r1:TinyZero的简介、特点、安装和使用方法、案例应用Logic-RL的简介、安装和使用方法、案例应用之详细攻略
LLMs之DeepSeek r1:TinyZero的简介、特点、安装和使用方法、案例应用Logic-RL的简介、安装和使用方法、案例应用之详细攻略 目录 TinyZero的简介 1、TinyZero的特点 TinyZero的安装和使用方法 1、安装 创建 conda 环境 数据准备 (倒计时任务) 多GPU (适用于 …...
爬取豆瓣电影 Top250 数据的脚本及调整方法
以下是一个完整的 Python 脚本,用于爬取豆瓣电影 Top250 的数据,包括电影名称、评分和短评。同时,我将提供应对豆瓣页面结构更新和反爬虫机制的调整方法。 安装必要的库 首先,确保安装了必要的库: bash复制 pip install requests beautifulsoup4 pandas示例代码 Pyth…...
Deepseek 接入Word处理对话框(隐藏密钥)
硅基流动邀请码:1zNe93Cp 邀请链接:网页链接 亲测deepseek接入word,自由调用对话,看截图有兴趣的复用代码(当然也可以自己向deepseek提问,帮助你完成接入,但是提问逻辑不一样给出的答案是千差万…...
Jupyter Notebook自动保存失败等问题的解决
一、未生成配置文件 需要在命令行中,执行下面的命令自动生成配置文件 jupyter notebook --generate-config 执行后会在 C:\Users\用户名\.jupyter目录中生成文件 jupyter_notebook_config.py 二、在网页端打开Jupyter Notebook后文件保存失败;运行代码…...
基于机器学习时序库pmdarima实现时序预测
目录 一、Pmdarima实现单变量序列预测1.1 核心功能与特性1.2 技术优势对比1.3 python案例1.3.1 时间序列交叉验证1.3.1.1 滚动交叉验证1.3.1.2 滑窗交叉验证 时间序列相关参考文章: 时间序列预测算法—ARIMA 基于VARMAX模型的多变量时序数据预测 基于机器学习时序库…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
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.…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...
