SpringCloud学习-实用篇02

news2024/11/17 23:37:32

以下内容的代码可见:SpringCloud_learn/day02


1.Nacos配置管理

之前提到的Nacos是作为注册中心,除此之外它还有配置管理功能


统一配置管理

假设有多个微服务之间有关联,此时修改了某个微服务的配置后其他相关的微服务也需要重启,十分麻烦,此时就需要Nacos进行统一的配置管理,并且实现配置更改热更新(修改配置后服务不需要重启即可生效),具体步骤如下:

在这里插入图片描述

  • Nacos中添加配置信息:

在这里插入图片描述

  • 填写配置信息:图中填写的配置是有热更新需求的配置(比如控制启用哪个服务的配置或者模板类型的配置就可写在这)

在这里插入图片描述

将部分配置放到Nacos后,此时微服务就要获取到这些配置,首先需要注意以下两点:

  • 获取步骤是先读取到Nacos中配置的内容,再将其和本地配置文件的内容进行合并
  • 假设将Nacos地址放在本地配置文件中,就无法先读取到Nacos的配置文件,所以将Nacos地址放在优先级较高的配置文件bootstrap.yml

在这里插入图片描述

Nacos和本地获取配置具体操作步骤如下:

  • 引入Nacos的配置管理客户端依赖:
<!--nacos配置管理依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
  • userservice中的resource目录添加一个bootstrap.yml文件(一般将与Nacos相关的配置放在这个文件中,同时将application.yml中重复的配置删除):
# ${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}作为文件ID去Nacos读取配置
spring:
  application:
    name: userservice  # 服务名称
  profiles:
    active: dev  # 环境
  cloud:
    nacos:
      server-addr: localhost:8848  # nacos地址
      config:
        file-extension: yaml  # 文件后缀名
  • 测试是否读到Naocs配置文件:输入http://localhost:8081/user/now看是否输出相应格式的日期
@Value("${pattern.dateformat}")
private String dateformat;

@GetMapping("now")
public String now(){
    return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
}

tips:

  • 如果无法一直无法读取到相应日期可以重新install该模块

配置自动刷新

Nacos中的配置文件变更后,微服务无需重启就可感知。有以下两种方式:

  • @Value注入的变量所在类上添加注解@RefreshScope
@Slf4j
@RestController
@RequestMapping("/user")
@RefreshScope
public class UserController {
    
    @Value("${pattern.dateformat}")
    private String dateformat;
    ...
}
  • 使用@ConfigurationProperties注解(推荐使用)

    • 首先在user-service服务中添加一个类config/PatternProperties用于读取patterrn.dateformat属性:
    @Data
    @Component
    @ConfigurationProperties(prefix = "pattern")
    public class PatternProperties {
        private String dateformat;
    }
    
    • UserController中使用该类代替@Value:之前的@Value@RefreshScope就不需要了
    @GetMapping("now")
    public String now() {
        return LocalDateTime
            .now()
            .format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()));
    }
    

tips:

  • 建议将一些关键参数和需要运行时调整的参数放到nacos配置中心,一般都是自定义配置

多环境配置共享

微服务启动时会从nacos读取多个配置文件,无论profile如何变化,[spring.application.name].yaml一定会加载,因此多环境共享配置可写入该文件

  • [spring.application.name]-[spring.profiles.active].yaml,如userservice-dev.yaml
  • [spring.application.name].yaml,如userservice.yaml

假设在能读取到的配置文件中存在多个系统的属性,具体该读取哪个配置文件?

  • 服务名-profile.yaml >服务名称.yaml > 本地配置(前两个就是Nacos中的配置)

tips:

  • 每次更换测试环境或开发环境都要在配置文件中改写十分麻烦,可以在配置中直接更改再启动服务

在这里插入图片描述


搭建Nacos集群

之前Nacos全是单节点,而在生产环境中一定要部署为集群状态。部署的集群结构如下:

  • 包含3个Nacos节点(因为还是在一台机器上实践,所以将它们端口配置为不一样即可)
  • 使用Nginx作为负载均衡器代理3个Nacos
  • Nacos的配置从数据库(这里还是以单点数据库为例)中读取

在这里插入图片描述

搭建集群步骤如下:

  • 初始化数据库:SQL代码见SQL.txt(之后在Nacos进行的配置都会写入该数据库)

  • 下载并配置Nacos

    • 进入Nacosconf目录,修改配置文件cluster.conf.example,重命名为cluster.conf
    • cluster.conf文件中添加以下内容:
    127.0.0.1:8845
    127.0.0.1.8846
    127.0.0.1.8847
    
    • 修改同一个目录下的application.properties文件,添加数据库配置:
    # 把注释符号去掉并修改相应信息即可
    spring.datasource.platform=mysql
    db.num=1
    db.url.0=jdbc:mysql://127.0.0.1:3306/xxx?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
    db.user.0=xxx
    db.password.0=xxx
    
  • 启动Nacos

    • Nacos文件夹复制三份并分别命名(nacos1、nacos2、nacos3
    • 分别修改三个文件夹中的conf/application.properties的端口号
    server.port=8845
    server.port=8846
    server.port=8847
    
    • 分别启动三个Nacos节点:startup.cmd(以集群启动不再加参数)
  • 配置Nginx反向代理:

    • 修改conf/nginx.conf文件:注意是添加到http{xxx}范围内
    upstream nacos-cluster {
        server 127.0.0.1:8845;
        server 127.0.0.1:8846;
        server 127.0.0.1:8847;
    }
    
    server {
        listen       80;
        server_name  localhost;
    
        location /nacos {
        	proxy_pass http://nacos-cluster;
        }
    }
    
    • 启动Nginx(start nginx.exe),在浏览器访问http://localhost/nacos即可(停止Nginx的命令为nginx.exe -s stop)
  • 修改服务中的application.yml文件:

spring:
  cloud:
    nacos:
      server-addr: localhost:80 # Nacos地址(即在Nginx中配置的代理地址)

2.http客户端Feign


Feign替代RestTemplate

以前在order-service中利用RestTemplate发起远程调用的代码如下,主要存在两个问题:

String url = "http://userservice/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);
  • 代码可读性差,编程体验不统一
  • 参数复杂,URL难以维护

Feign是一个声明式的http客户端,它可以优雅的实现http请求的发送,解决上述问题。使用Feign的步骤如下:

  • 引入依赖:
<!-- Feign客户端依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  • order-service的启动类添加注解开启Feign的功能:
@MapperScan("cn.itcast.order.mapper")
@EnableFeignClients
@SpringBootApplication
public class OrderApplication {
  ...
}
  • 编写Feign客户端:主要是基于SpringMVC的注解来声明远程调用的信息
@FeignClient("userservice")
public interface UserClient {
    // 下面代码和RestTemplate代码中其实都是一一对应的
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}
  • Feign客户端代替RestTemplate
// 使用Feign实现远程调用
@Autowired
private UserClient userClient;

public Order queryOrderById(Long orderId) {
    // 1.查询订单
    Order order = orderMapper.findById(orderId);
    // 2.查询用户
    User user = userClient.findById(order.getUserId());
    // 3.封装user信息
    order.setUser(user);  
    // 4.返回
    return order;
}

tips:

  • Feign的依赖包已经集成了ribbon,所以实现了负载均衡
  • 注意order-service服务的端口不要和nginx使用的8080端口冲突,同时把server-addr改为localhost:80

自定义Feign的配置

Feign可以使用自定义配置来覆盖默认配置,可修改的配置如下:

在这里插入图片描述

一般要配置的就是日志级别,配置Feign日志有两种方式:

  • 配置文件方式:可全局生效或局部生效

    feign:
      client:
        config:
          userservice:  # 写服务名称就是针对某个微服务的局部配置
          # default: # 写"default"就是全局配置
            loggerLevel: FULL  # 日志级别 
    
  • Java代码方式

    • 先声明一个Bean:该类不需要加注解标记为配置类
    public class DefaultFeignConfiguration {
        @Bean
        public Logger.Level logLevel(){
            return Logger.Level.BASIC;
        }
    }
    
    • 如果需要全局配置,则把它放到@EnableFeignClients这个注解中:
    @MapperScan("cn.itcast.order.mapper")
    @EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
    @SpringBootApplication
    public class OrderApplication {
      ...
    }
    
    • 如果需要局部配置,则把它放到@FeignClient这个注解中:
    @FeignClient(value = "userservice", configuration = DefaultFeignConfiguration.class)
    public interface UserClient {
        @GetMapping("/user/{id}")
        User findById(@PathVariable("id") Long id);
    }
    

Feign的性能优化

Feign底层的客户端实现:

  • URLConnection:默认实现,不支持连接池
  • Apache HttpClient:支持连接池
  • OKHttp:支持连接池

因此优化Feign的性能主要包括:

  • 使用连接池代替默认的URLConnection,具体步骤如下:

    • 引入依赖:
    <!-- Feign的httpClient依赖 -->
    <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-httpclient</artifactId>
    </dependency>
    
    • 配置连接池:
    feign:
      client:
        config:
          default:
            loggerLevel: BASIC  # 日志级别,BASIC即基本的请求和响应信息
      httpclient:
        enabled: true  # 开启feign对HttpClient的支持
        max-connections: 200  # 最大连接数
        max-connections-per-route: 50  # 每个路径的最大连接数
    
  • 日志级别最好用basicnone


Feign的最佳实践

Feign的客户端与Controller代码相似,可以对重复的代码进行简化。具体采用以下两种方式:

  • 给消费者(即order-service)的FeignClient和提供者(即user-service)的Controller定义统一的父接口作为标准:

    • 步骤:

      • 定义一个API接口,利用定义方法并基于SpringMVC注解做声明
      • Feign客户端和Controller都集成改接口

      在这里插入图片描述

    • 优缺点:

      • 简单且实现了代码共享
      • 服务提供方、服务消费方紧耦合
      • 参数列表中的注解映射并不会继承,因此Controller中必须再次声明方法、参数列表、注解
  • FeignClient抽取为独立模块,并且把接口有关的POJO、默认的Feign配置都放到这个模块中,提供给所有消费者使用

    在这里插入图片描述

    • 步骤:

      • 创建名为feign-api模块

      • feign-api中然后引入feignstarter依赖

      • order-service中的UserClientUserDefaultFeignConfiguration复制到feign-api(复制后将order-service相关代码删除)

      • order-servicepom文件中中引入feign-api的依赖:

      <!-- 引入feign-api -->
      <dependency>
          <groupId>cn.itcast.demo</groupId>
          <artifactId>feign-api</artifactId>
          <version>1.0</version>
      </dependency>
      
    • 注意点:现在UserClientcn.itcast.feign.clients包下,而order-service@EnableFeignClients注解是在cn.itcast.order包下,导致order-service启动类扫描不到UserClient,注入UserClient失败。解决方法如下:

      • 指定Feign应该扫描的包:会将该包下的所有clients全部扫描
      @EnableFeignClients(basePackages = "cn.itcast.feign.clients", 
                          defaultConfiguration = DefaultFeignConfiguration.class) 
      
      @SpringBootApplication
      public class OrderApplication {
          ...
      }
      
      • 指定FeignClient字节码:推荐使用
      @EnableFeignClients(clients = UserClient.class, 
                          defaultConfiguration = DefaultFeignConfiguration.class)  
      
      @SpringBootApplication
      public class OrderApplication {
          ...
      }
      

3.统一网关Gateway

它旨在为微服务架构提供一种简单有效的统一的API路由管理方式


为什么需要网关

Gateway网关是所有微服务的统一入口。其核心功能特性如下:

  • 身份认证和权限校验:需要校验用户是是否有请求资格,没有则进行拦截
  • 服务路由、负载均衡:网关不处理业务,而是根据某种规则把请求转发到某个微服务,该过程即路由。路由的目标服务有多个时需要做负载均衡
  • 请求限流:当请求流量过高时,在网关中按照下流的微服务能够接受的速度来放行请求,避免服务压力过大

在这里插入图片描述

SpringCloud中网关的实现包括两种:

  • SpringCloudGateway:基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能
  • zuul:基于Servlet的实现,属于阻塞式编程

搭建网关服务

具体步骤如下:

  • 创建新模块(如果没有使用模板创建则记得手动创建启动类),并引入SpringCloudGateway的依赖和nacos的服务发现依赖(网关也是一个服务):
<!-- 网关 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- nacos服务发现依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
  • 编写基础配置和路由规则:
server:
  port: 10010  # 网关端口
spring:
  application:
    name: gateway  # 服务名称
  cloud:
    nacos:
      #      server-addr: localhost:8848 # nacos地址(未配置集群和Nginx前)
      server-addr: localhost:80 # nacos地址(即在Nginx中配置的代理地址)
    gateway:
      routes: # 网关路由配置
        - id: user-service  # 路由id,自定义,唯一即可
          # uri: http://127.0.0.1:8081 # 可使用固定地址作为路由的目标地址
          uri: lb://userservice # 可使用服务名称作为路由的目标地址,其中lb即负载均衡
          predicates: # 路由断言,即判断请求是否符合路由规则的条件
            - Path=/user/**  # 按照路径匹配,只要以/user/开头就符合要求
  • 启动网关:之后访问http://localhost:10010/user/1时,因为符合/user/**规则,所以请求转发到http://userservice/user/1

网关路由的流程图如下:

在这里插入图片描述

网关路由可以配置的内容如下:

  • 路由id:路由的唯一标示
  • 路由目标uri:路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡
  • 路由断言predicates:判断路由的规则
  • 路由过滤器filters:对请求或响应做处理

断言工厂

在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件。例如Path=/user/**是按照路径匹配,该规则由PathRoutePredicateFactory类处理。以下是SpringCloudGateway的断言工厂:

在这里插入图片描述


过滤器工厂

GatewayFilter是网关中提供的一种过滤器,可对进入网关的请求和微服务返回的响应做处理:

在这里插入图片描述

Spring提供了多种不同的路由过滤器工厂:

在这里插入图片描述

当前过滤器写在某个具体路由下只对访问具体服务的请求有效,要对所有的路由都生效可将过滤器工厂写到default下:

spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes: 
        - id: user-service 
          uri: lb://userservice
          predicates: 
            - Path=/user/**  
        - id: order-service
          uri: lb://orderservice
          predicates:
            - Path=/order/**
          # 给所有进入userservice的请求添加请求头
          filters: # 针对某个服务请求的过滤器
            - AddRequestHeader=test filter1! # 添加请求头
      # 给所有服务的请求添加请求头
      default-filters: # 默认过滤器,会对所有的路由请求都生效
        - AddRequestHeader=test filter2! 

全局过滤器

之前介绍的每种过滤器的作用都是固定的,如果想在拦截请求后做自己的业务逻辑则没法实现(即GatewayFilter通过配置定义,处理逻辑固定),此时需要全局过滤器GlobalFilter

假设现在定义全局过滤器拦截请求,判断请求的参数是否满足下面条件(如果同时满足则放行,否则拦截):

  • 参数中是否有authorization
  • authorization参数值是否为admin

具体实现步骤如下:

  • 自定义类实现GlobalFilter接口
  • 添加@Order注解
  • 编写处理逻辑
// GlobalFilter接口的定义如下
public interface GlobalFilter {
    /***  处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
    *
    * @param exchange 请求上下文,里面可以获取Request、Response等信息
    * @param chain 用来把请求委托给下一个过滤器
    * @return {@code Mono<Void>} 返回标示当前过滤器业务结束
    */
    Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}

// 自定义类
@Order(-1)  // 参数值越小,优先级越大
@Component
public class AuthorizeFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1.获取请求参数
        MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
        // 2.获取authorization参数
        String auth = params.getFirst("authorization");
        // 3.校验
        if ("admin".equals(auth)) {
            // 符合要求则放行
            return chain.filter(exchange);
        }
        // 4.如果不符合要求则拦截
        // 4.1.禁止访问,设置状态码
        exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
        // 4.2.结束处理
        return exchange.getResponse().setComplete();
    }
}

过滤器执行顺序

请求路由后,会将当前路由过滤器和DefaultFilterGlobalFilter合并到一个过滤器链中,排序后依次执行每个过滤器。执行顺序如下:

  • 每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前
  • GlobalFilter通过实现Ordered接口或添加@Order注解来指定order值,由我们自己指定
  • 路由过滤器和defaultFilterorderSpring指定,默认是按照声明顺序从1递增(虽然两种过滤器声明在一个配置文件中,但分开计数)
  • 当过滤器的order值一样时按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行

跨域问题处理

跨域:域名不一致就是跨域

  • 域名不同: www.taobao.com和www.taobao.org、www.jd.com和miaosha.jd.com
  • 域名相同,端口不同:localhost:8080localhost:8081

跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,即ajax请求被浏览器拦截
解决方案:一般使用CORS(浏览器询问服务器能否允许某个请求跨域),网关处理跨域采用的同样是CORS方案,进行以下配置即可(可以通过resources/index.html进行跨域测试)

spring:
  cloud:
    gateway:
      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true  # 解决options请求被拦截间题
        corsConfigurations:
          '[/**]':
            al1owed0rigins: #允许哪些网站的跨域请求
              - "http://localhost:8090"
            allowedMethods: #允许的跨域ajax的请求方式
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*"  # 允许在请求中携带的头信息
            allowCredentials: true  # 是否允许携带cookie
            maxAge: 360000  # 这次跨域检测的有效期

tips:

  • 对于服务器端的两个模块间的请求不属于浏览器的请求,并且不是ajax请求,所以不会存在跨域问题
  • 浏览器询问服务器某个请求能否跨域属于options请求,所以需要解决询问请求被拦截的问题
  • 在跨域检测的有效期内每次请求都需要去询问下服务器,不跨域就放行。过了有效期后所有请求就直接放行,提升性能

参考

黑马程序员SpringCloud框架P24-P41


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Javaweb | 过滤器、配置、过滤器链、优先级

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; 过滤器 概念 过滤器&#xff08;Filter&#xff09;是处于客户端与服务器目标资源之间的一道过滤技术 用户的请求和响应都需要经过过滤器 过滤器作用 执行地位在Servl…

C++初阶 -1- C++入门part2

文章目录6.引用什么是引用&#xff1f;引用的使用引用的应用传值、传引用效率比较权限引用和指针的区别⭐7.内联函数8.auto关键字9.基于范围的for循环10.指针空值——nullptr6.引用 什么是引用&#xff1f; “别名” int a 0; int& b 0;&#x1f446;即 地址为0x00000…

【linux】:模拟文件基本操作以及文件在磁盘中如何存储的学习

文章目录 前言一、模拟C库文件操作二、磁盘文件总结前言 经过我们上一篇对linux系统文件操作的学习想必我们已经会使用系统文件接口了&#xff0c;今天我们就用系统文件接口来封装一个像C语言库那样的文件操作函数的函数来加深我们对文件操作的学习。 一、模拟C库文件操作 首…

通过Milo实现的OPC UA客户端连接并订阅Prosys OPC UA Simulation Server模拟服务器

背景 前面我们搭建了一个本地的 PLC 仿真环境&#xff0c;并通过 KEPServerEX6 读取 PLC 上的数据&#xff0c;最后还使用 UAExpert 作为 OPC 客户端完成从 KEPServerEX6 这个OPC服务器的数据读取与订阅功能&#xff1a;SpringBoot集成Milo库实现OPC UA客户端&#xff1a;连接…

新一代信息技术赋能,安科瑞搭建智慧水务体系的新思路

随着新时期治水方针的逐步落实&#xff0c;水利现代化、智能化建设已开启&#xff0c;物联网、图像识别、数字孪生等新技术的成熟&#xff0c;也为智慧水务体系的搭建提供了技术保障&#xff0c;新时代治水新思路正逐步得到落实。本文对智慧水务的总体架构与包含的建设内容进行…

Qt第六十二章:图标库QtAwesome的使用

目录 一、安装依赖 二、主页 三、文档 四、案例 1、图标 2、样式 3、alpha 通道 4、 多图标堆叠 5、动画 6、字体 五、系列 1、msc系列 2、fa5系列&#xff08;选择free栏&#xff09; 3、fa5s系列&#xff08;选择free栏&#xff09; 4、fa5b系列&#xff08;选…

由libunifex来看Executor的任务构建

前言 之前的一篇文章讲述了future的优缺点&#xff0c;以及future的组合性&#xff0c;其中也讲述了构建任务DAG一些问题&#xff0c;同时给出了比较好的方案则是Executor。 Executor还未进入标准&#xff08;C23&#xff09;&#xff0c;Executor拥有惰性构建及良好的抽象模型…

尚硅谷大数据技术Zookeeper教程-笔记03【源码解析-算法基础】

视频地址&#xff1a;【尚硅谷】大数据技术之Zookeeper 3.5.7版本教程_哔哩哔哩_bilibili 尚硅谷大数据技术Zookeeper教程-笔记01【Zookeeper(入门、本地安装、集群操作)】尚硅谷大数据技术Zookeeper教程-笔记02【服务器动态上下线监听案例、ZooKeeper分布式锁案例、企业面试真…

多模态大模型的发展、挑战与应用

多模态大模型的发展、挑战与应用 2023/04/15 研究进展 随着 AlexNet [1] 的出现&#xff0c;过去十年里深度学习得到了快速的发展&#xff0c;而卷积神经网络也从 AlexNet 逐步发展到了 VGG [2]、ResNet [3]、DenseNet [4]、HRNet [5] 等更深的网络结构。研究者们发现&#…

用vscode运行Java程序初体验

最近开始学习Java编程了&#xff0c;以前学习过C、C 、Python&#xff0c;主要用微软的visual studio code来运行python程序&#xff0c;于是就尝试了用vscode来运行java代码&#xff0c;记录一下使用的经验&#xff0c;帮助大家少走弯路。 安装了Java的集成编辑器IDE "Ec…

c++STL之关联式容器

目录 set容器 set的默认构造 set的插入与迭代器 set集合的元素排序 set集合的初始化及遍历 从小到大(默认情况下) 从大到小 仿函数 set的查找 pair的使用 multiset容器 map和multimap容器 map的插入与迭代器 map的大小 map的删除 map的查找 关联式容器&#…

【LeetCode: 337. 打家劫舍 III | 暴力递归=>记忆化搜索=>动态规划 | 树形dp】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

整数二分从入门到精通

前言&#xff1a; 开个玩笑&#xff0c;我们写算法可不能这样哈~ 好了&#xff0c;正片开始&#xff1a; 你是否曾经也有过整数二分因为一直死循环而苦恼&#xff0c;你是否因为搞不清楚整数二分的边界处理而焦躁&#xff0c;明明很简单的一道二分&#xff0c;但是最后就是搞…

Python入门教程+项目实战-9.1节: 字符串的定义与编码

目录 9.1.1 理解字符串 9.1.2 字符串的类型名 9.1.3 字符的数字编码 9.1.4 常用的字符编码 9.1.5 字符串的默认编码 9.1.6 字符串的编码与解码 9.1.7 转义字符详解 9.1.8 对字符串进行遍历 9.1.9 知识要点 9.1.10 系统学习python 9.1.1 理解字符串 理解字符串&#…

005:Mapbox GL添加全屏显示功能

第005个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中添加全屏显示功能 。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源代码(共60行)相关API参考:专栏目标示例效果 配置方式 1)查看基础设置:https://…

还在因为写项目函数太多而烦恼?C++模板一文带你解决难题

&#x1f4d6;作者介绍&#xff1a;22级树莓人&#xff08;计算机专业&#xff09;&#xff0c;热爱编程&#xff1c;目前在c&#xff0b;&#xff0b;阶段>——目标Windows&#xff0c;MySQL&#xff0c;Qt&#xff0c;数据结构与算法&#xff0c;Linux&#xff0c;多线程&…

轮廓查找与绘制

轮廓查找与绘制 1)什么是轮廓 轮廓可以简单认为成将连续的点&#xff08;连着边界&#xff09;连在一起的曲线&#xff0c;具有相同的颜色或者灰度&#xff0c;提取轮廓就是提取 这些具有相同颜色或者灰度的曲线&#xff0c;或者说是连通域&#xff0c;轮廓在形状分析和物体…

学习系统编程No.20【进程间通信之命名管道】

引言&#xff1a; 北京时间&#xff1a;2023/4/15/10:34&#xff0c;今天起床时间9:25&#xff0c;睡了快8小时&#xff0c;昨天刷视屏刷了一个小时&#xff0c;本来12点的时候发完博客洗把脸就要睡了&#xff0c;可惜&#xff0c;看到了一个标题&#xff0c;说实话&#xff0…

.Net路由操作!!!!

什么是路由 问题 答案 路由是什么&#xff1f; 路由系统负责处理传入的请求并选择控制器和操作方法来处理它们。 路由系统还用于在视图中生成路由&#xff0c;称为传出的URL 路由有什么用&#xff1f; 路由系统能够灵活地处理请求&#xff0c;面不是将URL与Visual Studio…

MySQL(31)-ubuntu20.04-下安装mysql5.7

ubuntu20.04 下apt 默认安装的是8.0版本&#xff0c;如果要安装5.7版有如下3种方式&#xff1a; 1 下载 MySQL 二进制压缩包&#xff0c;解压并设置相关的参数即可运行 2 通过命令 apt install 进行安装&#xff0c;先下载 MySQL 5.7 对应的源&#xff0c;然后执行安装命令 ap…