有状态(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 切换…...

go的一些知识点
一.package 1.新建项目 新建一个itying文件夹,在里面使用命令 就能生成一个go项目。生成一个go.mod 2.调用别的包的代码 按照下面的目录层级生成代码 //clac.go package calcfunc Add(x, y int) int {return x y } func Sub(x, y int) int {return x - y }…...

前端 vue3 对接科大讯飞的语音在线合成API
主要的功能就是将文本转为语音,可以播放。 看了看官方提供的demo,嗯....没看懂。最后还是去网上找的。 网上提供的案例,很多都是有局限性的,我找的那个他只能读取第一段数据,剩下的不读取。 科大讯飞的接口…...

缺省参数
一、概念 在声明或定义函数时为函数的参数指定一个默认值,调用时,如果对应参数没有传参,则使用其默认值,否则使用指定的实参 void TestFunc(int a 0) {cout<<a<<endl; }int main() {TestFunc(); // 没有传参&am…...

Stable Diffusion绘画 | 来训练属于自己的模型:炼丹启动
经过前面几轮辛苦的准备工作之后,现在开始进入终篇的炼丹环节。 在「上传素材」页面,点击「开始训练」: 可以在「查看进度-进度」中,查看模型训练的整体进度: 求助!!!操作「开始训练…...

08_OpenCV文字图片绘制
import cv2 import numpy as npimg cv2.imread(image0.jpg,1) font cv2.FONT_HERSHEY_SIMPLEXcv2.rectangle(img,(500,400),(200,100),(0,255,0),20) # 1 dst 2 文字内容 3 坐标 4 5 字体大小 6 color 7 粗细 8 line type cv2.putText(img,flower,(200,50),font,1,(0,0,250)…...

【笔记】选择题笔记+数据结构笔记
文章目录 2014 41方法一先序遍历方法二 连通分量是极大连通子图 一个连通图的生成树是一个极小连通子图 无向图的邻接表中,第i个顶点的度为第i个链表中的结点数 邻接表和邻接矩阵对不同的操作各有优势。 最短路径算法: 单源最短路径 已知图G(V,E),我们…...

浅谈汽车智能座舱如何实现多通道音频
一、引言 随着汽车智能座舱的功能迭代发展,传统的 4 通道、6 通道、8 通道等音响系统难以在满足驾驶场景的需求,未来对于智能座舱音频质量和通道数会越来越高。接下来本文将浅析目前智能座舱如何实现音频功放,以及如何实现多路音频功放方案。…...

系统架构设计师教程 第13章 13.1层次式体系结构概述 笔记
13.1 层次式体系结构概述 分层式体系结构是一种最常见的架构设计方法,能有效地使设计简化,使设计的系统机构清晰,便于提高复用能力和产品维护能力。 层次式体系结构设计是将系统组成一个层次结构,每一层为上层服务,并…...

cnn突破一(先搞定三层反馈神经网络bpnet,c#实现)
惦记cnn很久了,一直搞机器视觉,走不出来,现在megauging已经实现,说明书也写了不少,该突破的突破了,该改进的也改进了,一个心病治好了,有空把人工智能在机器视觉上的延伸,…...

如何创建一个docker,给它命名,且下次重新打开它
1.创建一个新的docker并同时命名 docker run -it --name one ubuntu:18.04 /bin/bash 这时候我们已经创建了一个docker,并且命名为"one" 2.关闭当前docker exit 3.这时docker已经终止了,我们需要使用它要重新启动 docker start one 4.现在可以重新打…...