SpringCloudAlibaba技术栈-Higress
1、什么是Higress?
云原生网关,干啥的?用通俗易懂的话来说,微服务架构下Higress 就像是一个智能的“交通警察”,它站在你的网络世界里,负责指挥和调度所有进出的“车辆”(也就是数据流量)。它的主要工作包括:
指挥交通:它告诉数据应该走哪条路,去哪个服务(就像告诉你去某个地方应该走哪条路)。
保障安全:它检查进出的数据,防止坏人(比如黑客)进来搞破坏,保护你的网络世界安全。
维护秩序:如果有太多数据同时涌进来(比如网站访问量突然暴增),它会采取措施,比如限制流量,确保系统不会因为太忙而崩溃。
记录情况:它会记录所有车辆的行驶情况,如果出了问题,可以帮忙查找原因。
适应各种路况:无论是云上的道路,还是自己家修的路(混合云环境),它都能管理得井井有条。
简而言之,Higress 就是帮助你的网络世界更加顺畅、安全、有序的一个工具。
2、Higress的安装
1、安装DockerCompose
序号 | 软件 | 版本 |
---|---|---|
1 | Centos | 7.5 |
2 | Linux内核 | 3.8之上 |
卸载之前的docker
yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-selinux \docker-engine-selinux \docker-engine \docker-ce
防火墙关掉
systemctl stop firewalld
设置安装仓库
#安装yum的工具包
yum install -y yum-utils \device-mapper-persistent-data \lvm2 --skip-broken
# 设置docker镜像源
yum-config-manager \--add-repo \https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.reposed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/yum.repos.d/docker-ce.repo
#将软件包信息提前在本地索引缓存,用来提高搜索安装软件的速度,建议执行这个命令可以提升yum安装的速度。
yum makecache fast
安装docker引擎
sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
启动docker
systemctl start docker
设置docker自启动(我不喜欢)
systemctl enable docker
检查是不是启动成功
docker version
2、搭建Higress
#创建Higress工作目录
mkdir higress; #进入Hogress文件夹
cd higress#创建higress-ai容器
docker run -d --name higress-ai -v ${PWD}:/data \-p 8001:8001 -p 80:8080 -p 8443:8443 \higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/all-in-one:latest
监听端口说明如下:
- 80 端口:Higress UI 控制台入口
- 8080 端口:网关 HTTP 协议入口
- 8443 端口:网关 HTTPS 协议入口
访问Higress控制台
http://192.168.66.100:8001/
自己设置密码即可,进去后创建服务来源为nacos
之后项目启动的时候需要先打开docker服务,然后再开启Higress的容器。
3、Higress配置Nacos注册中心
为啥要配置Nacos呢?因为微服务都在nacos上注册着。
nacos的下载安装见博客:
SpringCloudAlibaba技术栈-Nacos-CSDN博客
安装完成之后访问浏览器输入网址192.168.66.100:8848/nacos即可。
3、项目案例
1、创建网关微服务模块
创建完父项目添加依赖
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.zj</groupId><artifactId>testHigress</artifactId><version>1.0-SNAPSHOT</version><packaging>pom</packaging><name>testHigress</name><url>http://maven.apache.org</url><modules><module>order-service</module><module>auth</module></modules><properties><dubbo.version>3.2.4</dubbo.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>17</java.version><spring-boot.version>3.0.2</spring-boot.version><spring-cloud.version>2022.0.0</spring-cloud.version><spring-cloud-alibaba.version>2022.0.0.0</spring-cloud-alibaba.version><lombok.version>1.8.28</lombok.version></properties><dependencyManagement><dependencies><!-- SpringCloud 微服务 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency><!-- SpringCloud Alibaba 微服务 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring-cloud-alibaba.version}</version><type>pom</type><scope>import</scope></dependency><!-- SpringBoot 依赖配置 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>
</project>
创建子项目order-service并添加依赖。
<!-- springboot依赖包--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- nacos依赖包 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>
在resources文件夹下面创建application.yml文件。
spring:application:# 应用名字name: order-servicecloud:nacos:discovery:# Nacos注册中心的地址server-addr: 192.168.66.100:8848server:port: 8889
主要是为了将order-service服务注册到Nacos上。
编写主启动类。
@SpringBootApplication
@EnableDiscoveryClient
public class OderServiceApplication
{public static void main( String[] args ){SpringApplication.run(OderServiceApplication.class, args);}
}
编写测试控制器。
package com.zj.controller;/*控制器*/
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/order")
public class indexController {@GetMapping("/index")public String index(){return "hello higress";}
}
启动项目,检查nacos客户端是不是存在该服务。
浏览器访问控制器,检查是不是创建成功。localhost:8888/order/index 出现hi gress表示成功。
2、Higress路由配置
它的作用是根据一定的规则,将访问者的请求正确地发送到对应的服务或者后端服务器上。
安装Switchhosts
Switchhosts:切换hosts与编辑hosts,实现域名和地址的映射。
会出现写数据没权限的情况看这篇文章:
switchHosts应用时,没有写入 Hosts 文件的权限_没有写入 hosts 文件的权限。-CSDN博客
在Higress中创建数据来源:
在域名管理中创建域名:
配置访问order-service服务的路由:
如果不存在一级路由的话还需要重写路由(这里存在一级路由):
这样访问的时候由原来的localhost:8888/order/index 变为 www.zj.com/order/index 为啥呢?因为微服务在nacos上,higress会根据/order/index找到匹配的服务。
浏览器访问地址:
3、Higress策略配置-跨域配置
什么是跨域
当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
当前页面url | 被请求页面url | 是否跨域 | 原因 |
---|---|---|---|
http://www.test.com/ | http://www.test.com/index.html | 否 | 同源(协议、域名、端口号相同) |
http://www.test.com/ | https://www.test.com/index.html | 跨域 | 协议不同(http/https) |
http://www.test.com/ | 百度一下,你就知道 | 跨域 | 主域名不同(test/baidu) |
http://www.test.com/ | http://blog.test.com/ | 跨域 | 子域名不同(www/blog) |
http://www.test.com:8080/ | http://www.test.com:7001/ | 跨域 | 端口号不同(8080/7001) |
常见的报错就是:Access-Control-Allow-Origin。
Higress配置跨域访问order-service服务:
4、HTTP认证
Higress HTTP认证是一种保护网页或服务的机制,需要用户输入用户名和密码才能访问。这就像给你的网站或服务加了一把锁,只有知道密码的人才能进入。
常见的验证方案包括
1、Basic Authentication(基本认证)
Basic认证是最常见的HTTP认证方式之一。在Basic认证中,客户端发送请求时,会在请求头中包含一个"Authorization"字段,该字段包含了经过Base64编码的用户名和密码。
2、Digest Authentication(摘要认证)
Digest认证是一种更安全的认证方式。在Digest认证中,服务器会向客户端发送一个随机数(称为"nonce"),客户端根据该随机数和用户密码计算一个摘要,并将其发送给服务器。服务器收到摘要后,会验证其有效性。Digest认证相对于Basic认证而言,更难以被中间人攻击截获密码。
3、Bearer Token Authentication(令牌认证)
Bearer认证是一种使用令牌(Token)进行身份验证的方式。在Bearer认证中,客户端在请求头中添加一个"Authorization"字段,该字段包含了一个令牌信息。服务器在接收到请求后,会验证令牌的有效性,并根据令牌来识别用户身份。
4、OAuth(开放授权)
OAuth认证是一种开放标准的身份验证协议,用于授权第三方应用程序访问用户资源。在OAuth认证中,用户可以通过授权服务器授权第三方应用程序访问自己的资源。这种方式可以避免用户将密码直接提供给第三方应用程序。
(1)Basic 认证
暂略。
(2)JWT认证
啥叫JWT认证?JWT认证是一种通过令牌(token)来验证用户身份的方法。用户登录后,服务器会发一个像密码一样的令牌给用户,用户每次访问网站时都带上这个令牌,服务器检查令牌来确定用户是谁。这种方法不需要服务器记住用户的登录状态,令牌里有用户信息,还能保证安全。
传统的session认证的缺点:
- 安全性:CSRF攻击因为基于cookie来进行用户识别, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。
- 扩展性:对于分布式应用,需要实现 session 数据共享
- 性能:每一个用户经过后端应用认证之后,后端应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大,与REST风格不匹配。因为它在一个无状态协议里注入了状态。
JWT的认证方式:
业务流程:
- 客户端向API网关发起认证请求,请求中一般会携带终端用户的用户名和密码;
- 网关将请求直接转发给后端服务也就是auth服务模块;
- 后端服务读取请求中的验证信息(比如用户名、密码)进行验证,验证通过后使用私钥生成标准的token,返回给网关;
- 网关将携带token的应答返回给客户端,客户端需要将这个token缓存到本地;
- 客户端向API网关发送业务请求,请求中携带token;
- 网关使用用户设定的公钥对请求中的token进行验证,验证通过后,将请求透传给后端服务;
- 后端服务进行业务处理后应答;
- 网关将业务应答返回给客户端
JWT 结构
头部 / header
JSON对象,描述 JWT 的元数据。其中 alg 属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ 属性表示这个令牌(token)的类型(type),统一写为 JWT。
{
"alg": "HS256",
"typ": "JWT"
}alg
属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ
属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT
然后将头部进行Base64编码构成了第一部分,Base64是一种用64个字符来表示任意二进制数据的方法,Base64是一种任意二进制到文本字符串的编码方法,常用于在URL、Cookie、网页中传输少量二进制数据。载荷 / Payload
Payload
部分也是一个JSON
对象,用来存放实际需要传递的数据。JWT
指定七个默认字段供选择。除了默认字段之外,你完全可以添加自己想要的任何字段,一般用户登录成功后,就将用户信息存放在这里iss:发行人
exp:到期时间
sub:主题
aud:用户
nbf:在此之前不可用
iat:发布时间
jti:JWT ID用于标识该JWT{
"iss": "xxxxxxx",
"sub": "xxxxxxx",
"aud": "xxxxxxx",
"user": {
'username': 'itbaizhan',
'userId': 1
}
}签名 / Signature
- 签名部分是对上面的 头部、载荷 两部分数据进行的数据签名
- 为了保证数据不被篡改,则需要指定一个密钥,而这个密钥一般只有你知道,并且存放在服务端
(3)Higress策略配置-创建认证中心微服务
添加依赖
<dependencies><!--springboot--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--注册中心,当前的认证服务也需要将自己注册到注册中心才能被其他服务调用--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--JWT认证包--><dependency><groupId>org.bitbucket.b_c</groupId><artifactId>jose4j</artifactId><version>0.7.0</version></dependency><!--工具包--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.18</version></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies>
在resources文件夹下面创建application.yml文件。
#微服务名称
spring:application:name: auth-service
# 注册中心地址cloud:nacos:discovery:server-addr: 192.168.66.100:8848
#端口
server:port: 8889#还能添加数据库的配置信息,从数据库获取用户的信息认证用户的身份
创建主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class authApplication
{public static void main( String[] args ){SpringApplication.run(authApplication.class, args);}
}
(4)编写JWT工具类生成JWT
在此之前一定要把Linux的时间设置成北京时间。
生成公钥和私钥,用户也可以在这个站点https://mkjwk.org 生成用于token生成与验证的私钥与公钥。
public static void main(String[] args) {RsaJsonWebKey rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);final String publicKeyString = rsaJsonWebKey.toJson(JsonWebKey.OutputControlLevel.PUBLIC_ONLY);final String privateKeyString = rsaJsonWebKey.toJson(JsonWebKey.OutputControlLevel.INCLUDE_PRIVATE);System.out.println(publicKeyString);System.out.println(privateKeyString);
}
JWT工具类
package com.zj.utils;import org.jose4j.json.JsonUtil;
import org.jose4j.jwa.AlgorithmConstraints;
import org.jose4j.jwk.JsonWebKey;
import org.jose4j.jwk.RsaJsonWebKey;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.consumer.InvalidJwtException;
import org.jose4j.jwt.consumer.JwtConsumer;
import org.jose4j.jwt.consumer.JwtConsumerBuilder;
import org.jose4j.lang.JoseException;import java.security.PrivateKey;
import java.security.PublicKey;// Jwt工具类,包含生成和验证JWT令牌的方法
public class JwtUtils {// 私钥字符串,用于签名JWT令牌,这里存储的是RSA私钥的JSON表示public final static String privatejson = "{\"kty\":\"RSA\",\"n\":\"...\",\"e\":\"...\",\"d\":\"...\",\"p\":\"...\",\"q\":\"...\",\"dp\":\"...\",\"dq\":\"...\",\"qi\":\"...\"}";// 公钥字符串,用于验证JWT令牌,这里存储的是RSA公钥的JSON表示public final static String publicjson = "{\"kty\":\"RSA\",\"n\":\"...\",\"e\":\"...\"}";/*** 生成JWT令牌* @param userId 用户ID,将作为JWT负载的一部分* @param username 用户名,将作为JWT负载的一部分* @return 返回生成的JWT令牌字符串*/public static String sign(Long userId, String username) throws JoseException {// 创建JWT的声明部分,JwtClaims对象包含JWT的有效负载JwtClaims claims = new JwtClaims();claims.setIssuer("abcd"); // 设置JWT的发行者,通常是创建JWT的应用的名称claims.setAudience("audience"); // 设置JWT的接收者,通常是接收JWT的应用的名称claims.setExpirationTimeMinutesInTheFuture(10000); // 设置JWT的过期时间,这里设置为10000分钟后过期claims.setGeneratedJwtId(); // 自动生成JWT的唯一标识符claims.setIssuedAtToNow(); // 设置JWT的发行时间,即当前时间claims.setNotBeforeMinutesInThePast(2); // 设置JWT生效时间,即2分钟前claims.setSubject("subject"); // 设置JWT的主题,通常是关于JWT的描述信息claims.setClaim("userId", userId); // 添加自定义声明,这里是用户IDclaims.setClaim("username", username); // 添加自定义声明,这里是用户名// 创建JWT签名对象,用于生成签名后的JWT令牌JsonWebSignature jws = new JsonWebSignature();jws.setPayload(claims.toJson()); // 设置JWT的有效负载,即上面的claims对象转换成JSON字符串// 使用私钥签名JWT,私钥用于加密签名,确保JWT的完整性和真实性PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(privatejson)).getPrivateKey();jws.setKey(privateKey);// 设置密钥ID,可以用于区分不同的密钥对jws.setKeyIdHeaderValue("keyId");// 设置签名算法,这里使用RSA SHA-256算法jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);// 生成JWT令牌,即对有效负载进行签名并返回签名后的字符串String jwt = jws.getCompactSerialization();return jwt;}/*** 验证JWT令牌* @param token 要验证的JWT令牌字符串*/public static void checkJwt(String token) throws JoseException {// 使用公钥验证JWT,公钥用于解密签名,验证JWT的完整性和真实性PublicKey publicKey = new RsaJsonWebKey(JsonUtil.parseJson(publicjson)).getPublicKey();// 创建JWT消费者,用于验证和解码JWT令牌JwtConsumer jwtConsumer = new JwtConsumerBuilder().setRequireExpirationTime() // 要求JWT包含过期时间字段.setAllowedClockSkewInSeconds(30) // 允许时间偏移量,即服务器时间与JWT生成时间之间的差异.setRequireSubject() // 要求JWT包含主题字段.setExpectedIssuer("abcd") // 预期的发行者,必须与JWT中的发行者匹配.setExpectedAudience("audience") // 预期的接收者,必须与JWT中的接收者匹配.setVerificationKey(publicKey) // 设置用于验证签名的公钥.setJwsAlgorithmConstraints(new AlgorithmConstraints(AlgorithmConstraints.ConstraintType.WHITELIST, AlgorithmIdentifiers.RSA_USING_SHA256))// 设置只允许使用RSA SHA-256算法的JWT.build();try {// 解析和验证JWT令牌JwtClaims jwtClaims = jwtConsumer.processToClaims(token);System.out.println("JWT验证成功!");// 输出JWT中的声明信息System.out.println("JWT内容: " + jwtClaims);} catch (InvalidJwtException e) {// 如果JWT验证失败,打印错误信息System.out.println("JWT验证失败: " + e);}}// 主函数,用于测试JWT的生成和验证public static void main(String[] args) throws JoseException {// 生成JWT令牌String token = sign(123L, "testUser");System.out.println("生成的JWT令牌: " + token);// 验证JWT令牌checkJwt(token);}}
(5)编写认证中心控制器和服务层
package com.zj.controller;import com.zj.domain.LoginBodyDTO;
import com.zj.domain.R;
import com.zj.service.LoginService;
import org.jose4j.lang.JoseException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;/*** 用户层*/
@RestController
@RequestMapping("/auth")
public class LoginController {@Autowiredprivate LoginService loginService;/*** @RequestBody:将数据转换为java对象* @param loginBodyDTO* @return*/@PostMapping("/login")public R login(@RequestBody LoginBodyDTO loginBodyDTO) throws JoseException {System.out.println("啊哈哈哈哈");R login = loginService.login(loginBodyDTO);return login;}
}
编写统一结果返回集
package com.zj.domain;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;/*** 统一结果返回集*/
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class R {private Integer code;private String msg;public Object data;public static R fail( String msg) {R r = new R();r.setCode(500);r.setMsg(msg);return r;}public static R success( Object data) {R r = new R();r.setCode(200);r.setMsg("success");r.setData(data);return r;}
}
登录业务层
package com.zj.service;import com.zj.domain.LoginBodyDTO;
import com.zj.domain.R;
import com.zj.utils.JwtUtils;
import org.jose4j.lang.JoseException;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;@Service
public class LoginService {//登录public R login(LoginBodyDTO loginBodyDTO) throws JoseException {//1.用户名密码数据库校验if(StringUtils.isEmpty(loginBodyDTO.getUsername()) || StringUtils.isEmpty(loginBodyDTO.getPassword())){return R.fail("用户名或者密码为空");}//TODO 数据操作验证用户信息if(loginBodyDTO.getUsername().equals("admin") && loginBodyDTO.getPassword().equals("123456")){//颁发登录tokenString token = JwtUtils.sign(1001L,"admin");return R.success(token);}else{return R.fail("登录信息错误");}}}
创建Higess路由
启动项目验证授权服务是不是成功了
这就成功了。
(6)Higress策略配置-JWT配置
这个配置主要是针对微服务的这里主要是order-service,不是针对验证模块的,验证模块不需要添加,总不能让用户第一次登录就带着token吧。
因为在JWT认证流程中需要网关对用户的请求进行验证,也就是需要对用户的请求进行解密,解密成功才能访问微服务,否则直接不让访问。
因为访问每个微服务都需要进行身份的验证,因此需要全局配置JWT,在插件市场配置就是全局配置。
参数配置见文档:https://higress.cn/docs/latest/plugins/authentication/jwt-auth/?spm=36971b57.2ef5001f.0.0.2a932c1fXPZUk1
name | string | 必填 | - | 配置该consumer的名称,每个consumer相当于是一个策略。 |
jwks | string | 必填 | - | https://www.rfc-editor.org/rfc/rfc7517 指定的json格式字符串,是由验证JWT中签名的公钥(或对称密钥)组成的Json Web Key Set,其实就是公钥。 |
issuer | string | 必填 | - | JWT的签发者,需要和payload中的iss字段保持一致 |
开启order-service微服务权限认证。
idea上开启auth服务和order-serice服务测试:
先直接访问order-service模块显然没验证成功:
再登录一下获取token
再次请求order-service这次带上token
要注意Authorization的参数: Bearer+token
这样最基础的认证就OK 啦!
(7) Higress策略配置-Key 认证
global_auth | bool | 选填(仅实例级别配置) | - | 只能在实例级别配置,若配置为true,则全局生效认证机制; 若配置为false,则只对做了配置的域名和路由生效认证机制,若不配置则仅当没有域名和路由配置时全局生效(兼容老用户使用习惯)。 |
consumers | array of object | 必填 | - | 配置服务的调用者,用于对请求进行认证 |
keys | array of string | 必填 | - | API Key 的来源字段名称,可以是 URL 参数或者 HTTP 请求头名称 |
in_query | bool | in_query 和 in_header 至少有一个为 true | true | 配置 true 时,网关会尝试从 URL 参数中解析 API Key |
in_header | bool | in_query 和 in_header 至少有一个为 true | true | 配置 true 时,网关会尝试从 HTTP 请求头中解析 API Key |
在key认证的全局配置添加下面的配置:
credential: 2bda943c-ba2b-11ec-ba07-00163e1250b5 通过UUID生成的。keys就是在请求的时候要携带的参数,in_header就是放在请求的header中,in_query就是携带到请求的参数上。
在order-sevice服务上使用配置的key认证:
在不携带apikey参数的时候请求登录是不行的。
带上参数就能访问了。
带上参数访问order-service。
对于in_header式key认证是一样的。
相关文章:

SpringCloudAlibaba技术栈-Higress
1、什么是Higress? 云原生网关,干啥的?用通俗易懂的话来说,微服务架构下Higress 就像是一个智能的“交通警察”,它站在你的网络世界里,负责指挥和调度所有进出的“车辆”(也就是数据流量)。它的…...

uniapp 微信小程序开发使用高德地图、腾讯地图
一、高德地图 1.注册高德地图开放平台账号 (1)创建应用 这个key 第3步骤,配置到项目中locationGps.js 2.下载高德地图微信小程序插件 (1)下载地址 高德地图API | 微信小程序插件 (2)引入项目…...

Springboot:后端接收数组形式参数
1、接收端写法 PermissionAnnotation(permissionName "",isCheckToken true)PostMapping("/batchDeleteByIds")public ReturnBean webPageSelf( NotNull(message "请选择要删除的单据!") Long[] ids) {for (Long string : ids) {l…...

Postman[2] 入门——界面介绍
可参考官方 文档 Postman 导航 | Postman 官方帮助文档中文版Postman 拥有各种工具、视图和控件,帮助你管理 API 项目。本指南是对 Postman 主要界面区域的高级概述:https://postman.xiniushu.com/docs/getting-started/navigating-postman 1. Header&a…...
1月第四讲:Java Web学生自习管理系统
一、项目背景与需求分析 随着网络技术的不断发展和学校规模的扩大,学生自习管理系统的需求日益增加。传统的自习管理方式存在效率低下、资源浪费等问题,因此,开发一个智能化的学生自习管理系统显得尤为重要。该系统旨在提高自习室的利用率和…...

【Redis】Redis 典型应用 - 缓存 (cache)
目录 1. 什么是缓存 2. 使用 Redis 作为缓存 3. 缓存的更新策略 3.1 定期生成 3.2 实时生成 4. 缓存的淘汰策略 5. 缓存预热, 缓存穿透, 缓存雪崩 和 缓存击穿 关于缓存预热 (Cache preheating) 关于缓存穿透 (Cache penetration) 关于缓存雪崩 (Cache avalanche) 关…...

HTML——38.Span标签和字符实体
<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>span标签和字符实体</title><style type"text/css">h1{text-align: center;}p{text-indent: 2em;}span{color: red;}</style></head><…...

ROS2+OpenCV综合应用--10. AprilTag标签码追踪
1. 简介 apriltag标签码追踪是在apriltag标签码识别的基础上,增加了小车摄像头云台运动的功能,摄像头会保持标签码在视觉中间而运动,根据这一特性,从而实现标签码追踪功能。 2. 启动 2.1 程序启动前的准备 本次apriltag标签码使…...
python Celery 是一个基于分布式消息传递的异步任务队列系统
Celery 是一个基于分布式消息传递的异步任务队列系统,主要用于处理耗时任务、定时任务和周期性任务。它能够将任务分配到多个工作节点(Worker)上执行,从而提高应用程序的性能和可扩展性。Celery 是 Python 生态中最流行的任务队列…...

嵌入式硬件杂谈(七)IGBT MOS管 三极管应用场景与区别
引言:在现代嵌入式硬件设计中,开关元件作为电路中的重要组成部分,起着至关重要的作用。三种主要的开关元件——IGBT(绝缘栅双极型晶体管)、MOSFET(金属氧化物半导体场效应晶体管)和三极管&#…...

麒麟信安云在长沙某银行的应用入选“云建设与应用领航计划(2024)”,打造湖湘金融云化升级优质范本
12月26日,2024云计算产业和标准应用大会在北京成功召开。大会汇集政产学研用各方专家学者,共同探讨云计算产业发展方向和未来机遇,展示云计算标准化工作重要成果。 会上,云建设与应用领航计划(2024)建云用…...
好用的随机生成图片的网站
官网: Lorem Picsum 获取自定义大小的随机图像 https://picsum.photos/200/300 获取正方形图像 https://picsum.photos/200 获取特定类型的图像 通过添加到 /id/{image} url 的开头来获取特定图像。 https://picsum.photos/id/237/200/300 获取静态随机图像…...
添加 env 配置,解决import路径问题
添加 env 配置,解决import路径问题 { // 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。 // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid830387 “version”: “0.2.0”, “configurations”: [ {"name&q…...
Go work stealing 机制
Go语言的Work Stealing(工作窃取)机制是一种用于调度Goroutines(协程)的策略,其核心目的是最大化CPU使用率,减少任务调度的开销,并提高并发性能和吞吐量。以下是Go Work Stealing机制的详细解释…...

基础数据结构--二叉树
一、二叉树的定义 二叉树是 n( n > 0 ) 个结点组成的有限集合,这个集合要么是空集(当 n 等于 0 时),要么是由一个根结点和两棵互不相交的二叉树组成。其中这两棵互不相交的二叉树被称为根结点的左子树和右子树。 如图所示&am…...
《C++设计模式》策略模式
文章目录 1、引言1.1 什么是策略模式1.2 策略模式的应用场景1.3 本文结构概览 2、策略模式的基本概念2.1 定义与结构2.2 核心角色解析2.2.1 策略接口(Strategy)2.2.2 具体策略实现(ConcreteStrategy)2.2.3 上下文(Cont…...
JavaScript学习记录6
第一节 算数运算符 1. 概述 JavaScript 共提供10个算术运算符,用来完成基本的算术运算。 加法运算符x y减法运算符 x - y乘法运算符 x * y除法运算符x / y指数运算符x ** y余数运算符x % y自增运算符x 、x自减运算符--x 、x--数值运算符 x负数值运算符-x 减法、…...

如何在没有 iCloud 的情况下将数据从 iPhone 传输到 iPhone
概括 您可能会遇到将数据从 iPhone 转移到 iPhone 的情况,尤其是当您获得新的 iPhone 15/14 时,您会很兴奋并希望将数据转移到它。 使用iCloud最终可以做到这一点,但它的缺点也不容忽视,阻碍了你选择它。例如,您需要…...

Doris安装部署
Doris 概述 Apache Doris由百度大数据部研发(之前叫百度 Palo,2018年贡献到 Apache 社区后,更名为 Doris ),在百度内部,有超过200个产品线在使用,部署机器超过1000台,单一业务最大可…...

[服务器][教程]Ubuntu24.04 Server开机自动挂载硬盘教程
1. 查看硬盘ID ls -l /dev/disk/by-uuid可以看到对应的UUID所对应的分区 2. 创建挂载文件夹 创建好文件夹即可 3. 修改配置文件 sudo vim /etc/fstab把对应的UUID和创建的挂载目录对应即可 其中# Personal mount points下面的是自己新添加的 :分区定位ÿ…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...

剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...