spring-cloud微服务gateway

核心部分:routes(路由), predicates(断言),filters(过滤器)

pom依赖

 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-gateway</artifactId>
 </dependency>
 
 <dependency>
     <groupId>com.alibaba.cloud</groupId>
     <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
 </dependency>

yml配置网关

server:
  port: 8087
spring:
  application:
    name: gateway-nacos
  cloud:
    gateway:
      routes: #路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
        - id: product_route  #当前路由的标识,要求唯-
          uri: http://localhost:8086 #请求要转发到的地址
          order: 1 #路由的优先级,数字越小级别越高
          predicates: #断言(就是路由转发要满足的条件)
            - Path=/product-service/** #当请求路径满足Path指定的规则时,才进行路由转发
              #http://localhost:8087/product-service/product/9  路由器到⬇
              #http://localhost:8086/product-service/product/9
          filters: #过滤器,请求在传递过程中可以通过过滤器对其进行一定的修改
            - StripPrefix=1 #转发之前去掉1层路径
              ##http://localhost:8086/product/9

yml注册到nacos配置网关

server:
  port: 8087
spring:
  application:
    name: gateway-nacos
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.11.47:18848
        username: nacos
        password: nacos

    gateway:
      routes: #路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
        - id: product_route  #当前路由的标识,要求唯-
          uri: lb://product_naocs #lb指的是从nacos中按名称获取微服务,并遵循负载均衡策略
          order: 1 #路由的优先级,数字越小级别越高
          predicates: #断言(就是路由转发要满足的条件)
            - Path=/product-service/** #当请求路径满足Path指定的规则时,才进行路由转发
          filters: #过滤器,请求在传递过程中可以通过过滤器对其进行一定的修改
            - StripPrefix=1 #转发之前去掉1层路径,

yml配置网关(约定大于配置的方式,一般不用这样的配置),例如访问http://localhost:8087/product-service/product/9 ,中的product-service为服务的名字

server:
  port: 8087
spring:
  application:
    name: gateway-nacos
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.11.47:18848
        username: nacos
        password: nacos

    gateway:
      discovery:
        locator:
          enabled: true    #是否启动自动识别nacos服务(约定大于配置)

注意:若要使用自定义配置,则“不能开启注册中心的路由功能”,否则自定义的策略会失,设置中心路由功能为false

server:
 port: 8087
spring:
 application:
   name: gateway-nacos
 cloud:
   nacos:
     discovery:
       server-addr: 192.168.11.47:18848
       username: nacos
       password: nacos
   gateway:
     discovery:
       locator:
         enabled: false  #是否启动自动识别nacos服务(约定大于配置)

查看网关内置断言官网文档,如果用上时间可以设置获取使用方法:ZonedDateTime.now(),获取

内置断言例子,日期2024-01-20T17:42:47都可以访问,超过时间访问返回404

server:
  port: 8087
spring:
  application:
    name: gateway-nacos
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.11.47:18848
        username: nacos
        password: nacos

    gateway:
      routes: #路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
        - id: product_route #当前路由的标识,要求唯-
          uri: http://localhost:8086 #请求要转发到的地址
          order: 1 #路由的优先级,数字越小级别越高
          predicates: #断言(就是路由转发要满足的条件)
            - Path=/product-service/** #当请求路径满足Path指定的规则时,才进行路由转发
            - Before=2024-08-20T17:42:47.789-07:00[America/Denver]
          filters: #过滤器,请求在传递过程中可以通过过滤器对其进行一定的修改
            - StripPrefix=1 #转发之前去掉1层路径,

        - id: stock-nacos #当前路由的标识,要求唯-
          uri: http://localhost:8085 #请求要转发到的地址
          order: 1 #路由的优先级,数字越小级别越高
          predicates: #断言(就是路由转发要满足的条件)
            - Path=/stock-nacos/** #当请求路径满足Path指定的规则时,才进行路由转发
            - Before=2024-08-20T17:42:47.789-07:00[America/Denver]
          filters: #过滤器,请求在传递过程中可以通过过滤器对其进行一定的修改
            - StripPrefix=1 #转发之前去掉1层路径,

内部断言的类名是有断言前缀和后缀组成如下

Path+RoutePredicateFactory
RemoteAddr+RoutePredicateFactory
RemoteAddr+RoutePredicateFactory
Header+RoutePredicateFactory

  • 基于远程地址的断言工厂

  • RemoteAddrRoutePredicateFactory:接收一个IP地址段,判断请求主机地址是否在地址段中
- RemoteAddr=192.168.1.1/24
  • 基于Cookie的断言工厂

  • CookieRoutePredicateFactory:接收两个参数,cookie 名字和一个正则表达式。 判断请求cookie是否具有给定名称且值与正则表达式匹配。
- RemoteAddr=chocolate, ch.
  • 基于Header的断言工厂

  • HeaderRoutePredicateFactory:接收两个参数,标题名称和正则表达式,判断请求Header是否具有给定名称且值与正则表达式匹配。
- Header=X-Request-Id,\d+
  • 基于Host的断言工

  • HostRoutePredicateFactory:接收一个参数,主机名模式。判断请求的Host是否满足匹配规则
- Host=**.testhost.org
基于Method请求方法的
  • 基于Method请求方法的断言工厂

  • MethodRoutePredicateFactory:接收一个参数,判断请求类型是否跟指定的类型匹配
 - Method=GET
  1. 基于Path请求路径的断言工厂

  2. PathRoutePredicateFactory:接收一个参数,判断请求的URI部分是否满足路径规则。
#多个路径使用逗号,隔开
- Path=/foo/{segment}1 , /product/add
  • 基于Query请求参数的断言工厂

  • QueryRoutePredicateFactory:接收两个参数,请求param和正则表达式,判断请求参数是否具有给定名称且值与正则表达式匹配,
- Query=baz, ba.

基于Path请求路径的断言工厂

自定义路由断言工厂

可以查看路径路由的断言工厂,选择AbstractRoutePredicateFactory按Ctrl+H既可以显示出全部的路由断言工厂,可以复制一份修改成自定义的断言工厂

在这里插入图片描述

自定义路由断言工厂需要继承 AbstadRoutepredicatefacdoy类,重写 ap)y方法的透辑,在apy方法中可以通过 excthange.geiequest) 拿到 serneiHpReque 对象,从而可以获取到清求的参数、请求方式、请求头等信息

1. 必须spring组件 bean
2. 类必须加上RoutePredicateFactory作为结尾(底层的处理的约定大于配置自定会读取到的)
3. 必须继承AbstractRoutePredicateFactory
4. 必须声明静态内部类 声明属性来接收 配置文件中对应的断言的信息
5. 需要结合shortcutFieldOrder进行绑定
6. 通过apply进行逻辑判断 true就是匹配成功 false匹配失败

自定义路由断言工厂类

package com.test.gate.config;

import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

/**
 * @Description:
 * @Author: xu
 * @Data: 2024-2024/4/11-21
 * @Version: V1.0
 */
@Component
public class CheckAuthRoutePredicateFactory extends AbstractRoutePredicateFactory<CheckAuthRoutePredicateFactory.Config> {

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

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

    public Predicate<ServerWebExchange> apply(final Config config) {
        return new GatewayPredicate() {
            public boolean test(ServerWebExchange exchange) {
                if (config.getParam().equals("zhangSan")) {
                    return true;
                }
                return false;
            }

            public Object getConfig() {
                return config;
            }

            public String toString() {
                return String.format("Query: param=%s regexp=%s", config.getParam());
            }
        };
    }

    @Validated
    public static class Config {

        private String param;

        public Config() {
        }

        public String getParam() {
            return this.param;
        }

        public void setParam(String param) {
            this.param = param;
        }

    }
}

yml配置(如果一个路由里面有多个断言条件是且的关系,都需要满足才跳转uri)

server:
  port: 8087
spring:
  application:
    name: gateway-nacos
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.11.47:18848
        username: nacos
        password: nacos

    gateway:
#      discovery:
#        locator:
#          enabled: true    #是否启动自动识别nacos服务(约定大于配置)

      routes: #路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
        - id: product_route #当前路由的标识,要求唯-
          uri: http://localhost:8086 #请求要转发到的地址
          order: 1 #路由的优先级,数字越小级别越高
          predicates: #断言(就是路由转发要满足的条件)
            - Path=/product-service/**,/ddd/s #当请求路径满足Path指定的规则时,才进行路由转发
            - Before=2024-08-20T17:42:47.789-07:00[America/Denver]
            - CheckAuth=zhangSan1
          filters: #过滤器,请求在传递过程中可以通过过滤器对其进行一定的修改
            - StripPrefix=1 #转发之前去掉1层路径,

查看网关各种局部过滤器官网

自定义网关过滤器和自定义断言都全部类似

继承AbstractNameValueGatewavFilterFactory日我们的自定义名称必须要以GatewavFiterFactorv结尾并交给spring管理

package com.test.gate.config;

import com.alibaba.nacos.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

/**
 * @Description:
 * @Author: xu
 * @Data: 2024-2024/4/12-11
 * @Version: V1.0
 */
@Component

public class CheckAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<CheckAuthGatewayFilterFactory.Config> {
    private static Logger log = LoggerFactory.getLogger(CheckAuthGatewayFilterFactory.class);

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

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            log.info("调用checkAuthGatewayFilterFactory==="
                    + config.getName());

            String name = exchange.getRequest().getQueryParams().getFirst("name");
            if (StringUtils.isNotBlank(name)) {
                if (config.getName().equals(name)) {
                    chain.filter(exchange);
                } else {
                    //返回404
                    exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
                    exchange.getResponse().setComplete();
                }
                //1 正常请求
                chain.filter(exchange);
            }
            return null;
        };
    }

    public static class Config {
        private String name;

        public Config() {
        }

        public String getName() {
            return this.name;
        }

        public void setName(String prefix) {
            this.name = name;
        }
    }
}
server:
  port: 8087
spring:
  application:
    name: gateway-nacos
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.11.47:18848
        username: nacos
        password: nacos

    gateway:
#      discovery:
#        locator:
#          enabled: true    #是否启动自动识别nacos服务(约定大于配置)

      routes: #路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
        - id: product_route #当前路由的标识,要求唯-
          uri: http://localhost:8086 #请求要转发到的地址
          order: 1 #路由的优先级,数字越小级别越高
          predicates: #断言(就是路由转发要满足的条件)
            - Path=/product-service/**,/ddd/s #当请求路径满足Path指定的规则时,才进行路由转发
            - Before=2024-08-20T17:42:47.789-07:00[America/Denver]
            - CheckAuth=zhangSan1
          filters: #过滤器,请求在传递过程中可以通过过滤器对其进行一定的修改
            - StripPrefix=1 #转发之前去掉1层路径,
            - CheckAuth=lisi

全局过滤器(Global Filters)配置

在这里插入图片描述

自定义全局过滤器(Global Filters)配置类(一般都是实现认证或者授权,或者做日记记录,不需要在配置文件做任何配置)

package com.test.gate.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @Description:
 * @Author: xu
 * @Data: 2024-2024/4/12-20
 * @Version: V1.0
 */
@Component
public class LogGlobalFilter implements GlobalFilter {
    private static Logger log = LoggerFactory.getLogger(LogGlobalFilter.class);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        //做业务处理,授权或者日记记录
        log.info(exchange.getRequest().getPath().value());
        return chain.filter(exchange);
    }
}

要启用 Reactor Netty 访问日志,请设置-Dreactor,netty.http,server.accessLogEnabled=true,它必须是 Java 系统属性,而不是 Spring Boot 属性。如果是jar包启动,就将网关打包成jar包,如下运行

java -jar gateway.jar -Dreactor,netty.http,server.accessLogEnabled=true

idea配置网关日记打印,在vm配置 -Dreactor.netty.http.server.accessLogEnabled=true

在这里插入图片描述

将网关日志记录全部输出到日志文件。以下示例创建一个Logback.xml 配置

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 按天滚动的文件输出 -->
    <appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>G:\temptemptemp\gatewaylog\logfile.log</file> <!-- 修改为你想要保存日志文件的路径 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>G:\temptemptemp\gatewaylog\logfile.%d{yyyy-MM-dd}.log
            </fileNamePattern> <!-- 指定按日期滚动的文件名格式 -->
            <maxHistory>30</maxHistory> <!-- 保留最多30天的历史日志文件 -->
        </rollingPolicy>
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>


    <!-- 异步日志输出 -->
    <appender name="async" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="ROLLING_FILE"/> <!-- 将异步 appender 链接到文件输出 -->
    </appender>

    <!-- 记录器配置 -->
    <logger name="reactor.netty.http.server.AccessLog" level="INFO" additivity="false">
        <appender-ref ref="async"/> <!-- 将异步 appender 应用于特定的日志记录器 -->
        <appender-ref ref="STDOUT"/> <!-- 控制台输出 -->
    </logger>

    <!-- 根日志级别设置 -->
    <root level="info">
        <appender-ref ref="STDOUT"/> <!-- 控制台输出 -->
        <appender-ref ref="ROLLING_FILE"/> <!-- 将按天滚动的文件输出器添加到根输出器中 -->
    </root>

</configuration>

Gateway跨域配置(CORS Configuration),网关官网跨域配置

方法一:yml配置文件配置跨域

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':  #运行跨域访问的资源
            allowedOrigins: "https://docs.spring.io"  #跨域允许来源
            allowedMethods:
            - GET
            - POST

方法二:通过配置类设置跨域(注意UrlBasedCorsConfigurationSource 导入的包是import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource)

package com.test.gate.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;

/**
 * @Description:
 * @Author: xu
 * @Data: 2024-2024/4/12-22
 * @Version: V1.0
 */
@Configuration
public class CorsConfig {

    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}

网关限流整合sentinel官网

pom.xml添加依赖整合sentinel,和官网配置的有以下不一样是因为spring-cloud-alibaba-sentinel-gateway这个依赖比adapter依赖多了SentinelSCGAutoConfiguration自定注入例如很多需要的bean

<!--sentinel整台gateway  以前版本使用adapter-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<!--sentinel的依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

配置文件配置sentinel

#   配置sentinel
    sentinel:
      transport:
        dashboard: 127.0.0.1:8858   #sentiel的dashboard地址

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

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

相关文章

RabbbitMQ基本使用及其五种工作模型

初识MQ 同步通讯和异步通讯 什么是同步通讯呢&#xff1f;举个例子&#xff0c;你认识了一个小姐姐&#xff0c;聊的很火热&#xff0c;于是你们慢慢开始打电话&#xff0c;视频聊天&#xff0c;这种方式就成为同步通讯&#xff0c;那什么是一部通讯呢&#xff0c;同样的&…

gitlab(docker)安装及使用

GitLab GitLab 是一个用于仓库管理系统的开源项目&#xff0c;使用Git作为代码管理工具&#xff0c;并在此基础上搭建起来的Web服务。 下载(docker) 查询docker镜像gitlab-ce gitlab-ce是它的社区版 [rootlocalhost ~]# docker search gitlab-ce NAME …

OpenCV基本图像处理操作(六)——直方图与模版匹配

直方图 cv2.calcHist(images,channels,mask,histSize,ranges) images: 原图像图像格式为 uint8 或 float32。当传入函数时应 用中括号 [] 括来例如[img]channels: 同样用中括号括来它会告函数我们统幅图 像的直方图。如果入图像是灰度图它的值就是 [0]如果是彩色图像 的传入的…

SETR——Rethinking系列工作,展示使用纯transformer在语义分割任务上是可行的,但需要很强的训练技巧

题目:Rethinking Semantic Segmentation from a Sequence-to-Sequence Perspective with Transformers 作者: 开源:https://fudan-zvg.github.io/SETR 1.研究背景 1.1 为什么要研究这个问题? 自[ 36 ]的开创性工作以来,现有的语义分割模型主要是**基于全卷积网络( FCN )的…

ubuntu20.04安装+ros-noetic安装+内网穿透frp

刷机后的系统安装 ubuntu20.04安装安装ros-noetic安装各种必要的插件安装vscode内网穿透连接实验室主机配置frpc和frps文件运行完成自动化部署免密登录linux的免密登录windows上的免密登录 内网穿透的参考链接&#xff1a;如何优雅地访问远程主机&#xff1f;SSH与frp内网穿透配…

Python学习笔记 - 正则表达式

前言 正则表达式&#xff08;Regular Expression&#xff0c;在代码中常简写为 regex、regexp、RE 或 re&#xff09;是预先定义好的一个“规则字符串”&#xff0c;通过这个“规则字符串”可以匹配、查找、替换那些符合“规则”的文本&#xff0c;也就是说正则表达式针对的目标…

MSTP/RSTP的保护功能

目录 原理概述 实验目的 实验内容 实验拓扑 1.配置RSTP/MSTP 2.配置BPDU保护 3.配置根保护 4.配置环路保护 5.配置TC-BPDU保护 原理概述 在RSTP或MSTP交换网络中&#xff0c;为了防止恶意攻击或临时环路的产生&#xff0c;可配置保护功能来增强网络的健壮性和安全性。…

C++vector类(个人笔记)

vector类 1.熟悉vector接口以及使用1.1vector的定义1.2vector迭代器使用1.3vector空间增长1.4vector增删查改1.5vector迭代器失效问题&#xff08;重点&#xff09; 2.vector的一些笔试题3.模拟实现vector 1.熟悉vector接口以及使用 vector的C官网文档 1.1vector的定义 (con…

用python快速读取大文件几个GB以上的csv数据文件

用python快速读取大文件几个GB以上的csv数据文件 遇到几个GB的csv大文件,用python读取时,可以通过next()函数一行行来读取以提高效率,然后分批量进行处理。 1、文件格式例图 其中第一、第二行是数据行数、列数汇总。 2、流程 1、把csv第一、第二行的数据说明,先读取出来…

Windows远程桌面连接虚拟机Linux

Windows远程桌面连接虚拟机Linux 需要先打开虚拟机的启用VNC连接使用VNC客户端进行连接 yum install -y tigervnc-server #安装tigervnc-server vncserver #启动一个vnc进程 #第一次启动会要求设置密码 #如果需要更改密码可以使用vncpasswd进行更改密码 vncserver -list #查看…

ASUS华硕ROG幻13笔记本电脑GV301R工厂模式原厂OEM预装Windows11系统,恢复出厂开箱状态

适用于型号&#xff1a;GV301RC、GV301RE、GV301RA 工厂模式安装包&#xff1a;https://pan.baidu.com/s/1gLme1VqidpUjCLocgm5ajQ?pwddnbk 提取码&#xff1a;dnbk 工厂模式Win11安装包带有ASUS RECOVERY恢复功能、自带所有驱动、出厂主题壁纸、系统属性专属联机支持标志…

java算法day55 | 动态规划part16 ● 583. 两个字符串的删除操作 ● 72. 编辑距离

583. 两个字符串的删除操作 思路&#xff1a; 和1143.最长公共子序列这道题思路相同&#xff0c;只不过需要对return的数据做一些操作。 class Solution {public int minDistance(String word1, String word2) {int[][] dpnew int[word1.length()1][word2.length()1];for(int …

06_定时器中断

72分频 72MHz 72000000 经过72分频 1000000

【攻防世界】ics-07

<?php session_start();if (!isset($_GET[page])) {show_source(__FILE__);die(); }if (isset($_GET[page]) && $_GET[page] ! index.php) {include(flag.php); }else {header(Location: ?pageflag.php); } <?phpif ($_SESSION[admin]) {$con $_POST[con];$…

可溶性PFA材质三角漏斗耐腐蚀进口聚四氟乙烯漏斗低溶出析出

PFA全名为可溶性聚四氟乙烯、全氟烷氧基树脂&#xff0c;成品外观透明可视&#xff0c;便于观察&#xff0c;有着良好的化学稳定性、耐温性&#xff0c;耐受强酸强碱以及各种有机溶剂&#xff0c;且PFA原料本身较为洁净&#xff0c;金属离子溶出析出少&#xff0c;经过清洗后可…

OpenCV——SUSAN边缘检测

目录 一、SUSAN算法二、代码实现三、结果展示 OpenCV——SUSAN边缘检测由CSDN点云侠原创&#xff0c;爬虫自重。如果你不是在点云侠的博客中看到该文章&#xff0c;那么此处便是不要脸的爬虫。 一、SUSAN算法 Susan边缘检测是一种经典的边缘检测算&#xff0c;它由Susan Smith…

1044: 顺序栈基本操作的实现

解法&#xff1a; #include<iostream> #include<stack> using namespace std; int main() {int n, a, k;stack<int> sk;cin >> n;while (n--) {cin >> a;sk.push(a);}cin >> k;while (k--) {sk.pop();}if (!sk.empty()) {cout << s…

C语言 | 自定义类型:struct结构体(详解)

目录&#xff1a; --前言 1. 结构体类型的定义与基础结构 2. 结构体的使用 3. typedef相关 4. 结构体的自引用 5. 结构体内存对齐 6. 结构体传参 7. 结构体实现位段 --前言&#xff1a; c语言中内置类型&#xff0c;也有自定义的类型。 例如&#xff1a;内置类型 in…

用html写文本变形动画

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>文本变形动画</title><link rel"stylesheet" href"./style.css"> </head> <body> <!-- 两个文本部分…

给你的Qt软件加个授权

写在前面 环境&#xff1a; Win11 64位 VS2019 Qt5.15.2 核心思路&#xff1a; 将授权相关信息加密保存到License.txt中&#xff0c;软件运行时获取并解密授权信息&#xff0c;判断是否在限制期限内即可。 加解密部分使用第三方openssl库进行&#xff0c;因此需要手动在…