SpringCloud+Consul快速开发示例

简介

本章通过最新的springcloud版本与官方最新consul开源版服务,进行演示,如何快速搭建开发环境和注册与发现服务中心;

本文假设已知具备SpringCloud的基础开发能力,以及提前了解consul服务的使用,因此本文不会详细描述各API使用细节与服务作用;

主要演示以下几点

  • 将springcloud的服务注册到consul节点
  • 演示基于consul服务发现功能,完成loadBalanced负载均衡测试
  • 从consul服务配置中拉取指定运行环境配置到springCloud服务中,可获取指定key/value内容
  • 从springCloud服务向consul服务中推送自定义配置
  • 动态修改consul服务指定配置数据后,springCloud服务监听数据变更,重新加载并动态展示

环境

  • JDK:17
  • SpringCloud:2023.0.0
  • SpringBoot:3.2.0
  • SpringCloudConsul:4.1.0
  • Consul:v1.17.0

安装Consul

Consul是一个服务网格解决方案,提供了一个功能齐全的控制平面,具有服务发现、配置和分段功能。

在开发中常用的consul功能如下:

  • 服务注册与发现
  • Key/Value数据存储
  • 健康检查

官网

HashiCorp Developer

安装下载

https://releases.hashicorp.com/consul/1.17.0/consul_1.17.0_linux_amd64.zip

上传到服务器指定目录下,通过unzip consul_1.17.0_linux_amd64.zip 解压,获得consul执行文件,并移动到指定目录中,如:/opt/consul-1.70.0;

config配置

在consul安装目录下,分别创建config和data文件夹,进入config目录,创建consul.json单机配置文件,写入如下配置内容:

{
    "server":true,
    "bootstrap": false,
    "ui_config": {
      "enabled": true
    },
    "datacenter":"dc1",
    "log_level":"INFO",
    "node_name":"server1",
    "data_dir":"/opt/consul-1.70.0/data",
    "addresses":{
        "http":"0.0.0.0"
    },
    "ports":{
        "http":8500
    }
}

官网文档配置说明

Agents Overview | Consul | HashiCorp Developer

启动

# 命令行运行
./consul agent -config-dir=./config/consul.json
# 后台运行
nohup ./consul agent -config-file=./config/consul.json > log.out 2>&1 &

访问

http://主机IP:8500/

搭建工程

在Idea开发工具下创建一个名为consul-example的工程,或者可以通过https://start.spring.io/官方网页的Spring初始化工具,快速搭建项目工程;

工程结构

文件说明

  • MyWebApplicationConfig.java:工程初始化配置类
  • ConsulConfigWatchListener.java:consul配置中心配置变更监听类
  • CustomConsulClientService.java:自定义consul配置获取、推送测试业务类
  • ExampleRest.java:控制器测试方法类
  • ConsulExampleApplication.java:工程启动主类

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 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>3.2.0</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.consul.example</groupId>
   <artifactId>consul-example</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>consul-example</name>
   <description>Demo project for Spring Boot</description>
   <properties>
      <java.version>17</java.version>
      <spring-cloud.version>2023.0.0</spring-cloud.version>
   </properties>
   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-webflux</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-consul-config</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-consul-discovery</artifactId>
      </dependency>

      <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
         <optional>true</optional>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
      <dependency>
         <groupId>io.projectreactor</groupId>
         <artifactId>reactor-test</artifactId>
         <scope>test</scope>
      </dependency>
      <dependency>
         <groupId>com.github.ben-manes.caffeine</groupId>
         <artifactId>caffeine</artifactId>
         <version>3.1.8</version>
      </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>
            <configuration>
               <excludes>
                  <exclude>
                     <groupId>org.projectlombok</groupId>
                     <artifactId>lombok</artifactId>
                  </exclude>
               </excludes>
            </configuration>
         </plugin>
      </plugins>
   </build>

</project>

application.yml

# 本地服务访问
server:
  # 服务端口
  port: 8081
  # 服务IP
  address: 0.0.0.0

spring:
  profiles:
    # 指定运行环境,不填默认为default
    active: dev
  # 应用服务名
  application:
    name: consul-example
  config:
    # 此处在启动时会加载consul服务中指定prefixes下的default-context配置属性
    # 会根据spring.profiles.active加载default或dev配置目录,default为默认无目录后缀,dev为开发环境目录名后缀为-dev,其它如:test,prod等
    # 如:dev,则加载的文件为 consul/config/testApp-dev/data,如应配置${prefixes}/${default-context}${profile-separator}${spring.profiles.active}/目录下,对应的${data-key}键/值
    # 也可手动指定加载固定目录key/value配置,如:optional:consul:127.0.0.1:8500/config/testApp,无data-key指定后缀
    import: optional:consul:192.168.1.36:8500
  cloud:
    # consul配置
    # https://docs.spring.io/spring-cloud-consul/docs/4.0.2/reference/html/#registering-with-consul
    consul:
      # consul服务host和port
      host: 192.168.1.36
      port: 8500
      # 注册成服务
      service-registry:
        enabled: true
      config:
        # 启用配置中心管理
        enabled: true
        # 注册配置中心名称
        name: ${spring.application.name}
        # 是否运行时启用导入consul中心配置
        import-check:
          enabled: "true"
        # 注意此组合很重要:prefixes,default-context,profile-separator,format,data-key
        # 表示在consul服务上"Key/Value"菜单界面创建如下目录:config/testApp::dev/data,并且在testApp目录下,有一个为data的key名,值按yaml格式存储
        # 设置配置存储值的根文件夹名(前缀),consul默认情况下应用配置放在config目录下
        prefixes: [ config ]
        # 设置所有应用程序使用的文件夹名称(通常以项目名创建,并放在prefixes表示的config目录下)
        default-context: ${spring.application.name}
        # 设置用于分隔属性源中的配置文件名称和配置文件的分隔符的值,如:config/testApp-dev/data
        profile-separator: '-'
        # 设置注册中心配置的数据格式
        format: yaml
        # consul中核心key/value的key名
        data-key: data
        # 当注册中心的数据发生更改,则会发布刷新事件,向注册的端点服务发起调用通知
        watch:
          # 启用配置文件监视
          enabled: true
          # 查询conusl配置中心数据变更刷新间隔,用于判断当前应用相关配置数据是否已发生更改,如有获得最新数据,则发布刷新事件
          delay: 1000
          # 延迟等待多久后,如果检测到数据更新,则执行数据刷新事件重新加载配置,如未检查到更新,则继续使用旧配置;此项影响监听事件推送,默认为55s,官方建议小于60s以内
          # 此配置的目的是防止短时间内高频修改配置,避免重复加载配置,从而减少对服务稳定性与性能等影响
          wait-time: 10
        # 当 consul配置不可用时,只警告而不抛出异常,使应用可以正常运行(默认true)
        fail-fast: true
      # 向consul服务注册与发现、配置健康检查项
      # https://docs.spring.io/spring-cloud-consul/docs/4.0.2/reference/html/#spring-cloud-consul-discovery
      discovery:
        # 启用服务发现(默认true)
        enabled: true
        # 启用服务注册(默认true)
        register: true
        # 向注册中心提供的服务发现名称
        service-name: ${spring.application.name}
        # 指定数据中心名称,当存在多个注册中心集群时,此配置用作区分当前服务注册所在数据中心
        # datacenters: dc1
        # 向注册中心提供的健康检测地址;
        # 注:如果开启自定义management.server.port检测端口,则可以使用 ${management.server.servlet.context-path}映射检测路径
        health-check-path: /actuator/health
        # 向注册中心创建的实例ID,random.value生成随机数
        instance-id: ${spring.application.name}:${server.port}:${random.value}
        # 当健康检测超过指定时长内未恢复正常状态,则注销当前服务,表示当前服务不可用
        health-check-critical-timeout: 60s
        # 每次健康检测的请求超时限制
        health-check-timeout: 10s
        # 启用注册中心心跳检测
        heartbeat:
          # 开启心跳信号发送
          enabled: true
          # 发送间隔(默认30s)
          ttl: 10s
        # 自定义tags参数
        tags: version=1.0,author=JL,describes="springcloud+consul test exaple!"
        # 定时查询consul服务频率,如当服务上线下线能够及时获得,默认1000毫秒
        catalog-services-watch-delay: 5000

# 配置日志
logging:
  level:
    # log 级别
    org.springframework: info
    # 引入spring-cloud-starter-consul-discovery包,会在启动时抛BeanPostProcessorChecker警告,经检测此由bean的加载顺序引起,并非实际容器未创建原因
    # 关闭启动服务时的WARN警告 [xxxx] not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying).
    org.springframework.context.support.PostProcessorRegistrationDelegate: error
  file:
    # 配置日志保存相对路径和文件名
    name: ./logs/consul-catalina.log

#是否开启debug调试模式
debug: false

MyWebApplicationConfig.java

package com.consul.example.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.client.RestTemplate;

/**
 * @Description WEB配置与bean创建
 * @Version V1.0
 */
@Configuration(proxyBeanMethods = false)
public class MyWebApplicationConfig {
    /**
     * SpringRestTemplate 支持使用逻辑服务名称/id 而不是物理 URL 来查找服务。
     * Feign 和发现感知的 RestTemplate 都利用Spring Cloud LoadBalancer进行客户端负载平衡。
     * @return
     */
    @LoadBalanced
    @Bean
    public RestTemplate loadbalancedRestTemplate() {
        return new RestTemplate();
    }
}

ConsulConfigWatchListener.java

package com.consul.example.listener;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import java.util.Set;

/**
 * @Description 通过EnvironmentChangeEvent事件获得consul配置变更
 * @Version V1.0
 */
@Slf4j
@RefreshScope
@Component
public class ConsulConfigWatchListener implements ApplicationListener<EnvironmentChangeEvent> {

    /**
     * 从consul中修改key/value值后,动态刷新映射到变量上,需要在当前类上加入@RefreshScope注解
     */
    @Value("${test.name}")
    private String testName;

    /**
     * 监听器方法,获得EnvironmentChangeEvent事件回调
     * @param refreshEvent
     */
    //支持注解 @EventListener(classes = EnvironmentChangeEvent.class)
    @Override
    public void onApplicationEvent(EnvironmentChangeEvent refreshEvent) {
        log.info("事件执行 -- EnvironmentChangeEvent");
        Set<String> keys = refreshEvent.getKeys();
        for (String key : keys) {
            log.info("listener consul to config yaml update, key = {}, value = {}", key, testName);
        }
    }
}

CustomConsulClientService.java

package com.consul.example.service;

import com.ecwid.consul.v1.ConsulClient;
import com.ecwid.consul.v1.Response;
import com.ecwid.consul.v1.kv.model.GetValue;
import com.google.gson.Gson;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * @Description 推送配置到consul服务的key/value中
 * @Version V1.0
 */
@Slf4j
@Service
public class CustomConsulClientService {

    /**
     * consul客户端访问类
     */
    @Resource
    private ConsulClient consulClient;

    /**
     * key所在的目录前缀,格式为:config/应用名称/
     */
    @Value("#{'${spring.cloud.consul.config.prefixes[0]:}/'.concat('${spring.cloud.consul.config.default-context:}')}")
    private String keyPrefix;

    /**
     * consul配置多环境运行文件分隔符,如:default = config/testApp/, dev = config/testApp-dev/,其中-即为profile-separator配置
     */
    @Value("${spring.cloud.consul.config.profile-separator:}")
    private String profileSeparator;

    /**
     * 应用运行环境,如:default, dev, test
     */
    @Value("${spring.profiles.active:}")
    private String active;

    /**
     * 核心配置数据key名
     */
    @Value("${spring.cloud.consul.config.data-key:}")
    private String dataKey;

    /**
     * 推送配置到consul
     * @param value
     */
    public void pushConfig(String value) {
        pushConfig(dataKey, value);
    }

    /**
     * 推送配置到consul
     * @param key
     * @param value
     */
    public void pushConfig(String key, String value) {
        String configKey = getKeyPrefixPath() + key;
        log.info("push config to consul, {} = {}", configKey, value);
        consulClient.setKVValue(configKey, value);
    }

    /**
     * 获取基于应用环境类型的consul配置config文件夹目录
     * @return
     */
    private String getKeyPrefixPath() {
        if (!"default".equals(active)) {
            return keyPrefix + profileSeparator + active + "/";
        }
        return keyPrefix + "/";
    }

    /**
     * 获得指定key的value
     * @param key
     * @return
     */
    @SneakyThrows
    public String getConfigValue(String key) {
        String configKey = getKeyPrefixPath() + key;
        Response<GetValue> response = this.consulClient.getKVValue(configKey);
        if (response == null) {
            return null;
        }

        GetValue value = response.getValue();
        if (value != null) {
            log.info("consul config, key={}, value={}", configKey, value);
            return value.getDecodedValue(StandardCharsets.UTF_8);
        }
        return null;
    }

    /**
     * 获得指定key的value
     * @return
     */
    public String getConfigKeys() {
        return new Gson().toJson((getConfigKeyList(getKeyPrefixPath())));
    }

    /**
     * 获得指定前缀目录下所有key信息
     * @param keyPrefix
     * @return
     */
    public List<String> getConfigKeyList(String keyPrefix) {
        List<String> list = new ArrayList<>();
        try {
            Response<List<String>> response = this.consulClient.getKVKeysOnly(keyPrefix);
            if (response.getValue() == null) {
                return list;
            }
            for (String key : response.getValue()) {
                if (key != null && key.length() > 0) {
                    int index = key.lastIndexOf("/") + 1;
                    String temp = key.substring(index);
                    list.add(temp);
                }
            }
        } catch (Exception e) {
            log.error("get consul config error, execute to 'consulClient.getKVKeysOnly()' exception: {}, keyPrefix: {}", e.getMessage(), keyPrefix);
        }
        return list;
    }
}

ExampleRest.java

package com.consul.example.rest;

import com.consul.example.service.CustomConsulClientService;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.concurrent.CompletableFuture;

/**
 * @Description API控制器测试类
 * @Version V1.0
 */
@RefreshScope
@RestController
public class ExampleRest {

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private CustomConsulClientService customConsulClientService;

    @Value("${server.port:}")
    private String prot;
    /**
     * 从consul中修改key/value值后,动态刷新映射到变量上,需要在当前类上加入@RefreshScope注解
     */
    @Value("${test.name}")
    private String testName;

    /**
     * 测试示例,获取consul中的配置属性值
     * @return
     */
    @RequestMapping("/getName")
    public Object getName() {
        return "test.name: " + testName + "," + System.currentTimeMillis();
    }

    /**
     * 测试示例,推送配置到consul配置中心
     * @param value
     * @return
     */
    @RequestMapping("/pushConfig")
    public Object pushConfig(String value) {
        customConsulClientService.pushConfig(value);
        return HttpStatus.OK + "," + System.currentTimeMillis();
    }

    /**
     * 测试示例,获取当前运行环境下所配置的dataKey列表
     * @return
     */
    @RequestMapping("/getConfigKeys")
    public Object getConfigKeys() {
        String value = customConsulClientService.getConfigKeys();
        return value + "," + System.currentTimeMillis();
    }

    /**
     * 获取指定dataKey内容
     * @param key
     * @return
     */
    @RequestMapping("/getConfigValue")
    public Object getConfig(String key) {
        String value = customConsulClientService.getConfigValue(key);
        return value + "," + System.currentTimeMillis();
    }

    /**
     * 测试示例
     * @return
     */
    @RequestMapping("/info")
    public Object info() {
        return HttpStatus.OK +",prot:" + prot+ "," + System.currentTimeMillis();
    }

    /**
     * 测试示例,通过负载再次调用/info控制器方法
     * @return
     */
    @RequestMapping("/loadbalanced/info")
    public Object loadbalanced() {
        return getFirstProduct();
    }

    /**
     * 通过注册服务名请求指定路径(支持负载均衡)
     * @return
     */
    @SneakyThrows
    public String getFirstProduct() {
        //注意:此处需要异常请求,否则会引WebFlux同步阻塞抛错:block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-1
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            //使用注册名称consul-example,而不是IP:port的方式发起请求
            return this.restTemplate.getForObject("http://consul-example/info", String.class);
        });
        return completableFuture.get();
    }
}

ConsulExampleApplication.java

package com.consul.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * 启动类
 */
@SpringBootApplication
@EnableDiscoveryClient
public class ConsulExampleApplication {
   public static void main(String[] args) {
      SpringApplication.run(ConsulExampleApplication.class, args);
   }
}

服务测试

服务配置

此处将consul搭建在虚拟机linux环境上,访问:http://ip:8500/

此server1即为consul安装时config.json中所配置的node_name值,为consul服务节点本身信息;

启动consul-example工程,从ConsulExampleApplication启动类中右键Run或Debug运行;

查看consul服务nodes,serviceName=consul-example已成功获得心跳检测,注册成consul节点子服务成功;

需提前在consul服务中通过Key/Value菜单进入配置界面,通过右上角"Create"按钮,创建两个文件目录:config/consul-example/、config/consul-example-dev/,(注意:在consul界面中创建名称后带/则表示文件夹名),其中consul-example-dev配置目录表示spring.profiles.active=dev运行环境,默认不填则为default环竟加载consul-example配置目录,通过此方式,可以在一个consul集群或单节点上,建立多个可运行环境,如:dev,test,pro;但通常不建议放在一起,为了数据安全性,因该对不同的环境做独立conusl集群或单节点隔离运行;

进入consul-example-dev目录下,通过右上角"Create"按钮继续创建名为data的键(dataKey),data为工程项目代码application.yml配置里对应spring.cloud.consul.config.data-key,其中Value值即为项目运行过程中需要动态加载的内容;

接口测试

访问consul-example工程示例接口测试;

访问http://127.0.0.1:8081/info 获取简单响应

200 OK,1702374324638

访问http://127.0.0.1:8081/loadbalanced/info负载均衡接口,首先在idea里分别设置8081和8082两个服务端口并启动应用,在consul>Service里查注册服务信息,默认多次请求8081端口的API获取指定服务ID的负载均衡响应

200 OK,prot:8081,1702381796922

200 OK,prot:8082,1702381806726

访问http://127.0.0.1:8081/getConfigKeys,获取当前应用运行环境下config/consul-example-dev/配置目录中所有key名

["","data"],1702374354725

访问http://127.0.0.1:8081/getName,获取当前应用在指定运行环境下从config/consul-example-dev/data配置中拉取并加载到SpringCloud中的配置项类变量值

test.name: dev2,1702374505442

访问http://127.0.0.1:8081/getConfigValue?key=data,获取当前应用在指定运行环境下config/consul-example-dev/配置中data键名所有内容(注意:和上面getName有区别,通过consulClient客户端类获取)

test.name: dev2,1702374662615

访问http://127.0.0.1:8081/pushConfig?value=test.name:%20dev3,向当前应用在指定运行环境config/consul-example-dev/data键名中推送value配置

200 OK,1702375268604

控制台打印定时刷新配置后,推送的监听记录;手动在consul服务节点上修改配置,同样会触发ConsulConfigWatchListener.onApplicationEvent()方法;

2023-12-12T18:02:13.834+08:00  INFO 29428 --- [consul-example] [        task-14] c.c.e.service.CustomConsulClientService  : push config to consul, config/consul-example-dev/data = test.name: dev3
2023-12-12T18:02:20.528+08:00  INFO 29428 --- [consul-example] [TaskScheduler-1] c.c.e.l.ConsulConfigWatchListener        : 事件执行 -- EnvironmentChangeEvent
2023-12-12T18:02:20.529+08:00  INFO 29428 --- [consul-example] [TaskScheduler-1] c.c.e.l.ConsulConfigWatchListener        : listener consul to config yaml update, key = test.name, value = dev3
2023-12-12T18:02:20.529+08:00  INFO 29428 --- [consul-example] [TaskScheduler-1] o.s.c.e.event.RefreshEventListener       : Refresh keys changed: [test.name]

结尾

本章内容是根据spring官网的spring-cloud项目下的spring-cloud-consul组件文档描述进行参考与搭建,conusl配置与使用则来源于官网文档说明;同时还有许多consul服务功能的用法与集成,未在本文中演示,可以尝试自行去了解;更多内容,请上相关官网学习与了解;

到此完成一个简单的springcloud+consul注册与发现服务的工程开发,后续可以在此基础上,根据业务需要扩展开发;

谢谢!

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

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

相关文章

化学方程式小程序

brief introduction 相信大家上中学时都会被化学方程式折腾得死去活来&#xff0c;尤其是配平&#xff0c;怎么也算不对数字。于是我写出了这款近200行的自动配平程序&#xff0c;这是不是你们黑暗化学中的一丝光亮呢&#xff1f; usage 正常化学式输入&#xff0c;每一种物…

【Vue】elementUI表格,导出Excel

系列文章 【Vue】vue增加导航标签 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/134965353 【Vue】Element开发笔记 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/133947977 【Vue】vue&#xff0c;在Windows IIS平台…

windows下redis 设置开机自启动

1&#xff0c;在redis的目录下执行&#xff08;执行后就作为windows服务了&#xff09; redis-server --service-install redis.windows.conf 2&#xff0c;安装好后需要手动启动redis redis-server --service-start 3&#xff0c;停止服务 redis-server --service-stop

人工智能与大数据的紧密联系

随着科技的飞速发展&#xff0c;人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09;和大数据&#xff08;Big Data&#xff09;已成为当今社会的热门话题。人工智能在许多领域的应用越来越广泛&#xff0c;而大数据则提供了支持和驱动AI技术的巨大资源。本…

2023-12-16:用go语言,给定整数数组arr,求删除任一元素后, 新数组中长度为k的子数组累加和的最大值。 来自字节。

2023-12-16&#xff1a;用go语言&#xff0c;给定整数数组arr&#xff0c;求删除任一元素后&#xff0c; 新数组中长度为k的子数组累加和的最大值。 来自字节。 答案2023-12-16&#xff1a; 来自左程云。 灵捷3.5 大体步骤如下&#xff1a; 算法 maxSum1 分析&#xff1…

QT----第三天,Visio stdio自定义封装控件,鼠标事件,定时器,事件分发器过滤器,绘图事件

目录 第三天1 自定义控件封装2 QT鼠标事件3 定时器4 event事件分发器5 事件过滤器6 绘图事件Qpainter 源码&#xff1a;CPP学习代码 第三天 1 自定义控件封装 新建一个QT widgetclass&#xff0c;同时生成ui,h,cpp文件 在smallWidget.ui里添加上你想要的控件并调试大小 回到…

day01-报表技术POI

前言 报表[forms for reporting to the higher organizations]&#xff0c;就是向上级报告情况的表格。简单的说&#xff1a;报表就是用表格、图表等格式来动态显示数据&#xff0c;可以用公式表示为&#xff1a;“报表 多样的格式 动态的数据”。 1、开发环境搭建 功能说…

【Python动漫系列】哆啦A梦(完整代码)

文章目录 哆啦A梦环境需求完整代码程序分析系列文章哆啦A梦 《哆啦A梦》是由日本漫画家藤子F不二雄创作的一部科幻搞笑漫画,故事中的主角是一只来自未来的机器猫——哆啦A梦。该作品于1969年开始连载,至今已经持续了50多年,成为了日本乃至全球最受欢迎的漫画之一。 故事发…

c++_01_名字空间_复合类型_缺省参数_哑元函数

0 前言 C和C一样&#xff0c;都属于编译型语言 C和C一样&#xff0c;都属于强类型语言 C对C完全兼容&#xff0c;并提供更多面向对象的特性&#xff1a;语言风格更加简洁&#xff0c;类型检查更加严格 1 名字空间 namespace WHY&#xff1f;划分更精细的逻辑单元(逻辑空间)&…

AC843. n皇后问题--60

我们只需要把蓝色的往上移动就行了 if(!col[i][j]&&!dg[ui]&&!udg[])//1y&#xff08;i&#xff09;向下&#xff0c;x&#xff08;u&#xff09;向右为正。yxb的by-x一定>0,y-xb的bxy可能>0,这个不考虑&#xff0c;只看-bxy.

Python-数据分析可视化实例图

Python-数据分析可视化实例图 一&#xff1a;3D纹理图 运行效果图&#xff1a; Python代码&#xff1a; import math from typing import Unionimport pyecharts.options as opts from pyecharts.charts import Surface3Ddef float_range(start: int, end: int, step: Union[…

翻译: 工作使用ChatGPT的例子 Day-to-day usage of web UI LLMs

本周&#xff0c;我们将首先探讨生成型AI在商业中的作用&#xff0c;然后是其对社会的影响&#xff0c;例如对就业的影响。我们将从探讨如何在日常工作中使用网络用户界面访问生成型AI开始&#xff0c;然后再看看如何系统地分析一个企业&#xff0c;以识别使用生成型AI增强或自…

Linux面试题精选:提升你的面试准备

大家有关于JavaScript知识点不知道可以去 &#x1f389;博客主页&#xff1a;阿猫的故乡 &#x1f389;系列专栏&#xff1a;JavaScript专题栏 &#x1f389;ajax专栏&#xff1a;ajax知识点 &#x1f389;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 学习…

商用机器人,不好用是原罪

热潮褪去后&#xff0c;所有的问题都汇总成一个词&#xff0c;不好用。 从炙手可热到“大玩具” 一款产品好用与否&#xff0c;更多时候人们不会关心它先进的技术、工艺、用料&#xff0c;也不会考虑所谓的潮流趋势或前景&#xff0c;只会用最朴素的直观感受告诉你&#xff0…

LabVIEW开发地铁运行安全监控系统

LabVIEW开发地铁运行安全监控系统 最近昌平线发生的故障事件引起了广泛关注&#xff0c;暴露了现有地铁运行监控系统在应对突发情况方面的不足。为了提高地铁系统的运行安全性&#xff0c;并防止类似事件再次发生&#xff0c;提出了一套全面的地铁运行安全监控系统方案。此方案…

NAT——网络地址转换

目录 一、概念 二、NAT的分类 1.静态NAT 1.1 静态NAT的配置 1.2 利用eNSP小实验加强对静态NAT的理解 2、动态NAT 三、NAPT——端口映射 四、Easy IP 使用一个公网地址可以让所有人都上公网 一、概念 随着Internet的发展和网络应用的增多&#xff0c;IPv4地址枯竭已经成为…

【C语言(十)】

字符函数和字符串函数 一、字符分类函数 C语言中有⼀系列的函数是专门做字符分类的&#xff0c;也就是⼀个字符是属于什么类型的字符的。这些函数的使用都需要包含⼀个头文件是 ctype.h 这些函数的使用方法非常类似&#xff0c;我们就讲解⼀个函数的事情&#xff0c;其他的非…

鸿蒙4.0开发 - DevEco Studio如何使用Previewer窗口预览器报错

DevEco Studio预览器概况在HarmonyOS应用开发过程中&#xff0c;通过使用预览器&#xff0c;可以查看应用的UI效果&#xff0c;方便开发者实时查看应用的运行效果&#xff0c;随时调整代码。 1.正常启动 打开预览器的位置在DevEco Studio编辑界面的右上角部分&#xff0c;竖排…

MySQL低版本中:字符串中的数字、英文字符、汉字提取

我们如何提醒一个字段中的汉字和数字呢 高版本指mysql8.0以上 使用sql语句 SELECT REGEXP_REPLACE(column_name, [^\\p{Han}], ) AS chinese_characters FROM table_name;其中 column_name指名称列&#xff0c;table_name是表名 2.低版本使用 需要新建函数 DELIMITER $$DR…

ChatGPT4 Excel 高级复杂函数案例实践

案例需求: 需求中需要判断多个条件进行操作。 可以让ChatGPT来实现这样的操作。 Prompt:有一个表格B2单元格为入职日期,C2单元格为员工等级(A,B,C),D2单元格为满意度分数(1,2,3,4,5)请给入职一年以上,员工等级为A级并且满意度在3分以上的人发4000元奖金,给入…