当前位置: 首页 > news >正文

【项目篇】仿照RabbitMQ模拟实现消息队列

在这里插入图片描述

大家好呀
我是浪前

项目篇:仿照RabbitMQ模拟实现消息队列

今天是项目的第一篇,我们先来创建出最核心的几个类。

仿照RabbitMQ模拟实现消息队列

  • 创建Exchange类
  • MessageQueue类
  • Binding类
  • Message类
    • 1:BasicProperties类
    • 2:正文部分
    • 3:辅助用的一些属性:

开始之前,先给大家来一句哲理,给大家加加油~

如果你信, 有一天会要站到高处。
那现在的得与失,就不重要。 不至于有这么多的愤怒,不满,怀疑,怨念。 因为事后, 那都是小事,小钱,路人,故人。
没有敌人,大事,坏事,不可承受的损失。
如果你在乎。 那只可能是: 你不相信自己有一天会登顶, 会举世无双, 一览众山小。

我们是要创建一个SpringBoot项目:

这个项目里面包含了三个模块:

  1. 公共模块
  2. 客户端模块
  3. 服务器模块

目前我们先将brokerServer中的核心的概念表示出来:

  1. 交换机(exchange)
  2. 队列(queue)
  3. 绑定(binding)
  4. 消息(message)

上面的概念都是存储在brokerServer中的,所以对于客户端来说,客户端并不关心服务器有哪些交换机,有哪些队列,客户端只需要把当前的这些数据给发送到服务器(brokerServer),然后再经过brokerServer进行转发,所以上述的概念全部都放到mqserver这个包里面即可

所以第一步:
根据三个模块创建出三个包

第二步:
服务器的核心模块下,根据核心概念创建出这几个类,

下面这张图是交换机,队列,绑定需要写的所有属性:
在这里插入图片描述
下面这一张图是消息类需要撰写的所有属性:

下面我们一个一个地展开:

创建Exchange类

在这里插入图片描述

交换机里面有什么属性:
1: 交换机的身份标识(name)

//此处使用name来作为交换机的身份标识(唯一的)private String name;

2: 交换机的类型(枚举表示)

//交换机类型:DIRECT, FANOUT, TOPIC:private ExchangeType Type = ExchangeType.DIRECT;

枚举代码:这个枚举代码枚举了交换机的三种类型:

package org.example.mq.mqserver.core;  //枚举类型:  public enum ExchangeType {  DIRECT(0),  FANOUT(1),  TOPIC(2);  //属性type  private final int type;  //构造方法:  private ExchangeType(int type){  this.type = type;  }  public int getType(){  return type;  }  
}

3: 交换机是否要进行持久化存储

//该交换机是否要持久化存储? true表示要持久化存储, false表示不必持久化  
private boolean durable = false;  //默认先是false

有些交换机,队列,绑定是需要进行持久化存储的,但是有些交换机和队列绑定是不需要的:
那么有了这个是否要存储的属性之后,用户在使用的时候,就可以通过开关(boolean值)来决定要不要进行持久化

4:属性:自动删除:如果当前交换机没有生产者使用了,那么就会这个交换机就会自动删除(RabbitMQ):
这个属性先列在这里,后续可以自己去自行扩展:

private boolean autoDelete = false;

5: 属性:arguments表示的是创建交换机时指定的一些额外的参数选项(后续未实现,可自行扩展):

private Map<String,Object> arguments  = new HashMap<>();

什么叫做选项?
arguments可以称之为选项,也就是可选,可不选

可以有,也可以没有,通过这个选项来开启不同的功能:
女朋友可盐可甜,今天选择小盐模式的女友,明天选择一个小甜模式女友,我们就可以通过不同的风格来开启不同的选项,通故不同的选项来开启不同的功能

上述的就是大致的交换机的属性:
下面我们加上属性的Setter方法和Getter方法即可:

package org.example.mq.mqserver.core;  
/*  
这个类表示是交换机:  */  
import java.util.HashMap;  
import java.util.Map;  public class Exchange {  //此处使用name来作为交换机的身份标识(唯一的)  private String name;  //交换机类型:DIRECT, FANOUT, TOPIC:  private ExchangeType Type = ExchangeType.DIRECT;  //该交换机是否要持久化存储? true表示要持久化存储, false表示不必持久化  private boolean durable = false;  //默认先是false  //交换机没人使用的,那就自动进行删除操作  private boolean autoDelete = false;  //创建交换机的时候,指定一些额外的参数选项:  private Map<String,Object> arguments  = new HashMap<>();  public String getName() {  return name;  }  public void setName(String name) {  this.name = name;  }  public ExchangeType getType() {  return Type;  }  public void setType(ExchangeType type) {  Type = type;  }  public boolean isDurable() {  return durable;  }  public void setDurable(boolean durable) {  this.durable = durable;  }  public boolean isAutoDelete() {  return autoDelete;  }  public void setAutoDelete(boolean autoDelete) {  this.autoDelete = autoDelete;  }  public Map<String, Object> getArguments() {  return arguments;  }  public void setArguments(Map<String, Object> arguments) {  this.arguments = arguments;  }  
}

MessageQueue类

这个类是一个存储消息的的队列
在这里插入图片描述

拥有的属性一共如下所示:

1: 队列的身份标识:

private String name;

2:队列是否持久化: true表示持久化,false表示不持久化

private boolean durable;

3:exclusive(独有的,专有的):这个属性为true表示这个队列只能被一个消费者使用,别人用不了:

private boolean exclusive = false;

4:如果队列没有消费者使用,那就进行自动删除:true表示会自动删除,false表示不会自动删除

private boolean autoDelete = false;

5:选项功能:表示扩展参数,列在这里,暂时不实现:

private Map<String, Object>  arguments = new  HashMap<>();

虽然这些功能没有实现,但是把对应的字段都给列出来,
因为这些字段都是RabbitMQ支持的字段,在RabbitMQ中都有实现,我们这里也就顺便交代一下,一方面可以熟悉RabbitMQ的使用,一方面可以自己对项目进行扩展

之后我们加上Getter和Setter方法之后,这个MSGQueue类就创建完毕了:

所以这个存储消息的队列的属性代码如下所示:

package org.example.mq.mqserver.core;  import java.util.HashMap;  
import java.util.Map;  /*  
这个类表示是一个存储消息的队列  
MSG -> Message:  */public class MSGQueue {  //队列的身份标识:  private String name;  //队列是否持久化: true表示持久化,false表示不持久化  private boolean  durable;  //这个属性为true表示这个队列只能被一个消费者使用,别人用不了:  private boolean exclusive = false;  //如果队列没有消费者使用,那就进行自动删除:true表示会自动删除,false表示不会自动删除  private boolean autoDelete = false;  //选项功能:表示扩展参数,列在这里,暂时不实现:  private Map<String, Object> arguments = new HashMap<>();  public String getName() {  return name;  }  public void setName(String name) {  this.name = name;  }  public boolean isDurable() {  return durable;  }  public void setDurable(boolean durable) {  this.durable = durable;  }  public boolean isExclusive() {  return exclusive;  }  public void setExclusive(boolean exclusive) {  this.exclusive = exclusive;  }  public boolean isAutoDelete() {  return autoDelete;  }  public void setAutoDelete(boolean autoDelete) {  this.autoDelete = autoDelete;  }  public Map<String, Object> getArguments() {  return arguments;  }  public void setArguments(Map<String, Object> arguments) {  this.arguments = arguments;  }  
}

项目为什么要进行扩展,就只实现代码行不行?

我们的项目在精不在多,即使只有一个项目,但是这个项目功能很丰富,内容很全面,技术点很密集,代码量很庞大,项目很健硕,自己很熟悉了解所有的细节,难点,也是很厉害的,你一个项目顶得上别人的两个三个项目

如果你的项目和别人的冲突了,你的项目没有扩展,那么你大概率就危险了

反之,你如果做了5个项目,听起来很高大上很牛逼的框架项目,但是你一个项目细节都不了解,没有吃透,那么你大概率也是很危险的

Binding类

Binding这个类用来表示队列和交换机之间的关联关系:
在这里插入图片描述

既然这个类表示队列和交换机之间的关联关系,那么这个类就是既和交换机有关,同时也和队列有关:

下面列出Binding的属性:
1: 写出队列和交换机这两个的身份标识:

private  String  exchangeName;
private  String  queueName;

有了上面这身份标识之后,我们就知道是哪一个交换机和哪一个队列之间有关联关系了
如果一个交换机和多个队列有关联,那就new 出多个Binding对象就可以了

2:bindingKey:就是在出题,要求领红包的人要画出一个“兔子”才可以领到红包:
bindingKey就是要出的题目。

private  String bindingKey;

注意Binding这个类,是依附于Exchange和Queue的
比如:对于持久化来说,如果Exchange和Queue任何一个都没有进行持久化,那么此时针对这个Binding来进行持久化是没有意义的

之后我们加上Getter和Setter方法,此时Binding类就创建完毕了:

package org.example.mq.mqserver.core;  /*  
这个类表示队列和交换机之间的关联关系  */public class Binding {  // 写出队列和交换机这两个的身份标识:  private  String  exchangeName;  private  String  queueName;  //bindingKey:就是在出题,要求领红包的人要画出一个“兔子”才可以领到红包:  private  String bindingKey;  public String getExchangeName() {  return exchangeName;  }  public void setExchangeName(String exchangeName) {  this.exchangeName = exchangeName;  }  public String getQueueName() {  return queueName;  }  public void setQueueName(String queueName) {  this.queueName = queueName;  }  public String getBindingKey() {  return bindingKey;  }  public void setBindingKey(String bindingKey) {  this.bindingKey = bindingKey;  }  
}

Message类

Message类就是表示一个要传递的消息:

所以一个消息是怎么构成的呢?

一个Message主要包含三个部分:

1: 属性部分: 使用一个类BasicProperties
2: 正文部分:字节数组
3: 辅助用的一些属性

下面这张图是Message类的所有属性:
在这里插入图片描述

1:BasicProperties类

我们先来实现Message类的第一个部分:
BasicProperties类:

注意这个BasicProperties类也是需要我们自己去单独创建出来的:

下面我们先来介绍一下BasicProperties类中的属性:

1: 消息的唯一身份标识:messageId:此时为了保证唯一性,我们是使用了UUID来作为messageId

什么是UUID呢,UUID就是我们编程中的一个专门用来生成唯一id的算法:每调用一次UUID,所生成的id都是唯一的

private String messageId;

2:routingKey是一个消息上带有的内容,和bindingKey做匹配的暗号:

private  String routingKey;

如果当前的交换机的类型是DIRECT,此时routingKey就表示要转发的队列名字
如果当前交换机的类型是FANOUT,此时routitngKey就是无意义的(不使用)
如果当前交换机的类型是TOPIC,此时routingKey就要和bindingKey做匹配,符合要求的才能够转发给对应的队列

3:deliverMode就是表示消息是否要进行持久化,1就表示这个消息不持久化,2就表示消息要持久化

private  int deliverMode = 1;

其实针对RabbitMQ来说,BasicProperties里面还有很多别的属性,我们这里就暂时先不去实现了

最后给BasicProperties类加上Getter和Setter方法,这个BasicProperties类就定义好了:

package org.example.mq.mqserver.core;  public class BasicProperties {  //1.消息的身份标识:为了保证唯一性,我们使用UUID来作为messageId  private String messageId;  //2.routingKey是一个消息上带有的内容,和bindingKey做匹配的暗号  private  String routingKey;  //3.deliverMode就是表示消息是否要进行持久化,1就表示这个消息不持久化,2就表示消息要持久化  private  int deliverMode = 1;  public String getMessageId() {  return messageId;  }  public void setMessageId(String messageId) {  this.messageId = messageId;  }  public String getRoutingKey() {  return routingKey;  }  public void setRoutingKey(String routingKey) {  this.routingKey = routingKey;  }  public int getDeliverMode() {  return deliverMode;  }  public void setDeliverMode(int deliverMode) {  this.deliverMode = deliverMode;  }  
}

2:正文部分

接着我们去实现Message类的第二个部分:
正文部分:

2: 正文部分: byte【】
我们这个正文部分使用的是字节数组,说明正文部分是可以支持二进制数据的,如果是String数组的话,是只能表示文本的,无法表示二进制数据

private  byte[]  body;

3:辅助用的一些属性:

Message后续如果持久化之后,会被存储到文件中去,不是存储在数据库中的,
而且一个文件中会存储很多的消息,如何找到某个消息就是通过下面的两个偏移量在文件中找到消息的,同时采取前闭后开的区间:【offsetBeg,offsetEnd)

private long offsetBeg = 0;   //消息数据的开头距离文件开头的位置偏移(字节)
private long offsetEnd = 0;   //消息数据的结尾距离文件开头的位置偏移(字节)

使用下面这个辅助属性表示该消息在文件中是否是有效消息:
isValid 意思就是是否合法,是否有效:
针对文件中的消息,如果删除,就使用逻辑删除的方式进行删除操作:
0x1表示有效,0x0表示无效:

private  byte  isValid = 0x1;

什么是逻辑删除?
当我们删除数据库,删除硬盘文件,删除数据的时候,很多时候都是使用的是“逻辑删除”的操作:
不是真的直接把这一块硬盘上的数据删除了,而是把这块硬盘上的数据标记为了无效,此时这块硬盘上的空间仍然可以去使用,此处我们也是采取逻辑删除的方式去针对文件中的消息进行删除

接着我们在Message类中自行实现一些好用的方法:

1: 快速拿到和设置Message的messageId:

//调用这个方法之后,立即返回Message的id:  
public String getMessageId(){  return basicProperties.getMessageId();  
}//设置Message的MessageId:  
public void setMessageId(String messageId){  basicProperties.setMessageId(messageId);  
}

下面是获取到RoutingKey和设置RoutingKey:

//设置和获取到RoutingKey:  
public String getRoutingKey(){  return basicProperties.getRoutingKey();  
}  
//设置RoutingKey:  
public void setRoutingKey(String routingKey){  basicProperties.setRoutingKey(routingKey);  
}

下面是是否要进行持久化的方法:

//下面是设置了是否要进行持久化:  
//得到是否持久化的消息:  
public int getDeliverMode(){  return basicProperties.getDeliverMode();  
}  //下面是设置了是否要持久化:  
public void setDeliverMode(int mode){  basicProperties.setDeliverMode(mode);  
}

以上就是Message类的所有方法和属性,由于这个类的方法有些多了,想要直观地体现出来,有点麻烦,
所以我们就可以使用一个工厂方法,让工厂方法帮我们封装一下创建Message对象的过程
这个工厂方法中创建的Message对象,会自动生成一个唯一的MessageId

所以下面这个方法的目的是为了构造出一个Message对象

//创建一个工厂方法, 让工厂方法帮助我们封装一下创建Message对象的过程  
//这个方法中创建的Message对象,会自动生成一个唯一的MessageId  
public static Message createMessageWithId(String routingKey, BasicProperties basicProperties, byte[] body){  Message message = new Message();  if(basicProperties != null ){  //说明basicProperties是有值的,  message.setBasicProperties(basicProperties);  }  //更新了routingKey:  message.setRoutingKey(routingKey);  //更新messageId,生成一个随机的id并转为字符串:(M作为前缀)  message.setMessageId("M-"+UUID.randomUUID());  //更新消息的正文:  message.setBody(body);  return message;  }

为什么这个工厂方法中创建对象的时候,遗漏了offsetBeg和offsetEnd还有isValid呢?
因为这三个属性都是在消息进行持久化的时候才会使用的到的消息,在把消息写入到文件中之前再来设定这三个属性,而此处的工厂方法,只是在内存中创建了一个Message对象。

但是要注意:上面的Message对象,是需要能够在网络上进行传输,这个消息是需要进行网络传输的,并且这个消息也能够写入到文件当中去,此时就需要对Message进行序列化和反序列化,此时在我们的项目中,我们就直接使用标准库中自带的方式去完成这个消息的序列化和反序列化了

实现这个序列化的前提是要先去给每一个需要序列化的类实现一个叫做Serializable的接口:

public class Message   implements Serializable {

我们只需要实现这个接口就可以了,并不需要去重写接口里面的方法。
同时也需要给BasicProperties这个类也加上这个接口去一起实现序列化:

public class BasicProperties implements Serializable {

那么我们不使用json的方式去完成序列化和反序列化呢?
因为json本质上是文本格式,这个json里面存放的是文本类型的数据,而我们此处的Message存储的是二进制数据,这个二进制数据不能使用文本来表示,所以不可以使用json的方式来进行

虽然刚刚给整个Message类都进行了序列化处理,但是有两个属性是不需要被序列化保存到文件中的,因为当消息被写入到文件中之后,所在的位置就固定了,并不需要单独存储,这两个属性存在的目的主要是为了让内存中的Message对象能够快速找到对应的硬盘上的Message的位置,所以给这两个属性加上transient这个关键字就不会被序列化了:

private transient long offsetBeg =  0;
private transient long offsetEnd = 0;

到此为止,我们的Message类就算是编写完毕啦~,具体完整的Message类的代码如下所示:

package org.example.mq.mqserver.core;  import java.io.Serial;  
import java.io.Serializable;  
import java.util.UUID;  /*  
表示一个要传递的消息  */public class Message   implements Serializable {  //1.属性部分,使用一个名叫BasicProperties的类:  private BasicProperties basicProperties = new BasicProperties();  //2.正文部分:使用字节数组(可以表示二进制数据)  private byte[] body;  //辅助属性如下:  private  transient long offsetBeg = 0;   //消息数据的开头距离文件开头的位置偏移(字节)  private transient  long offsetEnd = 0;   //消息数据的结尾距离文件开头的位置偏移(字节)  //使用下面这个辅助属性表示该消息在文件中是否是有效消息:  //0x1表示有效,0x0表示无效:  private  byte  isValid = 0x1;  //创建一个工厂方法, 让工厂方法帮助我们封装一下创建Message对象的过程  //这个方法中创建的Message对象,会自动生成一个唯一的MessageId  public static Message createMessageWithId(String routingKey, BasicProperties basicProperties, byte[] body){  Message message = new Message();  if(basicProperties != null ){  //说明basicProperties是有值的,  message.setBasicProperties(basicProperties);  }  //更新了routingKey:  message.setRoutingKey(routingKey);  //更新messageId,生成一个随机的id并转为字符串:(M作为前缀)  message.setMessageId("M-"+UUID.randomUUID());  //更新消息的正文:  message.setBody(body);  return message;  }  //调用这个方法之后,立即返回Message的id:  public String getMessageId(){  return basicProperties.getMessageId();  }  //设置Message的MessageId:  public void setMessageId(String messageId){  basicProperties.setMessageId(messageId);  }  //设置和获取到RoutingKey:  public String getRoutingKey(){  return basicProperties.getRoutingKey();  }  //设置RoutingKey:  public void setRoutingKey(String routingKey){  basicProperties.setRoutingKey(routingKey);  }  //下面是设置了是否要进行持久化:  //得到是否持久化的消息:  public int getDeliverMode(){  return basicProperties.getDeliverMode();  }  //下面是设置了是否要持久化:  public void setDeliverMode(int mode){  basicProperties.setDeliverMode(mode);  }  public BasicProperties getBasicProperties() {  return basicProperties;  }  public void setBasicProperties(BasicProperties basicProperties) {  this.basicProperties = basicProperties;  }  public byte[] getBody() {  return body;  }  public void setBody(byte[] body) {  this.body = body;  }  public long getOffsetBeg() {  return offsetBeg;  }  public void setOffsetBeg(long offsetBeg) {  this.offsetBeg = offsetBeg;  }  public long getOffsetEnd() {  return offsetEnd;  }  public void setOffsetEnd(long offsetEnd) {  this.offsetEnd = offsetEnd;  }  public byte getIsValid() {  return isValid;  }  public void setIsValid(byte isValid) {  this.isValid = isValid;  }  
}

相关文章:

【项目篇】仿照RabbitMQ模拟实现消息队列

大家好呀 我是浪前 项目篇&#xff1a;仿照RabbitMQ模拟实现消息队列 今天是项目的第一篇&#xff0c;我们先来创建出最核心的几个类。 仿照RabbitMQ模拟实现消息队列 创建Exchange类MessageQueue类Binding类Message类1&#xff1a;BasicProperties类2&#xff1a;正文部分3&a…...

JAVA程序获取SVN提交记录

1.获取文件提交记录 private String userName "userName "; //svn账号 private String password "password "; //svn密码 private String urlString "urlString "; //svnurl 换成自己对应的svn信息 package com.tengzhi.common.dao;import…...

从检索到生成:RAG 如何重构大模型的知识边界?

目录 一、技术演进图谱说明 二、RAG 技术概述 &#xff08;一&#xff09;核心思想说明 &#xff08;二&#xff09;RAG 发展路径与研究范式 三、Naive RAG&#xff1a;最基础的检索增强生成范式 &#xff08;一&#xff09;Naive RAG 的标准流程 1. 索引&#xff08;In…...

rabbitmq-spring-boot-start版本优化升级

文章目录 1.前言2.优化升级内容3.依赖4.使用4.1发送消息代码示例4.2消费监听代码示例4.3 brock中的消息 5.RabbmitMq的MessageConverter消息转换器5.1默认行为5.2JDK 序列化的缺点5.3使用 JSON 进行序列化 6.总结 1.前言 由于之前手写了一个好用的rabbitmq-spring-boot-start启…...

SVN仓库突然没有权限访问

如果svn仓库突然出现无法访问的情况&#xff0c;提示没有权限&#xff0c;所有账号都是如此&#xff0c;新创建的账号也不行。 并且会突然提示要输入账号密码。 出现这个情况时&#xff0c;大概率库里面的文件有http或者https的字样&#xff0c;因为单独给该文件添加权限导致…...

vue实现静默打印pdf

浏览器中想要打印文件&#xff0c;不依靠浏览器自带的打印窗口&#xff0c;想要实现静默打印&#xff08;也就是不弹出打印对话框&#xff09;&#xff0c;同时控制打印份数的功能&#xff0c;一种方式是使用vue-plugin-hiprint和本地安装客户端electron-hiprint 本来是浏览器去…...

如何开启远程桌面连接外网访问?异地远程控制内网主机

实现远程桌面连接外网访问&#xff0c;能够突破地域限制&#xff0c;随时随地访问远程计算机&#xff0c;满足远程办公、技术支持等多种需求。下面为你详细介绍开启方法。 一、联网条件 确保本地计算机和远程计算机都有稳定的网络连接&#xff0c;有联网能上网。 二、开启远程…...

数据结构与算法学习笔记(Acwing提高课)----动态规划·数字三角形

数据结构与算法学习笔记----动态规划数字三角形 author: 明月清了个风 first publish time: 2025.4.23 ps⭐️终于开始提高课的题啦&#xff0c;借的人家的号看&#xff0c;以后给y总补票叭&#xff0c;提高课的题比之前的多很多啊哈哈哈哈&#xff0c;基本上每种题型都对应了…...

RK3568平台开发系列讲解(调试篇)debugfs文件系统及常见调试节点介绍

更多内容可以加入Linux系统知识库套餐(教程+视频+答疑) 🚀返回专栏总目录 文章目录 一、什么是debugfs二、/proc/filesystems三、debugfs的挂载3.1、fstab 的文件结构3.2、手动挂载与卸载四、debugfs 常见目录有哪些4.1、/sys/kernel/debug/gpio4.2、/sys/kernel/debug/…...

数字化转型避坑指南:中钧科技如何用“四个锚点”破解转型深水区

数字化转型浪潮下&#xff0c;企业常陷入四大典型陷阱&#xff1a;跟风式投入、数据沼泽化、流程伪在线、安全裸奔化。中钧科技旗下产品以“经营帮”平台为核心&#xff0c;通过针对性方案帮助企业绕开深坑。 陷阱一&#xff1a;盲目跟风&#xff0c;为数字化而数字化 许…...

数字化转型下的批发订货系统:降本增效的关键路径

随着数字化转型的不断深入&#xff0c;越来越多的企业开始拥抱现代化的技术和工具&#xff0c;以提升业务效率、降低运营成本。批发行业&#xff0c;作为一个高度依赖库存和订单管理的行业&#xff0c;数字化转型尤为关键。传统的批发订货系统存在信息不对称、操作复杂、效率低…...

一 、环境的安装 Anaconda + Pycharm + PaddlePaddle

《从零到一实践&#xff1a;系统性学习生成式 AI(NLP)》 一 、环境的安装 Anaconda Pycharm PaddlePaddle 1. Anaconda 软件安装 Anaconda 软件安装有大量的教程&#xff0c;此处不在说明&#xff0c;安装完成之后界面如下&#xff1a; 2. 创建 Anaconda 虚拟环境 Paddl…...

Dhtmlx Gantt教程

想实现的效果 插件安装&#xff1a; npm i dhtmlx-gantt使用该插件的时候&#xff0c;直接导入包和对应的样式即可&#xff1a; import { Gantt} from "dhtmlx-gantt"; import "dhtmlx-gantt/codebase/dhtmlxgantt.css";也可以安装试用版本&#xff0c;…...

大模型框架技术全景与下一代架构演进

‌一、大模型框架概述 ‌大模型框架‌是支撑千亿级参数模型训练、推理及产业落地的技术底座&#xff0c;涵盖分布式计算、高效内存管理、多模态融合等核心模块。从GPT-3到Gemini Ultra&#xff0c;大模型框架的迭代推动AI从“作坊式实验”迈向“工业化生产”。据Gartner预测&a…...

官方不存在tomcat10-maven-plugin插件

Maven 中央仓库中没有官方的tomcat10-maven-plugin。Apache Tomcat Maven 插件项目目前仅对以下插件提供官方支持&#xff1a; tomcat6-maven-plugin tomcat7-maven-plugin tomcat8-maven-plugin tomcat9-maven-plugin 如果你想使用 cargo 命令来跑支持 Jakarta EE 的 Tomcat 1…...

vue3 el-table 右击

在 Vue 3 中使用 Element Plus 的 <el-table> 组件时&#xff0c;如果你想实现右击&#xff08;右键点击&#xff09;事件的处理&#xff0c;你可以通过监听 contextmenu 事件来实现。contextmenu 事件在用户尝试打开上下文菜单&#xff08;通常是右键点击&#xff09;时…...

第一节:核心概念高频题-Vue3响应式原理与Vue2的区别

Vue2&#xff1a;基于Object.defineProperty监听对象属性&#xff0c;需手动处理数组方法重写 Vue3&#xff1a;采用Proxy代理实现全量响应式&#xff0c;支持动态新增属性和深层嵌套对象监听 一、实现机制对比 1. Vue2&#xff1a;基于 Object.defineProperty • 原理&#…...

【锂电池剩余寿命预测】CNN卷积神经网络锂电池剩余寿命预测(Pytorch完整源码和数据)

目录 效果一览程序获取程序内容代码分享效果一览 程序获取 获取方式一:文章顶部资源处直接下载:...

web刷题笔记

2024isctf ezrce 禁用了一些关键字符&#xff0c;查询函数&#xff0c;系统执行函数&#xff0c;执行函数都有&#xff0c;空格也和斜杆也禁用了&#xff0c;但是其他一些很大一部分字符都没有禁用&#xff0c;属于关键词禁用的类型&#xff0c;正常的步骤是去查一下列表&#…...

基于FPGA 和DSP 的高性能6U VPX 采集处理板

基于FPGA 和DSP 的高性能6U VPX 采集处理板&#xff0c;是一款处理架构采用FPGADSP 的高性能的6U VPX 采集处理板。板载4 片高速ADC 共8 个采集通道&#xff0c;可支持8 路采样率最高2.6Gsps/14Bit 的模拟信号通道。 板卡FPGA 采用Xilinx 公司KU 系列的XCKU115-2FLVF1924I&…...

uniapp中使用<cover-view>标签

文章背景&#xff1a; uniapp中遇到了原生组件(canvas)优先级过高覆盖vant组件 解决办法&#xff1a; 使用<cover-view>标签 踩坑&#xff1a; 我想实现的是一个vant组件库中动作面板的效果&#xff0c;能够从底部弹出框&#xff0c;让用户进行选择&#xff0c;我直…...

【JavaScript】详讲运算符--算术运算符

1、运算符简介 运算符也叫操作符&#xff0c;通过运算符可以对一个或多个值进行运算&#xff0c;比如&#xff1a;typeof就是运算符&#xff0c;可以来获得一个值的类型&#xff0c;它会将该值的类型以字符串的形式返回,即&#xff1a;typeof 变量名的结果为字符串类型。 <…...

.NET 6 + Dapper + User-Defined Table Type

大家都知道&#xff0c;对于SQL Server IN是有限制条件的&#xff0c;如果IN里面的内容过多&#xff0c;在执行的时候会被自动截断&#xff0c;因而导致查询到的结果不是实际需要的结果。 select * from Payments where Id in (1,2,3,4,...) 为了解决上面的限制&#xff0c;可以…...

使用 Conda 创建新环境

使用 Conda 创建新环境 在使用 Conda 进行包管理和环境隔离时&#xff0c;创建新环境是一个非常常见的操作。通过创建独立的环境&#xff0c;可以避免不同项目之间的依赖冲突&#xff0c;并且能够灵活地管理各个项目的运行环境。 以下是使用 Conda 创建和管理新环境的详细步骤…...

数据为基:机器学习中数值与分类数据的处理艺术及泛化实践

数据为基&#xff1a;机器学习中数值与分类数据的处理艺术及泛化实践 摘要 在机器学习实践中&#xff0c;数据质量对模型效果的影响往往超过算法选择。本文通过详实的案例解析&#xff0c;系统阐述数值型数据与分类数据的特征工程处理方法&#xff0c;揭示数据预处理对模型泛…...

Docker镜像与容器概念解析

Docker镜像与容器概念解析 -更适合大学生宝宝体制的docker学习指南 一、Docker镜像&#xff1a;应用程序的基因库 &#xff08;1&#xff09;本质特征&#xff1a;镜像是一个只读的二进制文件包&#xff0c;相当于应用程序的”基因图谱”。就像生物体的DNA决定了生物特征&a…...

基于GMM的语音识别

语音识别是近年来发展非常迅速的一项计算机智能技术&#xff0c;广泛应用在语音控制、身份识别等多个领域。本次项目主要研究语音识别的预处理过程和特征参数的提取环节。通过对原始语音信号进行预加重和分帧、加窗&#xff0c;滤除低频干扰&#xff0c;提升对语音识别有用的部…...

K8S安全认证

一。用户认证的基本框架 在K8S集群中&#xff0c;客户端通常有两类&#xff1a; 1.User Account&#xff1a;一般独立于K8S之外的其他服务管理的用过户账号 2.Service Account&#xff1a;K8S管理的账号&#xff0c;用于为Pod中的服务进程在访问K8S提供身份标识 ApiServer是…...

咖啡机语音芯片方案-WTN6040FP-14S直接驱动4欧/3W喇叭-大功率输出

一、开发背景 随着智能家居市场的快速发展和消费者对家电产品交互体验要求的不断提高&#xff0c;语音提示功能已成为现代咖啡机产品的重要卖点之一。传统咖啡机仅依靠指示灯和简单蜂鸣器提示&#xff0c;无法满足用户对操作引导、状态反馈和个性化体验的需求。 WTN6040FP-14大…...

Vue3集成百度实时语音识别

示例 SpeechRecognitionModal.vue 组件 <template><transition name"modal-fade"><div v-if"isOpen" class"modal-overlay" click.self"handleOverlayClick"><div class"modal-container"><div…...

C# 设计原则总结

跟着视频学习的&#xff0c;记录一下最后的总结。 接口隔离&#xff1a; 单一职责&#xff1a; 里氏替换&#xff1a; 依赖倒置; 迪米特法则; 开闭原则&#xff1a;...

zkPass案例实战之合约篇

目录 一、contracts/contracts/ProofVerifier.sol 1. License 和 Solidity 版本 2. 导入依赖 3. 合约声明和默认分配器地址 4. 验证证明 5. 验证分配器签名 6. 验证验证者签名 7. 签名前缀处理 8. 签名恢复 总结 二、contracts/contracts/SampleAttestation.sol 1. …...

docker学习笔记5-docker中启动Mysql的最佳实践

一、查找目录文件位置 1、mysql的配置文件路径 /etc/mysql/conf.d 2、mysql的数据目录 /var/lib/mysql 3、环境变量 4、端口 mysql的默认端口3306。 二、启动命令 1、启动命令说明 docker run -d -p 3306:3306 -v /app/myconf:/etc/mysql/conf.d # 挂载配置目录 -v…...

彻底禁用windows的语音识别快捷键win+ctrl+s

工作中经常使用ctrls保存&#xff0c;但是经常误触win&#xff0c;结果弹出如下对话框&#xff0c;甚是闹心&#xff1a; 搜索网络&#xff0c;问AI&#xff0c;竟然没有一个好用的不依赖常驻内存软件的办法&#xff0c;最终经过探索与验证&#xff0c;总算是彻底解决了此问题&…...

大数据学习(112)-Analytic函数集

&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一…...

文档构建:Sphinx全面使用指南 — 实战篇

文档构建&#xff1a;Sphinx全面使用指南 — 实战篇 Sphinx 是一款强大的文档生成工具&#xff0c;使用 reStructuredText 作为标记语言&#xff0c;通过扩展兼容 Markdown&#xff0c;支持 HTML、PDF、EPUB 等多种输出格式。它具备自动索引、代码高亮、跨语言支持等功能&#…...

欧拉环境(openEuler 22.03 LTS SP3)安装移动磐维数据库(PanWeiDB_V2.0-S2.0.2_B01)步骤

一、磐维数据库概述 中国移动磐维数据库&#xff08;ChinaMobileDB&#xff09;&#xff0c;简称“磐维数据库”&#xff08;PanWeiDB&#xff09;&#xff0c;是中国移动信息技术中心首个基于中国本土开源数据库打造的面向ICT基础设施的自研数据库产品。其产品内核能力基于华…...

【产品经理从0到1】产品规划

产品规划 已经知道要做什么功能&#xff0c;展示什么信息&#xff0c;那这些信息应该 以什么方式展现给用户&#xff1f; 信息架构的概念 一般的商场导览图&#xff0c;都有以下特征&#xff1a; • 每一层都由多个店铺组成&#xff1b; • 商场有出口&#xff0c;有入口&am…...

一篇文章学会开发第一个ASP.NET网页

*开发环境&#xff1a;Visual Studio 2022 ASP.NET Core 6.0* 一、开发环境准备 1.1 安装必备工具 Visual Studio 2022 Community&#xff08;免费版本&#xff09; .NET 6.0 SDK 验证安装&#xff1a;命令行执行 dotnet --version 显示6.0.x版本 1.2 创建新项目 打开VS…...

[架构之美]Ubuntu源码部署APISIX全流程详解(含避坑指南)

[架构之美]Ubuntu源码部署APISIX全流程详解(含避坑指南) 一、离线安装场景需求分析 1.1 典型应用场景 金融/政务内网环境生产环境安全合规要求边缘计算节点部署1.2 离线安装难点 #mermaid-svg-B25djI0XquaOb1HM {font-family:"trebuchet ms",verdana,arial,sans-s…...

【3】CICD持续集成-k8s集群中安装Jenkins-agent(主从架构)

一、背景&#xff1a; Jenkins Master/Slave架构&#xff0c;Master&#xff08;Jenkins本身&#xff09;提供Web页面让用户来管理项目和从节点&#xff08;Slave&#xff09;&#xff0c;项目任务可以运行在Master本机或者分配到从节点运行&#xff0c;一个Master可以关联多个…...

2024从Maven-MySQL-Nginx部署

1、IDEA配置全局Maven设置 第一步&#xff1a;File->Close Project返回到创建工程界面。 第二步&#xff1a;找到bulid---maven设置对应位置。 第三步&#xff1a;选中两栏后的Override---应用---关闭即可。 *************************************************************…...

MySQL运算符

目录 一、mysql运算符 1. 算数运算符 2. 比较运算符 2.1 等号运算符&#xff08;&#xff09; 2.2 不等于运算符 ! 3.非符号类型的运算符 3.1 空运算 IS NULL、 IS NOT NULL、 ISNULL 3.2 区间查询 BETWEEN 3.3 包含查询 IN、 NOT IN 3.4模糊查询LIKE 4. 逻辑运算符 4.1 AND(逻…...

什么是区块?

“区块”是区块链技术的基本组成部分&#xff0c;是加密货币交易的数字记录簿。一个区块就像是账本中的一页&#xff0c;详细记录了所有的交易细节。每个区块都包含基本信息&#xff0c;如最近的交易列表、标记区块创建时间的时间戳&#xff0c;以及称为“哈希值”的唯一加密代…...

爬虫学习——获取动态网页信息

对于静态网页可以直接研究html网页代码实现内容获取&#xff0c;对于动态网页绝大多数都是页面内容是通过JavaScript脚本动态生成(也就是json数据格式)&#xff0c;而不是静态的&#xff0c;故需要使用一些新方法对其进行内容获取。凡是通过静态方法获取不到的内容&#xff0c;…...

LSA六种类型

LAS --- 链路状态通告 链路状态类型、链路状态ID、通告路由器 --- LSA的三元组 --- 可以唯一标识出一条LSA Type --- OSPFv2中&#xff0c;常见的需要掌握LSA有6种 LS ID --- LSA的名字 --- 因为每一种LSA ID的生成方式都不相同&#xff0c;所以导致可能重复&#xff0c;则如…...

第七篇:linux之基本权限、进程管理、系统服务

第七篇&#xff1a;linux之基本权限、进程管理、系统服务 文章目录 第七篇&#xff1a;linux之基本权限、进程管理、系统服务一、基本权限1、什么是权限&#xff1f;2、为什么要有权限&#xff1f;3、权限与用户之间的关系&#xff1f;4、权限对应的数字含义5、使用chmod设定权…...

时序约束 记录

一、基础知识 1、fpga的约束文件为.fdc&#xff0c;synopsys的约束文件为.sdc。想通过fpga验证soc设计是否正确&#xff0c;可以通过syn工具(synplify)吃.fdc把soc code 转换成netlist。然后vivado P&R工具通过吃上述netlist、XDC 出pin脚约束、fdc时序约束三个约束来完成…...

fpga系列 HDL:跨时钟域同步 脉冲展宽同步 Pulse Synchronization

Pulse Synchronization 脉冲同步&#xff08;Pulse Synchronization&#xff09;是 FPGA 设计中处理跨时钟域信号传输的常见问题和关键细节。由于不同步的时钟域之间可能存在相位差或频率差异&#xff0c;可能会导致亚稳态问题或数据丢失。脉冲同步的主要目标是确保一个时钟域中…...

链表系列一>两数相加

目录 题目&#xff1a;解析&#xff1a;方法&#xff1a;代码&#xff1a;链表常用技巧&#xff1a; 题目&#xff1a; 链接: link 解析&#xff1a; 方法&#xff1a; 代码&#xff1a; /*** Definition for singly-linked list.* public class ListNode {* int val;* …...