Redis - Token JWT 概念解析及双token实现分布式session存储实战
Token
- 定义:令牌,访问资源接口(API)时所需要的资源凭证
一、Access Token
-
定义
:访问资源接口(API)时所需要的资源凭证,存储在客户端 -
组成
组成部分 说明 uid 用户唯一的身份标识 time 当前时间的时间戳 sign 签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串 -
验证流程
- 登录:客户端使用 username & password 请求登录
- 验证:服务端收到请求,验证 username & password
- 验证成功 → 服务端会签发一个 token 并把这个 token 发送给客户端
- 验证失败 → 登录失败
- 存储 token:客户端收到 token 以后,会把它存储起来,比如放在 cookie 里或者 localStorage 里
- 携带 token:客户端每次向服务端请求资源的时候需要携带服务端签发的 token(放在 HTTP 的 Header 中)
- 解析 token:服务端收到请求,解析客户端的 token 数据
- 验证成功 → 向客户端返回请求的数据
- 验证失败 → 拒绝请求,要求重新登录
二、Refresh Token
-
定义
:专用于刷新 access token 的 token -
功能
:减少重复登录操作,Access Token 失效时,客户端直接用 refresh token 去更新 access token,无需用户进行额外的操作 -
存储位置
:服务器的数据库 -
工作流程
JWT
一、概述
- 定义:JSON Web Token(简称 JWT),一种认证授权机制,是目前最流行的跨域认证解决方案
- 功能:实现跨域请求,用户只要在其中一个网站登录,再访问另一个网站就会自动登录(session 所有数据都保存在客户端,每次请求都发回服务器)
- 存储位置:HTTP 请求的头信息
Authorization
字段中,格式为:Authorization: Bearer <token>
- 基本格式:(Header.Payload.Signature)
二、组成部分
-
Header
-
定义:描述 JWT 的元数据(配置信息),记录令牌类型、签名算法等配置,由 Base64URL 算法转为字符串
-
示例
{"alg": "HS256", // 签名算法类型"typ": "JWT" // Token类型 }
-
-
Payload
-
定义:记录用户信息的数据(不是加密数据,不能存敏感信息)
-
示例
{"sub": "1234567890","name": "John Doe","admin": true }
-
-
Signature
-
定义:对前两部分(Header和Payload)的数字签名,用于验证消息的完整性和确保数据未被篡改。这是JWT安全性的核心保障
-
生成过程:
- 服务器持有一个密钥(secret),该密钥必须妥善保管且不能泄露
- 使用Header中指定的签名算法(默认为HMAC SHA256)
- 将编码后的Header和Payload用"."连接,再使用密钥和签名算法生成签名
-
获取签名方式:
HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
-
三、优缺点
- 优点
- JWT 是自包含的(内部包含了一些会话信息),因此减少了查询数据库的需要,有效使用 JWT,可以降低服务器查询数据库的次数
- JWT 不仅可以用于认证,也可以用于交换信息
- JWT 并不使用 Cookie 的,所以可以使用任何域名提供你的 API 服务而不需要担心跨域资源共享问题(CORS)
- 缺点
- JWT 的最大缺点:由于服务器不保存 session 状态,因此无法在使用过程中废止或更改某个 token 的权限。一旦 JWT 签发,在到期之前就会始终有效
- JWT 默认不加密,但也是可以加密(生成原始 Token 以后,可以用密钥再加密一次)
- JWT 不加密的情况下,不能将秘密数据写入 JWT
- JWT 本身包含了认证信息,一旦泄露,任何人都可以通过 JWT 获得该 JWT 的所有权限
四、工作流程
代码实现
⭐参考资料:
- https://blog.csdn.net/gitblog_09788/article/details/143407938#:~:text=1 JWT集成:生成安全的JWT令牌,用于用户身份验证。 2 Redis存储:将刷新令牌存储在Redis中,利用其高速特性进行快速校验。 3 双Token机制:,访问令牌:短寿命,用于直接的API访问。 刷新令牌:长寿命,用于在访问令牌过期时自动获取新令牌。 4 自动刷新:当访问令牌过期时,系统可自动利用有效的刷新令牌获取新的访问令牌。 5 安全性强化:通过Redis的过期策略、JWT的签名验证以及适当的访问控制,增强系统的安全性。
- GitHub - dolyw/ShiroJwt: API SpringBoot + Shiro + Java-Jwt + Redis(Jedis)
方案设计
-
方案对比
特性 JWT + Redis 白名单 JWT + Redis 存储用户会话 设计理念 无状态为主,Redis 仅辅助校验 强状态管理,Redis 为中心,JWT 辅助 Redis 存储压力 存储 jti
或少量数据,存储压力小存储完整会话信息,存储占用较高 实现复杂度 较低,直接存储 jti
和过期时间,校验简单较高,需要设计用户会话结构、处理多端登录等逻辑 主动失效能力 易实现:只需从 Redis 删除对应的 jti
即可易实现:删除会话即可失效 会话扩展能力 较弱,只适合验证 Token 是否有效 强,可以存储用户登录的扩展信息(设备、角色等) 支持多端登录 较弱,需要额外逻辑 强,天然支持多个会话实例 性能开销 性能更高(JWT 主要靠自包含验证,少量 Redis 查询) Redis 频繁交互性能略低,适合中等并发的场景 业务需求复杂度 简单业务场景 复杂业务场景 -
方案选择:JWT + Redis 存储用户会话,可以存储更多用户信息,并且没有泄露风险
校验请求
-
目标:过滤所有 token 为空或不合法的请求
-
代码(com.lloop.authcheckdemo.interceptor.UserLoginFilter)
@Slf4j @Component public class UserLoginFilter implements HandlerInterceptor {@ResourceJwtUtils jwtUtils;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {// 1. 获取tokenString token = request.getHeader(jwtUtils.header);// 2. 判断token是否有效ThrowUtils.throwIf(StringUtils.isEmpty(token), ErrorCode.NULL_ERROR, "请登录后操作!");ThrowUtils.throwIf(jwtUtils.isTokenExpired(token), ErrorCode.PARAMS_ERROR, "登录已过期!");ThrowUtils.throwIf(jwtUtils.checkBlacklist(token), ErrorCode.PARAMS_ERROR, "用户已被禁止登录!");// 3. token有效 => 记录登录用户信息UserTokenInfo userTokenInfo = jwtUtils.getUserInfoToken(token);ThrowUtils.throwIf(ObjectUtils.isEmpty(userTokenInfo), ErrorCode.NULL_ERROR, "对不起,身份认证出现错误,请重新登录...");UserHolder.saveUser(userTokenInfo);return true;}/*** 移除用户信息,防止内存溢出* @param request* @param response* @param handler* @param ex* @throws Exception*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {UserHolder.removeUser();}}
注册拦截器
-
目标:将校验请求的拦截器注册到项目中
-
注意:只需要匹配 controller 的路径部分,server.servlet.context-path 不用管
-
代码
@Configuration public class WebConfig implements WebMvcConfigurer {@Resourceprivate UserLoginFilter userLoginFilter;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(userLoginFilter).addPathPatterns("/**").excludePathPatterns("/login", "/register");}}
创建用户信息类
-
目标:解析用户token中存储的信息,存入 UserHolder 中供 Controller 调用
-
代码
@Data public class UserTokenInfo {/*** ID,唯一*/private Long id;/*** 账号*/private String account;/*** 用户昵称*/private String username;/*** 用户角色 0 - 普通用户 1 - 管理员*/private Integer role;}
创建JWT工具类
-
目标:创建、校验、解析 token
-
代码
@Data @Component public class JwtUtils {@Value("${jwt.secret}")public String secret;@Value("${jwt.header}")public String header;@Value("${jwt.expire.accessToken}")public Integer accessTokenExpire;@Value("${jwt.expire.refreshToken}")public Integer refreshTokenExpire;@ResourceRedisUtils redisUtils;private static final Gson gson = new Gson();/*** 获取用户信息** @param token* @return*/public UserTokenInfo getUserInfoToken(String token) {String subject = getTokenClaim(token).getSubject();UserTokenInfo userTokenInfo = gson.fromJson(subject, UserTokenInfo.class);return userTokenInfo;}/*** 获取 token 中注册信息** @param token* @return*/public Claims getTokenClaim(String token) {try {return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();} catch (Exception e) {return null;}}}
相关文章:
Redis - Token JWT 概念解析及双token实现分布式session存储实战
Token 定义:令牌,访问资源接口(API)时所需要的资源凭证 一、Access Token 定义:访问资源接口(API)时所需要的资源凭证,存储在客户端 组成 组成部分说明uid用户唯一的身份标识time…...
QT中使用OpenGL function
1.前言 QT做界面编程很方便,QTOpenGL的使用也很方便,因为QT对原生的OpenGL API进行了面向对象化的封装。 如: 函数:initializeOpenGLFunctions()...... 类:QOpenGLVertexArrayObject、QOpenGLBuffer、QOpenGLShader…...
STM32-笔记18-呼吸灯
1、实验目的 使用定时器 4 通道 3 生成 PWM 波控制 LED1 ,实现呼吸灯效果。 频率:2kHz,PSC71,ARR499 利用定时器溢出公式 周期等于频率的倒数。故Tout 1/2KHZ;Ft 72MHZ PSC71(喜欢设置成Ft的倍数&…...
MAC M4安装QT使用国内镜像源在线安装
MAC M4安装QT使用国内镜像源在线安装 一、下载安装包1. 访问[https://www.qt.io/](https://www.qt.io/)下载在线安装包2. 下载结果 二、创建QT账户,安装的时候需要三、安装1. 终端打开安装包2. 指定安装源3. 运行安装完的QT 一、下载安装包 1. 访问https://www.qt.…...
go语言中zero框架项目日志收集与配置
在 GoZero 项目中,日志收集和配置是非常重要的,尤其是在分布式系统中,日志可以帮助开发人员追踪和排查问题。GoZero 提供了灵活的日志系统,能够方便地进行日志的配置和管理。 以下是如何在 GoZero 项目中进行日志收集与配置的基本…...
springboot496基于java手机销售网站设计和实现(论文+源码)_kaic
摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本手机销售网站就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息&am…...
iClient3D for Cesium在Vue中快速实现场景卷帘
作者:gaogy 1、背景 iClient3D for Cesium是由SuperMap提供的一个前端3D地图客户端,提供了丰富的功能与接口,使得开发者能够在Web应用中快速集成并展现3D地理信息。而在Vue框架中集成iClient3D,不仅可以利用Vue的响应式特性提高开…...
Elasticsearch-索引的批量操作
索引的批量操作 批量查询和批量增删改 批量查询 #批量查询 GET product/_search GET /_mget {"docs": [{"_index": "product","_id": 2},{"_index": "product","_id": 3}] }GET product/_mget {"…...
TVS二极管选型【EMC】
TVS器件并联在电路中,当电路正常工作时,他处于截止状态(高阻态),不影响线路正常工作,当线路处于异常过压并达到其击穿电压时,他迅速由高阻态变为低阻态,给瞬间电流提供一个低阻抗导通…...
反编译APK获取xml资源
第一步去官网下载 jar 包 最新的即可 apktool官网下载地址 下载好重命名一下 改成 apktool.jar 第二步将你的 apk 和 jar 包放在同一个文件夹下面 第三步在该文件夹下打开 命令行 并输入 java -jar apktool.jar d 测试.apk回车后会正在解析 解析完成后,文件夹下…...
C++ 设计模式:装饰模式(Decorator Pattern)
链接:C 设计模式 链接:C 设计模式 - 桥接模式 装饰模式(Decorator Pattern)是一种结构型设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。装饰模式通过创建一个装饰类来包装原始类&…...
排序算法之快速排序、归并排序
目录 快速排序归并排序的意义 快速排序 思维步骤 具体思想 测试样例解释 代码实现 归并排序 思维步骤 具体思想 测试样例解释 代码实现 快速排序归并排序的意义 快速排序和归并排序不仅仅是一种方法,更重要的是其作为一种算法而节省时间,在…...
一文读懂变分自编码(VAE)
一文读懂变分自编码(VAE) 概述 变分自编码器(Variational Autoencoder, VAE)是一种生成模型,用于学习数据的潜在表示并生成与原始数据分布相似的新数据。它是一种概率模型,通过结合深度学习和变分推断的思想,解决了传…...
【每日学点鸿蒙知识】webview性能优化、taskpool、热更新、Navigation问题、调试时每次都卸载重装问题
1、HarmonyOS webview页面第二次,第三次打开感觉和第一次打开速度差不多,有优化吗,或者有没有webview秒开方案之类的? 目前没有webview秒开的方案,针对web场景的优化参考一下文档:https://developer.huawe…...
周记-唐纳德的《计算机程序设计艺术》
用代码生成代码 开发一个协议,字段有些多,每个字段是QT的属性,需要写Q_PROPERTY,一个一个编辑的话比较繁琐,耗费时间。后来就用代码生成了头文件和源文件,get和set还有signal函数,内容基本都是…...
AR 模型的功率谱
功率谱密度(Power Spectral Density, PSD)的表达式是从信号的自相关函数和系统的频率响应推导出来的,特别是对于 AR(Auto-Regressive,自回归)模型。以下是推导的过程: 1. AR 模型的定义…...
抖音小程序登录(前端通过tt.login获取code换取openId)
抖音小程序登录 抖音开放平台小程序登录: https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/develop/tutorial/basic-ability/microapp-login 前端(通过tt.login获取code) 流程 静默登录依赖小程序 API tt.login,把tt.loginsuccess 回调…...
Linux 更改Jenkins使用其他账户启动
Linux 更改Jenkins使用其他账户启动 步骤一:修改 Jenkins 配置文件1. 编辑 Jenkins 的 systemd 服务文件:2. 在编辑器中添加以下内容:3. 保存并退出编辑器 步骤二:更改 Jenkins 目录的权限步骤三:重新加载 systemd 配置…...
117.【C语言】数据结构之排序(选择排序)
目录 1.知识回顾 2.分析 设想的思路 代码 执行结果 编辑 错误排查和修复 详细分析出错点 执行结果 3.正确的思路 4.其他问题 1.知识回顾 参见42.5【C语言】选择排序代码 点我跳转 2.分析 知识回顾里所提到的文章的选择排序一次循环只比一个数字,和本文接下来要…...
读书系列2024
认知类 1、《人生没有太晚的开始》: 作者摩西奶奶。 书中经典语录:“与其着急忙慌地不知从何开始,不如一切都慢慢来,开始并坚持了,总会有结果的那一天。喜欢一件事,你就慢慢去做吧。” 2、《忏悔录》托尔…...
如何快速又安全的实现端口转发【Windows MAC linux通用】
背景 有很多程序是在虚拟机上运行的,返回的url 又是127.0.0.1。在个人电脑上调试需要解决这个问题。端口转发是一个不错的方法 可能的解决办法: 1.修改程序,返回虚拟机的ip (要改代码,换虚拟机还要再改代码…...
OpenGL变换矩阵和输入控制
在前面的文章当中我们已经成功播放了动画,让我们的角色动了起来,这一切变得比较有意思了起来。不过我们发现,角色虽然说是动了起来,不过只是在不停地原地踏步而已,而且我们也没有办法通过键盘来控制这个角色来进行移动…...
51单片机学习笔记——找不到REG52.H头文件,点亮一个LED
创建工程 将STC型号导入keil并使用 STC可以从官网下载,也可我这的网盘: 链接:https://pan.baidu.com/s/1bO85DPN3IFaXGhiKSwyOrA?pwd7f4h 提取码:7f4h 打开STC,选择“keil仿真设置”,选择“添加型号和头…...
07 基于OpenAMP的核间通信方案
引言 ZYNQ7020有两个CPU核心,这两个核心可以采用SMP或AMP方式进行调度,当采用AMP方式进行调度时核0和核1可以运行不同的操作系统,如核0运行Linux系统,提供有些复杂的用户交互工作,核1运行实时操作系统,对设…...
Ubuntu升级ssh版本到9.8
方案一:实测只有8.9有漏洞不推荐 1、更新软件包列表 sudo apt update 2、查找可用版本 apt-cache policy openssh-server 3、 选择版本 sudo apt install openssh-server1:9.8p1-<具体版本号> 4、 重启 sudo systemctl restart ssh 5、验证版本 /usr/sbin/ss…...
git设置项目远程仓库指向github的一个仓库
要将你的Git项目设置为指向GitHub上的远程仓库,你需要执行以下步骤: 创建GitHub仓库: 登录到你的GitHub账户。点击右上角的 “” 号,选择 “New repository” 创建一个新的仓库。填写仓库的名称,可以添加描述ÿ…...
【实战示例】面向对象的需求建模
前言 博主准备写一个以面向对象为核心思想的软件需求建模、领域建模的系列,总结一整套可落地的DDD的打法,前面几篇文章论述了如何进行面向对象的需求建模,本文将以一个简单的购物商城的需求来演示如何进行面向对象的需求建模。 面向对象的需…...
平方数的判断不用sqrt()函数
//判断一个数是不是平方数,13…(2*m-1)m*mn #include<stdio.h> int main(){ int n; scanf("%d",&n); int i; for(i1;n>0;i2){ nn-1; } if(n0){ printf("YES!\n"); …...
node.js之---回调函数
什么是回调函数? 为什么会有回调函数? 回调函数的特性 回调函数的应用场景 怎么解决回调地狱 什么是回调函数? 回调函数是一个函数,他作为参数传递给另外一个函数,并且会在另外一个函数执行完毕之后被调用&#…...
浏览器http缓存问题
一、什么是浏览器缓存 浏览器将请求过的资源(html、js、css、img)等,根据缓存机制,拷贝一份副本存储在浏览器的内存或者磁盘上。如果下一次请求的url相同时则根据缓存机制决定是读取内存或者磁盘上的数据还是去服务器请求资源文件…...
编写一个简单的引导加载程序(bootloader)
编写一个简单的引导加载程序(bootloader)通常用于嵌入式系统或自定义操作系统。这里,我将为你提供一个基于x86架构的简单汇编语言 bootloader 示例。这个 bootloader 将会在启动时打印一条消息到屏幕上。 使用 NASM 汇编器来编写这个 bootlo…...
Three.js 字体
在 Three.js 中,我们可以通过 FontLoader 加载字体,并结合 TextGeometry 创建 3D 文本。加载字体是因为字体文件包含了字体的几何信息,例如字体的形状、大小、粗细等,而 TextGeometry 则是根据字体信息生成 3D 文本的几何体。 在…...
Jenkins 构建流水线
在 Linux 系统上安装 Jenkins 服务,以及配置自动化构建项目 前置准备环境:docker、docker-compose、jdk、maven 一、环境搭建 1. Jenkins 安装 (1)拉取镜像 # 安装镜像包,默认安装最新版本 docker pull jenkins/jen…...
ES 磁盘使用率检查及处理方法
文章目录 1. 检查原因2. 检查方法3. 处理方法3.1 清理数据3.2 再次检查磁盘使用率 1. 检查原因 磁盘使用率在 85%以下,ES 可正常运行,达到 85%及以上会影响 PEIM 数据存储。 在 ES 磁盘分配分片控制策略中,为了保护数据节点的安全࿰…...
【回溯】LeetCode经典题目总结:组合、排列、子集、分割、N皇后、单词搜索
回溯 组合问题组合总和全排列子集分割回文串N皇后电话号码的字母组合单词搜索括号生成 组合问题 给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。 示例: 输入: n 4, k 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ] 树形结构࿱…...
uniapp开发小程序内嵌h5页面,video视频两边有细小黑色边框
1.问题如图 2.原因分析 是否为设置上述属性呢? 设置了,但是仍然有黑边。经过选中页面元素分析后,判断video元素本身就有这种特点,就是视频资源无法完全铺满元素容器。 3.解决方案...
Ubuntu meson使用
一 下载pip3 ,使用pip3下载 meson sudo apt install python3 sudo apt install python3-pip二 下载 nanjia sudo apt-get install ninja-build三 测试 meson 使用 1 同一个目录下创建两个文件 main.c #include<stdio.h> int main() {printf("meson t…...
实用技巧:关于 AD修改原理图库如何同步更新到有原理图 的解决方法
若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/144738332 长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV…...
算法排序算法
文章目录 快速排序[leetcode 215数组中的第K个最大元素](https://leetcode.cn/problems/kth-largest-element-in-an-array/)分析题解快速排序 桶排序[leetcode 347 前K个高频元素](https://leetcode.cn/problems/top-k-frequent-elements/)分析题解 快速排序 leetcode 215数组…...
植物大战僵尸杂交版3.0.2版本
更新内容 植物大战僵尸杂交版3.0.2版本的更新内容如下: • 修复BUG: • 游戏内贴图错乱的BUG。 • 无尽模式卡死的BUG。 • 卡牌模仿者的一系列BUG。 • 干扰车可能同时出现多辆的BUG。 • 冒险模式部分关卡无法过关的BUG。 • 新增内容…...
Kafka数据迁移全解析:同集群和跨集群
文章目录 一、同集群迁移二、跨集群迁移 Kafka两种迁移场景,分别是同集群数据迁移、跨集群数据迁移。 一、同集群迁移 应用场景: broker 迁移 主要使用的场景是broker 上线,下线,或者扩容等.基于同一套zookeeper的操作。 实践: 将需要新添加…...
自动化测试模型(一)
8.8.1 自动化测试模型概述 在自动化测试运用于测试工作的过程中,测试人员根据不同自动化测试工具、测试框架等所进行的测试活动进行了抽象,总结出线性测试、模块化驱动测试、数据驱动测试和关键字驱动测试这4种自动化测试模型。 线性测试 首先&#…...
selenium(三)
总结 一、web基础 html、dom对象、javascript基本语法二、元素定位: find_element(定位方式) 八大定位方式:id、name、class、tag_name、class_name、link_text、partial_link_text、xpath、cssxpath://标签名[属性名值 and/or 属性名值]//标签名[tex…...
7.若依参数设置、通知公告、日志管理
参数设置 对系统中的参数进行动态维护。 关闭验证码校验功能 打开页面注册功能 需要修改前端页面代码 通知公告 促进组织内部信息传递 若依只提供了一个半成品,只实现了管理员可以添加通知公告。 日志管理 追踪用户行为和系统运行状况。 登录日志 和操作日志…...
vsftpd虚拟用户及其权限配置
目录 一、应用场景二、配置过程1、安装软件2、新建本地用户3、修改vsftpd的配置文件4、新建虚拟用户目录5、配置虚拟用户(1)创建虚拟用户列表文件(2)生成虚拟用户数据库(3)配置pam认证(4&#…...
Android使用辅助服务AccessibilityService实现自动化任务
Android 辅助服务(AccessibilityService)旨在帮助具有视觉、身体或年龄相关限制的用户更轻松地使用 Android 设备和应用。通过辅助服务,可以将一些人工操作自动化,从而解放用户的双手。 因此我们可以使用它来实现一些自动化任务&a…...
brupsuite的基础用法常用模块(1)
proxy模块: Options: 设置代理端口,默认为8080端口,若8080端口被占用可在该界面更改代理端口. HTTP history: 拦截的历史请求,右键可做更多操作,很多操作与其他模块有关。(清除历史的话右键选择clear p…...
基础的基础之 pillow与opencv相比的特点与优缺点比较
Pillow 和 OpenCV 都是人工智能图像处理的必不可少的常用库,但它们有各自的特点和适用场景。 以下是它们的主要特点、优缺点以及适用场景的对比: 1. Pillow(Python Imaging Library) Pillow 是一个轻量级的图像处理库࿰…...
代码随想录算法训练营第51期第32天 | 理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯
理论基础 动态规划:dp,每一个状态都是由上个状态推导出来的,因为我是先写完三道题再看理论的,所以有点感概; 确定dp数组(dp table)以及下标的含义确定递推公式dp数组如何初始化确定遍历顺序举…...
街景主观感知1:街景图片两两对比程序
目录 1、为什么不用place pluse 2.0数据集?2、街景主观感知两两对比程序2.1 总框架2.2 两两对比程序流程2.2.1 准备数据集(即街景图片)2.2.2 数据集采用组合的思想构建排列前的两两对比csv2.2.3 两两对比程序使用 3、其他数据处理/程序/指导&…...