RabbitMQ——高级特性(SpringBoot实现)

news2024/11/22 21:17:57

本篇文章的内容与我之前如下这篇文章一样,只是使用技术不同,本篇文章使用SpringBoot实现RabbitMQ的高级特性!

RabbitMQ——高级特性_小曹爱编程!的博客-CSDN博客RabbitMQ——高级特性:1、RabbitMQ高级特性;2、RabbitMQ应用问题;3、RabbitMQ集群搭建https://blog.csdn.net/weixin_62993347/article/details/128521074?spm=1001.2014.3001.5502

准备工作

 我们首先建一个工程,接下来的代码都在这个工程里完成。

主要分为生产者和消费者

依赖

<!--AMQP依赖,包含RabbitMQ-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

yml主要配置

server:
  port: 8100
spring:
  rabbitmq:
    host: 101.43.13.118
    port: 5672
    username: admin
    password: 123456

在生产者端和消费者端都编写模板配置文件RabbitConfig,后面在配置文件里加队列、交换机等

@Configuration
public class RabbitConfig {
    @Resource
    //定义管理交换机、队列
    CachingConnectionFactory connectionFactory;

    //rabbitmq模板
    //定义rabbitTemplate对象操作可以在代码中方便发送消息
    @Bean(value = "rabbitTemplate")
    public RabbitTemplate rabbitTemplate(){
        return new RabbitTemplate(connectionFactory);
    }
    
}

 1、消息的可靠性投递

说到RabbitMQ里的消息可靠性投递,那我们不得不提到TCC事务(分布式事务)。

TCC事务

TCC的核心思想是:针对每一个操作都需要注册一个和其相对应的确认和补偿的操作,他分为三个阶段Try、Confirm和Cancel

  • Try 阶段主要是对业务系统做检测及资源预留
  • Confirm 阶段主要是对业务系统做确认提交,Try阶段执行成功并开始执行Confirm阶段时,默认Confirm阶段是不会出错的。即:只要Try成功,Confirm一定成功。若Confirm阶段真的出错了,需引入重试机制或人工处理。
  • Cancel阶段主要是在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。

RabbitMQ 为我们提供了两种方式用来控制消息的投递可靠性模式。

⚫ confirm 确认模式

⚫ return 退回模式

1、确认模式confirm的SpringBoot实现

生产端yml

server:
  port: 8100
spring:
  rabbitmq:
    host: 101.43.13.118
    port: 5672
    username: admin
    password: 123456
    virtual-host: /
    listener:
      simple:
        acknowledge-mode: manual  #开启ACK:手动确认
        retry:
          max-attempts: 5  #重试次数
          initial-interval: 5000  #重试间隔时间
          enabled: true  #开启消费重试
        default-requeue-rejected: false  #重试次数超过
    publisher-returns: true #开启回退模式
    publisher-confirm-type: correlated #确认模式开启(新版本)

首先在生产端的RabbitConfig文件里定义队列和交换机,并绑定。

    //队列
    @Bean
    public Queue confirmQueue(){
        return new Queue("confirm.queue");
    }
    //路由模式(routes)交换机(direct)
    @Bean
    public DirectExchange confirmExchange(){
        return new DirectExchange("confirmExchange");
    }
    //绑定路由交换机和队列
    //bind:队列
    //to:交换机
    //with:routingKey
    @Bean
    public Binding bindingDirectQueue(Queue confirmQueue,DirectExchange confirmExchange){
        return BindingBuilder.bind(confirmQueue).to(confirmExchange).with("confirm");
    }

书写一个测试方法,测试生产端,确认模式

@SpringBootTest(classes = com.chw.ProducerMain.class)
public class ProducerTesty {
    @Resource
    private RabbitTemplate rabbitTemplate;
    /**
     * 确认模式:
     * 步骤:
     * 1. 确认模式开启:ConnectionFactory中开启publisher-confirms="true"
     * yml里面配置了publisher-confirm-type: correlated #确认模式开启(新版本)
     * 2. 在rabbitTemplate定义ConfirmCallBack回调函数
     */
    @Test
    public void testConfirm() throws InterruptedException {
        //设置交换机处理失败消息的模式
        rabbitTemplate.setMandatory(true);
        //2. 定义回调
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            /**
             * @param correlationData 相关配置信息
             * @param ack   exchange交换机 是否成功收到了消息。true 成功,false代表失败
             * @param cause 失败原因
             */
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                System.out.println("confirm方法被执行了....");
                if (ack) {
                    //接收成功
                    System.out.println("接收成功消息" + cause);
                } else {
                    //接收失败
                    System.out.println("接收失败消息" + cause);
                    //做一些处理,让消息再次发送。
                }
            }
        });
        //关键关联数据
        CorrelationData data =new CorrelationData(UUID.randomUUID().toString());
        //3. 发送消息
        //接收成功
        //confirm方法被执行了....
        //接收成功消息null
        rabbitTemplate.convertAndSend("confirmExchange", "confirm", "message confirm....",data);
        //接收失败
        //confirm方法被执行了....
        //接收失败消息channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'confirmExchange111' in vhost '/', class-id=60, method-id=40)
//        rabbitTemplate.convertAndSend("confirmExchange111", "confirm", "message confirm....",data);
        Thread.sleep(200);
    }
}

2、return 退回模式

书写一个测试方法,测试生产端,退回模式

/**
     * 回退模式: 当消息发送给Exchange后,Exchange路由到Queue失败时 才会执行 ReturnCallBack
     * 步骤:
     * 1. 开启回退模式:publisher-returns="true"
     * yml里开启了
     * 2. 设置ReturnCallBack
     * 3. 设置Exchange处理消息的模式:
     *      1. 如果消息没有路由到Queue,则丢弃消息(默认)
     *      2. 如果消息没有路由到Queue,返回给消息发送方ReturnCallBack
     */
    @Test
    public void testReturn() throws InterruptedException {
        //设置交换机处理失败消息的模式
        rabbitTemplate.setMandatory(true);
        //2.设置ReturnCallBack
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            /**
             * @param message   消息对象
             * @param replyCode 错误码
             * @param replyText 错误信息
             * @param exchange  交换机
             * @param routingKey 路由键
             */
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
                System.out.println("return 执行了....");
                System.out.println(message);
                System.out.println(replyCode);
                System.out.println(replyText);
                System.out.println(exchange);
                System.out.println(routingKey);
                //处理
            }
        });
        //关键关联数据
        CorrelationData data =new CorrelationData(UUID.randomUUID().toString());
        //3. 发送消息
        rabbitTemplate.convertAndSend("confirmExchange", "confirm111", "message confirm....",data);
        /**
         * return 执行了....
         * (Body:'message confirm....' MessageProperties [headers={spring_returned_message_correlation=afa438b2-5e6e-41f9-91e5-cf0905bb4330}, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, deliveryTag=0])
         * 312
         * NO_ROUTE
         * confirmExchange
         * confirm111
         */
        Thread.sleep(200);
    }

1.2、Consumer ACK

ack指Acknowledge,确认。 表示消费端收到消息后的确认方式。

有三种确认方式:

yml里都可以配置

• 自动确认:acknowledge="none"

• 手动确认:acknowledge="manual"

• 根据异常情况确认:acknowledge="auto",(这种方式使用麻烦,不作讲解)

我们来到消费端

消费端yml

server:
  port: 8100
spring:
  rabbitmq:
    host: 101.43.13.118
    port: 5672
    username: admin
    password: 123456
    publisher-returns: true #开启回退模式
    publisher-confirm-type: correlated #确认模式开启(新版本)
    virtual-host: /
    listener:
      simple:
        acknowledge-mode: manual  #开启ACK:手动确认
        retry:
          max-attempts: 5  #重试次数
          initial-interval: 5000  #重试间隔时间
          enabled: true  #开启消费重试
        default-requeue-rejected: false  #重试次数超过
        prefetch: 1 #设置消费端一次拉取多少消息。

我们在业务层里写队列监听

/**
     * Consumer ACK机制:
     *  1. 设置手动签收。acknowledge="manual"
     *  yml里设置了
     *  2. 使用RabbitListener注解,写明监听的队列queue
     *  3. 如果消息成功处理,则调用channel的 basicAck()签收
     *  4. 如果消息处理失败,则调用channel的basicNack()拒绝签收,broker重新发送给consumer
     * @param message
     * @param channel
     * @throws IOException
     */
@Service
public class ConsumerService {
    @RabbitListener(queues = "confirm.queue")
    public void consumerAck(Message message, Channel channel) throws IOException {
        //message:队列里的消息的所有信息        
        long deliveryTag = message.getMessageProperties().getDeliveryTag();

        try {
            //1.接收转换消息
            System.out.println(new String(message.getBody()));

            //2. 处理业务逻辑
            System.out.println("处理业务逻辑...");
//            int i = 3/0;//出现错误
            //3. 手动签收
            channel.basicAck(deliveryTag,true);
        } catch (Exception e) {
            //e.printStackTrace();
            //4.拒绝签收
            //三个参数:tag -关联数据,bl-不批量确认,b1:true:放回队列,false:不放回队列
            /*
            第三个参数:requeue:重回队列。如果设置为true,则消息重新回到queue,broker会重新发送该消息给消费端
             */
            channel.basicNack(deliveryTag,true,true);
            //channel.basicReject(deliveryTag,true);
        }
    }
}

 1.3、消费端限流

/**
     * Consumer 限流机制
     *  1. 确保ack机制为手动确认。(在ack基础上)
     *  2. listener-container配置属性
     *  在yml里设置perfetch = 1,表示消费端每次从mq拉去一条消息来消费,直到手动确认消费完毕后,才会继续拉去下一条消息。
     * @param message
     * @param channel
     * @throws Exception
     */
    @RabbitListener(queues = "confirm.queue")
    public void consumerQos(Message message, Channel channel) throws Exception{
        Thread.sleep(1000);
        //1.获取消息
        System.out.println(new String(message.getBody()));
        //2. 处理业务逻辑
        //3. 签收
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),true);
    }

小结

在yml中配置 prefetch属性设置消费端一次拉取多少消息。

消费端的确认模式一定为手动确认。yml配置里acknowledge="manual"。

4、TTL

TTL 全称 Time To Live(存活时间/过期时间)

  • 当消息到达存活时间后,还没有被消费,会被自动清除。
  • RabbitMQ可以对消息设置过期时间,也可以对整个队列(Queue)设置过期时间

首先在生产端的RabbitConfig文件里定义队列和交换机,并绑定。

//ttl队列
    @Bean
    public Queue ttlQueue(){
        Map<String, Object> args = new HashMap<>(1);
        // x-message-ttl  声明队列的TTL:队列的过期时间
        args.put("x-message-ttl",10000);
        return QueueBuilder.durable("ttl.queue").withArguments(args).build();
    }
    //ttl通配符交换机
    @Bean
    public TopicExchange ttlExchange(){
        return new TopicExchange("ttlExchange");
    }
    //绑定TTL通配符交换机和TTL队列
    @Bean
    public Binding bindingDirectQueue(Queue ttlQueue,TopicExchange ttlExchange){
        return BindingBuilder.bind(ttlQueue).to(ttlExchange).with("ttl.#");
    }

书写测试方法测试TTL

/**
     * TTL:过期时间
     *  1. 队列统一过期
     *  2. 消息单独过期
     * 如果设置了消息的过期时间,也设置了队列的过期时间,它以时间短的为准。
     * 队列过期后,会将队列所有消息全部移除。
     * 消息过期后,只有消息在队列顶端,才会判断其是否过期(移除掉)
     */
    @Test
    public void testTtl() {
        /*for (int i = 0; i < 10; i++) {
            // 发送消息
            //十秒后队列里的消息会清空,因为ttl队列过期时间为10秒
            rabbitTemplate.convertAndSend("ttlExchange", "ttl.hehe", "message ttl....");
        }*/

        //消息的后处理对象,设置一些消息的参数信息
        MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                //1.设置message的信息
                message.getMessageProperties().setExpiration("5000");//设置消息的过期时间
                //2.返回该消息
                return message;
            }
        };
        //消息单独过期
//        rabbitTemplate.convertAndSend("ttlExchange", "ttl.hehe", "message ttl....",messagePostProcessor);

        for (int i = 0; i < 10; i++) {
            if(i == 5){
                //消息单独过期
                rabbitTemplate.convertAndSend("ttlExchange", "ttl.hehe", "message ttl....",messagePostProcessor);
            }else{
                //不过期的消息
                rabbitTemplate.convertAndSend("ttlExchange", "ttl.hehe", "message ttl....");
            }
        }
    }

TTL 小结

  • 设置队列过期时间使用参数:x-message-ttl,单位:ms(毫秒),会对整个队列消息统一过期。

  • 设置消息过期时间使用参数:expiration。单位:ms(毫秒),当该消息在队列头部时(消费时),会单独判断这一消息是否过期。

  • 如果两者都进行了设置,以时间短的为准。

1.5、死信队列

死信队列,英文缩写:DLX 。Dead Letter Exchange(死信交换机),当消息成为Dead message后,可以被重新发送到另一个交换机,这个交换机就是DLX。

队列绑定死信交换机:

给队列设置参数: x-dead-letter-exchange 和 x-dead-letter-routing-key

首先在生产端的RabbitConfig文件里定义队列和交换机,并绑定。

//正常dlx队列
    @Bean
    public Queue dlxQueue(){
        //正常队列关联死信交换机
        Map<String, Object> args = new HashMap<>(4);
        // x-dead-letter-exchange    这里声明当前队列绑定的死信交换机
        args.put("x-dead-letter-exchange", "dlxDeadExchange");
        // x-dead-letter-routing-key  这里声明当前队列的死信路由key
        args.put("x-dead-letter-routing-key","dlxDead.hehe");
        // x-message-ttl  声明队列的TTL 声明队列的过期时间
        args.put("x-message-ttl",10000);
        //设置队列的长度限制 max-length
        args.put("x-max-length",10);
        return QueueBuilder.durable("dlx.queue").withArguments(args).build();
    }
    //dlx死信队列
    @Bean
    public Queue dlxDeadQueue(){
        return new Queue("dlxDead.queue");
    }
    //dlx通配符交换机
    @Bean
    public TopicExchange dlxExchange(){
        return new TopicExchange("dlxExchange");
    }
    //dlx死信通配符交换机
    @Bean
    public TopicExchange dlxDeadExchange(){
        return new TopicExchange("dlxDeadExchange");
    }
    //绑定dlx正常队列
    @Bean
    public Binding bindingDxlQueue(Queue dlxQueue,TopicExchange dlxExchange){
        return BindingBuilder.bind(dlxQueue).to(dlxExchange).with("dlx.#");
    }
    //绑定dlx死信队列
    @Bean
    public Binding bindingDxlDeadQueue(Queue dlxDeadQueue,TopicExchange dlxDeadExchange){
        return BindingBuilder.bind(dlxDeadQueue).to(dlxDeadExchange).with("dlxDead.#");
    }

发送测试死信消息

/**
     * 发送测试死信消息:
     *  1. 过期时间
     *  2. 长度限制
     *  3. 消息拒收
     */
    @Test
    public void testDlx(){
        //1. 测试过期时间,死信消息
//        rabbitTemplate.convertAndSend("dlxExchange","dlx.haha","我是一条消息,我会死吗?");

        //2. 测试长度限制后,消息死信
       /* for (int i = 0; i < 20; i++) {
            rabbitTemplate.convertAndSend("dlxExchange","dlx.haha","我是一条消息,我会死吗?");
        }*/

        //3. 测试消息拒收
        rabbitTemplate.convertAndSend("dlxExchange","dlx.haha","我是一条消息,我会死吗?");
    }

测试消息拒收,需要涉及到消费者代码(消费者业务层里书写监听)

/**
     * 监听器监听正常队列
     * 打印结果:
     * 我是一条消息,我会死吗?
     * 处理业务逻辑...
     * 出现异常,拒绝接受
     * @param message
     * @param channel
     * @throws Exception
     */
    @RabbitListener(queues = "dlx.queue")
    public void consumerDlxQueue(Message message, Channel channel) throws Exception{
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try {
            //1.接收转换消息
            System.out.println(new String(message.getBody()));
            //2. 处理业务逻辑
            System.out.println("处理业务逻辑...");
            int i = 3/0;//出现错误
            //3. 手动签收
            channel.basicAck(deliveryTag,true);
        } catch (Exception e) {
            //e.printStackTrace();
            System.out.println("出现异常,拒绝接受");
            //4.拒绝签收,不重回队列 requeue=false
            //这样才能路由到死信队列去
            channel.basicNack(deliveryTag,true,false);
        }
    }

死信队列小结

1. 死信交换机和死信队列和普通的没有区别
2. 当消息成为死信后,如果该队列绑定了死信交换机,则消息会被死信交换机重新路由到死信队列

消息成为死信的三种情况:

1. 队列消息长度到达限制;
2. 消费者拒接消费消息,并且不重回队列;
3. 原队列存在消息过期设置,消息到达超时时间未被消费;

1.6、延迟队列 

延迟队列,即消息进入队列后不会立即被消费,只有到达指定时间后,才会被消费。

首先在生产端的RabbitConfig文件里定义队列和交换机,并绑定。

//正常队列
    //绑定,设置正常队列过期时间为30分钟
    @Bean
    public Queue orderQueue(){
        //正常队列关联死信交换机
        Map<String, Object> args = new HashMap<>(4);
        // x-dead-letter-exchange    这里声明当前队列绑定的死信交换机
        args.put("x-dead-letter-exchange", "dlxDeadOrderExchange");
        // x-dead-letter-routing-key  这里声明当前队列的死信路由key
        args.put("x-dead-letter-routing-key","dlxDeadOrder.hehe");
        // x-message-ttl  声明队列的TTL 声明队列的过期时间
        args.put("x-message-ttl",10000);
        //设置队列的长度限制 max-length
        args.put("x-max-length",10);
        return QueueBuilder.durable("Order.queue").withArguments(args).build();
    }
    //dlx死信队列
    @Bean
    public Queue dlxDeadOrderQueue(){
        return new Queue("dlxDeadOrder.queue");
    }
    //通配符交换机
    @Bean
    public TopicExchange orderExchange(){
        return new TopicExchange("orderExchange");
    }
    //dlx死信通配符交换机
    @Bean
    public TopicExchange dlxDeadOrderExchange(){
        return new TopicExchange("dlxDeadOrderExchange");
    }
    //绑定正常队列
    @Bean
    public Binding bindingOrderQueue(Queue orderQueue,TopicExchange orderExchange){
        return BindingBuilder.bind(orderQueue).to(orderExchange).with("order.#");
    }
    //绑定dlx死信队列
    @Bean
    public Binding bindingDxlDeadOrderQueue(Queue dlxDeadOrderQueue,TopicExchange dlxDeadOrderExchange){
        return BindingBuilder.bind(dlxDeadOrderQueue).to(dlxDeadOrderExchange).with("dlxDeadOrder.#");
    }

测试延迟队列发送消息

    @Test
    public  void testDelay() throws InterruptedException {
        //1.发送订单消息。 将来是在订单系统中,下单成功后,发送消息
        rabbitTemplate.convertAndSend("order_exchange","order.msg","订单信息:id=1,time=2019年8月17日16:41:47");
 
        //2.打印倒计时10秒
        for (int i = 10; i > 0 ; i--) {
            System.out.println(i+"...");
            Thread.sleep(1000);
        }
    }

消费者代码(消费者业务层里书写监听)

/**
     * 监听的是延迟队列里的死信队列!
     * @param message
     * @param channel
     * @throws Exception
     */
    @RabbitListener(queues = "dlxDeadOrder.queue")
    public void consumerDlxDeadOrder(Message message, Channel channel) throws Exception{
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try {
            //1.接收转换消息
            System.out.println(new String(message.getBody()));
            //2. 处理业务逻辑
            System.out.println("处理业务逻辑...");
            System.out.println("根据订单id查询其状态...");
            System.out.println("判断状态是否为支付成功");
            System.out.println("取消订单,回滚库存....");
            //3. 手动签收
            channel.basicAck(deliveryTag,true);
        } catch (Exception e) {
            //e.printStackTrace();
            System.out.println("出现异常,拒绝接受");
            //4.拒绝签收,不重回队列 requeue=false
            channel.basicNack(deliveryTag,true,false);
        }
    }

延迟队列小结

1. 延迟队列 指消息进入队列后,可以被延迟一定时间,再进行消费。

2. RabbitMQ没有提供延迟队列功能,但是可以使用 : TTL + 死信队列来实现延迟队列效果。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IDEA2021.3新建一个maven-archetype-webapp项目,发现在新建文件汇总,没有新建servlet文件选项

问题 我使用maven-webapp 模板新建了一个web项目&#xff0c;但是在新建文件的时候&#xff0c;发现没有servlet选项 解决 第一种&#xff1a;在pom中直接配置 <dependencies><dependency><groupId>javax.servlet</groupId><artifactId>java…

Linux进程信号产生以及捕捉

一.什么是信号 生活中&#xff0c;有哪些信号相关的场景呢&#xff0c;比如&#xff1a;红绿灯&#xff0c;闹钟&#xff0c;转向灯等等 1.这里我们要知道&#xff0c;你为什么认识这些信号呢&#xff0c;记住了对应场景下的信号&#xff0b;后续是有”动作“要你执行的 2.我们…

spring boot 项目打包镜像方式以及区分环境打包

springboot项目打包成docker镜像-贾玉珍-2023年2月8日方法一&#xff1a;将项目jar包手动推送到docker服务器上1.用maven对项目进行打包&#xff0c;打包成功后会有一个target目录&#xff0c;目录下有打好的项目jar包2.将jar包上传到服务器上&#xff0c;我用的是finalshell工…

Zabbix Agent item监控项讲解

前言 agent与snmp是Zabbix两种重要的监控方式&#xff0c;这一期主要介绍Zabbix Agent item监控项。。Zabbix agent分为主动代理、被动代理&#xff0c;配置item类型时&#xff0c;可以选择需要的类型&#xff1a; Zabbix agent &#xff1a;用于被动检查 Zabbix agent&…

【C语言进阶】结构体、位段、枚举和联合

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前是C语言学习者 ✈️专栏&#xff1a;C语言航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&a…

顶刊MS论文解读|数据驱动的动态定价和订购策略

作者&#xff1a;白静 金凯瑞 马玺渊 钟子俊编者按 本次解读的文章为“Data-Driven Dynamic Pricing and Ordering with Perishable Inventory in a Changing Environment”&#xff0c;于2022年发表在期刊 Management Science, 作者 N. Bora Keskin, Yuexing Li, Jing-Sheng …

推荐5款极大提高工作效率的办公软件!每个都是我精挑细选的

关于提高办公效率的相关软件&#xff0c;答主要把工作5年的独家秘方都拿出来了。分享的都是用过的且体验不错的软件&#xff0c;大多数是免费软件&#xff01; 按照使用场景&#xff0c;简单先分个类&#xff0c;分别是时间利用利器&#xff0c;流程优化软件&#xff0c;办公美…

论文投稿指南——中文核心期刊推荐(工程材料学)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

重生之我是赏金猎人-SRC漏洞挖掘(一)-某SRC测试系统无脑Getshell

0x01 前言 https://github.com/J0o1ey/BountyHunterInChina 欢迎大佬们点个star 0x02 资产收集到脆弱系统 在某src挖掘过程中&#xff0c;本人通过ssl证书对域名资产进行了收集&#xff0c;通过计算域名对应ip段的权重 整理出其C段资产&#xff0c;进行了批量目录扫描 查看…

Spring Boot两种格式的配置文件,你都了解吗?

目录 前言 一、properties配置文件 1.1、语法格式 1.2、读取配置文件 1.3、缺点分析 2、yml配置文件 2.1、yml语法 2.1.1、注意&#xff1a;value值的单双引号 2.2、yml配置读取 2.3、yml配置的不同数据类型 2.4、yml配置对象 2.5、yml配置集合 3、面试&#xff1a…

2023年浙江道路运输安全员考试真题题库及答案

百分百题库提供道路运输安全员考试试题、道路运输安全员考试预测题、道路运输安全员考试真题、道路运输安全员证考试题库等,提供在线做题刷题&#xff0c;在线模拟考试&#xff0c;助你考试轻松过关。 1.关于道路运输企业车辆技术管理机构的主要职责&#xff0c;在下列表述中最…

anaconda3文件夹被移动之后,如何操作可以复用原有conda环境

anaconda3文件夹被移动A-调整conda PATH地址B-更改.conda/environments.txt中的地址C-修改conda内的变量和每个环境的pip目录A-调整conda PATH地址 B-更改.conda/environments.txt中的地址 a. 优先切换到用户根目录 b. 查看隐藏conda目录 c. 编辑 vi .conda/environments.txt…

【服务器数据恢复】NetApp存储无法访问的数据恢复案例

服务器数据恢复环境&#xff1a; NetApp某型号存储&#xff1b; 配备SAS硬盘&#xff0c;该硬盘520字节一个扇区&#xff1b; 所有的lun映射到小型机使用&#xff0c;存放Oracle数据库文件&#xff0c;采用ASM裸设备存储方式。 服务器故障&#xff1a; 管理员误操作删除NetApp…

介电常数常用测量方法综述

张扬1&#xff0c;徐尚志1&#xff0c;赵文晖2&#xff0c;龚增2&#xff0c;赵晓群1 1同济大学&#xff0c;上海 2上海市计量测试技术研究院&#xff0c;上海 在设计电路、天线、电容器等过程中经常会涉及所用材料的介电常数, 所以深入了解介电常数的相关概念对实际工作有重…

【RuoYi-Vue-Plus】学习笔记 48 - 数据加密功能 Encrypt 源码分析

文章目录前言参考目录功能实现的准备知识1、目录结构说明2、一些准备知识2.1、自定义插件如何实现&#xff1f;2.2、Mybatis 拦截器的拦截点&#xff1f;2.3、关于 Intercepts 注解&#xff1f;2.4、关于拦截器中的 Interceptor() 方法和 plugin() 方法&#xff1f;功能调用流程…

企业数字化转型中信息化是什么

数字化转型带给企业的价值无疑是能够支撑起这股热潮的&#xff0c;这种流行趋势在数字化时代也并不意外。不过有一点值得注意&#xff0c;那就是数字化转型毕竟发展时间还不太长&#xff0c;虽然有未来加持&#xff0c;但又有多少企业能够在当下坚持数字化转型&#xff0c;顺利…

MYSQL的第四次索引视图

题目&#xff1a; 学生表&#xff1a;Student (Sno, Sname, Ssex , Sage, Sdept) 学号&#xff0c;姓名&#xff0c;性别&#xff0c;年龄&#xff0c;所在系 Sno为主键 课程表&#xff1a;Course (Cno, Cname,) 课程号&#xff0c;课程名 Cno为主键 学生选课…

[数据库迁移]-MySQL常见问题

[数据库迁移]-MySQL常见问题 森格 | 2023年2月 介绍&#xff1a;记录在MySQL数据库迁移过程中遇到的问题&#xff0c;以及解决方案。 文章目录[数据库迁移]-MySQL常见问题一、背景二、常见问题2.1 ERROR 20032.2 ERROR 12732.3 ERROR 10712.4 视图权限2.5 ERROR 1062三、总结一…

idea提交git时过滤掉不必要的文件 mes

.ignore插件的安装非常简单&#xff0c;如下图所示&#xff1a; 1.添加.gitignore 在项目上创建 在打开的面板中&#xff0c;执行如下图所示的选择&#xff1a; 3.在本地项目下文件上创建需要过滤文件后缀名 ### Example user template template ### Example user templa…

算法笔记(五)—— 二叉树

链表练习题&#xff1a; 1. 查两个链表的第一个入环结点&#xff0c;loop1,loop2。&#xff08;快慢指针&#xff0c;相交后&#xff0c;快指针放头节点&#xff09; 2. 当loop1null , loop2null时 如果两个链表最后一个结点不相等&#xff0c;那么一定不相交。 最后一个结点地…