轻量级 Java 权限认证框架——Sa-Token
文章目录
- Sa-Token 介绍
- SpringBoot 集成 Sa-Token
- Sa-Token 功能
- 登录认证
- 会话查询
- Token 查询
- 权限认证
- 权限校验
- 角色校验
- 注解鉴权
- 注册 Sa-Token 拦截器
- 关闭注解校验
- 路由拦截鉴权
- 注册 Sa-Token 路由拦截器
- [记住我] 模式
- 密码加密
- Sa-Token 集成 Redis
- 方式1、使用 jdk 默认序列化方式
- 方式2、使用 jackson 序列化方式
- 集成 Redis 注意
- 集成 Thymeleaf
- 1、引入依赖
- 2、注册标签方言对象
- 3、使用标签方言
- 登录判断
- 3.2、角色判断
- 权限判断
- 调用 Sa-Token 相关API
- Sa-Token使用问题汇总
- 访问静态资源
Sa-Token 介绍
Sa-Token 是一个轻量级 Java 权限认证框架,主要解决:登录认证、权限认证、单点登录、OAuth2.0、分布式Session会话、微服务网关鉴权 等一系列权限相关问题。
Sa-Token最新开发文档地址:https://sa-token.cc
Sa-Token功能结构图:
SpringBoot 集成 Sa-Token
-
创建 SpringBoot 项目
-
再 Pom.xml 文件中添加 Sa-Token 依赖
<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc --> <dependency><groupId>cn.dev33</groupId><artifactId>sa-token-spring-boot-starter</artifactId><version>1.34.0</version> </dependency>
注:如果你使用的
SpringBoot 3.x
,只需要将sa-token-spring-boot-starter
修改为sa-token-spring-boot3-starter
即可。 -
设置配置文件
支持零配置启动项目 ,但同时也可以在
application.yml
中增加如下配置。server:# 端口port: 8081############## Sa-Token 配置 (文档: https://sa-token.cc) ############## sa-token: # token名称 (同时也是cookie名称)token-name: satoken# token有效期,单位s 默认30天, -1代表永不过期 timeout: 2592000# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒activity-timeout: -1# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) is-concurrent: true# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) is-share: true# token风格token-style: uuid# 是否输出操作日志 is-log: false
Sa-Token 功能
登录认证
-
会话登录
// 会话登录:参数填写要登录的账号id,建议的数据类型:long | int | String, 不可以传入复杂类型,如:User、Admin 等等 StpUtil.login(Object id);
StpUtil.login()
函数让 Sa-Token 为这个账号创建了一个Token凭证,且通过 Cookie 上下文返回给了前端,除此之外,Sa-Token 在背后做了大量的工作,包括但不限于:- 检查此账号是否之前已有登录
- 为账号生成
Token
凭证与Session
会话 - 通知全局侦听器,xx 账号登录成功
- 将
Token
注入到请求上下文 - 等等其它工作……
在 Cookie 功能的加持下,我们可以仅靠
StpUtil.login(id)
一句代码就完成登录认证。- Cookie 可以从后端控制往浏览器中写入 Token 值。
- Cookie 会在前端每次发起请求时自动提交 Token 值。
-
注销登录
// 当前会话注销登录 StpUtil.logout();
-
是否登录
// 获取当前会话是否已经登录,返回true=已登录,false=未登录 StpUtil.isLogin();
-
检查登录
// 检验当前会话是否已经登录, 如果未登录,则抛出异常:`NotLoginException`,代表当前会话暂未登录,可能的原因有很多 StpUtil.checkLogin();
会话查询
// 获取当前会话账号id, 如果未登录,则抛出异常:`NotLoginException`
StpUtil.getLoginId();// 类似查询API还有:
StpUtil.getLoginIdAsString(); // 获取当前会话账号id, 并转化为`String`类型
StpUtil.getLoginIdAsInt(); // 获取当前会话账号id, 并转化为`int`类型
StpUtil.getLoginIdAsLong(); // 获取当前会话账号id, 并转化为`long`类型// ---------- 指定未登录情形下返回的默认值 ----------// 获取当前会话账号id, 如果未登录,则返回null
StpUtil.getLoginIdDefaultNull();// 获取当前会话账号id, 如果未登录,则返回默认值 (`defaultValue`可以为任意类型)
StpUtil.getLoginId(T defaultValue);
Token 查询
// 获取当前会话的token值
StpUtil.getTokenValue();// 获取当前`StpLogic`的token名称
StpUtil.getTokenName();// 获取指定token对应的账号id,如果未登录,则返回 null
StpUtil.getLoginIdByToken(String tokenValue);// 获取当前会话剩余有效期(单位:s,返回-1代表永久有效)
StpUtil.getTokenTimeout();// 获取当前会话的token信息参数
StpUtil.getTokenInfo();
权限认证
因为每个项目的需求不同,其权限设计也千变万化, 所以 Sa-Token 将 [ 获取当前账号权限码集合 ] 操作以接口的方式暴露给你,以方便你根据自己的业务逻辑进行重写。
新建一个类,实现 StpInterface
接口,例如以下代码:
/*** 自定义权限验证接口扩展*/
@Component // 保证此类被SpringBoot扫描,完成Sa-Token的自定义权限验证扩展
public class StpInterfaceImpl implements StpInterface {/*** 返回一个账号所拥有的权限码集合 */@Overridepublic List<String> getPermissionList(Object loginId, String loginType) {// 本list仅做模拟,实际项目中要根据具体业务逻辑来查询权限List<String> list = new ArrayList<String>(); list.add("user.add");list.add("user.update");list.add("user.get");// list.add("user.delete");list.add("art.*");return list;}/*** 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)*/@Overridepublic List<String> getRoleList(Object loginId, String loginType) {// 本list仅做模拟,实际项目中要根据具体业务逻辑来查询角色List<String> list = new ArrayList<String>(); list.add("admin");list.add("super-admin");return list;}}
参数解释:
- loginId:账号id,即你在调用
StpUtil.login(id)
时写入的标识值。 - loginType:账号体系标识,此处可以暂时忽略,在 [ 多账户认证 ] 章节下会对这个概念做详细的解释。
权限校验
// 获取:当前账号所拥有的权限集合
StpUtil.getPermissionList();// 判断:当前账号是否含有指定权限, 返回 true 或 false
StpUtil.hasPermission("user.add"); // 校验:当前账号是否含有指定权限, 如果验证未通过,则抛出异常: NotPermissionException
StpUtil.checkPermission("user.add"); // 校验:当前账号是否含有指定权限 [指定多个,必须全部验证通过]
StpUtil.checkPermissionAnd("user.add", "user.delete", "user.get"); // 校验:当前账号是否含有指定权限 [指定多个,只要其一验证通过即可]
StpUtil.checkPermissionOr("user.add", "user.delete", "user.get");
角色校验
// 获取:当前账号所拥有的角色集合
StpUtil.getRoleList();// 判断:当前账号是否拥有指定角色, 返回 true 或 false
StpUtil.hasRole("super-admin"); // 校验:当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException
StpUtil.checkRole("super-admin"); // 校验:当前账号是否含有指定角色标识 [指定多个,必须全部验证通过]
StpUtil.checkRoleAnd("super-admin", "shop-admin"); // 校验:当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可]
StpUtil.checkRoleOr("super-admin", "shop-admin");
权限通配符(“*”):Sa-Token允许你根据通配符指定泛权限,例如当一个账号拥有
art.*
的权限时,art.add
、art.delete
、art.update
都将匹配通过
注解鉴权
@SaCheckLogin
: 登录校验 —— 只有登录之后才能进入该方法。@SaCheckRole("admin")
: 角色校验 —— 必须具有指定角色标识才能进入该方法。@SaCheckPermission("user:add")
: 权限校验 —— 必须具有指定权限才能进入该方法。@SaCheckSafe
: 二级认证校验 —— 必须二级认证之后才能进入该方法。@SaCheckBasic
: HttpBasic校验 —— 只有通过 Basic 认证后才能进入该方法。@SaIgnore
:忽略校验 —— 表示被修饰的方法或类无需进行注解鉴权和路由拦截器鉴权。@SaCheckDisable("comment")
:账号服务封禁校验 —— 校验当前账号指定服务是否被封禁。
Sa-Token 使用全局拦截器完成注解鉴权功能,为了不为项目带来不必要的性能负担,拦截器默认处于关闭状态
因此,为了使用注解鉴权,你必须手动将 Sa-Token 的全局拦截器注册到你项目中
注册 Sa-Token 拦截器
以SpringBoot2.0
为例,新建配置类SaTokenConfigure.java
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {// 注册 Sa-Token 拦截器,打开注解式鉴权功能 @Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册 Sa-Token 拦截器,打开注解式鉴权功能 registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**"); }
}
保证此类被springboot
启动类扫描到即可
关闭注解校验
SaInterceptor
只要注册到项目中,默认就会打开注解校验,如果要关闭此能力,需要:
@Override
public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new SaInterceptor(handle -> {SaRouter.match("/**").check(r -> StpUtil.checkLogin());}).isAnnotation(false) // 指定关闭掉注解鉴权能力,这样框架就只会做路由拦截校验了 ).addPathPatterns("/**");
}
路由拦截鉴权
假设我们有如下需求:
项目中所有接口均需要登录认证,只有 “登录接口” 本身对外开放
那么给每个接口加上鉴权注解?手写全局拦截器?似乎都不是非常方便。
注册 Sa-Token 路由拦截器
以SpringBoot2.0
为例, 新建配置类SaTokenConfigure.java
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {// 注册拦截器@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册 Sa-Token 拦截器,校验规则为 StpUtil.checkLogin() 登录校验。registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin())).addPathPatterns("/**").excludePathPatterns("/user/doLogin"); }
}
以上代码,我们注册了一个基于 StpUtil.checkLogin()
的登录校验拦截器,并且排除了/user/doLogin
接口用来开放登录(除了/user/doLogin
以外的所有接口都需要登录才能访问)。
[记住我] 模式
Sa-Token的登录授权,默认就是[记住我]
模式,为了实现[非记住我]
模式,你需要在登录时如下设置 StpUtil.login()
函数的第二个参数:
// 设置登录账号id为10001,第二个参数指定是否为[记住我],当此值为false后,关闭浏览器后再次打开需要重新登录
StpUtil.login(10001, false);
- 勾选 [记住我] 按钮时:调用
StpUtil.login(10001, true)
,此时用户即使重启浏览器 Token 依然有效。 - 不勾选 [记住我] 按钮时:调用
StpUtil.login(10001, false)
,此时用户在重启浏览器后 Token 便会消失,导致会话失效。
密码加密
Sa-Token
支持摘要加密、对称加密、非对称加密、Base64加密等方式。
// md5加密
SaSecureUtil.md5("123456");// sha1加密
SaSecureUtil.sha1("123456");// sha256加密
SaSecureUtil.sha256("123456");
Sa-Token 集成 Redis
方式1、使用 jdk 默认序列化方式
<!-- Sa-Token 整合 Redis (使用 jdk 默认序列化方式) -->
<dependency><groupId>cn.dev33</groupId><artifactId>sa-token-dao-redis</artifactId><version>1.34.0</version>
</dependency>
方式2、使用 jackson 序列化方式
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
<dependency><groupId>cn.dev33</groupId><artifactId>sa-token-dao-redis-jackson</artifactId><version>1.34.0</version>
</dependency>
集成 Redis 注意
1. 无论使用哪种序列化方式,你都必须为项目提供一个 Redis 实例化方案,例如:
<!-- 提供Redis连接池 -->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>
2. 引入了依赖,我还需要为 Redis 配置连接信息吗?
需要!只有项目初始化了正确的 Redis 实例,Sa-Token
才可以使用 Redis 进行数据持久化,参考以下yml配置
:
spring: # redis配置 redis:# Redis数据库索引(默认为0)database: 1# Redis服务器地址host: 127.0.0.1# Redis服务器连接端口port: 6379# Redis服务器连接密码(默认为空)# password: # 连接超时时间timeout: 10slettuce:pool:# 连接池最大连接数max-active: 200# 连接池最大阻塞等待时间(使用负值表示没有限制)max-wait: -1ms# 连接池中的最大空闲连接max-idle: 10# 连接池中的最小空闲连接min-idle: 0
3. 集成 Redis 后,是我额外手动保存数据,还是框架自动保存?
框架自动保存。集成 Redis
只需要引入对应的 pom依赖
即可,框架所有上层 API 保持不变。
4. 集成包版本问题
Sa-Token-Redis 集成包的版本尽量与 Sa-Token-Starter 集成包的版本一致,否则可能出现兼容性问题。
集成 Thymeleaf
可以在 Thymeleaf 页面中使用 Sa-Token 相关API,俗称 —— 标签方言。
1、引入依赖
首先我们确保项目已经引入 Thymeleaf 依赖,然后在此基础上继续添加:
<!-- 在 thymeleaf 标签中使用 Sa-Token -->
<dependency><groupId>cn.dev33</groupId><artifactId>sa-token-dialect-thymeleaf</artifactId><version>1.34.0</version>
</dependency>
2、注册标签方言对象
在 SaTokenConfigure 配置类中注册 Bean
@Configuration
public class SaTokenConfigure {// Sa-Token 标签方言 (Thymeleaf版)@Beanpublic SaTokenDialect getSaTokenDialect() {return new SaTokenDialect();}
}
3、使用标签方言
然后我们就可以愉快的使用在 Thymeleaf 页面中使用标签方言了
登录判断
<h2>标签方言测试页面</h2>
<p>登录之后才能显示:<span sa:login>value</span>
</p>
<p>不登录才能显示:<span sa:notLogin>value</span>
</p>
3.2、角色判断
<p>具有角色 admin 才能显示:<span sa:hasRole="admin">value</span>
</p>
<p>同时具备多个角色才能显示:<span sa:hasRoleAnd="admin, ceo, cto">value</span>
</p>
<p>只要具有其中一个角色就能显示:<span sa:hasRoleOr="admin, ceo, cto">value</span>
</p>
<p>不具有角色 admin 才能显示:<span sa:lackRole="admin">value</span>
</p>
权限判断
<p>具有权限 user-add 才能显示:<span sa:hasPermission="user-add">value</span>
</p>
<p>同时具备多个权限才能显示:<span sa:hasPermissionAnd="user-add, user-delete, user-get">value</span>
</p>
<p>只要具有其中一个权限就能显示:<span sa:hasPermissionOr="user-add, user-delete, user-get">value</span>
</p>
<p>不具有权限 user-add 才能显示:<span sa:lackPermission="user-add">value</span>
</p>
调用 Sa-Token 相关API
以上的标签方言,可以满足我们大多数场景下的权限判断,然后有时候我们依然需要更加灵活的在页面中调用 Sa-Token 框架API
首先在 SaTokenConfigure 配置类中为 Thymeleaf 配置全局对象:
@Configuration
public class SaTokenConfigure {@Autowiredprivate void configureThymeleafStaticVars(ThymeleafViewResolver viewResolver) {viewResolver.addStaticVariable("stp", StpUtil.stpLogic);}}
然后就可以在页面上调用 StpLogic 的 API 了,例如:
<p>调用 StpLogic 方法调用测试</p>
<p th:if="${stp.isLogin()}">从SaSession中取值:<span th:text="${stp.getSession().get('name')}"></span>
</p>
Sa-Token使用问题汇总
访问静态资源
项目引入Sa-Token
后,需要对访问的静态资源路径放行,否则就会被拦截,那么需要在用户自创建的WebMvcConfigurer
实现类中,配置本地资源映射路径,并添加Sa-Token
拦截器的路由拦截规则,对访问静态资源的路径进行放行。
//配置本地资源映射路径 @Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");}// 注册Sa-token拦截器// 注册拦截器@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册 Sa-Token 拦截器,定义详细认证规则registry.addInterceptor(new SaInterceptor(handler -> {// 指定一条 match 规则SaRouter.match("/**") // 拦截.notMatch("/static/**") // 放行 /static/** 路径.check(r -> StpUtil.checkLogin()); // 执行校验登录})).addPathPatterns("/**");}
相关文章:

轻量级 Java 权限认证框架——Sa-Token
文章目录Sa-Token 介绍SpringBoot 集成 Sa-TokenSa-Token 功能登录认证会话查询Token 查询权限认证权限校验角色校验注解鉴权注册 Sa-Token 拦截器关闭注解校验路由拦截鉴权注册 Sa-Token 路由拦截器[记住我] 模式密码加密Sa-Token 集成 Redis方式1、使用 jdk 默认序列化方式方…...
算法复习(四、五、六)
动态规划 动态规划算法的有效性依赖于问题本身所具有的两个重要性质:最优子结构、重叠子问题 关于动态规划算法和备忘录方法的适用条件: 要求: 用分治法和动态规划法分别解决最大子段和问题(第四步求最优解不需要掌握ÿ…...

SORT与DeepSORT简介
一、MOT( mutil-object tracking)步骤 在《DEEP LEARNING IN VIDEO MUTIL-OBJECT TEACKING: A SURVEY》这篇基于深度学习多目标跟踪综述中,描绘了MOT问题的四个主要步骤 1.跟定视频原始帧 2.使用目标检测器如Faster-rcnn, YOLO, SSD等进行检测,获取目标…...

TCP/IP网络编程——多播与广播
完整版文章请参考: TCP/IP网络编程完整版文章 文章目录第 14 章 多播与广播14.1 多播14.1.1 多播的数据传输方式以及流量方面的优点14.1.2 路由(Routing)和 TTL(Time to Live,生存时间),以及加入组的办法14…...

K8S DNS解析过程和延迟问题
一、Linux DNS查询解析原理(对于调用glibc库函数gethostbyname的程序)我们在浏览器访问www.baidu.com这个域名,dns怎么查询到这台主机呢? 1、在浏览器中输入www.baidu.com域名,操作系统会先查找本地DNS解析器缓存&a…...

【JavaScript】js实现深拷贝的方法
前言 在js中我们想要实现深拷贝,首先要了解深浅拷贝的区别。 浅拷贝:只是拷贝数据的内存地址,而不是在内存中重新创建一个一模一样的对象(数组) 深拷贝:在内存中开辟一个新的存储空间,完完全全…...

RK3288 GPIO记录
1、引脚对应的GPIO 编号第一种 使用/sys/kernel/debug/gpio查询所有gpio引脚的基数第二种 cat /sys/class/gpio/gpiochip248/label对应的label就是GPIO引脚,例如下图GPIO8对应的基数就是2482、计算编号编号 基数 PIN脚如GPIO8的基数是248, GPIO8_A6的编…...

MongoDB介绍及使用教程
文章目录一、MongoDB介绍1. 什么是MongoDB2. 为什么要用MongoDB3. MongoDB的应用场景4. MongoDB基本概念二、MongoDB使用教程1.下载安装(Windows)2.MongoDB Conpass简单使用(选学)3.使用navicat连接MongoDB4.JAVA项目中使用MongoD…...

51单片机开发环境搭建 - VS Code 从编写到烧录
我安装并测试成功的环境: 操作系统:Windows 10 (22H2)单片机:STC89C52RCPython version: 3.7.6 在这之前,给51单片机写程序是用 Keil 5(编写编译)、STC-ISP(烧录),由于…...
python datetime、字符串和时间戳之间的相互转换12小时制和24小时制时间相互转化
文章目录1.字符串转datetime格式2.datetime转字符串3.时间戳转datetime格式4.datetime格式转时间戳5.应用:将12小时制的字符串转换为时间戳1.字符串转datetime格式 把字符串转换为datetime的格式 项目字符串的样子‘%m/%d/%Y %H:%M:%S’2/3/2023 15:30:20‘%m-%d-…...

百度百科词条怎么做?百度百科词条创建攻略分享
只要是想要将自己宣传出去的企业或是个人,都建议创建属于自己的百度百科词条,因为百度百科词条流量大、权重高、排名靠前,创建百度百科词条可以提高企业或是个人的知名度和口碑。 百度百科词条怎么做?每天都有用户在百度上搜索这…...

基于Hive的河北新冠确诊人数分析系统的设计与实现
项目描述 临近学期结束,还是毕业设计,你还在做java程序网络编程,期末作业,老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下,你想解决的问…...

k8s二进制部署
目录 一、环境准备 常见的k8s部署方式 关闭防火墙 关闭selinux 关闭swap 根据规划设置主机名 在master添加hosts 将桥接的IPv4流量传递到iptables的链 时间同步 二、部署etcd集群 1、master节点部署 #查看证书的信息 上传etcd-cert.sh 和etcd.sh 到/opt/k8s/ 目录…...

Windows出现0xc00d36e5错误怎么办?
当我们使用Windows Media Player来播放视频文件时,可能会出现无法播放,并显示0xc00d36e5错误代码。该错误可能是因为Windows Media Player不支持视频格式、注册表项损坏、系统配置问题、第三方应用程序冲突等。下面将开始介绍0xc00d36e5错误的解决方法&a…...

Idea搭建Spring5.3.x源码阅读环境
1. 概述 Spring是一个轻量级Java开源框架,在Java项目开发过程中已经离不开Spring全家桶了,包括Spring、SpringBoot、SpringCloud等,学习好Spring基础源码也有助于更好在项目中使用Spring相关组件,在学习源码前需要搭建好源码学习…...

2.20jdbc
一.数据库编程的必备条件编程语言:java c c Python数据库 Oracle,MySQL,SQL Server数据库驱动包:不同的数据库,对应不同的编程语言提供了不同的数据库驱动包:MySQL提供了Java的驱动包mysqlconnector-java,需要就Java操作MySQL需要该驱动包二.Java的数据库编程JDBC,即…...

【代码随想录训练营】【Day19休息】【Day20】第六章|二叉树|654.最大二叉树|617.合并二叉树|700.二叉搜索树中的搜索|98.验证二叉搜索树
最大二叉树 题目详细:LeetCode.654 这道题在题目几乎就说明了解题的思路了: 创建一个根节点,其值为 nums 中的最大值;递归地在最大值左边的子数组上构建左子树;递归地在最大值右边的子数组上构建右子树;…...

华为云计算之容灾技术
容灾是物理上的容错技术,不是逻辑上的容错同步远程复制:主备距离≤200km,只有在主备设备上都写成功,才会告诉主机写成功,不会丢失数据异步远程复制:主备距离>200km,只要主设备上写成…...

React系列之Redux
1 Redux概述 Redux 是 JavaScript 状态容器,提供可预测化的状态管理。Redux中文文档 Redux 和react没有必然关系,redux可以应用于各种框架,包括jquery,甚至js都可以使用redux,只不过redux和react更加搭配。redux也推…...

最简单得方法解决TCP分包粘包问题
如何用最简单的方法解决TCP传输中的分包粘包问题? 首先需要说明一点,分包粘包等等一系列的问题并不是协议本身存在的问题,而是程序员在写代码的时候,没有搞清楚数据的边界导致的。 看个简单的例子,TCP客户端不断的向服…...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程
STM32F1 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增…...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...