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

JWT使用教程

目录

  • JWT (JSON Web Token)
    • 1. JWT简介
      • (1) 什么是JWT
      • (2) JWT有什么用
      • (3) JWT认证方式
    • 2. JWT的组成部分
    • 3. 签名的目的
    • 4. JWT与Token的区别
    • 5 JWT的优势
    • 6 JJWT签发与验证token
      • (1) 引入依赖
      • (2) 创建 Token
      • (3) 解析Token
      • (4) 设置过期时间
      • (5) 自定义claims
    • 7. JWT自定义工具类

JWT (JSON Web Token)

1. JWT简介

(1) 什么是JWT

JWT是一种基于 Token 的认证授权机制.
JWT (JSON Web Token) 是目前最流行的跨域认证解决方案,是一种基于 Token 的认证授权机制。从 JWT 的全称可以看出,JWT 本身也是 Token,一种规范化之后的 JSON 结构的 Token。

(2) JWT有什么用

JWT最常见的场景就是授权认证,用户登录之后,后续的每个请求都将包含JWT, 系统在每次处理用户请求之前,都要先进行JWT的安全校验,通过校验之后才能进行接下来的操作。

(3) JWT认证方式

  • JWT通过数字签名的方式,以JSON对象为载体,在用户和服务器之间传递安全可靠的信息.

image.png

  1. 首先,前端通过Web表单将自己的用户名和密码发送到后端的接口。这一过程一般是一个HTTP POST请求。建议的方式是通过SSL加密的传输(https协议),从而避免敏感信息被嗅探。
  2. 后端核对用户名和密码成功后,将用户的id等其他信息作为JWT Payload(负载),将其与头部分别进行Base64编码拼接后签名,形成一个JWT(Token)。形成的JWT就是一个形同lll.zzz.xxx的字符串。 token head.payload.singurater
  3. 后端将JWT字符串作为登录成功的返回结果返回给前端。前端可以将返回的结果保存在localStorage或sessionStorage上,退出登录时前端删除保存的JWT即可。
  4. 前端在每次请求时将JWT放入HTTP Header中的Authorization位。(解决XSS和XSRF问题) HEADER
  5. 后端检查是否存在,如存在验证JWT的有效性。例如,检查签名是否正确;检查Token是否过期;检查Token的接收方是否是自己(可选)。
  6. 验证通过后后端使用JWT中包含的用户信息进行其他逻辑操作,返回相应结果。

2. JWT的组成部分

头部(Header)

  • 描述 JWT 的元数据,定义了生成签名的算法以及 Token 的类型。
 {"typ":"JWT","alg":"HS256"}//typ(Type):令牌类型,也就是 JWT。//alg(Algorithm) :签名算法,比如 HS256。

JWT签名算法中,一般有两个选择,一个采用HS256,另外一个就是采用RS256

进行BASE64编码https://base64.us/,编码后的字符串如下:eyJhbGciOiJIUzI1NiJ9

image.png

载荷(payload)

载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分

 {"sub":"1234567890","name":"John Doe","admin":true}

将上面的JSON数据进行base64编码,得到Jwt第二部分: eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

image.png

字段说明,下面的字段都是由 JWT的标准所定义的

 iss: jwt签发者sub: jwt所面向的用户aud: 接收jwt的一方exp: jwt的过期时间,这个过期时间必须要大于签发时间nbf: 定义在什么时间之前,该jwt都是不可用的.iat: jwt的签发时间jti: jwt的唯一身份标识,主要用来作为一次性token。

签名(signature)

服务器通过 Payload、Header 和一个密钥(Secret) 使用 Header 里面指定的签名算法(默认是 HMAC SHA256)生成。

Signature 部分是对前两部分的签名,作用是防止 Token(主要是 payload) 被篡改。

这个签名的生成需要用到:

  • Header + Payload。
  • 存放在服务端的密钥(一定不要泄露出去)。
  • 签名算法。

例如,如果要使用HMAC SHA256算法,则将通过以下方式创建签名:

 String encodeString = base64UrlEncode(header) + "." + base64UrlEncode(payload);String secret = HMACSHA256(encodeString,secret);

签名用于验证消息在此过程中没有更改,并且对于使用私钥进行签名的令牌,它还可以验证JWT的发送者是它所说的真实身份。

注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。

3. 签名的目的

最后一步签名的过程,实际上是对头部以及载荷内容进行签名。

image.png

一般而言,加密算法对于不同的输入产生的输出总是不一样的。对于两个不同的输入,产生同样的输出的概率极其地小(有可能比我成世界首富的概率还小)。所以,我们就把“不一样的输入产生不一样的输出”当做必然事件来看待吧。

所以,如果有人对头部以及载荷的内容解码之后进行修改,再进行编码的话,那么新的头部和载荷的签名和之前的签名就将是不一样的。而且,如果不知道服务器加密的时候用的密钥的话,得出来的签名也一定会是不一样的。

服务器应用在接受到JWT后,会首先对头部和载荷的内容用同一算法再次签名。那么服务器应用是怎么知道我们用的是哪一种算法呢?别忘了,我们在JWT的头部中已经用** alg字段指明了我们的加密算法了。

如果服务器应用对头部和载荷再次以同样方法签名之后发现,自己计算出来的签名和接受到的签名不一样,那么就说明这个Token的内容被别人动过的,我们应该拒绝这个Token,返回一个HTTP 401 Unauthorized响应。

image.png

4. JWT与Token的区别

Token 和 JWT (JSON Web Token) 都是用来在客户端和服务器之间传递身份验证信息的一种方式。但是它们之间有一些区别。

  • Token 是一个通用术词,可以指代任何用来表示身份的字符串。它可以是任何形式的字符串,并不一定是 JWT。
  • JWT 是一种特殊的 Token,它是一个 JSON 对象,被编码成字符串并使用秘密密钥进行签名。JWT 可以用来在身份提供者和服务提供者之间安全地传递身份信息,因为它可以被加密,并且只有拥有秘密密钥的方能解密。

总的来说,JWT 是一种特殊的 Token,它具有更强的安全性和可靠性。

5 JWT的优势

  • 简洁(Compact): 可以通过URL,POST参数或者在HTTP header发送,因为数据量小,传输速度也很快
  • 自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库
  • 因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持
  • 不需要在服务端保存会话信息,特别适用于分布式微服务。

6 JJWT签发与验证token

使用jjwt实现jwt的签发和解析获取payload中的数据.

JJWT是一个提供端到端的JWT创建和验证的Java库。永远免费和开源(Apache License,版本2.0)。

官方文档:https://github.com/jwtk/jjwt

(1) 引入依赖

 <!--jwt依赖--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency>

(2) 创建 Token

 @SpringBootTestclass SpringsecurityExampleApplicationTests {@Testvoid contextLoads() {}@Testpublic void testJJWT(){JwtBuilder builder = Jwts.builder().setId("9527")  //设置唯一ID.setSubject("hejiayun_community")   //设置主体.setIssuedAt(new Date())    //设置签约时间.signWith(SignatureAlgorithm.HS256, "mashibing");//设置签名 使用HS256算法,并设置SecretKey//压缩成String形式,签名的JWT称为JWSString jws = builder.compact();System.out.println(jws);/*** eyJhbGciOiJIUzI1NiJ9.* eyJqdGkiOiI5NTI3Iiwic3ViIjoiaGVqaWF5dW5fY29tbXVuaXR5IiwiaWF0IjoxNjgxMTM1ODY2fQ.* ybkDJLVj1Fsi8m3agyxtyd0wxv7lHDqCWNOLN-eOxC8*/}}

运行打印结果:

 eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI5NTI3Iiwic3ViIjoiaGVqaWF5dW5fY29tbXVuaXR5IiwiaWF0IjoxNjgxMTM1ODY2fQ.ybkDJLVj1Fsi8m3agyxtyd0wxv7lHDqCWNOLN-eOxC

(3) 解析Token

我们刚才已经创建了token ,在web应用中这个操作是由服务端进行然后发给客户端,客户端在下次向服务端发送请求时需要携带这个token(这就好像是拿着一张门票一样),那服务端接到这个token 应该解析出token中的信息(例如用户id),根据这些信息查询数据库返回相应的结果。

解析JJWS的方法如下:

  1. 使用该 Jwts.parser()方法创建 JwtParserBuilder实例。
  2. setSigningKey() 与builder中签名方法signWith()对应,parser中的此方法拥有与signWith()方法相同的三种参数形式,用于设置JWT的签名key,用户后面对JWT进行解析。
  3. 最后,parseClaimsJws(String)用您的jws调用该方法,生成原始的JWS。
  4. 如果解析或签名验证失败,则整个调用将包装在try / catch块中。
 @Testpublic void parserJWT(){String JWS = "eyJhbGciOiJIUzI1NiJ9." +"eyJqdGkiOiI5NTI3Iiwic3ViIjoiaGVqaWF5dW5fY29tbXVuaXR5IiwiaWF0IjoxNjgxMTM1ODY2fQ." +"ybkDJLVj1Fsi8m3agyxtyd0wxv7lHDqCWNOLN-eOxC8";//claims = 载荷 (payload)try {Claims claims = Jwts.parser().setSigningKey("mashibing").parseClaimsJws(JWS).getBody();System.out.println(claims);} catch (Exception e) {System.out.println("Token验证失败! !");e.printStackTrace();}}

运行打印结果:

 {jti=9527, sub=hejiayun_community, iat=1681135866}iat: jwt的签发时间jti: jwt的唯一身份标识,主要用来作为一次性token。sub: jwt所面向的用户

(4) 设置过期时间

有很多时候,我们并不希望签发的token是永久生效的,所以我们可以为token添加一个过期时间。

  • 创建token 并设置过期时间
     @Testpublic void testJJWT2(){long currentTimeMillis = System.currentTimeMillis();Date expTime = new Date(currentTimeMillis);JwtBuilder builder = Jwts.builder().setId("9527")  //设置唯一ID.setSubject("hejiayun_community")   //设置主体.setIssuedAt(new Date())    //设置签约时间.setExpiration(expTime)     //设置过期时间.signWith(SignatureAlgorithm.HS256, "mashibing");//设置签名 使用HS256算法,并设置SecretKey//压缩成String形式,签名的JWT称为JWSString jws = builder.compact();System.out.println(jws);/*** eyJhbGciOiJIUzI1NiJ9.* eyJqdGkiOiI5NTI3Iiwic3ViIjoiaGVqaWF5dW5fY29tbXVuaXR5IiwiaWF0IjoxNjgxMTM3MjI0LCJleHAiOjE2ODExMzcyMjR9.* evc01MRxLjpbksbMLdVPM9sJGYGhpC3UYOfm4-0sMGE  */}
  • 解析TOKEN
 打印效果: 异常信息: JWT签名与本地计算的签名不匹配。JWT有效性不能断言,也不应该被信任Token验证失败! !io.jsonwebtoken.MalformedJwtException: JWT strings must contain exactly 2 period characters. Found: 

(5) 自定义claims

我们刚才的例子只是存储了id和subject两个信息,如果你想存储更多的信息(例如角色)可以定义自定义claims。

创建测试类,并设置测试方法:

     @Testpublic void testJJWT3(){long currentTimeMillis = System.currentTimeMillis()+100000000L;Date expTime = new Date(currentTimeMillis);JwtBuilder builder = Jwts.builder().setId("9527")  //设置唯一ID.setSubject("hejiayun_community")   //设置主体.setIssuedAt(new Date())    //设置签约时间.setExpiration(expTime)     //设置过期时间.claim("roles","admin")       //设置角色.signWith(SignatureAlgorithm.HS256, "mashibing");//设置签名 使用HS256算法,并设置SecretKey//压缩成String形式,签名的JWT称为JWSString jws = builder.compact();System.out.println(jws);/*** eyJhbGciOiJIUzI1NiJ9.* eyJqdGkiOiI5NTI3Iiwic3ViIjoiaGVqaWF5dW5fY29tbXVuaXR5IiwiaWF0IjoxNjgxMTM3MjI0LCJleHAiOjE2ODExMzcyMjR9.* evc01MRxLjpbksbMLdVPM9sJGYGhpC3UYOfm4-0sMGE*/}

解析TOKEN,打印结果

 {jti=9527, sub=hejiayun_community, iat=1681137464, exp=1681237464, roles=admin}

7. JWT自定义工具类

/*** JWT工具类*/
public class JwtUtil {//有效期为public static final Long JWT_TTL = 60 * 60 *1000L;// 60 * 60 *1000  一个小时//设置秘钥明文public static final String JWT_KEY = "pan";public static String getUUID(){String token = UUID.randomUUID().toString().replaceAll("-", "");return token;}/*** 生成jtw* @param subject token中要存放的数据(json格式)* @return*/public static String createJWT(String subject) {JwtBuilder builder = getJwtBuilder(subject, null, getUUID());// 设置过期时间return builder.compact();}/*** 生成jtw* @param subject token中要存放的数据(json格式)* @param ttlMillis token超时时间* @return*/public static String createJWT(String subject, Long ttlMillis) {JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 设置过期时间return builder.compact();}private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;SecretKey secretKey = generalKey();long nowMillis = System.currentTimeMillis();Date now = new Date(nowMillis);if(ttlMillis==null){ttlMillis=JwtUtil.JWT_TTL;}long expMillis = nowMillis + ttlMillis;Date expDate = new Date(expMillis);return Jwts.builder().setId(uuid)              //唯一的ID.setSubject(subject)   // 主题  可以是JSON数据.setIssuer("sg")     // 签发者.setIssuedAt(now)      // 签发时间.signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥.setExpiration(expDate);}/*** 创建token* @param id* @param subject* @param ttlMillis* @return*/public static String createJWT(String id, String subject, Long ttlMillis) {JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 设置过期时间return builder.compact();}public static void main(String[] args) throws Exception {String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJjYWM2ZDVhZi1mNjVlLTQ0MDAtYjcxMi0zYWEwOGIyOTIwYjQiLCJzdWIiOiJzZyIsImlzcyI6InNnIiwiaWF0IjoxNjM4MTA2NzEyLCJleHAiOjE2MzgxMTAzMTJ9.JVsSbkP94wuczb4QryQbAke3ysBDIL5ou8fWsbt_ebg";Claims claims = parseJWT(token);System.out.println(claims);}/*** 生成加密后的秘钥 secretKey* @return*/public static SecretKey generalKey() {byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");return key;}/*** 解析** @param jwt* @return* @throws Exception*/public static Claims parseJWT(String jwt) throws Exception {SecretKey secretKey = generalKey();return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();}}

相关文章:

JWT使用教程

目录 JWT (JSON Web Token)1. JWT简介(1) 什么是JWT(2) JWT有什么用(3) JWT认证方式 2. JWT的组成部分3. 签名的目的4. JWT与Token的区别5 JWT的优势6 JJWT签发与验证token(1) 引入依赖(2) 创建 Token(3) 解析Token(4) 设置过期时间(5) 自定义claims 7. JWT自定义工具类 JWT (J…...

【大模型系列篇】如何解决DeepSeek-R1结构化输出问题,使用PydanticAl和DeepSeek构建结构化Agent

今日号外&#xff1a;&#x1f525;&#x1f525;&#x1f525; DeepSeek开源周&#xff1a;炸场&#xff01;DeepSeek开源FlashMLA&#xff0c;提升GPU效率 下面我们开始今天的主题&#xff0c;deepseek官方明确表示deepseek-r1目前不支持json输出/function call&#xff0c;可…...

老旧android项目编译指南(持续更)

原因 编译了很多项目&#xff0c;找到了一些可观的解决办法 1. android studio里面的jdk版本切换 jdk版本切换在这里&#xff0c;一般安卓开发需要用到4个版本的jdk,jdk8, jdk11, jdk17, jdk21新版的android stuio是默认使用高版本的jdk,所以切换版本是很有必要的 2. 命令…...

linux中安装部署Jenkins,成功构建springboot项目详细教程

参考别人配置Jenkins的git地址为https&#xff0c;无法连上github拉取项目&#xff0c;所以本章节介绍通过配置SSH地址来连github拉取项目 目录&#xff1a; 1、springboot项目 1.1 创建名为springcloudproject的springboot项目工程 1.2 已将工程上传到github中&#xff0c;g…...

AI开发利器:Anaconda

在Python开发过程中&#xff0c;不同的项目可能会依赖不同版本的Python以及各种不同版本的库。比如&#xff0c;项目A可能依赖Python 3.8和某个特定版本的numpy、TensorFlow和PyTorch&#xff0c;而项目B可能需要Python 3.9以及另一个版本的numpy库。如果直接在系统中安装Pytho…...

java网络编程--基于TCP协议的网络编程

Scoket介绍 利用 TCP 协议进行通信的两个应用程序是有主次之分的&#xff0c; 一个是服务器程序&#xff0c;一个是客户端程序&#xff0c; 两者的功能和编写方法不太一样&#xff0c; 其中 ServerSocket 类表示 Socket 服务器端&#xff0c;Socket 类表示 Socket 客户端。 服…...

PageHelper新发现

PageHelper 背景解决reasonablepageSizeZero 背景 今天发现了一个很有趣的现象&#xff0c;接手一个很老的项目springmvc项目、使用PageHelper分页实现常见的后端接口分页功能。但是发现当页码参数大于实际的页码数时、正常不应该返回数据&#xff0c;但是目前确一直返回数据不…...

Redis 数据结构和使用详解(带示例)

Redis 支持的主要数据结构及其对应操作命令的详细解释&#xff0c;结合具体使用场景和示例&#xff1a; 1. 字符串&#xff08;String&#xff09; 用途&#xff1a;存储文本、数值或二进制数据&#xff0c;适用于缓存、计数器等。 常用命令&#xff1a; SET key value&#x…...

深度解读 Chinese CLIP 论文:开启中文视觉对比语言预训练

目录 论文概述1.论文摘要2.论文脑图3.论文创新3.1模型构建3.2训练方法3.3数据构建3.4部署优化 4.模型架构 论文解析1. 引言2. 方法2.1数据说明2.2预训练方法2.2.1模型初始化方法2.2.2两阶段预训练方法 2.3预训练细节2.3.1模型初始化2.3.2第一阶段预训练2.3.3第二阶段预训练2.3.…...

SpringBoot 2 后端通用开发模板搭建(异常处理,请求响应)

目录 一、环境准备 二、新建项目 三、整合依赖 1、MyBatis Plus 数据库操作 2、Hutool 工具库 3、Knife4j 接口文档 4、其他依赖 四、通用基础代码 1、自定义异常 2、响应包装类 3、全局异常处理器 4、请求包装类 5、全局跨域配置 补充&#xff1a;设置新建类/接…...

【Oracle专栏】sqlplus显示设置+脚本常用显示命令

Oracle相关文档&#xff0c;希望互相学习&#xff0c;共同进步 风123456789&#xff5e;-CSDN博客 1.内容概述 本文主要针对oracle 运维中常用知识点进行整理&#xff0c;包括&#xff1a; 1&#xff09;sqlplus模式下&#xff0c;为了方便查询设置相应的行宽、列宽、行数。…...

DeepSeek 助力 Vue3 开发:打造丝滑的页眉(Header)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…...

JVM线程分析详解

java线程状态&#xff1a; 初始(NEW)&#xff1a;新创建了一个线程对象&#xff0c;但还没有调用start()方法。运行(RUNNABLE)&#xff1a;Java线程中将就绪&#xff08;ready&#xff09;和运行中&#xff08;running&#xff09;两种状态笼统的称为“运行”。 线程对象创建…...

【备赛】点亮LED

LED部分的原理图 led前面有锁存器&#xff0c;这是为了防止led会受到lcd的干扰&#xff08;lcd也需要用到这些引脚&#xff09;。 每次想要对led操作&#xff0c;就需要先打开锁存器&#xff0c;再执行操作&#xff0c;最后关闭锁存器。 这里需要注意的是&#xff0c;引脚配置…...

【音视频】编解码相关概念总结

NALU RTP PS流 三者总体关系 NALU在RTP中的应用&#xff1a;视频流的RTP传输通常将NALU作为基本的单元进行传输。每个RTP包携带一个或多个NALU&#xff0c;这些NALU包含了视频编码数据。RTP协议通过其头部信息&#xff08;如时间戳、序列号等&#xff09;帮助接收端重新排列和…...

Python爬虫(四)- Selenium 安装与使用教程

文章目录 前言一、简介及安装1. Selenium 简介2. Selenium 安装 二、Selenium 基本使用1. 导入Selenium2. 启动浏览器3. 打开网页4. 获取页面标题5. 关闭浏览器6. 完整示例代码 三、Selenium WebDriver1. 简介2. 基本操作2.1 启动浏览器2.2 关闭浏览器2.3 打开网页2.4 关闭当前…...

Node.js项目启动流程以及各个模块执行顺序详解

Node.js项目启动流程以及各个模块执行顺序的问题。首先&#xff0c;我需要仔细阅读并理解我搜索到的资料&#xff0c;从中提取关键信息&#xff0c;然后综合这些信息组织成一个结构化的回答。 首先&#xff0c;根据我搜索到的资料都详细描述了Node.js的启动流程&#xff0c;涉及…...

各种类型网络安全竞赛有哪些 网络安全大赛的简称

本文是对入门学习的一些概念了解和一些常规场景记录 1.CTF&#xff08;capture the flag&#xff09;是夺旗赛的意思。 是网络安全技术人员之间进行攻防的比赛。 起源1996年DEFCON全球黑客大会&#xff0c;替代之前真实攻击的技术比拼。 (DEFCON极客大会诞生1993&#xff0c;…...

浅谈人工智能与深度学习的应用案例研究

人工智能与深度学习的应用案例研究 人工智能(AI)与深度学习技术正以惊人的速度渗透到社会生活的各个领域,从医疗健康到艺术创作,从金融风控到城市治理,其应用案例不断突破传统边界。以下是近年来具有代表性的六大应用方向及具体案例: 一、医疗健康:精准诊断与药物研发 医…...

vue2版本elementUI的table分页实现多选逻辑

1. 需求 我们需要在表格页上实现多选要求&#xff0c;该表格支持分页逻辑。 2. 认识属性 表格属性 参数说明类型可选值默认值data显示的数据array——row-key行数据的 Key&#xff0c;用来优化 Table 的渲染&#xff1b;在使用 reserve-selection 功能与显示树形数据时&…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

docker 部署发现spring.profiles.active 问题

报错&#xff1a; org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...

Vue 模板语句的数据来源

&#x1f9e9; Vue 模板语句的数据来源&#xff1a;全方位解析 Vue 模板&#xff08;<template> 部分&#xff09;中的表达式、指令绑定&#xff08;如 v-bind, v-on&#xff09;和插值&#xff08;{{ }}&#xff09;都在一个特定的作用域内求值。这个作用域由当前 组件…...

针对药品仓库的效期管理问题,如何利用WMS系统“破局”

案例&#xff1a; 某医药分销企业&#xff0c;主要经营各类药品的批发与零售。由于药品的特殊性&#xff0c;效期管理至关重要&#xff0c;但该企业一直面临效期问题的困扰。在未使用WMS系统之前&#xff0c;其药品入库、存储、出库等环节的效期管理主要依赖人工记录与检查。库…...

深入解析光敏传感技术:嵌入式仿真平台如何重塑电子工程教学

一、光敏传感技术的物理本质与系统级实现挑战 光敏电阻作为经典的光电传感器件&#xff0c;其工作原理根植于半导体材料的光电导效应。当入射光子能量超过材料带隙宽度时&#xff0c;价带电子受激发跃迁至导带&#xff0c;形成电子-空穴对&#xff0c;导致材料电导率显著提升。…...

【Java多线程从青铜到王者】单例设计模式(八)

wait和sleep的区别 我们的wait也是提供了一个还有超时时间的版本&#xff0c;sleep也是可以指定时间的&#xff0c;也就是说时间一到就会解除阻塞&#xff0c;继续执行 wait和sleep都能被提前唤醒(虽然时间还没有到也可以提前唤醒)&#xff0c;wait能被notify提前唤醒&#xf…...