服务网关GateWay基础

      • 1. 网关基础介绍
        • 1.1 网关是什么
        • 1.2 为啥要用网关
        • 1.3 常见的网关组件
          • Nginx
          • Netflix Zuul
          • Spring Cloud Gateway
          • Kong
          • APISIX
          • 综合比较
      • 2. gateWay的使用
        • 2.1 springCloud整合gateway
        • 2.2 GateWay的相关用法
        • 2.3 GateWay路由使用示例
          • 基本用法
          • 转发/重定向
          • 负载请求
          • 动态路由
        • 2.5 断言(Predicate)
          • 自定义断言
        • 2.6 过滤器(Filter )
          • 自定义局部Filter
          • 自定义全局Filter

1. 网关基础介绍

1.1 网关是什么

​ 在微服务架构中,由于系统和服务的细分,导致系统结构变得非常复杂, 为了跨平台、统一集中管理api,同时不暴露后置服务。甚至有时候需要对请求进行一些安全、负载均衡、限流、熔断、灰度等中间操作,基于此类种种的客观需求一个类似综合前置的系统就产生了,这就是API网关(API Gateway)。(网关)是一种在微服务架构中使用的服务器端组件,用于管理请求的转发和路由。它充当了系统的入口点,接收来自客户端的请求,并将其转发到相应的微服务实例上。

1.2 为啥要用网关

项目使用了微服务架构后,没有统一的网关服务,客户端直接与具体的微服务交互

  1. 安全隐患:服务端直接暴露,服务器易受攻击。
  2. 日志、监控、鉴权等统一操作 需要在不同微服务上重复处理
  3. 服务拆分或者合并,重构困难。

随着微服务架构在落地的过程中,如何统一入口,统一安全、高性能等问题成为新的挑战,所以微服务网关的重要性就体现出来了。

网关的核心功能

网关提供了统一的请求入口

  • 统一入口:可以进行日志、监控、限流等统一化的需求,屏蔽服务协议细节。
  • 权限控制:统一入口处可以进行用户的认证授权、请求的过滤、验证。
  • 负载均衡:根据规则将请求路由到不同的后端服务。

以下是 Gateway 的详解:

  1. 请求路由:Gateway 提供了灵活且强大的路由功能,可以根据请求的 URL、请求头、请求方法等条件将请求路由到不同的后端微服务。通过配置路由规则,可以实现 URL 重写、请求过滤、请求转发等功能。
  2. 负载均衡:Gateway 集成了负载均衡的能力,可以以均衡的方式将请求分发给多个后端微服务的实例。通过与负载均衡器(如 Ribbon、Spring Cloud LoadBalancer)配合使用,可以提高系统的可扩展性和容错性。
  3. 安全认证与授权:Gateway 可以作为安全层,处理身份验证和授权的问题。它可以集成认证服务器(如 Spring Security、OAuth2),对请求进行身份验证,并根据配置的权限规则控制访问授权。
  4. 请求过滤与增强:Gateway 具备强大的过滤器功能,可以对请求进行修改、验证、限流等操作。通过编写自定义的过滤器,可以实现请求日志记录、请求转换、请求重试等功能。
  5. 动态路由:Gateway 支持动态路由的功能,可以根据配置的规则动态地将请求路由到目标微服务。这使得系统能够动态调整路由规则,而无需重新部署或重启网关。
  6. 监控与统计:Gateway 提供了丰富的监控和统计功能,可以通过集成监控平台(如 Spring Cloud Sleuth、Prometheus)来收集和展示关于请求流量、性能指标等方面的数据。

总结来说,Gateway 是微服务架构中的入口组件,它通过灵活的路由、负载均衡、安全认证、请求过滤等功能,为系统提供了高效、可靠的请求处理机制。它可以帮助实现微服务的解耦、横向扩展、安全性和可维护性。在使用 Gateway 时,需要考虑系统的架构需求、性能要求和安全要求,并根据实际情况进行配置和定制化开发。

1.3 常见的网关组件

对比这几种网关可以从多个方面进行分析,包括性能、扩展性、生态支持、功能丰富程度等。下面是对这几种网关的详细分析:

Nginx

优点:

  1. 性能优越: Nginx以其高性能而闻名,适用于高并发和大规模负载的场景。
  2. 反向代理和负载均衡: 提供强大的反向代理和负载均衡功能。
  3. 灵活性: 可以通过Lua脚本进行二次开发,扩展功能。

缺点:

  1. 微服务集成: 不直接支持微服务架构,需要额外的开发和配置。
  2. 功能相对简单: 相较于专门的微服务网关,功能相对简单,需要额外的配置和开发来实现一些高级功能。
Netflix Zuul

优点:

  1. 微服务集成: 与Spring Cloud整合,天然支持微服务架构。
  2. 易于使用: 使用简单,适合初学者。

缺点:

  1. 性能问题: 在大规模微服务架构中,性能可能会成为瓶颈。
  2. 更新慢: 由于Netflix停止维护,可能会缺乏新功能和及时的安全更新。
Spring Cloud Gateway

优点:

  1. WebFlux: 基于WebFlux,支持异步和非阻塞式的请求处理。
  2. 灵活性: 支持Groovy脚本,可以灵活扩展功能。
  3. 微服务集成: 与Spring Cloud生态系统无缝集成,天然支持微服务。

缺点:

  1. 相对年轻: 相对较新,可能在一些功能上不如成熟的解决方案。
Kong

优点:

  1. 高可用性: 基于Nginx和Lua,提供高可用性和易扩展性。
  2. 插件系统: 支持丰富的插件系统,提供了许多现成的扩展。
  3. 易扩展: 易于扩展和定制,适合大型复杂场景。

缺点:

  1. 相对庞大: 相对于简单的网关,Kong可能显得庞大一些。
APISIX

优点:

  1. 云原生: 基于云原生技术,支持高性能和可扩展性。
  2. 插件系统: 提供丰富的插件系统,易于定制和扩展。
  3. 易于使用: 设计简单,易于使用。

缺点:

  1. 相对较新: 与其他解决方案相比,APISIX相对较新,可能在一些方面不如成熟的解决方案。
综合比较
  • 性能: Nginx在性能上有优势,但其他网关也在不同程度上提供了高性能。
  • 微服务集成: Spring Cloud Gateway和Netflix Zuul天然支持微服务架构。
  • 灵活性: Kong和APISIX提供了更丰富的插件系统,具有更高的灵活性和可扩展性。
  • 生态支持: Spring Cloud Gateway和Zuul是Spring Cloud生态的一部分,与其他Spring Cloud组件天然集成。
  • 社区活跃度: Nginx、Spring Cloud Gateway、Kong都有活跃的社区支持,而Netflix Zuul的社区支持相对较少。
  • 成熟度: Nginx和Netflix Zuul相对来说更成熟,而Spring Cloud Gateway、Kong和APISIX相对较新。

选择适合自己需求的网关取决于具体的业务场景、性能要求、团队技术栈等因素。

2. gateWay的使用

2.1 springCloud整合gateway
  • maven依赖
 <!--spring cloud gateway 网关-->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-gateway</artifactId>
 </dependency>
  • 添加配置
spring:
  cloud:
    gateway:
      routes:
        - id: example-route   # 路由的Id,没有固定规则但要求唯一,建议配合服务名
          uri: http://com.xiu.com  # 匹配后提供服务的路由根路径地址
          predicates:                
            - Path=/api-gateway/xiu/**         # 断言 路径相匹配的进行路由
          filters:
            - StripPrefix=1        #去掉请求的第一个路径元素

上述配置意思:当请求路径匹配 /api-gateway/xiu/** 时,会将请求转发到 http://com.xiu.com,并去除掉请求路径的第一个路径元素。

比如访问http://ip:port/api-gateway/xiu/sayHello 则会通过路由访问真实的请求地址为http://com.xiu.com/sayHello

路由主要有四个配置:

  • 路由id(id): 没有固定规则但要求唯一,建议配合服务名
  • 路由目标(uri): 匹配后提供服务的路由地址
  • 路由断言(predicates):判断路由的规则 - Path=/xiu/** 需要匹配的路由
  • 路由过滤器(filters):对请求或响应做处理
  • 开启网关

应用程序主类上添加 @EnableGateway 注解或者 spring.cloud.gateway.enabled=true启用 Spring Cloud Gateway。

其实默认网关是开启的,所以不加上述配置也行也可以

2.2 GateWay的相关用法

下面是GateWay的请求流程概述

在这里插入图片描述

一个请求进入网关,首先请求会通过GateWay Handler Mapping 进行路由匹配,匹配成功后请求会交由GateWay Web Handler。请求会经过一系列的过滤器链(责任链模式),进行每个filer的前置和后置处理。

2.3 GateWay路由使用示例
基本用法

​ Route 路由 网关的基本组成部分。它由一个ID、一个目标URI、一组谓词predicates和一组过滤器filters组成

  • 配置predicates
spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        #简写 
        - Cookie=mycookie,regexp
        #完整写法
        - name: Cookie
          args:
            name: mycookie2
            regexp: regexp

上述配置的predicates 标识 请求中必须要包含Cookie参数 且cookie的name 为mycookie,value为regex 正则表达式匹配的值。

  • 配置filters
spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        filters:
        #简写
        - AddRequestHeader=token, 111

如上,会给匹配的请求添加 请求头为token=111的header信息。

转发/重定向

转发是GateWay最普通的功能,我们大部分的路由规则也都是进行转发处理。

spring:
  cloud:
    gateway:
      routes:
        # 转发路由配置 路径匹配/forward/** 请求路由到http://www.baidu.com上
        - id: forward-route
          uri: http://www.baidu.com
          predicates:
            - Path=/forward/**
          filters:
            - StripPrefix=1
        # 重定向路由配置  路径匹配/redirect/** 请求路由到http://www.jd.com上,原来的uri不起作用了
        - id: redirect-route
          uri: https://www.baidu.com
          predicates:
            - Path=/redirect/**
          filters:
            - RedirectTo=302,https://www.jd.com
负载请求

​ 在实际工作场景中,大部分需要路由转发的微服务都是多个实例,并部署到不同的服务机器上(不同的ip或者不同的域名),所以这里的uri 直接写死ip不合适。此处可以将网关服务作为微服务注册到注册中心,其可以从注册中心获取到所有服务实例同时路由配置中uri 使用lb://,这样,客户端请求网关,路径匹配成功后,网关会将请求负载到多个实例中的其中一个,这样服务变更不用频繁修改路由配置。

  • 引入注册中心依赖
 <dependency>
     <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
 </dependency>
  • 开启服务注册

​ 主类中添加@EnableDiscoveryClient

  • yml配置
spring:
  cloud:
    nacos:
      discovery:
        server-addr: ip:port
        namespace: my-namespace
    gateway:
      routes:  
        - id: customer
          #此处uri没有写死,而是使用了(load blance) lb://${service_name} 负载均衡策略到某个具体实例
          uri: lb://customer-server
          predicates:
            - Path=/api-gateway/customer/**
          filters:
            - StripPrefix=2
动态路由

上述服务路由配置都是硬编码配置这种配置方式,在启动网关服务后,将无法修改路由配置,若有新服务上线的话,则需要重新部署网关服务。如果使用动态路由则能很好的解决上述问题。

  • 添加pom依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  • 暴露网关服务端点
management:
  endpoints:
    web:
      exposure:
        include: '*'
        exclude: env
  endpoint:
    health:
      show-details: always
     
#通过如下两个url进行访问(端口根据以及ip根据自己设定进行调整)     
#http://localhost:9001/actuator
#http://localhost:9001/actuator/gateway/routes      
  • 实现动态路由相关功能
@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {

    @Resource
    private RouteDefinitionWriter routeDefinitionWriter;

    //事件发布组件 用于网关运行中 发布RefreshRoutesEvent事件刷新内存中路由配置
    @Resource
    private ApplicationEventPublisher publisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }

    //新增路由
    public void add(RouteDefinition routeDefinition){
        /**
         * 新增的Actuator Endpoint,刷新路由的时候,先加载路由配置到内存中,
         * 然后再使用RefreshRoutesEvent事件刷新内存中路由配置。
         */
        routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
    }

    // 删除路由
    public void delete(String id){
        routeDefinitionWriter.delete(Mono.just(id)).subscribe();
    }
}
  • 添加路由入口

    可以通过暴露API接口、或者容器启动的时候添加

    @Service
    public class RouterConfig  implements InitializingBean {
    
        private final static Logger log = LoggerFactory.getLogger(RouterConfig.class);
        @Resource
        private DynamicRouteServiceImpl dynamicRouteService;
    
        @Override
        public void afterPropertiesSet() throws Exception {
            //模拟容器启动过程中 添加动态路由
            //路由数据可以在服务启动过程中从存储层获取
            RouteDefinition route = new RouteDefinition();
            route.setId("example-route");
            route.setUri(new URI("lb://customer-server"));
            //添加 predicates
            List<PredicateDefinition>  predicates = Lists.newArrayList();
            //path 断言
            PredicateDefinition path = new PredicateDefinition();
            path.setName("Path");
            Map<String,String> args = Maps.newHashMap();
            args.put("pattern","/api-gateway/customer/**");
            path.setArgs(args);
            predicates.add(path);
            route.setPredicates(predicates);
            //添加filter
            List<FilterDefinition> filters = Lists.newArrayList();
            FilterDefinition filter = new FilterDefinition();
            filter.setName("StripPrefix");
            Map<String,String> filterArgs = Maps.newHashMap();
            filterArgs.put("_genkey_0","2");
            filter.setArgs(filterArgs);
            filters.add(filter);
            route.setFilters(filters);
    
            String routJson = JSON.toJSONString(route);
            log.info("添加的路由信息:{}",routJson);
    
            dynamicRouteService.add(route);
        }
    }
    

    等价于

          routes:  
            - id: customer
              #此处uri没有写死,而是使用了(load blance) lb://${service_name} 负载均衡策略到某个具体实例
              uri: lb://customer-server
              predicates:
                - Path=/api-gateway/customer/**
              filters:
                - StripPrefix=2
    

    访问http://ip:port/api-gateway/customer/v1/customer/sayHello 会转发到customer模块的某个实例节点http://ip:port/v1/customer/sayHello。

2.5 断言(Predicate)

断言就是说: 在 什么条件下 才能进行路由转发。 gateWay提供了如下多种断言
在这里插入图片描述

自定义断言

设置传入的age参数在指定范围区间才能正常访问。

/**
 * 自定义的断言工厂<br>
 * 1.名称必须是 ${配置}+RoutePredicateFactory<br>
 * 2.必须继承AbstractRoutePredicateFactory<配置类>
 */
@Component
public class AgeRoutePredicateFactory  extends AbstractRoutePredicateFactory<AgeRoutePredicateFactory.Config> {
    public AgeRoutePredicateFactory() {
        super(AgeRoutePredicateFactory.Config.class);
    }
    //用于从配置文件中获取参数值赋值到配置类中的属性上
    @Override
    public List<String> shortcutFieldOrder() {
        //这里的顺序要跟配置文件中的参数顺序一致
        return Arrays.asList("minAge", "maxAge");
    }
    //断言
    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new Predicate<ServerWebExchange>() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                //从serverWebExchange获取传入的参数
                String ageStr = serverWebExchange.getRequest().getQueryParams().getFirst("age");
                if (StringUtils.isNotEmpty(ageStr)) {
                    int age = Integer.parseInt(ageStr);
                    return age > config.getMinAge() && age < config.getMaxAge();
                }
                return true;
            }
        };
    }
    //配置类
    @Data
    public  static class Config{
        private int minAge;
        private int maxAge;
    }
}

上面的代码创建了一个AgeRoutePredicateFactory 自定义的断言组件。自定义的断言类名是"Age"+"RoutePredicateFactory"的形式。

所以在断言语句中可以配置Age。

配置 指定参数在年龄范围的请求才会被路由到对应的。

    gateway:
      routes:
        #负载均衡
        - id: customer
          # 此处uri没有写死,而是使用了(load balance) 
          # lb://${service_name} 负载均衡策略到某个具体实例
          uri: lb://customer-server
          predicates:
            - Path=/api-gateway/customer/**
            - Age=24,35 # 限制年龄只有在24到35岁之间的人才能找到工作
          filters:
            - StripPrefix=2

请求

http://127.0.0.1:8804/api-gateway/customer/v1/customer/sayHello?age=30 #请求正常转发
http://127.0.0.1:8804/api-gateway/customer/v1/customer/sayHello?age=15 #请求不会转发
#注意转发到的真实请求地址需要接收GET请求的参数age。
2.6 过滤器(Filter )

在SpringCloud Gateway中内置了很多不同类型的网关路由过滤器。如下

过滤器工厂作用参数
AddRequestHeader为原始请求添加HeaderHeader的名称及值
AddRequestParameter为原始请求添加请求参数参数名称及值
AddResponseHeader为原始响应添加HeaderHeader的名称及值
DedupeResponseHeader剔除响应头中重复的值需要去重的Header名称及去重策略
Hystrix为路由引入Hystrix的断路器保护HystrixCommand的名称
FallbackHeaders为fallbackUri的请求头中添加具体的异常信息Header的名称
PrefixPath为原始请求路径添加前缀前缀路径
PreserveHostHeader为请求添加一个preserveHostHeader=true的属性,路由过滤器会检查该属性以决定是否要发送原始的Host
RequestRateLimiter用于对请求限流,限流算法为令牌桶keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus
RedirectTo将原始请求重定向到指定的URLhttp状态码及重定向的url
RemoveHopByHopHeadersFilter为原始请求删除IETF组织规定的一系列Header默认就会启用,可以通过配置指定仅删除哪些Header
RemoveRequestHeader为原始请求删除某个HeaderHeader名称
RemoveResponseHeader为原始响应删除某个HeaderHeader名称
RewritePath重写原始的请求路径原始路径正则表达式以及重写后路径的正则表达式
RewriteResponseHeader重写原始响应中的某个HeaderHeader名称,值的正则表达式,重写后的值
SaveSession在转发请求之前,强制执行WebSession::save操作
secureHeaders为原始响应添加一系列起安全作用的响应头无,支持修改这些安全响应头的值
SetPath修改原始的请求路径修改后的路径
SetResponseHeader修改原始响应中某个Header的值Header名称,修改后的值
SetStatus修改原始响应的状态码HTTP 状态码,可以是数字,也可以是字符串
StripPrefix用于截断原始请求的路径使用数字表示要截断的路径的数量
Retry针对不同的响应进行重试retries、statuses、methods、series
RequestSize设置允许接收最大请求包的大小。如果请求包大小超过设置的值,则返回 413 Payload Too Large请求包大小,单位为字节,默认值为5M
ModifyRequestBody在转发请求之前修改原始请求体内容修改后的请求体内容
ModifyResponseBody修改原始响应体的内容修改后的响应体内容
Default为所有路由添加过滤器过滤器工厂名称及值
自定义局部Filter
/**
 * 自定义的局部过滤器工厂<br>
 * 1.名称必须是 ${配置}+GatewayFilterFactory<br>
 * 2.必须继承AbstractGatewayFilterFactory<配置类>
 */
@Component
public class LogGatewayFilterFactory extends AbstractGatewayFilterFactory<LogGatewayFilterFactory.Config> {

    public LogGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("consoleLog");
    }

    @Override
    public GatewayFilter apply(Config config) {
       return new GatewayFilter() {
           @Override
           public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
               if (config.isConsoleLog()) {
                   System.out.println("consoleLog已经开启了....");
               }
               return chain.filter(exchange);
           }
        };
    }
    @Data
    public static class Config{
        private boolean consoleLog;
    }
}

配置

    gateway:
      routes:
       - id: customer
          #此处uri没有写死,而是使用了(load balance) lb://${service_name} 负载均衡策略到某个具体实例
          uri: lb://customer-server
          predicates:
            - Path=/api-gateway/customer/**
            - Age=24,35 # 限制年龄只有在24到35岁之间的人才能找到工作
          filters:
            - StripPrefix=2
            - Log=true #开启日志打印
自定义全局Filter
/**
 * 自定义的局部过滤器工厂<br>
 * 需要实现GlobalFilter、Ordered<br>
 */
@Component
public class MyGlobalGateWayFactory implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("全局过滤器前置处理");
        return chain.filter(exchange)
                .then(Mono.fromRunnable(
                        () -> System.out.println("全局过滤器后置处理")
                ));
    }
    @Override
    public int getOrder() {
        return 0;
    }
}

使用@Component直接会生效。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录 797. 所有可能的路径

题目 给你一个有 n 个节点的 有向无环图&#xff08;DAG&#xff09;&#xff0c;请你找出所有从节点 0 到节点 n-1 的路径并输出&#xff08;不要求按特定顺序&#xff09; graph[i] 是一个从节点 i 可以访问的所有节点的列表&#xff08;即从节点 i 到节点 graph[i][j]存在一…

电视音频中应用的音频放大器

电视机声音的产生原理是将电视信号转化为声音&#xff0c;然后通过扬声器将声音播放出来。当我们打开电视并选择频道时&#xff0c;电视机首先从天线或有线电视信号中获取声音信号。声音信号经过放大器放大之后&#xff0c;就能够通过扬声器发出声音。电视机声音的产生原理和音…

React【Day4下+5】

环境搭建 使用CRA创建项目&#xff0c;并安装必要依赖&#xff0c;包括下列基础包 Redux状态管理 - reduxjs/toolkit 、 react-redux路由 - react-router-dom时间处理 - dayjsclass类名处理 - classnames移动端组件库 - antd-mobile请求插件 - axios 配置别名路径 1. 背景知识…

Java | Leetcode Java题解之第32题最长的有效括号

题目&#xff1a; 题解&#xff1a; class Solution {public int longestValidParentheses(String s) {int left 0, right 0, maxlength 0;for (int i 0; i < s.length(); i) {if (s.charAt(i) () {left;} else {right;}if (left right) {maxlength Math.max(maxlen…

【Linux】NFS网络文件系统搭建

一、服务端配置 #软件包安装 [roothadoop01 ~]# yum install rpcbind nfs-utils.x86_64 -y [roothadoop01 ~]# mkdir /share#配置文件修改 #格式为 共享资源路径 [主机地址] [选项] # [roothadoop01 ~]# vi /etc/exports /share 192.168.10.0/24(rw,sync,no_root_squash) #…

智慧社区整体解决方案(PPT)

1、背景与现状分析 2、解决方案 3、功能及应用场景介绍 软件资料清单列表部分文档&#xff1a; 工作安排任务书&#xff0c;可行性分析报告&#xff0c;立项申请审批表&#xff0c;产品需求规格说明书&#xff0c;需求调研计划&#xff0c;用户需求调查单&#xff0c;用户需求…

机器视觉系统:PVC片材表面缺陷检测的锐利“眼睛”

PVC片材作为一种广泛应用于建筑、包装、医疗等领域的塑料材料&#xff0c;其表面质量对于产品的性能和使用寿命至关重要。然而&#xff0c;在生产过程中&#xff0c;PVC片材可能会出现多种表面缺陷&#xff0c;如划痕、污渍、气泡、压痕等。为了确保产品质量&#xff0c;机器视…

【五十九】【算法分析与设计】高精度加法和高精度减法

高精度加法 高精度加法&#xff0c;也称为大数加法&#xff0c;是一种能够处理超过标准数据类型&#xff08;如 int 或 long&#xff09;允许范围的大数字的算法。 高精度数字通常无法使用单一的标准数据类型来存储。一个常见的方法是使用数组或字符串来表示每一位数字。例如…

算法课程笔记——STL键值对map

map当下标无限的数组 重点是对应关系&#xff0c;一般不修改compare 类比set 没有lowerbound&#xff0c;因为遍历是无序的 ; map不能用sort函数排序 但可用vector转化为map使用 std::set<std::pair<TKEY, mutable TVAL> > ≈ std::map<TKEY, TVAL>

电子印章盖骑缝章

电子印章盖骑缝章是指在电子文档&#xff08;如PDF文件&#xff09;中&#xff0c;使用电子印章技术&#xff0c;为文档添加一个跨越多页、连续显示的电子印章图像&#xff0c;以模拟传统纸质文档上的骑缝章效果。以下是实现电子印章盖骑缝章的步骤&#xff1a; 一. 准备电子印…

C++_特殊类的设计和单例模式

文章目录 学习目标&#xff1a;1.请设计一个类&#xff0c;不能被拷贝2. 请设计一个类&#xff0c;只能在堆上创建对象3. 请设计一个类&#xff0c;只能在栈上创建对象4. 请设计一个类&#xff0c;不能被继承5. 请设计一个类&#xff0c;只能创建一个对象(单例模式) 特殊类的设…

C++修炼之路之多态--多态的条件与例外,重载+重写+重定义

目录 前言 一&#xff1a;构成多态的条件及一些特殊情况&#xff08;前提是构成父子类&#xff09; 1.多态是在不同的继承关系的类对象&#xff0c;去调用同一函数&#xff0c;产生了不同的结果 2.两个条件 3.三同的两个例外 1.协变---返回值类型可以不同&#xff0c;但必…

外贸客户开发软件哪个好用一点,效果好数据精准的?

选择外贸客户开发软件时&#xff0c;你需要考虑软件的功能、易用性、数据质量以及价格等因素。以下是一些常用的外贸客户开发软件&#xff0c;它们都具有不同的特点和优势&#xff1a; 易谷歌地图数据采集大师&#xff1a; 专为做外贸的朋友开发的一款基于谷歌地图数据采集的软…

Python-VBA函数之旅-hash函数

目录 一、hash函数的定义&#xff1a; 二、hash函数的工作方式&#xff1a; ​三、hash函数的优缺点&#xff1a; 四、hash函数的常见应用场景&#xff1a; 1、hash函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&…

C++进阶:搜索树

目录 1. 二叉搜索树1.1 二叉搜索树的结构1.2 二叉搜索树的接口及其优点与不足1.3 二叉搜索树自实现1.3.1 二叉树结点结构1.3.2 查找1.3.3 插入1.3.4 删除1.3.5 中序遍历 2. 二叉树进阶相关练习2.1 根据二叉树创建字符串2.2 二叉树的层序遍历I2.3 二叉树层序遍历II2.4 二叉树最近…

37、Tomato(VulnHub)

Tomato 一、nmap 2211是ssh的端口&#xff0c;21的ftp也不是弱密码 二、web渗透 随便看看 目录爆破 /seclists/Discovery/Web-Content/common.txt /antibot_image/antibots/readme.txt 发现该站点存在反爬机制 /antibot_image/antibots/info.php 提示我们该网页存在个参数 GET&…

Java高阶私房菜:高并发之线程池底层原理学习

以往我们需要获取外部资源&#xff08;数据源、Http请求等&#xff09;时&#xff0c;需要对目标源创建链接对象&#xff0c;三次握手成功后方可正常使用&#xff0c;为避免持续的资源占用和可能的内存泄漏&#xff0c;还需要调用目标对象close方法释放资源销毁对象。这一建一销…

排序算法集合

912. 排序数组 趁着这道题总结下排序方法 1.快速排序 算法描述 1.从数列中挑出一个元素&#xff0c;称为"基准"&#xff08;pivot&#xff09;&#xff0c; 2.重新排序数列&#xff0c;所有比基准值小的元素摆放在基准前面&#xff0c;所有比基准值大的元素摆在基…

稀碎从零算法笔记Day54-LeetCode:39. 组合总和

题型&#xff1a;数组、树、DFS、回溯 链接&#xff1a;39. 组合总和 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数…

智慧化赋能园区新未来:探讨智慧园区如何以科技创新为引擎,推动产业转型升级

随着科技的飞速发展&#xff0c;智慧化已成为推动园区产业升级和转型的重要引擎。智慧园区&#xff0c;以其高效、便捷、智能的特性&#xff0c;正逐步改变传统的产业园区模式&#xff0c;为产业发展注入新的活力。本文旨在探讨智慧园区如何以科技创新为引擎&#xff0c;推动产…