有状态(Session) VS 无状态(Token)
目录
概念
JWT
Token在项目中使用
概念
有状态和无状态服务是两种不同的服务架构,两者的不同之处在于对于服务状态的处理。
1、有状态服务
是指程序在执行过程中生成的中间数据,服务器端一般都要保存请求的相关信息,每个请求可以默认地使用以前的请求信息。示意图如下:

上图中,浏览器客户端请求后台数据,通过nginx负载均衡到3个tomcat服务器上,并且将Session信息保存在redis中,下一次客户端发送请求时,服务器检查session信息是否存在、是否有效、是否过期,检查无问题后,接受客户端请求并返回数据到客户端。此种情况为有状态,即服务端保存了客户信息(session中的信息)。
2、无状态服务。
是指容器在运行时,不在容器中保存任何数据,而将数据统一保存在容器外部。服务器端所能够处理的过程必须全部来自于请求所携带的信息,以及其他服务器端自身所保存的、并且可以被所有请求所使用的公共信息。

上图中,浏览器客户端请求后台数据时,携带了token信息,nginx负载均衡到tomcat服务器上,服务器通过解密token,判断用户的请求是否有效(用户是否登录,是否过期,token是否伪造),对真实有效的token,服务端接受客户端请求并返回数据到客户端。此种情况为无状态,即服务端没有保存客户信息。
3、有状态、无状态比较
| 特点 | 有状态 | 无状态 |
| 优点 | 服务端控制状态,方便处理 比如设置Session过期时间; 强制设置Session下线 | 无存储,简单方便 去中心化(有状态下session集中存放Redis) |
| 缺点 | 服务端存储了客户信息,增加服务器压力 | 服务器控制能力弱 |
技术趋势:新架构的项目往往采用无状态模式
JWT
JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用 JWT 在用户和服务器之间传递安全可靠的信息。一个 JWT 实际上就是一个字符串,它由三部分组成,头部、载荷与签名。前两部分需要经过 Base64 编码,后一部分通过前两部分 Base64 编码后再加密而成。
JWT组成:Header + Payload + Signature
Header:头部用于描述关于该 JWT 的最基本的信息,例如其类型以及签名所用的算法等,如{"type":"JWT","alg":"HS256"},Base64 加密header后的字符串为(JWT官网 可以验证):eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Payload:一般添加用户的相关信息或其他业务需要的必要信息,但不建议添加敏感信息,因为该部分在客户端可解密。如:{"id":"1","name":"张三","sex":"male"},Base64 加密Payload后的字符串为(JWT官网 可以验证):eyJpZCI6IjEiLCJuYW1lIjoi5byg5LiJIiwic2V4IjoibWFsZSJ9
Signature:这个部分需要 Base64 加密后的 header 和 Base64 加密后的 payload 使用 “.” 连接组成的字符串,然后通过 header 中声明的加密方式进行加盐 salt组合加密,然后就构成了 jwt 的第三部分。如:salt设置为abc,Signature字符串为:mZKsezNd5e5Q0Gi4vdeyEH3-ilxG_qEHkZp0gn7ayr0
综上,公式如下:
Token = Base64(Header).Base64(Payload).Base64(Signature)
Signature = Header指定的签名算法(Base64(header).Base64(payload),秘钥)
生成后的token信息为:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEiLCJuYW1lIjoi5byg5LiJIiwic2V4IjoibWFsZSJ9.mZKsezNd5e5Q0Gi4vdeyEH3-ilxG_qEHkZp0gn7ayr0
Token在项目中使用
使用场景:在实际开发中,用户登录成功后,后端生成 jwt 返回给前端,之后前端与后端交互时携带 jwt 信息,让后端验证 jwt 的合法性。使用步骤如下:
1、添加依赖pom.xml
主要依赖:jsonwebtoken
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.6</version><relativePath/></parent><groupId>com.gingko</groupId><artifactId>springboot</artifactId><version>0.0.1-SNAPSHOT</version><name>springboot</name><dependencies><!-- 依赖spring-web--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- springboot默认数据源(HikariCP)--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><!-- mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency><!-- 整合MyBatis --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.2</version></dependency><!-- SpringBoot 的AOP实现 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- junit 依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><!-- SpringBoot 健康检查 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><!-- lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.0</version><scope>provided</scope></dependency><!-- jwt token --><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.10.7</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.10.7</version><scope>runtime</scope></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.10.7</version><scope>runtime</scope></dependency><!-- fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.83</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.1</version><configuration><source>${maven.compiler.source}</source><target>${maven.compiler.target}</target><encoding>${project.build.sourceEncoding}</encoding></configuration></plugin></plugins></build></project>
2、token生成工具类【JWTUtils】
属性:密钥secret、token过期时间(秒)expireTimeSeconds 来自配置文件application.yml:

package com.gingko.common;import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import javax.crypto.SecretKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;@Slf4j
@RequiredArgsConstructor
@Component
public class JWTUtils {/*** 秘钥*/@Value("${JWT.secret}")private String secret;/*** 有效期,单位秒* - 默认2周*/@Value("${JWT.expireTimeSeconds}")private Long expireTimeSeconds;/*** 从token中获取claim** @param token token* @return claim*/public Claims getClaimsFromToken(String token) {try {return Jwts.parser().setSigningKey(this.secret.getBytes()).parseClaimsJws(token).getBody();} catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | IllegalArgumentException e) {log.error("token解析错误", e);throw new IllegalArgumentException("Token invalided.");}}/*** 获取token的过期时间** @param token token* @return 过期时间*/public Date getExpirationDateFromToken(String token) {return getClaimsFromToken(token).getExpiration();}/*** 判断token是否过期** @param token token* @return 已过期返回true,未过期返回false*/private Boolean isTokenExpired(String token) {Date expiration = getExpirationDateFromToken(token);return expiration.before(new Date());}/*** 计算token的过期时间** @return 过期时间*/private Date getExpirationTime() {return new Date(System.currentTimeMillis() + this.expireTimeSeconds * 1000);}/*** 为指定用户生成token** @param claims 用户信息* @return token*/public String generateToken(Map<String, Object> claims) {Date createdTime = new Date();Date expirationTime = this.getExpirationTime();byte[] keyBytes = secret.getBytes();SecretKey key = Keys.hmacShaKeyFor(keyBytes);return Jwts.builder().setClaims(claims).setIssuedAt(createdTime).setExpiration(expirationTime).signWith(key, SignatureAlgorithm.HS256).compact();}/*** 判断token是否非法** @param token token* @return 未过期返回true,否则返回false*/public Boolean validateToken(String token) {return !isTokenExpired(token);}/*** 测试类* @param args*/public static void main(String[] args) {// 1. 初始化JWTUtils jwtUtils = new JWTUtils();jwtUtils.expireTimeSeconds = 1209600L;jwtUtils.secret = "abcdefghijklmnopqrstuvwxyzgingkoabcdefghijklmnopqrstuvwxyz";// 2.设置用户信息HashMap<String, Object> objectObjectHashMap = new HashMap<>();objectObjectHashMap.put("id", "1");objectObjectHashMap.put("name", "张三");// 测试1: 生成tokenString token = jwtUtils.generateToken(objectObjectHashMap);// 会生成类似该字符串的内容:eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi5byg5LiJIiwiaWQiOiIxIiwiaWF0IjoxNzI4MDE1NzkzLCJleHAiOjE3MjkyMjUzOTN9.2aLCkg0LpoPZXMyK_VfmGHuDcZB3oLQdFQOg6nfOAnASystem.out.println("token:" + token);// 测试2: token合法且未过期,返回true,上面生成的tokenString someToken = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi5byg5LiJIiwiaWQiOiIxIiwiaWF0IjoxNzI4MDE1NzkzLCJleHAiOjE3MjkyMjUzOTN9.2aLCkg0LpoPZXMyK_VfmGHuDcZB3oLQdFQOg6nfOAnA";Boolean validateToken = jwtUtils.validateToken(someToken);System.out.println("token是否合法:" + validateToken);// 测试3: 获取用户信息Claims claims = jwtUtils.getClaimsFromToken(someToken);System.out.println("用户信息:" + claims);// 测试4: 解密Header,token的第一段(以.为边界)String encodedHeader = "eyJhbGciOiJIUzI1NiJ9";byte[] header = Base64.decodeBase64(encodedHeader.getBytes());System.out.println("header:" + new String(header));// 测试5: 解密Payload,token的第二段(以.为边界)String encodedPayload = "eyJuYW1lIjoi5byg5LiJIiwiaWQiOiIxIiwiaWF0IjoxNzI4MDE1NzkzLCJleHAiOjE3MjkyMjUzOTN9";byte[] payload = Base64.decodeBase64(encodedPayload.getBytes());System.out.println("payload:" + new String(payload));// 测试6: 这是一个被篡改的token,因此会报异常,说明JWT是安全的boolean tokenValidFlag = jwtUtils.validateToken("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi5byg5LiJIiwiaWQiOiIxIiwiaWF0IjoxNzI4MDE1NzkzLCJleHAiOjE3MjkyMjUzOTN9.C2aLCkg0LpoPZXMyK_VfmGHuDcZB3oLQdFQOg6nfOAnA");System.out.println("token被修改验证是否有效:" + tokenValidFlag);}
}
3、登录请求/toLogin
代码说明:登录成功后,返回前台token信息,前台可以保存token信息,发送其他请求时在请求的header带上token
package com.gingko.controller;import com.gingko.common.GenericWebResult;
import com.gingko.common.JWTUtils;
import com.gingko.entity.User;
import com.gingko.service.UserService;
import com.gingko.vo.req.UserLoginReq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;@RestController
@RequestMapping("user")
@Slf4j
public class UserController {@Resourceprivate UserService userService;@Resourceprivate JWTUtils jwtUtils;@PostMapping("/toLogin")public GenericWebResult toLogin(@RequestBody UserLoginReq userLoginReq) {GenericWebResult result = null;String userId = userLoginReq.getUserId();String userPassword = userLoginReq.getUserPassword();User userFromDB = this.userService.getByUserId(userId);if(userFromDB != null) {if(!userPassword.equals(userFromDB.getUserPassword())) {result = GenericWebResult.error("用户名或密码不正确");}}else {result = GenericWebResult.error("用户名或密码不正确");}//生成token并返回到前台Map<String, Object> claims = new HashMap<>();claims.put("userId",userLoginReq.getUserId());String token = jwtUtils.generateToken(claims);result = GenericWebResult.ok("登录成功",token);return result;}
}
4、配置登录拦截器
配置登录拦截器,并注册到webConfig中,拦截除登录之外的所有请求,拦截器中校验请求header中是否存在token及校验token是否合法
package com.gingko.config;import com.gingko.interceptor.LogInterceptor;
import com.gingko.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import javax.annotation.Resource;/*** web配置类,配置拦截器*/
@Configuration
public class WebConfig implements WebMvcConfigurer {@Resourceprivate LogInterceptor logInterceptor;//日志拦截器@Resourceprivate LoginInterceptor loginInterceptor;//登录拦截器@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(logInterceptor).addPathPatterns("/**").excludePathPatterns("/test/*");//测试相关的不用日志拦截registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/user/toLogin");//登录不用拦截}
}
package com.gingko.interceptor;import com.alibaba.fastjson.JSON;
import com.gingko.common.GenericWebResult;
import com.gingko.common.JWTUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;//登录拦截器,校验token是否合法
@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {@Resourceprivate JWTUtils jwtUtils;/*** 校验token是否合法* @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token = request.getHeader("token");response.setContentType("application/json");response.setCharacterEncoding("UTF-8");log.info("登录校验开始,token:{}", token);if (token == null || token.isEmpty()) {log.info("token为空,请求被拦截");response.setStatus(HttpStatus.UNAUTHORIZED.value());GenericWebResult genericWebResult = GenericWebResult.error("token为空,请求被拦截");String resultStr = JSON.toJSONString(genericWebResult);response.getWriter().write(resultStr);return false;}Boolean validateToken = null;try {validateToken = jwtUtils.validateToken(token);}catch (Exception e) {log.warn( "token无效,请求被拦截" );GenericWebResult genericWebResult = GenericWebResult.error("token无效,请求被拦截");String resultStr = JSON.toJSONString(genericWebResult);response.getWriter().write(resultStr);return false;}if(!validateToken) {log.warn( "token无效,请求被拦截" );GenericWebResult genericWebResult = GenericWebResult.error("token无效,请求被拦截");String resultStr = JSON.toJSONString(genericWebResult);response.getWriter().write(resultStr);return false;}return true;}
}
5、postman方式测试接口
假设数据库user表存在userId=thunder、密码为123456的记录

模拟其他请求,前台带上正确的token:

模拟其他请求,前台带上伪造的token:

相关文章:
有状态(Session) VS 无状态(Token)
目录 概念 JWT Token在项目中使用 概念 有状态和无状态服务是两种不同的服务架构,两者的不同之处在于对于服务状态的处理。 1、有状态服务 是指程序在执行过程中生成的中间数据,服务器端一般都要保存请求的相关信息,每个请求可以默认地使…...
天坑!Spark+Hive+Paimon+Dolphinscheduler
背景: 数据中台项目使用Spark+Hive+Paimon做湖仓底层,调度任务使用的是基于Dolphinscheduler进行二开。在做离线脚本任务开发时,在Paimon库下执行非查询类SQL报错。 INSERT报错 DELETE报错 现状: 原始逻辑为数据中台中选择的Paimon数据源,实际上在Dolphinscheduler中是…...
JAVA——IO框架
目录 一、框架 二、导入框架步骤 三、测试 一、框架 框架就是为了解决某类问题,编写的一套类、接口等。大多数框架都是第三方研发的 好处: 在框架的基础上开发,提高开发效率 框架的形式:一般是把类、接口编译成class形式,再…...
项目管理系统如何实现项目申报流程自动化?
传统的项目申报流程往往繁琐复杂,涉及众多环节和部门间的协作,不仅耗时费力,还容易因人为疏忽而导致错误或延误。随着信息技术的飞速发展,项目管理系统的出现为项目申报流程的自动化提供了可能,极大地提升了申报效率和…...
ndb9300public-ndb2excel简介
1 引言 ndb9300是一个自己定义的机载导航数据库劳作(不敢称为项目)代号,其中3表示是第3种数据库。 多年前,对在役民航客机中的某型机载导航数据库的二进制文件进行分析,弄明白它的数据结构后做了几个工具,…...
C++:const成员
const修饰成员变量,要在初始化列表中进行初始化。 const修饰成员函数,要放在函数后,称为常函数。常函数不能修改普通成员变量。 const修饰的对象,称为常对象。常对象不能修改普通成员变量,只能读取。 常对象只能使用…...
基于ROS的激光雷达点云物体检测
环境 RTX 2060(后面关于算力) ubuntu 18.04 ROS melodic (ubuntu 18.04安装ROS melodic可以参看我这篇文章ubuntu 18.04安装ROS系统) CUDA 10.0 cudnn 7.6.5 caffe cmake 3.18.0(不能低于3.12.2) opencv 3…...
大模型训练环境搭建
硬件资源说明 本教程基于GPU 3090的服务器 资源类型 型号 核心指标 CPU Intel(R) Xeon(R) Bronze 3204 CPU 1.90GHz 12核 内存 / 125Gi GPU NVIDIA GeForce RTX 3090 24G显存 注意:接下来的部分命令需要使用科学上网,需要事先配置好。 安…...
使用Java调用GeoTools实现全球国家矢量数据入库实战
目录 前言 一、相关数据介绍 1、无空间参考的数据 2、有空间参考的数据 3、空间信息表物理模型 二、全球国家空间数据入库 1、后台实体类图 2、后台实体对象关键代码 三、时空数据入库实践 1、读取无空间参考数据 2、入库成果及注意事项 四、总结 前言 在当今世界&…...
计算机毕业设计 基于Python的广东旅游数据分析系统的设计与实现 Python+Django+Vue Python爬虫 附源码 讲解 文档
🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点…...
Springboo通过http请求下载文件到服务器
这个方法将直接处理从URL下载数据并将其保存到文件的整个过程。下面是一个这样的方法示例: import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection…...
使用CSS实现酷炫加载
使用CSS实现酷炫加载 效果展示 整体页面布局 <div class"container"></div>使用JavaScript添加loading加载动画的元素 document.addEventListener("DOMContentLoaded", () > {let container document.querySelector(".container&q…...
【STM32-HAL库】AHT10温湿度传感器使用(STM32F407ZGT6配置i2c)(附带工程下载连接)
一、温湿度传感器: 温湿度传感器是一种能够检测环境中的温度和湿度,并将其转化为电信号输出的装置。它在智能家居、工业自动化、气象监测、农业等领域有着广泛的应用。 原理: 温湿度传感器通常基于不同的物理原理,以下是一些常见…...
深入理解网络通信: 长连接、短连接与WebSocket
在现代网络应用开发中,选择合适的通信方式对于应用的性能、效率和用户体验至关重要。本文将深入探讨三种常见的网络通信方式:长连接、短连接和WebSocket,分析它们的特点、区别以及适用场景。 1. 短连接 © ivwdcwso (ID: u012172506) 1.1 定义 短连接是指客户端和服务器…...
Linux·环境变量与进程地址空间
1. 命令行参数 各位可能见过main函数也是有参数的,只是我们平时写的代码都比较简单,用不到main函数的参数,下面我们看一下main函数的参数是什么又是怎么用的 我们看这样一段代码 其编译运行后的效果是这样的 我们将main函数后面的那两个参数叫…...
MYSQL 乐观锁
乐观锁是一种用于处理并发控制的策略,特别适用于读多写少的场景。在 MySQL 数据库中,乐观锁通常通过版本号或时间戳来实现。下面将详细介绍乐观锁的概念、实现方式以及在 MySQL 中的应用。 1. 乐观锁的概念 乐观锁的基本思想是:在对数据进行…...
SpringCloud入门(十二)全局过滤器和跨域
一、全局过滤器 全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。 区别在于GatewayFilter通过配置定义,处理逻辑是固定的,如果我们希望拦截请求,做自己的业务逻辑则没办法实现。而GlobalFilt…...
51单片机系列-按键检测原理
🌈个人主页:羽晨同学 💫个人格言:“成为自己未来的主人~” 独立按键是检测低电平的。 下面我们来看一张对应的电路原理图: 在这张图当中,P1,P2,P3内部都上拉了电阻,但是P0没有&am…...
基于元神操作系统实现NTFS文件操作(五)
1. 背景 本文主要介绍$Root元文件的解析。先介绍元文件的构成及各个部分的结构,然后结合上一篇博文中读取到的元文件内容,对测试磁盘中目标分区的根目录进行展示。 2. $Root元文件解析 (1)$Root元文件的结构 $Root元文件由两部…...
AutoCAD学习
AutoCAD学习 最基本操作 命令用途说明空格键确认键也可以是重复刚才的命令回车键也是确认键鼠标右键也可以选择确认LINE、L直线命令绘制直线DLI线性尺寸标注DIMLINEAR鼠标滚轮滚动放大缩小视图界面鼠标中键按住移动视图DAL对齐线性标注DIMALIGNED F8 正交模式ORTHOMODE Tab 切换…...
【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
从零开始了解数据采集(二十八)——制造业数字孪生
近年来,我国的工业领域正经历一场前所未有的数字化变革,从“双碳目标”到工业互联网平台的推广,国家政策和市场需求共同推动了制造业的升级。在这场变革中,数字孪生技术成为备受关注的关键工具,它不仅让企业“看见”设…...
Python环境安装与虚拟环境配置详解
本文档旨在为Python开发者提供一站式的环境安装与虚拟环境配置指南,适用于Windows、macOS和Linux系统。无论你是初学者还是有经验的开发者,都能在此找到适合自己的环境搭建方法和常见问题的解决方案。 快速开始 一分钟快速安装与虚拟环境配置 # macOS/…...
