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

Sa-Token实现分布式登录鉴权(Redis集成 前后端分离)

文章目录

    • 1. Sa-Token 介绍
    • 2. 登录认证
      • 2.1 登录与注销
      • 2.2 会话查询
      • 2.3 Token 查询
    • 3. 权限认证
      • 3.1 获取当前账号权限码集合
      • 3.2 权限校验
      • 3.3 角色校验
    • 4. 前后台分离(无Cookie模式)
    • 5. Sa-Token 集成 Redis
    • 6. SpringBoot 集成 Sa-Token
      • 6.1 创建项目
      • 6.2 添加依赖
      • 6.3 设置配置文件
      • 6.4 创建启动类
      • 6.5 定义用户信息类
      • 6.6 自定义权限验证接口扩展
      • 6.7 创建测试Controller
      • 6.8 运行

1. Sa-Token 介绍

Sa-Token 是一个轻量级 Java 权限认证框架,主要解决:登录认证、权限认证、单点登录、OAuth2.0、分布式Session会话、微服务网关鉴权 等一系列权限相关问题。

功能结构图

在这里插入图片描述

2. 登录认证

对于一些登录之后才能访问的接口(例如:查询我的账号资料),我们通常的做法是增加一层接口校验:

  • 如果校验通过,则:正常返回数据。
  • 如果校验未通过,则:抛出异常,告知其需要先进行登录。

那么,判断会话是否登录的依据是什么?我们先来简单分析一下登录访问流程:

  • 用户提交 name + password 参数,调用登录接口。
  • 登录成功,返回这个用户的 Token 会话凭证。
  • 用户后续的每次请求,都携带上这个 Token
  • 服务器根据 Token 判断此会话是否登录成功。

所谓登录认证,指的就是服务器校验账号密码,为用户颁发 Token 会话凭证的过程,这个Token 也是我们后续判断会话是否登录的关键所在。

在这里插入图片描述

2.1 登录与注销

// 会话登录:参数填写要登录的账号id,建议的数据类型:long | int | String, 不可以传入复杂类型,如:User、Admin 等等
StpUtil.login(Object id);  

只此一句代码,便可以使会话登录成功,实际上,Sa-Token 在背后做了大量的工作,包括但不限于:

  • 检查此账号是否之前已有登录
  • 为账号生成 Token 凭证与 Session 会话
  • 通知全局侦听器,xx 账号登录成功
  • Token 注入到请求上下文
  • 等等其它工作……

只需要记住关键一点:Sa-Token 为这个账号创建了一个Token凭证,且通过 Cookie 上下文返回给了前端

此处仅仅做了会话登录,但并没有主动向前端返回 Token 信息。严格来讲是需要的,只不过 StpUtil.login(id) 方法利用了 Cookie 自动注入的特性,省略了你手写返回 Token 的代码。

// 当前会话注销登录
StpUtil.logout();// 获取当前会话是否已经登录,返回true=已登录,false=未登录
StpUtil.isLogin();// 检验当前会话是否已经登录, 如果未登录,则抛出异常:`NotLoginException`
StpUtil.checkLogin();

2.2 会话查询

// 获取当前会话账号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);

2.3 Token 查询

// 获取当前会话的token值
StpUtil.getTokenValue();// 获取当前`StpLogic`的token名称
StpUtil.getTokenName();// 获取指定token对应的账号id,如果未登录,则返回 null
StpUtil.getLoginIdByToken(String tokenValue);// 获取当前会话剩余有效期(单位:s,返回-1代表永久有效)
StpUtil.getTokenTimeout();// 获取当前会话的token信息参数
StpUtil.getTokenInfo();

3. 权限认证

所谓权限认证,核心逻辑就是判断一个账号是否拥有指定权限:

  • 有,就让你通过。
  • 没有?那么禁止访问!

深入到底层数据中,就是每个账号都会拥有一个权限码集合,框架来校验这个集合中是否包含指定的权限码。

例如:当前账号拥有权限码集合 ["user-add", "user-delete", "user-get"],这时候我来校验权限 "user-update",则其结果就是:验证失败,禁止访问

在这里插入图片描述

3.1 获取当前账号权限码集合

因为每个项目的需求不同,其权限设计也千变万化,因此 [ 获取当前账号权限码集合 ] 这一操作不可能内置到框架中, 所以 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("101");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:账号体系标识,此处暂时忽略,可以详细了解 [ 多账户认证 ]

3.2 权限校验

然后就可以用以下api来鉴权了

// 获取:当前账号所拥有的权限集合
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");    

3.3 角色校验

在Sa-Token中,角色和权限可以独立验证

// 获取:当前账号所拥有的角色集合
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都将匹配通过

上帝权限:当一个账号拥有 "*" 权限时,他可以验证通过任何权限码 (角色认证同理)

前端有了鉴权后端还需要鉴权吗?

需要!

前端的鉴权只是一个辅助功能,对于专业人员这些限制都是可以轻松绕过的,为保证服务器安全,无论前端是否进行了权限校验,后端接口都需要对会话请求再次进行权限校验

4. 前后台分离(无Cookie模式)

何为无 Cookie 模式?
Cookie 模式:特指不支持 Cookie 功能的终端,通俗来讲就是我们常说的 —— 前后台分离模式

  1. 后端将 token 返回到前端

首先调用 StpUtil.login(id) 进行登录。
调用 StpUtil.getTokenInfo() 返回当前会话的 token 详细参数。

  • 此方法返回一个对象,其有两个关键属性:tokenNametokenValue(token 的名称和 token 的值)。
  • 将此对象传递到前台,让前端人员将这两个值保存到本地。
  1. 前端将 token 提交到后端
  • 无论是app还是小程序,其传递方式都大同小异。
  • 那就是,将 token 塞到请求header里 ,格式为:{tokenName: tokenValue}
  1. 只要按照如此方法将token值传递到后端,Sa-Token 就能像传统PC端一样自动读取到 token 值,进行鉴权
  2. 你可能会有疑问,难道我每个ajax都要写这么一坨?岂不是麻烦死了?
    你当然不能每个 ajax 都写这么一坨,因为这种重复性代码都是要封装在一个函数里统一调用的。

5. Sa-Token 集成 Redis

Sa-Token 默认将数据保存在内存中,此模式读写速度最快,且避免了序列化与反序列化带来的性能消耗,但是此模式也有一些缺点,比如:

  • 重启后数据会丢失。
  • 无法在分布式环境中共享数据。

为此,Sa-Token 提供了扩展接口,你可以轻松将会话数据存储在 RedisMemcached等专业的缓存中间件中, 做到重启数据不丢失,而且保证分布式环境下多节点的会话一致性。

以下是官方提供的 Redis 集成包:

<!-- 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>
  1. 配置Redis 连接信息
spring: # redis配置 redis:# Redis数据库索引(默认为0)database: 0# 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
  1. 集成 Redis 后,是我额外手动保存数据,还是框架自动保存?
    框架自动保存。集成 Redis 只需要引入对应的 pom依赖 即可,框架所有上层 API 保持不变。

  2. 集成包版本问题
    Sa-Token-Redis 集成包的版本尽量与 Sa-Token-Starter 集成包的版本一致,否则可能出现兼容性问题。

6. SpringBoot 集成 Sa-Token

以最新版本 1.34.0为例

6.1 创建项目

在 IDE 中新建一个 SpringBoot 项目,例如:sa-token-demo-springboot

6.2 添加依赖

在项目中添加依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
<dependency><groupId>cn.dev33</groupId><artifactId>sa-token-spring-boot-starter</artifactId><version>1.34.0</version>
</dependency>
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
<dependency><groupId>cn.dev33</groupId><artifactId>sa-token-dao-redis-jackson</artifactId><version>1.34.0</version>
</dependency>
<!-- 提供Redis连接池 -->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency>

6.3 设置配置文件

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: falsespring:# redis配置redis:# Redis数据库索引(默认为0)database: 0# Redis服务器地址host: 127.0.0.1# Redis服务器连接端口port: 6379# Redis服务器连接密码(默认为空)password: abc123# 连接超时时间timeout: 10slettuce:pool:# 连接池最大连接数max-active: 200# 连接池最大阻塞等待时间(使用负值表示没有限制)max-wait: -1ms# 连接池中的最大空闲连接max-idle: 10# 连接池中的最小空闲连接min-idle: 0

6.4 创建启动类

@SpringBootApplication
public class SaTokenDemoApplication {public static void main(String[] args) throws JsonProcessingException {SpringApplication.run(SaTokenDemoApplication.class, args);System.out.println("启动成功:Sa-Token配置如下:" + SaManager.getConfig());}
}

6.5 定义用户信息类

@Data
@Accessors(chain = true)
@AllArgsConstructor
public class UserInfo {private Long userId;private String name;private String email;
}

6.6 自定义权限验证接口扩展

@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.get");// list.add("user.delete");
//        list.add("art.*");//从redis中获取权限List<String> authList = (List<String>) StpUtil.getSession().get("authList");return authList;}/*** 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)* @param loginId 账号id,即你在调用 StpUtil.login(id) 时写入的标识值* @param loginType 账号体系标识* @author: yh* @date: 2023/2/12*/@Overridepublic List<String> getRoleList(Object loginId, String loginType) {// 本list仅做模拟,实际项目中要根据具体业务逻辑来查询角色List<String> list = new ArrayList<String>();list.add("admin");list.add("super-admin");return list;}
}

6.7 创建测试Controller

@RestController
@RequestMapping("/user")
public class UserController {/*** 测试登录,浏览器访问: http://localhost:8081/user/doLogin?username=zhang&password=123456*/@RequestMapping("/doLogin")public SaResult doLogin(String username, String password) {// 此处仅作模拟示例,真实项目需要从数据库中查询数据进行比对 if("zhang".equals(username) && "123456".equals(password)) {// 第1步,先登录上StpUtil.login(10001);}//第2步,加载用户信息和权限信息StpUtil.getSession().set("loginInfo", new UserInfo(10001L, "张三", "123123@163.com"));//加载权限,只给user.add的权限List<String> authList = new ArrayList<String>();authList.add("user.add");StpUtil.getSession().set("authList", authList);// 第3步,获取 Token  相关参数SaTokenInfo tokenInfo = StpUtil.getTokenInfo();// 第4步,返回给前端return SaResult.data(tokenInfo);}/*** 查询登录状态*/@RequestMapping("/isLogin")public String isLogin() {return "当前会话是否登录:" + StpUtil.isLogin();}/*** 获取用户信息*/@RequestMapping("/getUserInfo")public UserInfo getUserInfo() {UserInfo loginInfo = (UserInfo) StpUtil.getSession().get("loginInfo");return loginInfo;}/*** 测试方法校验权限*/@GetMapping(value = "/add")public String add(){StpUtil.checkPermission("user.add");return "ok";}@GetMapping(value = "/update")public String update(){StpUtil.checkPermission("user.update");return "ok";}
}

6.8 运行

启动项目,Copy Configuration再启动一个实例,这时候我们就同时启动了两个实例

在这里插入图片描述

在这里插入图片描述

这样就可以测试出在集群部署情况下登录信息会不会有问题,然后用接口测试工具依次访问上述测试接口

1、 登录

http://localhost:8081/user/doLogin?username=zhang&password=123456

在这里插入图片描述

此时查看redis中数据,可以看到登录信息和权限都保存在redis中了

在这里插入图片描述

2、 查询登录状态

http://localhost:8081/user/isLogin

注意header里没有cookie

在这里插入图片描述

把登录接口返回的tokenNametokenValue加入到请求header

在这里插入图片描述

只有请求携带对应的token,登录状态才为:true

3、 获取用户信息

这里调用端口为8082的实例
http://localhost:8082/user/getUserInfo

在这里插入图片描述

4、 调用添加用户接口

测试是否有添加接口权限,登录的时候我们赋予了添加用户的权限

http://localhost:8082/user/add

在这里插入图片描述

5、 调用更新用接口

测试是否有更新用户接口权限,登录的时候我们没有赋予更新用户的权限

http://localhost:8082/user/update

在这里插入图片描述

在这里插入图片描述

结果可以看到没有更新用户接口的权限。

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=rrez71s8jyqy

相关文章:

Sa-Token实现分布式登录鉴权(Redis集成 前后端分离)

文章目录1. Sa-Token 介绍2. 登录认证2.1 登录与注销2.2 会话查询2.3 Token 查询3. 权限认证3.1 获取当前账号权限码集合3.2 权限校验3.3 角色校验4. 前后台分离&#xff08;无Cookie模式&#xff09;5. Sa-Token 集成 Redis6. SpringBoot 集成 Sa-Token6.1 创建项目6.2 添加依…...

leaflet显示高程

很多地图软件都能随鼠标移动动态显示高程。这里介绍一种方法&#xff0c;我所得出的。1 下载高程数据一般有12.5m数据下载&#xff0c;可惜精度根本不够&#xff0c;比如mapbox的免费在线的&#xff0c;或者91卫图提供百度网盘打包下载的&#xff0c;没法用&#xff0c;差距太大…...

电子学会2022年12月青少年软件编程(图形化)等级考试试卷(三级)答案解析

目录 一、单选题(共25题&#xff0c;共50分) 二、判断题(共10题&#xff0c;共20分) 三、编程题(共3题&#xff0c;共30分) 青少年软件编程&#xff08;图形化&#xff09;等级考试试卷&#xff08;三级&#xff09; 一、单选题(共25题&#xff0c;共50分) 1. 默认小猫角色…...

ubuntu 驱动更新后导致无法进入界面

**问题描述&#xff1a; **安装新ubuntu系统后未禁止驱动更新导致无法进入登录界面。 解决办法&#xff1a; 首先在进入BIOS中&#xff0c;修改设置以进行命令行操作&#xff0c;然后卸载已有的系统驱动&#xff0c;最后安装新的驱动即可。 开机按F11进入启动菜单栏&#xf…...

解决访问GitHub时出现的“您的连接不是私密连接”的问题!

Content问题描述解决办法问题描述 访问github出现您的连接不是私密连接问题&#xff0c;无法正常访问&#xff0c;如下图所示&#xff1a; 解决办法 修改hosts文件。hosts文件位于&#xff1a;C:\Windows\System32\drivers\etc\hosts 首先在https://www.ipaddress.com/查找两…...

初识数据仓库

一、什么是数据仓库数据库 --> OLTP&#xff1a;&#xff08;on-line transaction processing&#xff09;翻译为联机事务处理记录某类业务事件的发生&#xff0c;如购买行为&#xff0c;银行交易行为&#xff0c;当行为产生后&#xff0c;系统会记录是谁在何时何地做了何事…...

FilenameUtils工具类部分源码自研

FilenameUtils工具类部分源码自研getExtension(orgFileName)源码如下逐行分析getExtension(orgFileName)源码如下 public class FilenameUtils {public static int indexOfExtension(String fileName) throws IllegalArgumentException {if (fileName null) {return -1;} els…...

【前端领域】3D旋转超美相册(HTML+CSS)

世界上总有一半人不理解另一半人的快乐。 ——《爱玛》 目录 一、前言 二、本期作品介绍 3D旋转相册 三、效果展示 四、详细介绍 五、编码实现 index.html style.css img 六、获取源码 公众号获取源码 获取源码&#xff1f;私信&#xff1f;关注&#xff1f;点赞&…...

Java——聊聊JUC中的原子变量类

文章目录&#xff1a; 1.什么是原子变量类&#xff1f; 2.AtomicInteger&#xff08;基本类型原子变量类&#xff09; 3.AtomicIntegerArray&#xff08;数组类型原子变量类&#xff09; 4.AtomicMarkableReference&#xff08;引用类型原子变量类&#xff09; 5.AtomicInteger…...

elasticsearch索引与搜索初步

ES支持cURL交互&#xff0c;使用http请求完成索引和搜索操作&#xff0c;最基本的格式如下&#xff1a;创建索引我们可以使用PUT方法创建索引&#xff0c;通过指定“索引”、“类型”、“文档ID”锁定文档&#xff0c;通过参数指定文档的数据。红色部分的路由分别指定了“索引”…...

【Python】多线程与多进程学习笔记

本文是一篇学习笔记&#xff0c;学习内容主要来源于莫凡python的文档&#xff1a;https://mofanpy.com/tutorials/python-basic/threading/thread 多线程 线程基本结构 开启子线程的简单方式如下&#xff1a; import threadingdef thread_job():print(This is a thread of %…...

MySQL基础知识点

1.在Linux上安装好MySQL8.0之后&#xff0c;默认数据目录的具体位置是什么&#xff1f;该目录下都保存哪些数据库组件&#xff1f;在目录/usr/sbin、/usr/bin、/etc、/var/log 分别保存哪些组件&#xff1f; 答&#xff1a;默认数据目录&#xff1a;/var/lib/mysql。保存有mysq…...

代码随想录算法训练营第五十九天| 583. 两个字符串的删除操作、72. 编辑距离

Leetcode - 583dp[i][j]代表以i-1结尾的words1的子串 要变成以j-1结尾的words2的子串所需要的次数。初始化&#xff1a; "" 变成"" 所需0次 dp[0][0] 0, ""变成words2的子串 需要子串的长度的次数,所以dp[0][j] j, 同理&#xff0c;dp[i][0] …...

指针引用字符串问题(详解)

通过指针引用字符串可以更加方便灵活的使用字符串。 字符串的引用方式有两种&#xff0c;下面简单介绍一下这两种方法。 1.用字符数组来存放一个字符串。 1.1 可以通过数组名和下标来引用字符串中的一个字符。 1.2 还可以通过数组名和格式声明符%s输出整个字符串。 具体实…...

数据结构——哈夫曼树编程,输入权值实现流程图代码

一、须知 本代码是在数据结构——哈夫曼树编程上建立的&#xff0c;使用时需将代码剪切到C等软件中。需要输入权值方可实现流程图&#xff0c;但是还需要按照编程换算出的结果自己用笔画出流程图。 下面将代码粘贴到文章中&#xff0c;同时举一个例子&#xff1a;二、代…...

【MySQL】 事务

&#x1f60a;&#x1f60a;作者简介&#x1f60a;&#x1f60a; &#xff1a; 大家好&#xff0c;我是南瓜籽&#xff0c;一个在校大二学生&#xff0c;我将会持续分享Java相关知识。 &#x1f389;&#x1f389;个人主页&#x1f389;&#x1f389; &#xff1a; 南瓜籽的主页…...

Java测试——selenium常见操作(2)

这篇博客继续讲解一些selenium的常见操作 selenium的下载与准备工作请看之前的博客&#xff1a;Java测试——selenium的安装与使用教程 先创建驱动 ChromeDriver driver new ChromeDriver();等待操作 我们上一篇博客讲到&#xff0c;有些时候代码执行过快&#xff0c;页面…...

【三维点云】01-激光雷达原理与应用

文章目录内容概要1 激光雷达原理1.1 什么是激光雷达&#xff1f;1.2 激光雷达原理1.3 激光雷达分类三角法TOF法脉冲间隔测量法幅度调制的相位测量法相干法激光雷达用途2 激光雷达安装、标定与同步2.1 激光雷达安装方式考虑因素2.2 激光雷达点云用途2.3 数据融合多激光雷达数据融…...

自动驾驶感知——物体检测与跟踪算法|4D毫米波雷达

文章目录1. 物体检测与跟踪算法1.1 DBSCAN1.2 卡尔曼滤波2. 毫米波雷达公开数据库的未来发展方向3. 4D毫米波雷达特点及发展趋势3.1 4D毫米波雷达特点3.1.1 FMCW雷达角度分辨率3.1.2 MIMO ( Multiple Input Multiple Output)技术3.2 4D毫米波雷达发展趋势3.2.1 芯片级联3.2.2 专…...

C语言(内联函数(C99)和_Noreturn)

1.内联函数 通常&#xff0c;函数调用都有一定的开销&#xff0c;因为函数的调用过程包含建立调用&#xff0c;传递参数&#xff0c;跳转到函数代码并返回。而使用宏是代码内联&#xff0c;可以避开这样的开销。 内联函数&#xff1a;使用内联diamagnetic代替函数调用。把函数…...

图卷积神经网络(GCN)理解与tensorflow2.0 代码实现 附完整代码

图(Graph),一般用 $G=(V,E)$ 表示,这里的$V$是图中节点的集合,$E$ 为边的集合,节点的个数用$N$表示。在一个图中,有三个比较重要的矩阵: 特征矩阵$X$:维度为 $N\times D$ ,表示图中有 N 个节点,每个节点的特征个数是 D。邻居矩阵$A$:维度为 $N\times N$ ,表示图中 N…...

模电学习6. 常用的三极管放大电路

模电学习6. 常用的三极管放大电路一、判断三极管的工作状态1. 正偏与反偏的概念2. 工作状态的简单判断二、三种重要的放大电路1. 共射电路2. 共集电极放大电路3. 共基极放大电路一、判断三极管的工作状态 1. 正偏与反偏的概念 晶体管分P区和N区&#xff0c; 当P区电压大于N区…...

Lesson 6.6 多分类评估指标的 macro 和 weighted 过程 Lesson 6.7 GridSearchCV 的进阶使用方法

文章目录一、多分类评估指标的 macro 和 weighted 过程1. 多分类 F1-Score 评估指标2. 多分类 ROC-AUC 评估指标二、借助机器学习流构建全域参数搜索空间三、优化评估指标选取1. 高级评估指标的选用方法2. 同时输入多组评估指标四、优化后建模流程在正式讨论关于网格搜索的进阶…...

基于 Python 实时图像获取及处理软件图像获取;图像处理;人脸识别设计 计算机毕设 附完整代码+论文 +报告

界面结果:图像获取;图像处理;人脸识别 程序结构设计 图形用户界面设计与程序结构设计是互为表里的。或者说,程序结构设计是软件设计最本质、最核心的内容。徒有界面而内部逻辑结构混乱的软件一无是处。 Windows 操作系统是一款图形化的操作系统,相比于早期的计算机使用的命…...

前后端RSA互相加解密、加签验签、密钥对生成(Java)

目录一、序言二、关于PKCS#1和PKCS#8格式密钥1、简介2、区别二、关于JSEncrypt三、关于jsrsasign四、前端RSA加解密、加验签示例1、相关依赖2、cryptoUtils工具类封装3、测试用例五、Java后端RSA加解密、加验签1、CryptoUtils工具类封装2、测试用例六、前后端加解密、加验签交互…...

基于Java+SpringBoot+Vue前后端分离学生宿舍管理系统设计与实现

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建、毕业项目实战、项目定制✌ 博主作品&#xff1a;《微服务实战》专栏是本人的实战经验总结&#xff0c;《S…...

前端高频面试题—JavaScript篇(二)

&#x1f4bb;前端高频面试题—JavaScript篇&#xff08;二&#xff09; &#x1f3e0;专栏&#xff1a;前端面试题 &#x1f440;个人主页&#xff1a;繁星学编程&#x1f341; &#x1f9d1;个人简介&#xff1a;一个不断提高自我的平凡人&#x1f680; &#x1f50a;分享方向…...

【微信小游戏开发笔记】第二节:Cocos开发界面常用功能简介

Cocos开发界面常用功能简介 本章只介绍微信小游戏开发时常用的功能&#xff0c;其他功能不常用&#xff0c;写多了记不住&#xff08;其实是懒 -_-!&#xff09;&#xff1a; 层级管理器&#xff0c;用于操作各个节点。资源管理器&#xff0c;用于操作各种文件资源。场景编辑…...

3分钟,学会了一个调试CSS的小妙招

Ⅰ. 作用 用于调试CSS , 比控制台添更加方便&#xff0c;不需要寻找 &#xff1b;边添加样式&#xff0c;边可以查看效果&#xff0c;适合初学者对CSS 的理解和学习&#xff1b; Ⅱ. 快速实现&#xff08;两边&#xff09; ① 显示这个样式眶 给 head 和 style 标签添加一个…...

【项目精选】基于jsp的健身俱乐部会员系统

点击下载源码 社会可行性 随着社会的发展和计算机技术的进步&#xff0c;人类越来越依赖于信息化的管理系统&#xff0c;这种系统能更加方便的获得信息以及处理信息。人们都改变了过去的思维&#xff0c;开始走向了互联网的时代&#xff0c;在 可行性小结 本章在技术可行性上…...

wordpress建站企业站/关键词有哪几种

1.查询一张表&#xff1a;select * from 表名&#xff1b;2.查询指定字段&#xff1a;select 字段1&#xff0c;字段2&#xff0c;字段3....from 表名&#xff1b;3.where条件查询&#xff1a;select 字段1&#xff0c;字段2&#xff0c;字段3 frome 表名 where 条件表达式&…...

wordpress查询数据库插件/制作网站要花多少钱

RasterIO的用法参考&#xff1a; 在MFC项目中添加一个对话框DlgFastShow&#xff0c;添加一个按钮 &#xff0c;在头文件中添加如下代码&#xff1a; 1 public: 2 GDALDataset* m_pDataset; 3 double m_dScale; //现有图框与图像的比值 4 5 int m_iMi…...

平面设计可以做网站/专业拓客团队怎么收费

题目描述 返回参数 a 和 b 的逻辑且运算结果 示例1 输入 false, true 输出 false 代码 function and(a, b) {return a && b; } 运行环境&#xff1a;JavaScript 运行时间&#xff1a;1058ms 占用内存&#xff1a;77832KB...

拉新接单网/贵阳百度seo点击软件

生成树协议是一种二层管理协议&#xff0c;它通过有选择性地阻塞网络冗余链路来达到消除网络二层环路的目的&#xff0c;同时具备链路的备份功能。 54ne.com生成树协议和其他协议一样&#xff0c;是随着网络的不断发展而不断更新换代的。“生成树协议”是一个广义的概念&#x…...

网站内做链接/关键一招

线段树解决的问题 假设给定一个数组&#xff0c;长度为1000&#xff0c;要求 1~200 范围上所有的数都统一增加6&#xff1b;7 ~ 375 范围上的所有数都更新为4&#xff1b;查询3 ~ 999 范围上所有的数的累加和。 所以&#xff0c;线段树解决的问题就是&#xff1a; 1.区间上的…...

wordpress+php允许上传文件大小/怎么给公司做网站

1、GUI偏重功能和页面测试&#xff0c;应使用工具如Selenium、QTP&#xff08;UFT&#xff09;来完成自动化测试。 Selenium简介&#xff1a; 1.0核心是Selenium RC&#xff0c;RC Server Client Lib组成&#xff0c;RCServer包括Launcher、Http Proxy、Selenium Core三个部…...