【SpringCloud】Eureka的使用

3. Eureka

3.1 Eureka 介绍

Eureka主要分为两个部分:

EurekaServer:

作为注册中心Server端,向微服务应用程序提供服务注册,发现,健康检查等能力。

EurekaClient:

服务提供者,服务启动时,会向 EurekaServer 注册自己的信息 (IP,端口,服务信息
等),Eureka Server 会存储这些信息。

3.2 搭建 Eureka 服务

Eureka 是一个单独的服务,所以咱们要手动搭建出 Eureka 服务器。

这里使用父子项目来搭建 Eureka 服务,先创建一个 spring-cloud-demo 的父项目:

在这里插入图片描述

后续所有的项目创建都在这个父项目中创建子项目。

在这里插入图片描述

直接复制下面 spring-cloud-demo 的 pom.xml 文件

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>spring-cloud-demo</artifactId><version>1.0-SNAPSHOT</version><packaging>pom</packaging><modules></modules><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.6</version><relativePath/> <!-- lookup parent from repository --></parent><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><java.version>17</java.version><spring-cloud.version>2022.0.3</spring-cloud.version></properties><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></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><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>${mybatis.version}</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>${mysql.version}</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter-test</artifactId><version>${mybatis.version}</version><scope>test</scope></dependency></dependencies></dependencyManagement>
</project>

pom.xml 关键部分解析:

  1. <modules>
    定义子模块(当前为空),用于多模块项目管理。所有子模块需在此声明,Maven 会按顺序构建。
  2. <parent>
    继承 Spring Boot 的默认配置(如插件、依赖管理),版本为 3.1.6,简化项目配置。
  3. <properties>
    统一定义变量,便于维护版本:
    • Java 版本:17
    • Spring Cloud:2022.0.3
  4. <dependencies>
    当前仅引入 Lombok(代码简化工具),<optional>true</optional> 表示不传递依赖给子模块。
  5. <dependencyManagement>
    统一管理依赖版本,子模块引用时无需指定版本:
    • 引入 Spring Cloud 全家桶的版本控制
    • 锁定 MyBatis 和 MySQL 驱动版本
    • 测试用 MyBatis 依赖(仅测试范围生效)

记得删除掉父工程的 src 目录,因为后续不会在父工程中写代码。

有了上述操作,咱们的父工程就创建好了,接下来开始创建子工程。

下面开始在父工程底下创建一个子模块,也就是用这个子模块去搭建 Eureka 服务:

在这里插入图片描述

创建子模块项目名为 eureka-server:
在这里插入图片描述

此时点击 Create 后,就会发现 spring-cloud-demo 目录下出现了 eureka-server 子项目,同时在父项目的 pom.xml 中的 modules 里出现了咱们子模块的名字

在这里插入图片描述

在子项目 eureka-server 的 pom.xml <dependencies> </dependencies> 中引入 eureka-server 依赖:

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

在子项目 eureka-server 的 pom.xml <project> </project> 加入项目构件插件

<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins>
</build>

记得点击右上角 maven 的刷新,或者打开 maven 面板点击 Reload ALL Maven Project 按钮重新加载下依赖。

由于创建的子项目是一个空的项目,所以需要手动创建好对应的包和子模块的启动类:

EurekaServerApplication.class 代码如下:

package com.zlcode.eureka;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {public static void main(String[] args) {SpringApplication.run(EurekaServerApplication.class, args);}
}

编写配置文件,这里需要手动在 resoureces 中创建该项目的配置文件 papplication.yml

# Eureka相关配置
# Eureka 服务
server:port: 10010
spring:application:name: eureka-server
eureka:instance:hostname: localhostclient:# 表示是否从Eureka Server获取注册信息,默认为true.因为这是一个单点的Eureka Server,# 不需要同步其他的Eureka Server节点的数据,这里设置为falsefetch-registry: false# 表示是否将自己注册到Eureka Server,默认为true.由于当前应用就是Eureka Server,故而设置为false.register-with-eureka: falseservice-url:# 设置Eureka Server的地址,查询服务和注册服务都需要依赖这个地址defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

有了上述的操作,就能执行 eureka-server 项目中的 main 方法了。

在浏览器中输入 http://127.0.0.01:10010 就能发现此时 eureka-server 已经成功启动了。

在这里插入图片描述

3.3 创建cook服务和waiter服务

接下来再来创建两个子项目,分别是 厨师(cook) 和 服务员(waiter),厨师需要让服务员上菜。

创建厨师服务和服务员服务跟创建 Eureka 项目一致,创建的流程这里就省略了,也就是在 spring-cloud-demo 目录下创建厨师子模块和服务员子模块。

### 3.3.1 cook-service 模块配置代码

cook-service 的 pom.xml 文件如下:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.example</groupId><artifactId>spring-cloud-demo</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cook-service</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></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></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

cook-service 的 application.yml 文件如下:

server:port: 8080
spring:application:name: cook-service # 添加服务器名称
#Eureka Client
eureka:client:service-url:# eureka 地址defaultZone: http://127.0.0.1:10010/eureka/

cook-service 的 启动类 文件如下:

package com.zlcode.cook;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class CookServiceApplication {public static void main(String[] args) {SpringApplication.run(CookServiceApplication.class, args);}
}

3.3.2 waiter-service 模块配置代码

waiter-service 的 pom.xml 文件如下:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.example</groupId><artifactId>spring-cloud-demo</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>waiter-service</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></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></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

waiter-service 的 application.yml 文件如下:

server:port: 9090
spring:application:name: waiter-service # 添加服务器名称
#Eureka Client
eureka:client:service-url:# eureka 地址defaultZone: http://127.0.0.1:10010/eureka/

waiter-service 的 启动类 文件如下:

package com.zlcode.waiter;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class WaiterServiceApplication {public static void main(String[] args) {SpringApplication.run(WaiterServiceApplication.class, args);}
}

3.3.3 cook 实体类

将 CookInfo 创建在 cookie-service/*/cook/model/目录下:

package com.zlcode.cook.model;import lombok.Data;@Data
public class CookInfo {private Integer cookId;private String cookieName;
}

3.3.4 waiter 实体类

将 WaiterInfo 创建在 waiter-service/*/waiter/model/目录下:

package com.zlcode.waiter.model;import lombok.Data;@Data
public class WaiterInfo {private Integer waiterId;private String waiterName;
}

3.4 服务注册

启动咱们的 waiter-service 和 cook-service 项目,就能自动的进行 eureka 的服务注册了,因为咱们在 .yml 已经配置好了 eureka 的地址。
在这里插入图片描述

启动 waiter 和 cook 后,刷新 http://127.0.0.1:10010 就能发现:

在这里插入图片描述

通过上面可以看到,已经把 cook-service 和 waiter-service 注册到咱们部搭建的 eureka-server 服务中了。

上述这样的操作,咱们就称作为服务注册。

由于 cook-service 想通过 eureka-server 去发现 waiter-service 所以,也要让 cook-service 自己在 eureka 中注册,这样一来 cook-service 就可以从 eureka-server 中去发现 waiter-service 服务。

3.5 服务发现

前面咱们说,厨师想通过喊服务员名字来让服务员上菜,但是呢它并不知道当前哪些服务员是能提供服务的,于是便需要向 eureka-server 去获取可用服务列表,于是厨师就不需要关注服务员叫什么了。

咱们对 cook-service 和 waiter-service 分别创建一个 controller 包,在 cook 的 controller 包中新建 CookController类,在 waiter 的 controller 中新建 WaiterController 类,此处咱们就不新建 Service 层 和 Mapper 层了,这里只是为了学习服务发现,所以使用一层演示就足够了。

对于 waiter 服务来说,就提供一个接口,这个接口就是执行一个模拟的任务:

package com.zlcode.waiter.controller;import jakarta.websocket.server.PathParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/waiter")
@Slf4j
public class WaiterController {@RequestMapping("/up")public String up(@PathParam("content") String content) {log.info("正在执行: " + content);return "执行: " + content + "成功!";}
}

上述 waiter 就提供了 /waiter/up 这个接口,比如传递的 content 为 “给55桌上红烧肉”,这个请求就会打印一下这个content,然后再模拟返回结果。下面咱们来使用 postman 测试这个接口的可用性:

在这里插入图片描述

这里可用发现 waiter 服务的 up 接口成功返回了预期的值,同时在 waiter 的控制台也能看到:

在这里插入图片描述

调用 waiter 的 up 方法后,成功的模拟执行了上菜操作!

接下来咱们看一下 cook 提供了哪个接口:

package com.zlcode.cook.controller;import jakarta.websocket.server.PathParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController
@RequestMapping("/cook")
public class CookController {@Autowiredprivate DiscoveryClient discoveryClient;@RequestMapping("/ok")public String ok(@PathParam("content")String content) {// 通过 discoveryClient 从 eureka-server 获取服务列表List<ServiceInstance> instances = discoveryClient.getInstances("waiter-service");String uri = instances.get(0).getUri().toString(); // 拿到服务列表的第一个 ip:端口号// ----------------------------------------------------------// 这里咱们拿到了 waiter 的 ip 地址和端口号// 也就是知道了服务员的名字,那么要如何告诉服务员你需要让他上菜呢?// 当然现实中可用喊一嗓子,但在代码中呢?// ---------------------------------------------------------return "";}
}

此时这里就可用通过 discoveryClient.getInstances 实例列表,此处是获取名字为 waiter-service 的服务列表,获取后,通过 instances.get(0).getUri().toString(); 获取这个实例的 ip 和 端口号。

为什么这里可能会有多个实例呢?别忘记了,把同一个项目换成不同的端口号,分别运行,这就是两个服务,同时这两个服务都进行服务注册,此时 eureka 上就会有两个这样的服务了,只是对应的端口号不同,如果端口号相同,但是ip不同,也就是在不同的主机上,这样也是 ok 的。

但是这里只启动了一个 waiter-service 服务,所以咱们取第 0 个就ok了。

ip 和端口号是拿到了,可是如何调用 waiter-service 服务提供的 up 接口呢?

其实也很简单,既然都拿到ip端口号了,直接使用 ip+端口号/waiter/up?content=“xxx” 这个 url 给 waiter 发一个 http 请求就ok了,但是使用 js 发 http 请求相信都会,但是在 Java 中如何给发送 http 请求呢?

这里可用使用 Spring 提供的 RestTemplate 类,通过这个可用发送一个 http 请求,但是注意了!!!

想认识 RestTemplate 就得知道什么是 Rest。

REST(Representational State Transfer),表现层资源状态转移。

简单来说:REST描述的是在网络中Client和Server的⼀种交互形式,REST本身不实用,实用的是如何设计RESTfulAPI(REST风格的网络接口)接口类似于:

GET/blog/{blogId}:查询博客
DELETE/blog/{blogId}:删除博客

而 RestTemplate 是Spring提供,封装HTTP调⽤,并强制使用RESTful风格。它会处理HTTP连接和关闭,只需要使用者提供资源的地地和参数即可。

所以要想使用这个 RestTemplate 进行 http 请求,先得把咱们 waiter 服务的 up 接口改成 Rest 风格的接口:

package com.zlcode.waiter.controller;import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/waiter")
@Slf4j
public class WaiterController {@RequestMapping("/up/{content}")public String up(@PathVariable("content") String content) {log.info("正在执行: " + content);return "执行: " + content + "成功!";}
}

接下来在 cook-service 项目中先定义 RestTemplate,把这个对象交给 Spring 容器管理,在 cook 目录下创建 config 目录,在这个目录下创建一个 BeanConfig 类,在这个类中定义好咱们要用的 RestTemplate 就 OK 了。

package com.zlcode.cook.config;import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;@Configuration
public class BeanConfig {@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}

接下来修改 CookConroller 的 ok 接口:

package com.zlcode.cook.controller;import jakarta.websocket.server.PathParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;import java.util.List;@RestController
@RequestMapping("/cook")
public class CookController {@Autowiredprivate DiscoveryClient discoveryClient;@Autowiredprivate RestTemplate restTemplate;// 咱们的 cook 里面的接口可以不遵循 Rest 规范,// 只要保证使用 restTemplate 调用的接口遵守 Rest 规范就ok了@RequestMapping("/ok")public String ok(@PathParam("content")String content) {// 通过 discoveryClient 从 eureka-server 获取服务列表List<ServiceInstance> instances = discoveryClient.getInstances("waiter-service");String uri = instances.get(0).getUri().toString(); // 拿到服务列表的第一个 ip:端口号// 通过 restTemplate 给 waiter-service 发送 http 请求String url = uri + "/waiter/up/{content}";// 第一个参数是请求 url, // 第二个参数是这个请求的返回值类型的class对象, // 第三个参数是占位符对应的值String resp = restTemplate.getForObject(url, String.class, content);return "调用成功, 已收到 waiter 的响应: " + resp;}
}

此时咱们此处的代码,就是 cook 厨师,通过 eureka 注册中心获取到服务列表,拿到第一个服务的 ip和端口,通过这个 ip 和 端口 拼接上完整的接口路由,带上参数,就实现了远程方法调用了。

此处如果服务员离职了,来了个新的服务员,对于厨师来说,没有任何影响,厨师只需要关注注册中心有哪些服务列表就行了。

3.6 服务注册和发现的注意点

List<ServiceInstance> instances = discoveryClient.getInstances("waiter-service");
String uri = instances.get(0).getUri().toString(); // 拿到服务列表的第一个 ip:端口号
String url = uri + "/waiter/up/{content}";
String resp = restTemplate.getForObject(url, String.class, content);

上面代码是服务发现和远程调用的重要代码。

上面的 discoveryClient.getInstances(“waiter-service”) 这里方法的形参,waiter-service 就像是给这个服务取了一个名字,比如传菜的都叫做服务员,只要名字叫 waiter-service 的服务,都能获取到,那么注册中心是如何知道每个服务的名字呢?

在这里插入图片描述

观察 waiter-service 的 spring.application.name 的值是 waiter-server,注册中心就是通过这个 name 来区分的,所以也就是有可能出现如下的情况:

服务A 的名字:waiter-service 这个服务只提供了 test 接口
服务B 的名字:waiter-service 这个服务只提供了 hello 接口

由于服务 AB 启动时都会进行服务注册,那么问题来了,通过discoveryClient.getInstances(“waiter-service”) 会拿到两个实例,也就是可以获取两个服务的 ip 和 端口号,假设 服务C 想调用 test 接口,而服务C 只知道 name 为 waiter-service 的服务提供了 test 接口,但是服务C不知道的是:AB都叫 test-service,但是服务B没有提供 test 接口。

如果此时 C 通过 instances.get(0).getUri().toString();,拿到的是服务B的ip和端口,此时再通过 restTemplate 进行调用 test 接口,那问题就大了!!

也就是说,如果统称为服务员,那么必须都得具备传菜的接口服务。

所以对于这里的 spring.application.name 的值,要保证相同的 name 它所提供的服务(接口)要是一致的!

在这里插入图片描述

现在咱们就来复现上面这种情况,先创建 B/hello 和 A/test 接口,并且这两个服务都叫做 waiter-service。

AController:

package com.zlcode.waiter.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class AController {@RequestMapping("test")public String test () {return "成功调用了 服务A 的 test 接口";}
}

BController:

package com.zlcode.waiter.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class BController {@RequestMapping("/hello")public String hello() {return "成功调用了 服务B 的 hello 接口";}
}

启动这两个服务A和服务B,服务A的端口为9091,服务B的端口为9092,此时可以发现 服务A 只提供了 test 接口,服务B 只提供了 hello 接口。

在这里插入图片描述

此时启动服务A和服务B,都发现已经成功使用 waiter-service 这个名字进行服务注册了。

然后使用服务C去获取 waiter-service 对应的服务列表,调用下这两个服务的 test 接口:

package com.zlcode.cook.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;@Slf4j
@RestController
@RequestMapping("/C")
public class CController {@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate DiscoveryClient discoveryClient;@RequestMapping("/run")public void run() {List<ServiceInstance> instances = discoveryClient.getInstances("waiter-service");for (ServiceInstance instance : instances) {String uri = instance.getUri().toString();log.info("获取到服务器地址:" + uri);String url = uri + "/test";try {String resp = restTemplate.getForObject(url, String.class);log.info(uri + " 调用服务器 test 接口成功! resp: " + resp);} catch (Exception e) {e.printStackTrace();log.error("服务器: " + uri + "没有提供 test 接口.");}}}
}

上述就是服务C,咱们给它运行在 8080 端口上,然后调用 127.0.0.1/C/run 这个接口后,他就会从注册中心获取 waiter-service 服务信息,此时能拿到两个,9091 端口是提供了 test 接口服务的,而 9092 则没有提供 test 接口服务。

在 postman 调用 127.0.0.1/C/run 观察项目打印日志:

在这里插入图片描述

果然不出所料,没有提供 test 接口的服务B就会报 404 错误。所以现在你理解了服务名的重要性了吗?

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

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

相关文章

构建大语言模型应用:简介(第一部分)

本专栏聚焦大语言模型&#xff08;LLM&#xff09;相关内容的解析&#xff0c;通过检索增强生成&#xff08;RAG&#xff09;应用的视角来进行。 本系列文章 简介&#xff08;本文&#xff09;数据准备句子转换器向量数据库搜索与检索大语言模型开源检索增强生成评估大语言模…

Python:日志模块操作及基本配置,日志格式化输出

logger(日志管理器)&#xff1a;用户默认是root&#xff0c;其配置步骤为&#xff1a; 1.初始化对象 2.设置级别 3.定义handler(控制台或文件显示) 4.格式化输出 import logging #创建log文件并设置级别 logging.basicConfig(filenametext.log, levellogging.DEBUG) #在文…

The selected directory is not a valid home for Go SDK

安装完毕Go和GoLand之后&#xff0c;重新配置GoLand的GOROOT时&#xff0c;可能会报错 The selected directory is not a valid home for Go SDK 需要找到安装Go的目录&#xff0c;我的目录如下 D:\SoftFolder\Go\src\runtime\internal\sys 进入到sys文件下&#xff0c;找到…

pycharm找不到conda可执行文件解决办法

配置一个新项目&#xff0c;需要使用远程服务器环境的时候&#xff0c;找不到anaconda里面的python可执行文件&#xff0c;怎么都解决不了&#xff0c;很尴尬&#xff0c;看了很多&#xff0c;终于找到一个博客有用&#xff1a; https://blog.csdn.net/weixin_43912188/articl…

Blender多摄像机怎么指定相机渲染图像

如题目所说&#xff0c;当blender的场景里面有摄像机的时候&#xff0c;按F12可以预览渲染结果&#xff0c;但是当有多个摄像机的时候就不知道使用哪个进行渲染了。 之前在网上没有找到方法&#xff0c;就用笨方法&#xff0c;把所有的摄像机删除&#xff0c;然后设置自己需要…

org.apache.maven.surefire:surefire-junit-platform:jar:2.22.2 Maven打包失败

org.apache.maven.surefire:surefire-junit-platform:jar:2.22.2 解决办法 勾上这个&#xff0c;打包时跳过测试代码

CKS认证 | Day3 K8s容器运行环境安全加固

一、最小特权原则&#xff08;POLP&#xff09; 1&#xff09;最小特权原则 (Principle of least privilege&#xff0c;POLP) &#xff1a; 是一种信息安全概念&#xff0c;即为用户提供执行其工作职责所需的最 小权限等级或许可。 最小特权原则被广泛认为是网络安全的最佳实…

项目-苍穹外卖(十七) Apache POI+导出数据

一、介绍 二、入门案例 package com.sky.test;import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.io.File; import java.io.FileNotFoundException; import jav…

2023第十四届蓝桥杯大赛软件赛国赛C/C++ 大学 B 组(真题题解)(C++/Java题解)

本来想刷省赛题呢&#xff0c;结果一不小心刷成国赛了 真是个小迷糊〒▽〒 但&#xff0c;又如何( •̀ ω •́ )✧ 记录刷题的过程、感悟、题解。 希望能帮到&#xff0c;那些与我一同前行的&#xff0c;来自远方的朋友&#x1f609; 大纲&#xff1a; 一、子2023-&#xff…

Cannot find a valid baseurl for repo: centos-sclo-sclo/x86_64

​ rpm -Uvh https://repo.zabbix.com/zabbix/5.0/rhel/7/x86_64/zabbix-release-latest-5.0.el7.noarch.rpmyum clean allyum macache fast​ 编辑配置文件 /etc/yum.repos.d/zabbix.repo and enable zabbix-frontend repository. [zabbix-frontend]...enabled1... 下载相关…

【STM32】WDG看门狗(学习笔记)

学习来源----->江协科技STM32 WDG简介 WDG&#xff08;Watchdog&#xff09;看门狗看门狗可以监控程序的运行状态&#xff0c;当程序因为设计漏洞、硬件故障、电磁干扰等原因&#xff0c;出现卡死或跑飞现象时&#xff0c;看门狗能及时复位程序&#xff0c;避免程序陷入长…

Nginx RTMP 服务器开发设计与实现

引言 Nginx 是一个高性能的 Web 服务器和反向代理服务器&#xff0c;广泛应用于大规模网站的高并发访问中。RTMP&#xff08;Real-Time Messaging Protocol&#xff09;是由 Adobe 提出的一个用于流媒体传输的协议&#xff0c;广泛应用于视频直播领域。通过 Nginx 的 RTMP 模块…

plantsimulation编辑图标怎么把图标旋转90°

1、打开要旋转的图标&#xff0c;点击“导出” 2、随意设置个文件名&#xff0c;点击保存。 3、用画图打开&#xff0c;点击旋转后保存。 4、新建一个图标&#xff0c;点击导入&#xff0c;选择刚刚保存的文件即可。

Jmeter性能测试

Jmeter性能测试 一、性能测试介绍 1、什么叫做性能测试&#xff1f; &#xff08;1&#xff09;通过某些工具或手段来检测软件的某些指标是否达到了要求&#xff0c;这就是性能测试 &#xff08;2&#xff09;指通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系…

OpenCV基础——梯度计算、边缘检测、图像金字塔

接上期&#xff1a; OpenCV基础——图像滤波和形态学操作-CSDN博客 一.梯度计算 上贴已经讲过&#xff0c;梯度可以浅显地理解为图像中发生颜色变化的局部区域&#xff0c;也即边界点。本质上是通过构造与卷积核相同的矩阵&#xff0c;计算边缘区域像素点的差异值——也即梯度…

英语学习笔记1

目录 第一部分 例句解析 句子一 原文&#xff1a;Learning English is never easy but always rewarding!翻译&#xff1a;学习英语从来都不容易但总是有回报的&#xff01; 句子二 原文&#xff1a;Sometimes the detailed work of understanding grammar and building v…

测试测试 测试

**非常详细的视频和文字教程&#xff0c;讲解常见的openmv教程包括 巡线、物体识别、圆环识别、阈值自动获取等。非常适合学习openmv、K210、K230等项目 视频合集链接在 openmv教程合集 openmv入门到项目开发 openmv和STM32通信 openmv和opencv区别 openmv巡线 openmv数字识别教…

CSS rem、vw/vh、less

目录 分辨率、视口与二倍图 一、分辨率与像素基础 1. 物理像素&#xff08;Physical Pixels&#xff09; 2. 逻辑像素&#xff08;CSS 像素&#xff09; 二、视口&#xff08;Viewport&#xff09;控制 1. 视口类型 2. 设置理想视口 三、二倍图&#xff08;Retina/HiD…

【数电】半导体存储电路

组合逻辑电路输入和输出之间是确定关系&#xff0c;与之前的历史记录没有任何关系。时序逻辑电路则有相应的存储元件&#xff0c;要把之前的状态保存起来。 要构成时序逻辑电路&#xff0c;必须要有相应的存储元件&#xff0c;第五章讲述相应的存储元件 一、半导体存储电路概…

OPPO手机如何实时翻译会议视频?视频翻译轻松应对多语言场景

在全球化日益深入的今天&#xff0c;跨语言沟通已成为职场和生活中的常见需求。无论是参加国际会议、观看外语视频&#xff0c;还是与海外客户交流&#xff0c;语言障碍都可能成为效率的绊脚石。幸运的是&#xff0c;OPPO手机凭借其强大的功能和智能化设计&#xff0c;为用户提…