SpringCloud(十一)Bus消息总线、Stream消息驱动

2023-05-16

一、Bus消息总线

需求:分布式自动刷新配置功能;

解决:SpringCloud Bus配合Spring cloud Config使用可以实现配置的动态刷新。

1、概述

定义:Spring Cloud Bus是用来将分布式系统的节点与轻量级消息系统链接起来的框架,它整合了Java的事件处理机制和消息中间件的功能。

Spring Clud Bus目前支持RabbitMQ和Kafka。

在这里插入图片描述

通俗定义:bus称之为springcloud中消息总线,主要用来在微服务系统中实现远端配置更新时通过广播形式通过所有客户端刷新配置信息,避免手动重启服务的工作。

能干什么?

Spring Cloud Bus能管理和传播分布式系统间的消息,就像一个分布式执行器, 可用于广播状态更改、事件推送等,也可以当作微服务间的通信通道。

在这里插入图片描述

为何被称为总线?

在微服务架构的系统中,通常会使用轻量级的消息代理来构建一个共用的消息主题, 并让该系统中所有微服务实例都连接上来。由于该主题中产生的消息会被所有实例监听和消费,所以称它为消息总线。在总线上的各个实例,都可以方便地广播一些需要让其他连接在该 主题上的实例都知道的消息。

基本原理

ConfigClient实例都监听MQ中同一个topic(默认是springCloudBus)。当一个服务刷新数据的时候,它会把这个信息放入到Topic中,这样其它监听同一Topic的服务就能得到通知,然后去更新自身的配置。

2、RabbitMQ环境配置

  1. 安装Erlang,下载地址:opt_win64_21.3.exe
  2. 安装RabbitMQ,下载地址:rabbitmq-server 3.7.14
  3. 进入RabbitMQ安装目录下的sbin目录

在这里插入图片描述

  1. 输入以下命令启动管理功能
  • 在sbin目录下运行命令行窗口cmd
  • 输入命令rabbitmq-plugins enable rabbitmq management,这样就可以添加可视化插件了。
  • 这样就添加了rabbitmq界面,只需要启动rabbitmq即可
  1. 访问地址查询是否安装成功:

在浏览器上输入 http://127.0.0.1:15672

  1. 输入账号密码并登录:guest guest

在这里插入图片描述

3、SpringCloud Bus动态刷新全局广播

必须先具备良好的RabbitMQ环境

为了实现广播效果,我们新建3366微服务(同3355模块)

  • cloud-config-client-3366
  • POM
  • YML
  • 启动类
  • controller

设计思想

1)利用消息总线触发一个客 户端/bus/refresh,而刷新所有客户端的配置

在这里插入图片描述

2)利用消息总线触发一个服务端ConfigServer的/bus/refresh端点,而刷新所有客户端的配置

在这里插入图片描述

图二的架构显然更加适合,图一不适合的原因如下:

  • 打破了微服务的职责单一-性,因为微服务本身是业务模块,它本不应该承担配置刷新的职责。
  • 破坏了微服务各节点的对等性。
  • 有一定的局限性。例如,微服务在迁移时,它的网络地址常常会发生变化,此时如果想要做到自动刷新,那就会增加更多的修改

具体实现步骤

  1. 给cloud-config-center-3344配置中心服务端添加消息总线支持
  • POM
<!--添加消息总线RbbitMQ支持-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  • YML:注意写的位置要对齐
  #rabbit相关配置
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

#rabbitmq相关配置,暴露bus刷新配置的端点
management:
  endpoints:  #暴露bus刷新配置的端点
    web:
      exposure:
        include: 'bus-refresh'  #凡是暴露监控、刷新的都要有actuator依赖,bus-refresh就是actuator的刷新操作
  1. 给cloud-config-client-3355客户端添加消息总线支持
  • POM
<!--添加消息总线RbbitMQ支持-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  • YML
  #rabbit相关配置 15672是web管理界面的端口,5672是MQ访问的端口
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
  1. 给cloud-config-client-3366客户端添加消息总线支持
  • 操作同上
  1. 测试如下
  • 修改GitHub上配置文件新增版本号
  • 只需要3344发一次,其他处处生效:curl -X POST "http://localhost:3344/actuator/bus-refresh"
  • 查询配置中心:http://config-3344:3344/config-dev.yml
  • 查看客户端:http://localhost:3355/configInfo;http://localhost:3366/configInfo
    此时获取配置信息,发现后已经刷新了

一次修改,广播通知,处处生效

4、SpringCloud Bus动态刷新定点通知

需求:不想全部通知,只想定点通知。只通知3355,不通知3366

简单来说:

  • 指定具体某一个实例生效而不是全部
  • 公式:http://localhost:配置中心的端口号/actuator/bus-refresh/{destination}
  • /bus/refresh请求不再发送到具体的服务实例上,而是发给config server并通过destination参数类指定需要更新配置的服务或实例

具体实现:

curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:3355"

总结:

在这里插入图片描述

二、Stream消息驱动

1、消息驱动概述

定义:屏蔽底层消息中间件的差异,降低切换成本,统一消息的编程模型。

1. 什么是SpringCloud Stream?

官方定义Spring Cloud Stream是一个构建消息驱动微服务的框架

应用程序通过inputs或者outputs与Spring Cloud Stream中binder对象交互。
通过我们配置来binding(绑定),而Spring Cloud Stream的binder对象负责与消息中间件交互。
所以,我们只需要搞清楚如何与Spring Cloud Stream交互就可以方便使用消息驱动的方式。

通过使用Spring Integration来连接消息代理中间件以实现消息事件驱动。
Spring Cloud Stream为一些供应商的消息中间件产品提供了个性化的自动化配置实现,引用了发布-订阅、消费组、分区的三个核心概念。

目前仅支持RabbitMQ、Kafka

官网文档

SpringCloud Steam中文指导手册

2. 设计思想

标准MQ(没有引出Springcloud):

  • 生产者/消费者之间靠消息媒介传递信息内容:Message
  • 消息必须走特定的通道:消息通道MessageChannel
  • 消息通道里的消息如何被消费呢,谁负责收发处理:消息通道MessageChannel的子接口SubscribleChannel,由MessageHandle消息处理器锁订阅

为什么要用Cloud Stream?

这些中间件的差异性导致我们实际项目开发给我们造成了一定的困扰,我们如果用了两个消息队列的其中一种,后面的业务需求,我想往另外一种消息队列进行迁移,这时候无疑就是一个灾难性的,一大堆东西都要重新推倒重新做,因为它跟我们的系统耦合了,这时候springcloud Stream给我们提供了一种解耦合的方式。

Stream凭什么可以统一底层差异?

在没有绑定器这个概念的情况下,我们的SpringBoot应用要直接与消息中间件进行信息交互的时候,于各消息中间件构建的初衷不同,它们的实现细节上会有较大的差异性
通过定义绑定器作为中间层,完美地实现了应用程序与消息中间件细节之间的隔离
通过向应用程序暴露统一的Channel通道, 使得应用程序不需要再考虑各种不同的消息中间件实现。
通过定义绑定器Binder作为中间层,实现了应用程序与消息中间件细节之间的隔离

Binder

  • INPUT对应于消费者
  • OUTPUT对应于生产者
    在这里插入图片描述

通过定义绑定器Binder作为中间层,实现了应用程序与消息中间件细节之间的隔离。

Stream中的消息通信方式遵循了发布-订阅模式:Topic主题进行广播

  • 在RabbitMQ就是Exchange
  • 在Kakfa中就是Topic

3. Springcloud Stream标准流程套路

在这里插入图片描述

  • Binder:很方便的连接中间件,屏蔽差异
  • Channel:通道,是队列Mueue的一种抽象,在消息通讯系统中就是实现存储和转发的媒介,通过Channel对队列进行配置
  • Source和Sink:简单的可理解为参照对象是Spring Cloud Stream自身,从Stream发布消息就是输出,接受消息就是输入。

4. 编码API和常用注解

在这里插入图片描述

2、案例说明

RabbitMQ环境是通的;

工程中创建三个子模块;

1)cloud-stream-rabbitmq-provider8801:作为生产者进行发消息模块
2)cloud-stream-rabbitmq-consumer8802:作为消息接收模块
3)cloud-stream-rabbitmq-consumer8803:作为消息接收模块

3、消息驱动之生产者

  1. 新建cloud-stream-rabbitmq-provider8801

  2. POM

<dependencies>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
     </dependency>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-actuator</artifactId>
     </dependency>

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

     <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-stream-rabbit</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>
 </dependencies>
  1. YML
server:
  port: 8801

spring:
  application:
    name: cloud-stream-provider
  cloud:
    stream:
      binders: # 在此处配置要绑定的rabbitMQ的服务信息
      defaultRabbit: # 表示定义的名称,用于binding的整合
        type: rabbit # 消息中间件类型
        environment: # 设置rabbitMQ的相关环境配置
          spring:
            rabbitmq:
              host: localhost
              port: 5672
              username: guest
              password: guest
      bindings: # 服务的整合处理
        ouput: # 这个名字是一个通道的名称
          destination: studyExchange # 表示要使用的exchange名称定义
          content-type: application/json # 设置消息类型,本次为json,文本则设为text/plain
          #binder: defaultRabbit # 设置要绑定的消息服务的具体设置

eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka
  instance:
    lease-renewal-interval-in-seconds: 2 # 设置心跳的间隔时间,默认30
    lease-expiration-duration-in-seconds: 5 # 超过5秒间隔,默认90
    instance-id: send-8801.com # 主机名
    prefer-ip-address: true # 显示ip
  1. 主启动类
@SpringBootApplication
public class StreamMQMain8801 {

    public static void main(String[] args) {
        SpringApplication.run(StreamMQMain8801.class, args);
    }
}
  1. 业务类

发送接口实现类

//这不是传统的service,这是和rabbitmq打交道的,不需要加注解@Service
//这里不调用dao,调用消息中间件的service
//信道channel和exchange绑定在一起
@EnableBinding(Source.class) // 定义消息推动管道
public class MessageProviderImpl implements MessageProvider {

    // 消息发送管道
    @Resource
    private MessageChannel output;

    @Override
    public String send() {
        String serial = UUID.randomUUID().toString();
        output.send(MessageBuilder.withPayload(serial).build());
        System.out.println("serial = " + serial);
        return null;
    }
}

Controller

@RestController
public class SendMessageController {
    @Resource
    private MessageProvider messageProvider;

    @GetMapping("/sendMessage")
    public String sendMessage(){
        return messageProvider.send();
    }
}
  1. 测试

1)启动7001
2)rabbitMQ:http://localhost:15672
3)启动8801
4)访问:http://localhost:8801/sendMessage
在这里插入图片描述

4、消息驱动之消费者

  1. 新建cloud-stream-rabbitmq-consumer8802
  2. POM
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

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

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-stream-rabbit</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>
</dependencies>
  1. YML
server:
  port: 8802

spring:
  application:
    name: cloud-stream-consumer
  cloud:
    stream:
      binders: # 在此处配置要绑定的rabbitMQ的服务信息
        defaultRabbit: # 表示定义的名称,用于binding的整合
          type: rabbit # 消息中间件类型
          environment: # 设置rabbitMQ的相关环境配置
            spring:
              rabbitmq:
                host: localhost
                port: 5672
                username: guest
                password: guest
      bindings: # 服务的整合处理
        input: # 这个名字是一个通道的名称
          destination: studyExchange # 表示要使用的exchange名称定义
          content-type: application/json # 设置消息类型,本次为json,文本则设为text/plain
          #binder: defaultRabbit # 设置要绑定的消息服务的具体设置
          #group: atguiguA
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka
  instance:
    lease-renewal-interval-in-seconds: 2 # 设置心跳的间隔时间,默认30
    lease-expiration-duration-in-seconds: 5 # 超过5秒间隔,默认90
    instance-id: receive-8802.com #主机名
    prefer-ip-address: true # 显示ip
  1. 主启动类
@SpringBootApplication
public class StreamMQMain8802 {

    public static void main(String[] args) {
        SpringApplication.run(StreamMQMain8802.class, args);
    }
}
  1. 业务类
@Component
@EnableBinding(Sink.class)
public class ReceiveMessageListenerController {

    @Value("${server.port}")
    private String serverPort;

    @StreamListener(Sink.INPUT)
    public void input(Message<String> message){
        System.out.println("消费者1号,------->接收到的消息: "+message.getPayload()+"\t port: "+serverPort);
    }
}
  1. 测试8801发送8802接收消息

访问:http://localhost:8801/sendMessage

在这里插入图片描述

5、分组消费与持久化

  1. 依照8802,clon出来一个运行8803:cloud-stream-rabbitmq-consumer8803
  2. 启动

RabbitMQ,7001(服务注册),8801(消息生产),8802(消息消费),8803(消息消费)

  1. 运行后有两个问题
  • 重复消费问题
  • 消息持久化问题
  1. 消费

目前8802/8803 同时都接收到了,存在重复消费问题

如何解决分组和持久化

生产中实际案例

比如在如下场景中,订单系统我们做集群部署,都会从RabbitMQ中获取订单信息,那如果一个订单同时被两个服务获取到,那么就会造成数据错误,我们得避免这种情况。

这时我们就可以使用Stream中的消息分组来解决。

注意:在Stream中处于同一个group中的多个消费者是竞争关系,就能够保证消息只会被其中一个应用消费一次。
不同组是可以全面消费的(重复消费),同一组内会发生竞争关系,只有其中一个可以消费

  1. 分组

原理

微服务应用放置于同一个group中,就能够保证消息只会被其中一个应用消费一次。
不同的组是可以消费的,同一个组内会发生竞争关系,只有其中一个可以消费。

1)8802/8803都变成不同组,group两个不同

修改8002YML

group: atguiguA

修改8003YML

group: atguiguB

在这里插入图片描述
结论:还是重复消费。

所以:8802/8803实现了轮询分组,每次只有一个消费者;8801模块的发的消息只能被8802或8803其中一个接收到,这样避免了重复消费。

2)8802/8803都变成相同组,group两个相同

修改8002YML

group: atguiguA

修改8003YML

group: atguiguA

结论:同一个组的多个微服务案例,每次只会有一个能拿到。

  1. 持久化
  • 通过上述,解决了重复消费问题,再看看持久化
  • 停止8802/8803并去除掉8802的分组group: atguiguA,8803的分组group:atguiguA没有去掉
  • 8801先发送4条消息到rabbitmq
  • 先启动8802,无分组属性配置,后台没有打出来消息。
  • 再启动8803,有分组属性配置,后台打出来了MQ上的消息。

如果有收获!!! 希望老铁们来个三连,点赞、收藏、转发。
创作不易,别忘点个赞,可以让更多的人看到这篇文章,顺便鼓励我写出更好的博客
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SpringCloud(十一)Bus消息总线、Stream消息驱动 的相关文章

  • OpenXML 在写入元素时挂起

    我有一个程序 它基本上从数据库中提取数据 将其缓存到文件中 然后将该数据导出为多种格式 Excel Excel 2003 CSV 我正在使用 OpenXML SDK 2 0 来完成 Excel 工作 这些导出过程并行运行 使用Paralle
  • 使用一个套接字创建 2 个流

    我正在尝试创建一个在互联网上运行的多人游戏 问题是我正在尝试获取流上的输入 但由于某种原因我无法使用一个套接字创建 2 个流 我将解释一下 Socket s new Socket 127 0 0 1 5001 ObjectInputStre
  • 使用 ostream 进行 C++ 日志记录

    我正在制作一个记录器 我想创建一个函数log 以流作为输入 例如 log hello lt lt lt lt world lt lt 10 lt lt n 我也希望它是线程安全的 我重新定义了 lt lt 运算符所以我可以这样做 log l
  • 如何通过管道将 OutputStream 传输到 StreamingDataHandler?

    我在 JAX WS 中有一个 Java Web 服务 它从另一个方法返回一个 OutputStream 我似乎无法弄清楚如何将 OutputStream 流式传输到返回的 DataHandler 中 除了创建一个临时文件 写入它 然后再次将
  • 在随机端口上运行微服务时,Eureka 无法找到端口

    我在 Spring Boot 应用程序中使用 eureka 进行服务发现 使用功能区进行负载平衡 当我在修复端口上运行在 eureka 注册的微服务时 它工作正常 但是当我在随机端口上运行它们时 尽管我可以看到在 eureka 仪表板上注册
  • 引起原因:java.lang.IllegalStateException:您需要为git存储库配置一个uri

    我正在开发Microservices with Spring Boot 2 0 Eureka and Spring Cloud参考 https piotrminkowski wordpress com 2018 04 26 quick gu
  • 即使使用stream_set_blocking,PHP SSH2流内容仍为空?

    我正在开发一个工具 它使用 PECL SSH2 扩展通过 SSH2 从远程主机读取 iptables 配置 我能够成功连接到主机 进行身份验证并执行命令 我遇到的问题是有时该流不包含任何数据 Load the current firewal
  • 创建流而无需从中创建物理文件

    我需要创建一个包含服务器上存在的文档的 zip 文件 我使用 Net Package 类来执行此操作 并创建一个新的 Package 即 zip 文件 我必须具有物理文件或流的路径 我试图不创建一个实际的 zip 文件 而是创建一个存在于内
  • 带有属性占位符的 Spring Cloud AWS SQS SendTo 注释

    这个问题 https github com spring cloud spring cloud aws issues 65建议 SendTo 注释支持属性占位符 但我无法让它工作 这是我想要做的一些简化的代码片段 比尝试用文字解释更容易 我
  • 如何在 python apache beam 中展平多个 Pcollection

    应该如何实现位于以下位置的以下逻辑 https beam apache org documentation pipelines design your pipeline https beam apache org documentation
  • C++ 中有标准的日期/时间类吗?

    C stl 有标准时间类吗 或者我是否必须在写入流之前转换为 c 字符串 例如 我想将当前日期 时间输出到字符串流 time t tm ostringstream sout sout lt lt tm lt lt ends 在本例中 我将当
  • 媒体播放器准备时的进度条

    我试图弄清楚如何在我的媒体播放器准备流文件时显示 正在加载 请稍候 的进度条 现在发生的事情是在歌曲准备好后显示 我怎样才能解决这个问题 mediaPlayerLoadingBar ProgressDialog show PlaylistA
  • 在 FFmpeg 中使用 -filter_complex amerge 时混合流

    我目前遇到 ffmpeg 及其过滤器之一的问题 我正在尝试将视频的 2 个音频流合并为一个 为此我尝试了这个命令 ffmpeg i home maniaplanet Videos ManiaPlanet 2014 08 21 20 09 1
  • SpringBoot @SqsListener - 不工作 - 有异常 - TaskRejectedException

    我有一个 AWS SQS 队列中已有 5000 条消息 示例消息类似于 Hello 1 我创建了一个 SpringBoot 应用程序 并在其中一个组件类中创建了一个从 SQS 读取消息的方法 package com example aws
  • Zuul -> Eureka Server,基本身份验证问题

    如果流程不包含基本授权 我就可以访问该服务 如果我使用基本授权 它会抛出 消息 访问此资源需要完全身份验证 以下是我的观察 在 ZuulFilter 的 run 方法中 我得到了值 request getHeader 授权 gt 基本 c2
  • 如何将整个流读入 std::string ?

    我正在尝试将整个流 多行 读入字符串中 我正在使用这段代码 它有效 但它冒犯了我的风格感 当然有更简单的方法吗 也许使用字符串流 void Obj loadFromStream std istream stream std string s
  • c# 模拟 IFormFile CopyToAsync() 方法

    我正在对一个异步函数进行单元测试 该函数将 IFormFile 列表转换为我自己的任意数据库文件类列表 将文件数据转换为字节数组的方法是 internal async Task
  • 图片加载性能

    我已经尝试了几个小时从文件加载图像的各种方法 请看一下这两种方法 public Image SlowLoad string path return Image FromFile path public Image FastLoad stri
  • 如何通过基本身份验证确保 Spring Cloud Eureka 服务的安全?

    我在同一主机上设置了多个尤里卡服务器实例 他们使用主机名 eureka primary secondary 和 tertiary 这些主机名在主机文件中定义为 localhost 别名 一切都工作正常 它们都是可见的 并且可以作为不同的实例
  • 设置了 server.contextPath 的 Spring Boot 与通过 Eureka Server 访问 hystrix.stream 的 URL

    我有运行 Turbine 实例的 Eureka Server 以及连接到它的一些发现客户端 一切正常 但如果我注册一个发现客户端server contextPath设置后 它没有被识别InstanceMonitor涡轮流无法结合其hystr

随机推荐

  • 微信小程序基础

    文章目录 一 微信小程序介绍1 为什么是微信 程序2 官 微信 程序体验 二 微信小程序准备工作1 注册账号2 登录小程序3 获取APPID4 开发工具 三 第 个微信 程序1 打开微信开发者 具2 新建 程序项 3 填写项 信息4 成功5
  • 微信小程序之动态添加、删除指定view和获取input值

    遇到的问题 xff1a 动态的添加指定的view内容 嗯 很简单 wx for就搞定 xff01 xff01 动态添加的内容中有input xff0c 最终获取值的时候 xff0c 要获取到所有input的值并且是一个数组 动态删除指定的已
  • LibTorch:tensor.index_select()

    LibTorch中的tensor index select 方法与PyTorch中的用法类似 xff0c 作用都是在指定的tensor维度dim上按照index值索引向量 先看一下在LibTorch中的声明 xff1a inline Ten
  • 【微信小程序常见问题】bindtap事件传参 | wx.navigateTo()传参

    目的 xff1a 微信小程序中某个控件的点击事件bindtap触发时如何传参 举例实现 xff1a 1 wxml文件 这里的参数名是 item xff0c 参数值是 doubleperson lt view class 61 34 radi
  • 【微信小程序组件】自定义单选(多选)切换颜色按钮组件

    问题所在 xff1a 在小程序开发中 xff0c 官网提供的表单组件不足以满足我们的需求 xff0c 所以我们需要自定义组件 这里我们以按钮为例 需求 xff1a 1 默认按钮都不选中 xff0c 当点击一个按钮选中且按钮变色 xff0c
  • useGeneratedKeys=“true“作用

    使用 mysql 自增长序列 xff0c 新插入一条数据时 xff0c 怎么得到主键 xff1f 加入以下属性即可 xff1a useGeneratedKeys 61 true keyProperty 61 id id xff1a 根据自己
  • 【毕业设计】便宜购商城管理系统(Springboot+Jsp+支付宝+Echarts)

    便宜购商城项目是一套电商系统 xff0c 包括商城前台系统及商城后台系统 xff0c 基于 Spring Boot 2 X 及相关技术栈开发 前台商城系统包含首页登录 商品分类 首页轮播 商品搜索 商品展示 购物车 订单结算 订单流程 个人
  • IDEA中使用Debug调试详解

    在现在的开发中 xff0c 我们经常采用Debug来追踪代码的运行流程 xff0c 通常在程序运行过程中出现异常 xff0c 启用Debug模式可以分析定位异常发生的位置 xff0c 以及在运行过程中参数的变化 通常我们也可以启用Debug
  • nrm报错 [ERR_INVALID_ARG_TYPE]

    nrm 1 2 1报错 xff1a TypeError ERR INVALID ARG TYPE The 34 path 34 argument must be of type string Received undefined at va
  • SVN下载、拉取远程库、上传代码及注意问题

    1 下载SVN客户端 首先进入在SVN官网 xff0c 下载SVN客户端 xff1b 官网地址 xff1a https tortoisesvn net downloads html 选择 Downloads xff0c 选择自己电脑对应的版
  • vscode / idea 使用SVN及查看历史记录

    一 vscode使用 SVN 1 在vscode插件中心搜索svn 进行安装 xff08 我这里已经安装完毕了 xff09 注意 xff1a 插件安装成功 xff0c 需要重新启动软件 安装成功后会出现如下的图标 xff1a 2 桌面右键使
  • int和Integer有什么区别

    面试中会问道int和Integer的区别 xff0c 这里我们详细说一下 Integer是int的包装类 xff1b int是基本数据类型 Integer变量必须实例化后才能使用 xff1b int变量不需要 Integer实际是对象的引用
  • Java 垃圾回收机制与几种垃圾回收算法

    一 如何确定某个对象是 垃圾 xff1f 这一小节先了解一个最基本的问题 xff1a 如果确定某个对象是 垃圾 xff1f 既然垃圾收集器的任务是回收垃圾对象所占的空间供新的对象使用 xff0c 那么垃圾收集器如何确定某个对象是 垃圾 xf
  • Ubuntu18下编译安装torchvision—C++API的详细过程

    最近使用libtorch做网络模型的部署 xff0c 在编写后处理代码时用到了官方自带的nms h文件 xff0c 但该文件需要安装torchvision xff0c 而torchvision并不包含在官方的LibTorch包中 xff0c
  • Element UI 树形控件整合带图标的下拉功能菜单(tree + dropdown + input)

    本文主要讲述 xff1a 自定义树形控件 lt el tree gt 需求说明 xff1a Element UI 官网提供的树形控件包含基础的 可选择的 自定义节点内容的 带节点过滤的以及可拖拽节点的树形结构 如下 xff1a 我想要的效果
  • Vue子组件调用父组件的方法

    子组件 xff1a span class token tag span class token tag span class token punctuation lt span template span span class token
  • Element UI 自定义穿梭框的数据项

    文章目录 需求官网说明实现效果具体步骤附加需求 xff1a 调节穿梭框高宽度 需求 穿梭框中显示的内容是包含多个字段的数据 xff08 把表格的几个字段在穿梭框中展示 xff09 以及修改相应的样式 xff0c 查看 Element UI
  • Vue集成百度的Ueditor的前后端实现

    找了很多写过的文章 xff0c 也具体试验过都写的不太完整 xff0c 这款编辑器借用Vue提供的语法糖实现了数据的双向绑定 xff0c 不用你自己去getContent或setContent 对比其他的富文本编辑器 xff0c Uedit
  • SpringCloud(十)Config配置中心

    微服务就意味着要将单体应用中的业务拆分成一个个子服务 xff0c 每个服务的粒度相对较小 xff0c 因此系统中会出现大量的服务 由于每个服务都需要必要的配置信息才能运行 xff0c 所以一套集中式的 动态的配置管理设施是必不可少的 Spr
  • SpringCloud(十一)Bus消息总线、Stream消息驱动

    一 Bus消息总线 需求 xff1a 分布式自动刷新配置功能 xff1b 解决 xff1a SpringCloud Bus配合Spring cloud Config使用可以实现配置的动态刷新 1 概述 定义 xff1a Spring Clo