【Spring Cloud 八】Spring Cloud Gateway网关

gateway网关

  • 系列博客
  • 背景
  • 一、什么是Spring Cloud Gateway
  • 二、为什么要使用Spring Cloud Gateway
  • 三、 Spring Cloud Gateway 三大核心概念
    • 4.1 Route(路由)
    • 4.2 Predicate(断言)
    • 4.3 Filter(过滤)
  • 五、Spring Cloud Gateway是如何工作的
  • 四、 如何使用Spring Cloud Gateway进行服务路由
    • 4.1搭建服务A
      • pom文件
      • yml配置文件
      • 启动类
      • controller类
    • 4.2 搭建服务B
      • pom文件
      • yml配置文件
      • 启动类
      • controller类
    • 4.3搭建Spring Cloud Gateway服务
      • pom文件
      • yml配置文件
      • 启动类
    • 4.4启动项目
    • 4.5动态路由
  • 五、gateway过滤器
    • 5.1自定义全局过滤器
  • 六、使用gateway做token校验
    • 6.1实现的大致流程示意图:![](https://img-blog.csdnimg.cn/3001fa8b45324a61a95e0c06263528a7.png)
    • 6.2实现代码
      • gateway服务
        • pom.xml文件
        • TokenCheckFilter类
      • login-service服务
        • pom.xml文件
        • LoginController类
      • 访问测试
  • 总结
  • 升华

系列博客

【Spring Cloud一】微服务基本知识
【Spring Cloud 三】Eureka服务注册与服务发现
【Spring Cloud 四】Ribbon负载均衡
【Spring Cloud 五】OpenFeign服务调用
【Spring Cloud 六】Hystrix熔断
【Spring Cloud 七】Sleuth+Zipkin 链路追踪

背景

在项目中是使用了Gateway做统一的请求的入口,以及统一的跨域处理以及统一的token校验。但是这些工作都是之前的同事来做的,正好在新项目中也需要使用其进行统一的token校验。本着对Gateway更精进一步所以博主就对Gateway进行了较为全面的学习了解,包括动态路由、自定义过滤器、token校验和续活。

一、什么是Spring Cloud Gateway

Spring Cloud Gateway提供一种简单有效的方法来路由到对应的API上,并可以提供一些额外的功能,安全性、监控、度量、负载等等。

我们可以这样理解,Spring Cloud Gateway将该项目中所有服务对外提供的API聚集起来,并向外提供唯一的入口,同时提供了一些额外的功能,安全性、监控、度量、负载等等。

没使用Spring Cloud Gateway 之前的示意图
在这里插入图片描述
使用Spring Cloud Gateway之后的示意图:
在这里插入图片描述

二、为什么要使用Spring Cloud Gateway

  1. 统一入口并解除客户端与服务端的耦合:在微服务架构中,每个微服务都有自己入口,在没有它的时候客户端需要大量微服务的地址,会照成复杂的客户端代码。并且会暴露服务端的细节,如果服务端发生变化,可能会影响到客户端代码,导致维护困难。
  2. 动态路由和负载均衡:Spring Cloud GateWay 提供动态路由来应对当;网关来能够在多个服务实例之间进行负载均衡,提供整个系统的高可用。
  3. 请求过滤:在微服务架构中,可能需要对请求进行鉴权、身份验证一个中心化的地方来处理这些请求过滤和处理逻辑可以减少重复的代码和逻辑。
  4. 反应式和高性能:由于微服务架构的复杂性,需要一个能够处理高并发请求的解决方案,以确保系统在高负载情况下保持稳定。Spring Cloud Gateway是基于webFlux框架实现的,而webFlux框架底层使用了高性能Reactor模式通信框架的Netty。

三、 Spring Cloud Gateway 三大核心概念

4.1 Route(路由)

路由是由一个ID、一个目的URI、一组断言、一组Filter组成。
如果路由断言为真,那么说明这个路由被匹配上了。

4.2 Predicate(断言)

是一个java8函数断言。输入类型是一个Spring Framewordk ServerWebExchange。可以让你匹配HTTP上的任何请求。比如请求头和参数。

4.3 Filter(过滤)

是Spring WebFilter的实例,Spring Cloud Gateway中的Filter分为两种,分贝是Gateway Filter和Global Filter(一个是针对某一个路由的filter,例如对某一个接口做限流;一个是针对全局的filter,例如token校验,ip黑名单)。过滤器Filter将会对请求和响应进行修改处理。

五、Spring Cloud Gateway是如何工作的

Spring 官网
在这里插入图片描述
客户端向Spring Cloud Gateway发出请求。如果网关处理器映射器确定请求与路由匹配,则会将其发送到网关web处理器。它通过特定的过滤器链来运行请求。过滤器被虚线分割的原因是过滤器可以在发送代理请求之前和之后运行对应的逻辑。

四、 如何使用Spring Cloud Gateway进行服务路由

示例项目示意图:
在这里插入图片描述
备注:Eureka的搭建可以参考这篇博客:【Spring Cloud 三】Eureka服务注册与服务发现

这里之所以使用Eureka是为了之后做动态路由和负载均衡。

4.1搭建服务A

pom文件

<?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.3.12.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.wangwei</groupId><artifactId>login-service</artifactId><version>0.0.1-SNAPSHOT</version><name>login-service</name><description>login-service</description><properties><java.version>8</java.version><spring-cloud.version>Hoxton.SR12</spring-cloud.version></properties><dependencies><!--		<dependency>-->
<!--			<groupId>org.springframework.boot</groupId>-->
<!--			<artifactId>spring-boot-starter-data-redis</artifactId>-->
<!--		</dependency>--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

yml配置文件

server:port: 8081spring:application:name: login-serviceeureka:client:service-url:defaultZone: http://localhost:8761/eurekaregister-with-eureka: true #设置为fasle 不往eureka-server注册,默认为truefetch-registry: true #应用是否拉取服务列表到本地registry-fetch-interval-seconds: 10 #为了缓解服务列表的脏读问题,时间越短脏读越少 性能相应的消耗回答instance: #实例的配置instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}hostname: localhost #主机名称或者服务ipprefer-ip-address: true #以ip的形式显示具体的服务信息lease-renewal-interval-in-seconds: 10 #服务实例的续约时间间隔

启动类

@SpringBootApplication
@EnableEurekaClient
public class LoginServiceApplication {public static void main(String[] args) {SpringApplication.run(LoginServiceApplication.class, args);}}

controller类

@RestController
public class LoginController {@GetMapping("doLogin")public String doLogin(){return "登陆成功";}
}

4.2 搭建服务B

pom文件

<?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.3.12.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.wangwei</groupId><artifactId>teacher-service</artifactId><version>0.0.1-SNAPSHOT</version><name>teacher-service</name><description>teacher-service</description><properties><java.version>8</java.version><spring-cloud.version>Hoxton.SR12</spring-cloud.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

yml配置文件

server:port: 8082spring:application:name: teacher-serviceeureka:client:service-url:defaultZone: http://localhost:8761/eurekaregister-with-eureka: true #设置为fasle 不往eureka-server注册,默认为truefetch-registry: true #应用是否拉取服务列表到本地registry-fetch-interval-seconds: 10 #为了缓解服务列表的脏读问题,时间越短脏读越少 性能相应的消耗回答instance: #实例的配置instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}hostname: localhost #主机名称或者服务ipprefer-ip-address: true #以ip的形式显示具体的服务信息lease-renewal-interval-in-seconds: 10 #服务实例的续约时间间隔

启动类

@SpringBootApplication
@EnableEurekaClient
public class TeacherServiceApplication {public static void main(String[] args) {SpringApplication.run(TeacherServiceApplication.class, args);}}

controller类

@RestController
public class TeacherController {@GetMapping("teach")public String teach(){return "教书学习";}
}

4.3搭建Spring Cloud Gateway服务

pom文件

<?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.3.12.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.wangwei</groupId><artifactId>gateway-server</artifactId><version>0.0.1-SNAPSHOT</version><name>gateway-server</name><description>gateway-server</description><properties><java.version>8</java.version><spring-cloud.version>Hoxton.SR12</spring-cloud.version></properties><dependencies>
<!--		<dependency>-->
<!--			<groupId>org.springframework.boot</groupId>-->
<!--			<artifactId>spring-boot-starter-data-redis</artifactId>-->
<!--		</dependency>-->
<!--		<dependency>-->
<!--			<groupId>org.springframework.boot</groupId>-->
<!--			<artifactId>spring-boot-starter-data-redis-reactive</artifactId>-->
<!--		</dependency>--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

yml配置文件

server:port: 81 #?????80spring:application:name: gateway-servercloud:gateway:enabled: trueroutes:- id: login-service-route # 路由的id  保持唯一uri: http://localhost:8081 #uri统一资源标识符  url 统一资源定位符#uri: lb://login-service #??lb负载均衡predicates: # 断言是给某一个路由来设定的一种匹配规则 默认不能作用在动态路由上- Path=/doLogin # 匹配规则 只要你Path配置上了/doLogin 就往uri转发并将路径带上- id: teacher-service-routeurl:  http://localhost:8082predicates:- Path=/teacheureka:client:service-url:defaultZone: http://localhost:8761/eurekaregister-with-eureka: true #设置为fasle 不往eureka-server注册,默认为truefetch-registry: true #应用是否拉取服务列表到本地registry-fetch-interval-seconds: 10 #为了缓解服务列表的脏读问题,时间越短脏读越少 性能相应的消耗回答instance: #实例的配置instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}hostname: localhost #主机名称或者服务ipprefer-ip-address: true #以ip的形式显示具体的服务信息lease-renewal-interval-in-seconds: 10 #服务实例的续约时间间隔

启动类

@SpringBootApplication
@EnableEurekaClient
public class GatewayServerApplication {public static void main(String[] args) {SpringApplication.run(GatewayServerApplication.class, args);}}

4.4启动项目

依次启动Eureka服务,gateway服务和两个服务A和服务B。

进行调用服务A和服务B:
如下图所示通过gateway的ip+端口+路径调用到对应的服务A中和服务B中。

在这里插入图片描述

在这里插入图片描述

4.5动态路由

在微服务中通常一个服务的实例有多个,那我们网关如何做负载均衡呢?
gateway帮我们做了很多东西,只要我们集成注册中心(nacos、Eureka、zoomkeeper)并添加对应的配置gateway就可以自动帮我们进行负载均衡。

方式一:
添加对应的配置信息,来开启动态路由

    gateway:enabled: trueroutes:- id: login-service-route # 路由的id  保持唯一uri: http://localhost:8081 #uri统一资源标识符  url 统一资源定位符#uri: lb://login-service #??lb负载均衡predicates: # 断言是给某一个路由来设定的一种匹配规则 默认不能作用在动态路由上- Path=/doLogin # 匹配规则 只要你Path配置上了/doLogin 就往uri转发并将路径带上- id: teacher-service-routeuri:  http://localhost:8082predicates:- Path=/teachdiscovery:locator:enabled: true #开启动态路由  开启通过应用名称找到服务的功能lower-case-service-id: true  # 开启服务名称小写

请求服务时需要带上对应的服务名称
在这里插入图片描述

方式二:
添加对应的配置:uri: lb://login-service #lb负载均衡

    gateway:enabled: trueroutes:- id: login-service-route # 路由的id  保持唯一#uri: http://localhost:8081 #uri统一资源标识符  url 统一资源定位符uri: lb://login-service #lb负载均衡predicates: # 断言是给某一个路由来设定的一种匹配规则 默认不能作用在动态路由上- Path=/doLogin # 匹配规则 只要你Path配置上了/doLogin 就往uri转发并将路径带上- id: teacher-service-routeuri:  http://localhost:8082predicates:- Path=/teach

在这里插入图片描述

推荐使用方式一进行统一的配置负载均衡。

五、gateway过滤器

过滤器按照作用范围可以分为两种,Gateway Filter和Global Filter。

Gateway Filter:网关过滤器需要通过 spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上或通过 spring.cloud.default-filters 配置在全局,作用在所有路由上。

Global Filter:全局过滤器,不需要配置路由,系统初始化作用在所有路由上。

全局过滤器一般用于:统计请求次数、限流、token校验、ip黑名单拦截等。

5.1自定义全局过滤器

@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {/*** 过滤的方法* 职责链模式* 网关里面有使用 mybatis的二级缓存有变种职责链模式* @param exchange* @param chain* @return*/@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//针对请求的过滤 拿到请求 header url 参数。。。ServerHttpRequest request = exchange.getRequest();//HttpServletRequest 这个是web里面的//ServerHttpRequest webFlux里面 响应式里面的String path=request.getURI().getPath();System.out.println(path);HttpHeaders headers=request.getHeaders();System.out.println(headers);String name = request.getMethod().name();String hostString = request.getHeaders().getHost().getHostString();System.out.println(hostString);//响应相关数据ServerHttpResponse response = exchange.getResponse();//微服务 肯定是前后端分离的 一般前后端通过数据传输是json格式//{"code":200,"msg":"ok"}//设置编码 响应头response.getHeaders().set("content-type","application/json;charset=utf-8");//组装业务返回值HashMap<String ,Object> map=new HashMap<>(4);map.put("code", HttpStatus.UNAUTHORIZED.value());map.put("msg","你未授权");ObjectMapper objectMapper=new ObjectMapper();//把一个map转换为字节byte[] bytes = new byte[0];try {bytes = objectMapper.writeValueAsBytes(map);} catch (JsonProcessingException e) {throw new RuntimeException(e);}//通过buffer工厂将字节数组包装成一个数据报DataBuffer wrap = response.bufferFactory().wrap(bytes);return response.writeWith(Mono.just(wrap));//放行,到下一个过滤器//return chain.filter(exchange);}/*** 制定顺序的方法* 越小越先执行* @return*/@Overridepublic int getOrder() {return 0;}
}

请求接口进行访问,可以发现当前请求已经被拦截下来。

在这里插入图片描述

六、使用gateway做token校验

6.1实现的大致流程示意图:

6.2实现代码

gateway服务

pom.xml文件

在pom文件中新增redis的依赖

		<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

注意博主是在本机安装的redis所以不需要在服务中添加对应的redis配置。

TokenCheckFilter类

新建TokenCheckFilter类并实现全局过滤器和Ordered

package com.wangwei.gatewayserver.filter;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.util.Arrays;
import java.util.HashMap;
import java.util.List;@Component
public class TokenCheckFilter implements GlobalFilter, Ordered {/*** 指定好放行的路径,白名单*/public static final List<String> ALLOW_URL= Arrays.asList("/doLogin","/myUrl");@Autowiredprivate StringRedisTemplate redisTemplate;/*** 和前端约定好 一般放在请求头类里面一般key为 Authorization value bearer token* 1.拿到请求url* 2.判断放行* 3.拿到请求头* 4.拿到token* 5.校验* 6.放行/拦截* @param exchange* @param chain* @return*/@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();String path = request.getURI().getPath();if (ALLOW_URL.contains(path)) {return chain.filter(exchange);}//检查List<String> authorization = request.getHeaders().get("Authorization");if (!CollectionUtils.isEmpty(authorization)){String token = authorization.get(0);if(StringUtils.hasText(token)){//约定好的有前缀的bearer tokenString realToken = token.replaceFirst("bearer ", "");if (StringUtils.hasText(realToken)&&redisTemplate.hasKey(realToken)){return chain.filter(exchange);}}}//拦截ServerHttpResponse response = exchange.getResponse();response.getHeaders().set("content-type","application/json;charset=utf-8");//组装业务返回值HashMap<String ,Object> map=new HashMap<>(4);map.put("code", HttpStatus.UNAUTHORIZED);map.put("msg","未授权");ObjectMapper objectMapper=new ObjectMapper();//把一个map转换为字节byte[] bytes = new byte[0];try {bytes = objectMapper.writeValueAsBytes(map);} catch (JsonProcessingException e) {throw new RuntimeException(e);}//通过buffer工厂将字节数组包装成一个数据报DataBuffer wrap = response.bufferFactory().wrap(bytes);return response.writeWith(Mono.just(wrap));}@Overridepublic int getOrder() {return 0;}
}

login-service服务

pom.xml文件

在pom文件中新增redis的依赖

		<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

注意博主是在本机安装的redis所以不需要在服务中添加对应的redis配置。

LoginController类

在LoginController类中新增doLogin方法

@Autowiredpublic StringRedisTemplate redisTemplate;@PostMapping("doLogin")public String doLogin(@RequestBody User user){//tokenString token= UUID.randomUUID().toString();//存起来redisTemplate.opsForValue().set(token,user.toString(), Duration.ofSeconds(7200));return token;}

访问测试

http://localhost:81/doLogin

由于在gateway将该/doLogin放入了白名单,所以该请求不会进行token校验,发送请求成功之后会返回token
在这里插入图片描述
访问http://localhost:81/teach,并在请求头中添加token,最后可以看到请求访问成功。

在这里插入图片描述

如果我们不在请求头中添加对应的token或者token为错误token,那么gateway会将请求进行拦截。

在这里插入图片描述

总结

  1. gateway在微服务中起到了很重要的作用,作为项目请求的统一入口。
  2. gateway也体现了我们软件设计的复用思想,可以统一进行跨域处理,进行token校验。
  3. gateway比较重要的一块是关于他的过滤器,通过实现过滤器的接口,可以自定义过滤器,提供了很强大的可扩展支持

升华

通过学习gateway不光是学习gateway更重要的是学习软件设计思想。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/96458.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Datawhale Django后端开发入门Task01 Vscode配置环境

首先呢放一张运行成功的截图纪念一下&#xff0c;感谢众多小伙伴的帮助呀&#xff0c;之前没有配置这方面的经验 &#xff0c;但还是一步一步配置成功了&#xff0c;所以在此以一个纯小白的经验分享如何配置成功。 1.选择要建立项目的文件夹&#xff0c;打开文件找到目标文件夹…

全面梳理Python下的NLP 库

一、说明 Python 对自然语言处理库有丰富的支持。从文本处理、标记化文本并确定其引理开始&#xff0c;到句法分析、解析文本并分配句法角色&#xff0c;再到语义处理&#xff0c;例如识别命名实体、情感分析和文档分类&#xff0c;一切都由至少一个库提供。那么&#xff0c;你…

公网远程连接Redis数据库详解

文章目录 1. Linux(centos8)安装redis数据库2. 配置redis数据库3. 内网穿透3.1 安装cpolar内网穿透3.2 创建隧道映射本地端口 4. 配置固定TCP端口地址4.1 保留一个固定tcp地址4.2 配置固定TCP地址4.3 使用固定的tcp地址连接 前言 洁洁的个人主页 我就问你有没有发挥&#xff0…

一站式自动化测试平台-Autotestplat

3.1 自动化平台开发方案 3.1.1 功能需求 3.1.3 开发时间计划 如果是刚入门、但有一点代码基础的测试人员&#xff0c;大概 3 个月能做出演示版(Demo)进行自动化测试&#xff0c;6 个月内胜任开展工作中项目的自动化测试。 如果是有自动化测试基础的测试人员&#xff0c;大概 …

实现Java异步调用的高效方法

文章目录 为什么需要异步调用&#xff1f;Java中的异步编程方式1. 使用多线程2. 使用Java异步框架 异步调用的关键细节结论 &#x1f389;欢迎来到Java学习路线专栏~实现Java异步调用的高效方法 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff1a;IT陈寒的博…

Redis基本操作

根据哔站黑马教学笔记写的笔记&#xff1a;https://www.bilibili.com/video/BV1cr4y1671t?p1&vd_source6a3f27eeec2d16afabc65c8f5e06eac7 1. 初识Redis2. Redis常见命令2.1 通用命令2.2 String 类型2.2.1 String 的常见命令2.2.2 key 结构 2.3 Hash 类型2.4 List 类型2.…

第58步 深度学习图像识别:Transformer可视化(Pytorch)

一、写在前面 &#xff08;1&#xff09;pytorch_grad_cam库 这一期补上基于基于Transformer框架可视化的教程和代码&#xff0c;使用的是pytorch_grad_cam库&#xff0c;以Bottleneck Transformer模型为例。 &#xff08;2&#xff09;算法分类 pytorch_grad_cam库中包含的…

2023.8.19-2023.8.XX 周报【人脸3D+虚拟服装方向基础调研-Cycle Diffusion\Diffusion-GAN\】更新中

学习目标 1. 这篇是做diffusion和gan结合的&#xff0c;可以参照一下看看能不能做cyclegan的形式&#xff0c;同时也可以调研一下有没有人follow这篇论文做了类似cyclegan的事情 Diffusion-GAN论文精读https://arxiv.org/abs/2206.02262 2. https://arxiv.org/abs/2212.06…

无涯教程-TensorFlow - 优化器

Optimizers是扩展类&#xff0c;其中包括用于训练特定模型的附加信息&#xff0c;Optimizers类使用给定的参数初始化&#xff0c;用于提高速度和性能&#xff0c;以训练特定模型。 TensorFlow的基本Optimizers是- tf.train.Optimizer 此类在tensorflow/python/training/opti…

高级艺术二维码制作教程

最近不少关于二维码制作的&#xff0c;而且都是付费。大概就是一个好看的二维码&#xff0c;扫描后跳转网址。本篇文章使用Python来实现&#xff0c;这么简单花啥钱呢&#xff1f;学会&#xff0c;拿去卖便宜点吧。 文章目录 高级二维码制作环境安装普通二维码艺术二维码动态 …

vue中实现文字检索时候将搜索内容标红

实现结果 html&#xff1a; <div class"searchBox"><span class"bt">标&#8195&#8195题</span><div class"search"><div class"shuru"><!-- <span class"title">生产经营<…

安装软件包

安装软件包 创建一个名为 /home/curtis/ansible/packages.yml 的 playbook : 将 php 和 mariadb 软件包安装到 dev、test 和 prod 主机组中的主机上 将 RPM Development Tools 软件包组安装到 dev 主机组中的主机上 将 dev 主机组中主机上的所有软件包更新为最新版本 vim packa…

Spring Cloud 系列之OpenFeign:(7)链路追踪zipkin

传送门 Spring Cloud Alibaba系列之nacos&#xff1a;(1)安装 Spring Cloud Alibaba系列之nacos&#xff1a;(2)单机模式支持mysql Spring Cloud Alibaba系列之nacos&#xff1a;(3)服务注册发现 Spring Cloud 系列之OpenFeign&#xff1a;(4)集成OpenFeign Spring Cloud …

填充柄功能

单元格右下角十字符号 顺序式填充 输入1,2&#xff0c;直接拉取即可实现顺序1到10. 复制式填充 CtrlD或者拉取&#xff0c;选择右下角复制单元格。 规律式填充 输入星期一&#xff0c;星期二&#xff0c;下拉一直可以到星期日 自定义填充 选择文件-》选项-》自定义序列 输…

proteus结合keil-arm编译器构建STM32单片机项目进行仿真

proteus是可以直接创建设计图和源码的&#xff0c;但是源码编译它需要借助keil-arm编译器&#xff0c;也就是我们安装keil-mdk之后自带的编译器。 下面给出一个完整的示例&#xff0c;主要是做一个LED灯闪烁的效果。 新建工程指定路径&#xff0c;Schematic,PCB layout都选择默…

leetcode292. Nim 游戏(博弈论 - java)

Nim 游戏 Nim 游戏题目描述博弈论 上期经典算法 Nim 游戏 难度 - 简单 原题链接 - Nim游戏 题目描述 你和你的朋友&#xff0c;两个人一起玩 Nim 游戏&#xff1a; 桌子上有一堆石头。 你们轮流进行自己的回合&#xff0c; 你作为先手 。 每一回合&#xff0c;轮到的人拿掉 1 -…

Mac OS下应用Python+Selenium实现web自动化测试

在Mac环境下应用PythonSelenium实现web自动化测试 在这个过程中要注意两点&#xff1a; 1.在终端联网执行命令“sudo pip install –U selenium”如果失败了的话&#xff0c;可以尝试用命令“sudo easy_install selenium”来安装selenium; 2.安装好PyCharm后新建project&…

AI 绘画Stable Diffusion 研究(八)sd采样方法详解

大家好&#xff0c;我是风雨无阻。 本文适合人群&#xff1a; 希望了解stable Diffusion WebUI中提供的Sampler究竟有什么不同&#xff0c;想知道如何选用合适采样器以进一步提高出图质量的朋友。 想要进一步了解AI绘图基本原理的朋友。 对stable diffusion AI绘图感兴趣的朋…

C++11并发与多线程笔记(10) future其他成员函数、shared_future、atomic

C11并发与多线程笔记&#xff08;10&#xff09; future其他成员函数、shared_future、atomic 1、std::future 的成员函数1.1 std::future_status 2、std::shared_future&#xff1a;也是个类模板3、std::atomic原子操作3.1 原子操作概念引出范例&#xff1a;3.2 基本的std::at…

LangChain手记 Chains

整理并翻译自DeepLearning.AILangChain的官方课程&#xff1a;Chains&#xff08;源代码可见&#xff09; Chains 直译链&#xff0c;表达的意思更像是对话链&#xff0c;对话链的背后是思维链 LLM Chain&#xff08;LLM链&#xff09; 首先介绍了一个最简单的例子&#xff0c…