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

spring-boot rabbitmq整合

文章请参考:Springboot 整合RabbitMq ,用心看完这一篇就够了

mven依赖

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.amqp</groupId><artifactId>spring-rabbit-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies>

配置rabbitmq

配置生产者

spring:rabbitmq:host: localhostport: 5672username: rootpassword: rootvirtual-host: pers-xrb

配置queue

 @Beanpublic Queue TestDirectQueue(){return new Queue("direct-queue",true);}

Queue的构造函数如下:

Queue(String name, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)

Queue有如下几个属性:

  1. name-the name of the queue - must not be null; set to “” to have the broker generate the name.(不能为空,如果想让服务器自动生成的话,那么设置为"")
  2. durable- true if we are declaring a durable queue (the queue will survive a server restart)(是否持久化,如果想在服务器重启的时候仍然存在,那么设置为true,默认和推荐设置为true)
  3. exclusive-true if we are declaring an exclusive queue (the queue will only be used by the declarer’s connection) (排他性,默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable)
  4. autoDelete-true if the server should delete the queue when it is no longer in use(自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除,默认是false)

所以通常的初始化构造函数是
在这里插入图片描述

配置exchange

  @BeanDirectExchange TestDirectExchange() {return new DirectExchange("TestDirectExchange", true, false);}

绑定

    @BeanBinding bindingDirect() {return BindingBuilder.bind(TestDirectQueue()).to(TestDirectExchange()).with("TestDirectRouting");}

配置触发器

@RestController("/rabbit-mq-sender")
public class SendMessageController {private final RabbitTemplate rabbitTemplate;public SendMessageController(RabbitTemplate rabbitTemplate) {this.rabbitTemplate = rabbitTemplate;}@GetMapping("/sendDirectMessage")public String sendDirectMessage() {String messageId = String.valueOf(UUID.randomUUID());String messageData = "test message, hello!";String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));Map<String, Object> map = new HashMap<>(3);map.put("messageId", messageId);map.put("messageData", messageData);map.put("createTime", createTime);//将消息携带绑定键值:TestDirectRouting 发送到交换机TestDirectExchangerabbitTemplate.convertAndSend("TestDirectExchange","TestDirectRouting", map);return "ok";}
}

发送后,可以看到ui界面的信息
在这里插入图片描述

配置消费者

基本配置和配置生产者没有什么区别,除了这里需要配置的是监听器和指定监听器的处理器,声明消费者类为监听器@DirectReceiver,指定方法为处理器@RabbitHandler

@Service
@Slf4j
@RabbitListener(queues = "TestDirectQueue")     // 指定监听的队列
public class DirectReceiver {@RabbitHandlerpublic void process(Object testMessage) {try {TimeUnit.SECONDS.sleep(1);log.debug("DirectReceiver[TestDirectQueue]消费者收到消息  : " + testMessage.toString());} catch (InterruptedException e) {throw new RuntimeException(e);}}
}

启动服务器后,就可以直接监听和消费mq信息了,如果需要增加一个消费者,那么copy一个DirectReceiver实例,命名为DirectReceiver2就行了。默认的消费策略是轮询策略,这个方法待优化,很明显在现实开发过程中是不可能这么写的。

生产者的confirm和return机制

RabbitMq发消息的流程
在这里插入图片描述
从上面的图,我们可以看到一个mq发送的话,可能会出现如下几种情况

  1. 未找到交换机
  2. 找到交换机,但是未绑定queue
  3. 找到了queue,消息推送成功

confirm机制

confirm机制是对于生产者和服务器broker来说的。

生产者将信道设置成confirm模式,一旦信道进入confirm模式,所有在该信道上面发布的消息都会被指派一个唯一的ID(从1开始,单调递增),一旦消息被投递到所有匹配的队列之后,broker就会发送一个ACK给生产者(包含消息的唯一ID)

在这里插入图片描述

return机制

returnCallback 未投递到queue退回模式

confrim 模式只能保证消息到达 broker,不能保证消息准确投递到目标 queue 里。在有些业务场景下,我们需要保证消息一定要投递到目标 queue 里,此时就需要用到 return 退回模式。这里需要exchange触发无法查找queue的场景,也就是说exchange存在,但是queue不存在

配置confirm和return

  1. 修改yml配置
spring:rabbitmq:host: localhostport: 5672username: rootpassword: rootvirtual-host: pers-xrbpublisher-confirms: true    #确认消息已发送到交换机(Exchange)publisher-returns: true     #确认消息已发送到队列(Queue)
  1. 自定义rabbitMqTemplate
@Beanpublic RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate rabbitTemplate = new RabbitTemplate();rabbitTemplate.setConnectionFactory(connectionFactory);//设置开启Mandatory,才能触发回调函数,无论消息推送结果怎么样都强制调用回调函数rabbitTemplate.setMandatory(true);rabbitTemplate.addAfterReceivePostProcessors(message -> {byte[] body = message.getBody();log.info("received body is:{}", body);return message;});// set confirm callbackrabbitTemplate.setConfirmCallback((correlationData, isAck, cause) -> {System.out.println("ConfirmCallback:     " + "相关数据:" + correlationData);System.out.println("ConfirmCallback:     " + "确认情况:" + isAck);System.out.println("ConfirmCallback:     " + "原因:" + cause);});// set return callbackrabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {System.out.println("ReturnCallback:     " + "消息:" + message);System.out.println("ReturnCallback:     " + "回应码:" + replyCode);System.out.println("ReturnCallback:     " + "回应信息:" + replyText);System.out.println("ReturnCallback:     " + "交换机:" + exchange);System.out.println("ReturnCallback:     " + "路由键:" + routingKey);});return rabbitTemplate;}
  1. 增加触发接口
    private static Map<String, Object> getMqMessage() {String messageId = String.valueOf(UUID.randomUUID());String messageData = "test message, hello!";String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));Map<String, Object> map = new HashMap<>(3);map.put("messageId", messageId);map.put("messageData", messageData);map.put("createTime", createTime);return map;}/*** 4.1 exchange and queue not exist*/@GetMapping("/sendNotExistExchangeMessage")public String sendNotExistExchangeMessage() {Map<String, Object> map = getMqMessage();//将消息携带绑定键值:TestDirectRouting 发送到交换机TestDirectExchangerabbitTemplate.convertAndSend("NotExistExchangeExchange","NotExistExchangeExchangeQueue", map);return "ok";}/*** 4.2 exchange exist but queue not exist*/@GetMapping("/sendNotExistQueueButExchangeMessage")public String sendNotExistQueueButExchangeMessage() {Map<String, Object> map = getMqMessage();//将消息携带绑定键值:TestDirectRouting 发送到交换机TestDirectExchangerabbitTemplate.convertAndSend("NotExistQueueButExchangeExchange","NotExistQueueButExchangeQueue", map);return "ok";}
  1. 测试
    为了测试两种情形,我们分别为
    1. 交换机exchange不存在
    2. 交换机存在但是队列不存在
    3. exchange和queue都存在
4.1 交换机exchange不存在

调用对应的接口 http://localhost:9876/rabbit-mq-sender/sendNotExistExchangeMessage
在日志台会出现如下信息:
在这里插入图片描述
这个时候只会调用confirmcallback,confirmcallback会告诉你这个exchange是不存在的。

4.2,交换机存在但是queue不存在的场景,

我们调用对应的api接口
http://localhost:9876/rabbit-mq-sender/sendNotExistQueueButExchangeMessage
不过在这之前,我们需要先在声明一个exchange

  /*** Direct交换机 起名:NotExistQueueButExchangeExchange*/@BeanDirectExchange NotExistQueueButExchange() {return new DirectExchange("NotExistQueueButExchangeExchange", true, false);}

查看日志台,信息如下:
在这里插入图片描述
我们会发现,confirmcallback和returnCallback两个函数其实都是调用了的,在confirmcallback中,返回结果告诉了我们isAck是true的,但是returnCallback中告诉我们No_route,表示没有找到对应的路由
,在exchange的ui中,我们可以看到我们有两个exchange
在这里插入图片描述

4.3 那如果所有的都是正常的呢?[confirm|return]callback会返回什么呢?我们调用api测试下:

http://localhost:9876/rabbit-mq-sender/sendDirectMessage
日志台结果如下:
在这里插入图片描述
这个时候是只调用confirmCallback的

消费者接收到消息的消费确认机制

如果消费者消费后怎么告诉rabbitmq服务器呢?通常来说消费者消费后会返回一个信息给服务器表达了服务器已经接受并且告诉服务器消费结果和后续的处理,总结来说,消费者要告诉消费者如下消息

  1. 是否消费成功-这决定服务器是否要删除消息
  2. 如果消费失败,那么需要重新放回队列吗?

消费者接收的确认机制主要存在三种模式

  1. 自动确认,这也是默认的消息确认情况。 AcknowledgeMode.NONE

RabbitMQ成功将消息发出(即将消息成功写入TCP Socket)中立即认为本次投递已经被正确处理,不管消费者端是否成功处理本次投递。
所以这种情况如果消费端消费逻辑抛出异常,也就是消费端没有处理成功这条消息,那么就相当于丢失了消息。
一般这种情况我们都是使用try catch捕捉异常后,打印日志用于追踪数据,这样找出对应数据再做后续处理。

  1. 根据业务来处理,这个根据自己的业务需求来处理,不细说
  2. 手动确认, 这个比较关键,也是我们配置接收消息确认机制时,多数选择的模式。

消费者收到消息后,手动调用basic.ack/basic.nack/basic.reject后,RabbitMQ收到这些消息后,才认为本次投递成功,换句话说,这也是和业务做耦合的。

消费者收到消息后,手动调用对应的方法后,RabbitMQ收到这些消息后,才认为本次投递成功。手动确认分如下情况,消费成功和消费失败。
1. basicAck用于肯定确认
2. basicNack用于否认确定
3. basicReject 用于否认确认,但和basic.nack相比有一个限制,一次只能拒绝单条信息

basic.reject

basicReject 表示否认确认,

 /*** Reject a message. Supply the deliveryTag from the {@link com.rabbitmq.client.AMQP.Basic.GetOk}* or {@link com.rabbitmq.client.AMQP.Basic.Deliver} method* containing the received message being rejected.* @see com.rabbitmq.client.AMQP.Basic.Reject* @param deliveryTag the tag from the received {@link com.rabbitmq.client.AMQP.Basic.GetOk} or {@link com.rabbitmq.client.AMQP.Basic.Deliver}* @param requeue true if the rejected message should be requeued rather than discarded/dead-lettered* @throws java.io.IOException if an error is encountered*/void basicReject(long deliveryTag, boolean requeue) throws IOException;

入参有两个

  1. deliveryTag-消息体发送标志,不细说
  2. requeue-是否重新放在队列中,次还会消费这消息。设置false,就是告诉服务器,我已经知道这条消息数据了,因为一些原因拒绝它,而且服务器也把这个消息丢掉就行。 下次不想再消费这条消息了。

使用拒绝后重新入列这个确认模式要谨慎,因为一般都是出现异常的时候,catch异常再拒绝入列,选择是否重入列。

但是如果使用不当会导致一些每次都被你重入列的消息一直消费-入列-消费-入列这样循环,会导致消息积压。

channel.basicNack

也是相当于设置不消费某条消息。
源码如下

 /*** Reject one or several received messages.** Supply the <code>deliveryTag</code> from the {@link com.rabbitmq.client.AMQP.Basic.GetOk}* or {@link com.rabbitmq.client.AMQP.Basic.GetOk} method containing the message to be rejected.* @see com.rabbitmq.client.AMQP.Basic.Nack* @param deliveryTag the tag from the received {@link com.rabbitmq.client.AMQP.Basic.GetOk} or {@link com.rabbitmq.client.AMQP.Basic.Deliver}* @param multiple true to reject all messages up to and including* the supplied delivery tag; false to reject just the supplied* delivery tag.* @param requeue true if the rejected message(s) should be requeued rather* than discarded/dead-lettered* @throws java.io.IOException if an error is encountered*/void basicNack(long deliveryTag, boolean multiple, boolean requeue)throws IOException;

Reject one or several received messages,很显然是否认一个或多个接受到的消息体,重点是第二个参数:是指是否针对多条消息;如果是true,也就是说一次性针对当前通道的消息的tagID小于当前这条消息的,都拒绝确认。

同样使用不确认后重新入列这个确认模式要谨慎,因为这里也可能因为考虑不周出现消息一直被重新丢回去的情况,导致积压。

消费者消费机制case(在消费者项目里)

  1. 首先,我们需要设定一个通用的receiver,这个receiver是通用的receiver(之前的相关监听器可以先注释掉,以免造成多个同类型监听器都监听同一个队列。如果有的话)
public class MyAckMessageReceiver implements ChannelAwareMessageListener {@Overridepublic void onMessage(Message message, Channel channel) throws Exception {long deliveryTag = message.getMessageProperties().getDeliveryTag();String strictRequired = null;try {byte[] body = message.getBody();ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(body));Map<String, String> msgMap = (Map<String, String>) ois.readObject();String messageId = msgMap.get("messageId");String messageData = msgMap.get("messageData");String createTime = msgMap.get("createTime");strictRequired = msgMap.get("strictRequired");ois.close();System.out.println("  MyAckReceiver  messageId:" + messageId + "  messageData:" + messageData + "  createTime:" + createTime);System.out.println("消费的主题消息来自:" + message.getMessageProperties().getConsumerQueue());//第二个参数,手动确认可以被批处理,当该参数为 true 时,则可以一次性确认 delivery_tag 小于等于传入值的所有消息channel.basicAck(deliveryTag, true);} catch (IOException | ClassNotFoundException e) {boolean isRequeue = strictRequired != null && strictRequired.contains("1");channel.basicReject(deliveryTag, isRequeue);e.printStackTrace();}}
}
  1. 配置一个MessageListenerConfig,代码如下:
@Configuration
public class MessageListenerConfig {@BeanMyAckMessageReceiver messageReceiver() {return new MyAckMessageReceiver();}@Beanpublic SimpleMessageListenerContainer simpleMessageListenerContainer(CachingConnectionFactory connectionFactory,MyAckMessageReceiver myAckMessageReceiver) {SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);container.setConcurrentConsumers(1);container.setMaxConcurrentConsumers(1);container.setAcknowledgeMode(AcknowledgeMode.MANUAL); // RabbitMQ默认是自动确认,这里改为手动确认消息//设置一个队列container.setQueueNames("TestDirectQueue");//如果同时设置多个如下: 前提是队列都是必须已经创建存在的//  container.setQueueNames("TestDirectQueue","TestDirectQueue2","TestDirectQueue3");//另一种设置队列的方法,如果使用这种情况,那么要设置多个,就使用addQueues//container.setQueues(new Queue("TestDirectQueue",true));//container.addQueues(new Queue("TestDirectQueue2",true));//container.addQueues(new Queue("TestDirectQueue3",true));container.setMessageListener(myAckMessageReceiver);return container;}

在container中指定消息队列和对应的receiver处理器

相关文章:

spring-boot rabbitmq整合

文章请参考&#xff1a;Springboot 整合RabbitMq &#xff0c;用心看完这一篇就够了 mven依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></depende…...

CentOS7安装redis redis常用命令

Redis简介Redis是一个开源免费的、使用C语言编写的NoSQL 数据库。Redis基于内存运行并支持持久化(RDB、AOF方式将数据保存在磁盘)&#xff0c;采用key-value (键值对)的存储形式。Redis数据类型Redis支持五种数据类型&#xff1a;string&#xff08;字符串&#xff09;&#xf…...

世界文明的脉络

人类文明大体上可分为农耕文明、海洋文明和游牧文明三大类别&#xff0c;文明的标志一般是文字、青铜器、城市以及礼仪性建筑等要素。据此&#xff0c;史学家目前已发现了巴比伦文明、埃及文明、印度文明、华夏文明、希腊文明和波斯文明六种主要文明&#xff0c;其中前四种文明…...

map和set 的封装

文章目录引入key-value模型map和set底层setset的几个重要接口mapmap几个重要的接口map和set的封装引入 对于map和set的引入&#xff0c;我们用一道在程序中常见的问题解决&#xff1a; 给定一个数组int arr[]{1,2,1,3,1,4,1,5,5,2,3,4,5};&#xff0c;给出以下问题的解决方案&…...

Springboot集成kafka(环境搭建+演示)|超级详细,建议收藏

Springboot集成kafka一、前言&#x1f525;二、环境说明&#x1f525;三、概念&#x1f525;四、CentOS7安装kafka&#x1f525;1.下载kafka安装包2.下载好后&#xff0c;进行解压六、kafka项目集成&#x1f525;1️⃣pom引入2️⃣配置kafka3️⃣一个kafka消息发送端4️⃣定义一…...

Qt 绘制图表 - Qt Charts版

一、前言 自从 Qt 发布以来&#xff0c;给广大跨平台界面研发人员带来了无数的福利。但是Qt自己却一直没有提供自带的图表库&#xff0c;这就使得 QWT、QCustomPlot 等第三方图表库有了巨大的生存空间&#xff0c;为了降低开发成本&#xff0c;大家都涌向了这些第三方库。这种…...

Java学习笔记 --- JavaScript

一、JavaScript介绍 JavaScript语言诞生主要是完成页面的数据验证。因此它运行在客户端&#xff0c;需要运行浏览器来解析执行JavaScript代码。JS是Netcape网景公司的产品&#xff0c;最早取名为LiveScript&#xff1b;为了吸引更多java程序员。更名为 JavaScript JS是弱类型&…...

AP5216 平均电流型LED 降压恒流驱动器

产品描述 AP5216 是一款 PWM工作模式, 高效率、外围简单、内置功率管&#xff0c;适用于5V&#xff5e;100V输入的高精度降压 LED 恒流驱动芯片。输出最大功率可达 9W&#xff0c;最大电流 1.0A。 AP5216 可实现全亮/半亮功能切换&#xff0c;通过MODE 切换&#xff1a;全亮/…...

B站的多个视频教程,怎样生成一个二维码?

商业插画视频教程、电商运营视频教程、在线网课视频、舞蹈视频教程、摄影视频教程、语言学习教程、纪录片视频…所有你发布在哔哩哔哩上的视频&#xff0c;都可以放在一个二维码里面。 任何人只要扫描这个二维码&#xff0c;就能在线观看你的这些视频教程&#xff01;分享起来…...

深入底层源码的Listener内存马(内存马系列篇三)

写在前面 继前面的FilterServlet内存马技术&#xff0c;这是系列文章的第三篇了&#xff0c;这篇将给大家带来的是Listener内存马技术。 前置 什么是Listener&#xff1f; 监听器 Listener 是一个实现特定接口的 Java 程序&#xff0c;这个程序专门用于监听另一个 Java 对象…...

云端需求助力跑赢周期,金山办公有望借助ChatGPT加速腾飞

与微软在办公领域“搏杀”了三十年的金山办公&#xff0c;或许正在迎来自己的“第二春”。2月25日&#xff0c;金山办公&#xff08;688111&#xff09;发布2022年度业绩快报&#xff0c;全年营收38.85亿元人民币&#xff08;单位下同&#xff09;&#xff0c;同比增加18.44%&a…...

Vulnhub靶场----8、DC-8

文章目录一、环境搭建二、渗透流程三、思路总结一、环境搭建 DC-8下载地址&#xff1a;https://download.vulnhub.com/dc/DC-8.zip kali&#xff1a;192.168.144.148 DC-8&#xff1a;192.168.144.156 二、渗透流程 1、信息收集nmap -T5 -A -p- -sV -sT 192.168.144.156思路&am…...

Makefile 和 Shell 脚本的区别与联系

以下内容转载于博客Makefile 和 shell 脚本的区别与联系&#xff0c;有删改与内容添加。 参考内容&#xff1a;初学Makefile指南 一、什么是 Makefile&#xff1f; Makefile 描述了整个工程的编译、链接规则。当源码文件比较多的时候就不适合通过输入 gcc 命令来编译&#xf…...

java25种设计模式之工厂模式

Java设计模式 - 工厂模式 工厂模式是一种创建模式&#xff0c;因为此模式提供了更好的方法来创建对象。 在工厂模式中&#xff0c;我们创建对象而不将创建逻辑暴露给客户端。 例子 在以下部分中&#xff0c;我们将展示如何使用工厂模式创建对象。 由工厂模式创建的对象将是…...

力扣-2020年最后一次登录

大家好&#xff0c;我是空空star&#xff0c;本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目&#xff1a;1890. 2020年最后一次登录二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行结果5.…...

[蓝桥杯] 数学与简单DP问题

文章目录 一、简单数学问题习题练习 1、1 买不到的数目 1、1、1 题目描述 1、1、2 题解关键思路与解答 1、2 饮料换购 1、2、1 题目描述 1、2、2 题解关键思路与解答 二、DP问题习题练习 2、1 背包问题 2、1、1 题目描述 2、1、2 题解关键思路与解答 2、2 摘花生 2、2、1 题目…...

浏览器的渲染过程解析

文章目录浏览器渲染进程有哪些&#xff1f;浏览器的渲染过程浏览器渲染进程有哪些&#xff1f; GUI线程&#xff1a;负责渲染浏览器页面&#xff0c;解析html&#xff0c;css&#xff0c;构建DOM树&#xff0c;CSS规则树&#xff0c;渲染树和绘制页面&#xff0c;当界面需要重…...

【C++容器】std::fstream读写文件错误【2023.03.03】

std::fstream使用细节 1.文件不存不支持时打开文件模式不得有ios::in • 如果文件不存在且打开时包括了ios::in模式则打开文件会失败。 fstream m_f;m_f.open("d://123.csv", ios::in | ios::out | ios::binary);//文件不存在则会打开失败• 我这边尝试行得通的做…...

UVM实战--带有寄存器的加法器

一.整体的设计结构图 这里将DUT换成加法器&#xff0c;可以理解为之前UVM加法器加上寄存器&#xff0c;这里总线的功能不做修改&#xff0c;目的看代码的移植那些部分需要修改。 二.各个组件代码详解 2.1 DUT module dut( input clk, input rst_n, input…...

笔记--学习mini3d代码

主要是记录学习mini3d代码时&#xff0c;查的资料&#xff1b; 从github下载的代码&#xff1a; GitHub - skywind3000/mini3d: 3D Software Renderer in 700 Lines !!3D Software Renderer in 700 Lines !! Contribute to skywind3000/mini3d development by creating an a…...

图片服务器

文章目录一、项目简介二、功能及场景三、业务设计四、数据库设计准备图片表准备实体类五、API设计常用功能封装文件上传文件上传获取图片列表接口获取图片内容删除图片接口六、项目优化七、测试自动化测试测试用例一、项目简介 图片服务器&#xff1a;解决项目中插入图片的问题…...

【JAVA程序设计】【C00110】基于SSM(非maven)的车辆维修管理系统

基于SSM&#xff08;非maven&#xff09;的车辆维修管理系统项目简介项目获取开发环境项目技术运行截图项目简介 基于ssm框架非maven开发的车辆维修管理系统共分为三个角色&#xff1a;管理员、用户 管理员角色包含以下功能&#xff1a; 查看用户、添加用户、查看车辆信息、故…...

微积分小课堂:用动态的眼光去找问题的最优解(最大值/最小值)【中学里的解题技巧】

文章目录 引言I 最优化问题1.1 不同形式的最优化1.2 用动态的眼光去找问题的最优解引言 把比较数大小的问题,变成了寻找函数变化拐点的问题,将这两个问题等同起来,需要发明一种工具,叫做导数。有了导数这个工具,求最大值问题就变成了解方程的问题。 用变化的眼光找到最优…...

网络爬虫和相关工具

在理想的状态下&#xff0c;所有ICP&#xff08;Internet Content Provider&#xff09;都应该为自己的网站提供API接口来共享它们允许其他程序获取的数据&#xff0c;在这种情况下爬虫就不是必需品&#xff0c;国内比较有名的电商平台&#xff08;如淘宝、京东等&#xff09;、…...

OSSFs挂载工具简介

OSSFs挂载工具 OSSFs挂载工具简介 ​ ossfs允许您在Linux系统中将对象存储OSS的存储空间&#xff08;Bucket&#xff09;挂载到本地文件系统。挂载完成后&#xff0c;您能够像操作本地文件一样操作OSS的对象&#xff08;Object&#xff09;&#xff0c;从而实现数据共享。 ​…...

Spring 容器创建初始化,获取bean流程分析

Spring 容器创建初始化&#xff0c;获取bean流程分析 Spring 容器创建初始化 流程分析 1、首先读取bean.xml 文件 2、扫描指定的包 com.hspedu.spring.component 2.1、扫描包&#xff0c;得到bean的class对象&#xff0c;排除包下不是bean的 2.2、扫描将bean信息封装BeanDef…...

无聊小知识.03 Springboot starter配置自动提示

1、前言Springboot项目配置properties或yaml文件时候&#xff0c;会有很多spring相关的配置提示。这个是如何实现的&#xff1f;如果我们自己的配置属性&#xff0c;能否也自动提示&#xff1f;2、Springboot配置自动提示其实IDE是通过读取配置信息的元数据而实现自动提示的。S…...

2023-03-03 mysql-join类别-分析

目录 摘要: mysql版本: DDL: 表结构: 插入数据: JOIN: 一. SELECT 二. INNER JOIN...

Saleen 系列来袭!

由 Ghostopunch 创作&#x1f47b;&#x1f94a; Ghostpunch 将 Saleen Automotive 带入 The Sandbox 元宇宙&#xff01; 是 Saleen Automotive 于 1984 年由汽车界的梦想家 Steve Saleen 创立&#xff0c;目标是将经过比赛验证的性能带入大街小巷和元宇宙……&#x1f609; 5…...

如何优雅地处理Java中的null值?使用Optional类来实现!

当我们在Java编程时&#xff0c;经常会遇到处理null值的问题。在Java 8中&#xff0c;引入了一个Optional类来解决这个问题。Optional类可以看作是一个容器&#xff0c;用于包装一个可能为null的值。它提供了一些方便的方法&#xff0c;以优雅地处理null值的情况。 下面我将详…...

在唐山做网站多少钱/郑州网站优化公司

1、查看 /opt 整个目录大小 [rootlocalhost xml_onvif]# df -h /opt Filesystem Size Used Avail Use% Mounted on /dev/sda2 18G 12G 5.3G 69% / 2、查看 /opt 目录下的文件大小 [rootlocalhost xml_onvif]# ls -lh /opt/ total 442M drwxr-xr…...

长垣县住房和城乡建设局网站/宁波企业seo推广

随时随地阅读更多技术实战干货&#xff0c;获取项目源码、学习资料&#xff0c;请关注源代码社区公众号(ydmsq666) 有时候&#xff0c;程序需要管理系统音量&#xff0c;或者直接让系统静音&#xff0c;这就可以借助AudioManager来实现。在通过getSystemService(Service.AUDIO_…...

成都企业网站建设/石家庄新闻网

创建使用 Web 部件的简单页面 不需要执行任何操作即可启用 Web 部件个性化设置&#xff1b;默认情况下为 Web 部件控件集启用该功能。当第一次在某个站点上运行 Web 部件页时&#xff0c;ASP.NET 将设置一个默认的个性化设置提供程序来存储用户个性化设置。默认提供程序使用在站…...

网站注册域名查询/自己做网站如何赚钱

zfrisch..5我喜欢上一个答案&#xff0c;但是我觉得它缺乏代码清晰度&#xff0c;并且没有真正涵盖如何使用标签。我将值移到数据对象数组中以便于声明。我将其他值(例如百分比)明确声明为数据对象的属性或单独的变量。我认为&#xff0c;这更易于阅读。如果您对此感兴趣&#…...

wordpress 上传任意附件/搜狐视频

如何判断R为第几范式&#xff1f; 已知一个关系模式的属性之间的语义&#xff0c;也就是相互依赖的关系&#xff0c;如何判断该模式满足第几范式&#xff1f; 1、首先要通过语义把属性之间的函数依赖关系列出来&#xff0c; 2、然后确定哪些属性组合可以候选码&#xff0c;从…...

在电脑上做苗木网站/百度在线客服中心

给霍尼韦尔官方打电话咨询了下&#xff0c;发现两者区别不大&#xff0c;唯一的区别是400B可以和主机联动&#xff0c;也就是主机关的时候&#xff0c;400B也可以自动关闭&#xff0c;不需要手动去关闭电源&#xff0c;这样非常方便。 本来官方是只有400A的时候&#xff0c;但是…...