尚品汇-商品上下架完善(更新ES)、延迟消息(四十四)

news2024/11/14 12:17:35

目录:

(1)改造商品搜索上下架

(2)延迟消息

(1)改造商品搜索上下架

定义商品上下架常量

rabbit-util模块中导入常量类MqConst
/**
 * 商品上下架.
 */
public static final String EXCHANGE_DIRECT_GOODS = "exchange.direct.goods";
public static final String ROUTING_GOODS_UPPER = "goods.upper";
public static final String ROUTING_GOODS_LOWER = "goods.lower";
//队列
public static final String QUEUE_GOODS_UPPER  = "queue.goods.upper";
public static final String QUEUE_GOODS_LOWER  = "queue.goods.lower";

service-list与service-product引入依赖与配置

<!--rabbitmq消息队列-->
<dependency>
   <groupId>com.atguigu.gmall</groupId>
   <artifactId>rabbit-util</artifactId>
   <version>1.0</version>
</dependency>

service-product发送消息

我在商品上架与商品添加时发送消息

商品上架

实现类

@Override
@Transactional
public void onSale(Long skuId) {
    // 更改销售状态
    SkuInfo skuInfoUp = new SkuInfo();
    skuInfoUp.setId(skuId);
    skuInfoUp.setIsSale(1);
    skuInfoMapper.updateById(skuInfoUp);

    //商品上架 交换机 路由key 队列
    rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_GOODS, MqConst.ROUTING_GOODS_UPPER, skuId);
}

商品下架

@Override
@Transactional
public void cancelSale(Long skuId) {
    // 更改销售状态
    SkuInfo skuInfoUp = new SkuInfo();
    skuInfoUp.setId(skuId);
    skuInfoUp.setIsSale(0);
    skuInfoMapper.updateById(skuInfoUp);

    //商品下架  交换机 路由key 队列
    rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_GOODS, MqConst.ROUTING_GOODS_LOWER, skuId);
}

service-list消费消息

package com.atguigu.gmall.list.receiver;

import com.atguigu.gmall.constant.MqConst;
import com.atguigu.gmall.list.service.SearchService;
import com.rabbitmq.client.Channel;
import lombok.SneakyThrows;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class ListReceiver {


    @Autowired
    private SearchService searchService;

    //监听上架队列
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            value =@Queue(value = MqConst.QUEUE_GOODS_UPPER,durable = "true",autoDelete = "false"),
            exchange =@Exchange(value = MqConst.EXCHANGE_DIRECT_GOODS,autoDelete = "false"),
            key = {MqConst.ROUTING_GOODS_UPPER}
    ))
    public void upperGoodsToEs(Long skuId, Message message, Channel channel){

        try {
            //判断
            if(skuId!=null){
                //操作搜索模块操作ES的上架方法
                searchService.upperGoods(skuId);



            }
        } catch (Exception e) {
            //写入日志文件 ,,写入数据库, 对接程序员手机短信
            e.printStackTrace();
        }

       //消息确认    // 参数一:消息的唯一标识,参数二:是否批量确认 false 确认一个消息,true 批量确认
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }



    //监听下架队列

    //监听上架队列
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            value =@Queue(value = MqConst.QUEUE_GOODS_LOWER,durable = "true",autoDelete = "false"),
            exchange =@Exchange(value = MqConst.EXCHANGE_DIRECT_GOODS,autoDelete = "false"),
            key = {MqConst.ROUTING_GOODS_LOWER}
    ))
    public void lowerGoodsToEs(Long skuId, Message message, Channel channel){

        try {
            //判断
            if(skuId!=null){
                //操作搜索模块操作ES的下架方法
                searchService.lowerGoods(skuId);



            }
        } catch (Exception e) {
            //写入日志文件 ,,写入数据库, 对接程序员手机短信
            e.printStackTrace();
        }


           //消息确认    // 参数一:消息的唯一标识,参数二:是否批量确认 false 确认一个消息,true 批量确认
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }
}

测试

启动后台管理页面

http://localhost:8888/#/product/sku/list

操作商品的上架,下架。动态更改es中的数据。

全部下架,页面查看:

上架几个:

(2)延迟消息

前面解决了搜索与商品服务的问题,下面解决这个问题订单取消问题:

 

延迟消息有两种实现方案:

  1. 基于死信队列
  2. 集成延迟插件

1.基于死信实现延迟消息

使用RabbitMQ来实现延迟消息必须先了解RabbitMQ的两个概念:消息的TTL和死信Exchange,通过这两者的组合来实现延迟队列

消息的TTL(Time To Live)

消息的TTL就是消息的存活时间。RabbitMQ可以对队列和消息分别设置TTL。对队列设置就是队列没有消费者连着的保留时间,也可以对每一个单独的消息做单独的设置。超过了这个时间,我们认为这个消息就死了,称之为死信。

如何设置TTL:

我们创建一个队列queue.temp,在Arguments 中添加x-message-ttl 为5000 (单位是毫秒),那所在压在这个队列的消息在5秒后会消失。

死信交换机  Dead Letter Exchanges

一个消息在满足如下条件下,会进死信路由,记住这里是路由而不是队列,一个路由可以对应很多队列。

(1) 一个消息被Consumer拒收了,并且reject方法的参数里requeue是false。也就是说不会被再次放在队列里,被其他消费者使用。

(2)上面的消息的TTL到了,消息过期了。

(3)队列的长度限制满了。排在前面的消息会被丢弃或者扔到死信路由上。

Dead Letter Exchange其实就是一种普通的exchange,和创建其他exchange没有两样。只是在某一个设置Dead Letter Exchange的队列中有消息过期了,会自动触发消息的转发,发送到Dead Letter Exchange中去。

 

我们现在可以测试一下延迟队列。

(1)创建死信队列

(2)创建交换机

(3)建立交换器与队列之间的绑定

(4)创建队列

代码实现

 

在service-mq 中添加配置类:前面我们使用注解的方式进行创建交换机队列,下面我们用配置类进行创建 

package com.atguigu.gmall.mq.config;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DeadLetterMqConfig {
    // 声明一些变量

       public static final String exchange_dead = "exchange.dead";
    public static final String routing_dead_1 = "routing.dead.1";
    public static final String routing_dead_2 = "routing.dead.2";
    public static final String queue_dead_1 = "queue.dead.1";
    public static final String queue_dead_2 = "queue.dead.2";

    // 定义交换机
    @Bean
    public DirectExchange exchange(){
        return new DirectExchange(exchange_dead,true,false,null);
    }

    @Bean
    public Queue queue1(){
        // 设置如果队列一 出现问题,则通过参数转到exchange_dead,routing_dead_2 上!
        HashMap<String, Object> map = new HashMap<>();
        // 参数绑定 此处的key 固定值,不能随意写
        map.put("x-dead-letter-exchange",exchange_dead);
        map.put("x-dead-letter-routing-key",routing_dead_2);
        // 设置延迟时间
        map.put("x-message-ttl", 10 * 1000);
        // 队列名称,是否持久化,是否独享、排外的【true:只可以在本次连接中访问】,是否自动删除,队列的其他属性参数
        return new Queue(queue_dead_1,true,false,false,map);
    }

    @Bean
    public Binding binding(){
        // 将队列一 通过routing_dead_1 key 绑定到exchange_dead 交换机上
        return BindingBuilder.bind(queue1()).to(exchange()).with(routing_dead_1);
    }

    // 这个队列二就是一个普通队列
    @Bean
    public Queue queue2(){
        return new Queue(queue_dead_2,true,false,false,null);
    }

    // 设置队列二的绑定规则
    @Bean
    public Binding binding2(){
        // 将队列二通过routing_dead_2 key 绑定到exchange_dead交换机上!
        return BindingBuilder.bind(queue2()).to(exchange()).with(routing_dead_2);
    }
}

配置发送消息

package com.atguigu.gmall.mq.controller;


@RestController
@RequestMapping("/mq")
@Slf4j
public class MqController {

   @Autowired
   private RabbitTemplate rabbitTemplate;

   @Autowired
   private RabbitService rabbitService;

 @GetMapping("sendDeadLettle")
   public Result sendDeadLettle() {
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
     this.rabbitService.convertAndSend(DeadLetterMqConfig.exchange_dead, DeadLetterMqConfig.routing_dead_1, "我是延迟消息");
      System.out.println(" 消息发送时间:"+sdf.format(new Date()) );
      return Result.ok();
   }
}

 

消息接收方

package com.atguigu.gmall.mq.receiver;

@Component
@Configuration
public class DeadLetterReceiver {

    //消费的是队列2,队列1,没有人消息,超过超时时间后会变成死信
    @RabbitListener(queues = DeadLetterMqConfig.queue_dead_2)
    public void get(String msg) {
        System.out.println("Receive:" + msg);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("消息接收时间: " + sdf.format(new Date()));
         System.out.println("消息内容为:"+msg)
    }
}

 

2.基于延迟插件实现延迟消息

Rabbitmq实现了一个插件x-delay-message来实现延时队列

插件安装

1. 首先我们将刚下载下来的rabbitmq_delayed_message_exchange-3.9.0.ez文件上传到RabbitMQ所在服务器,下载地址:https://www.rabbitmq.com/community-plugins.html

2. 切换到插件所在目录,执行 docker cp rabbitmq_delayed_message_exchange-3.9.0.ez rabbitmq:/plugins 命令,将刚插件拷贝到容器内plugins目录下

3. 执行 docker exec -it rabbitmq /bin/bash 命令进入到容器内部,并 cd plugins 进入plugins目录

4. 执行 ls -l|grep delay  命令查看插件是否copy成功

5. 在容器内plugins目录下,执行 rabbitmq-plugins enable rabbitmq_delayed_message_exchange  命令启用插件

6. exit命令退出RabbitMQ容器内部,然后执行 docker restart rabbitmq 命令重启RabbitMQ容器

代码实现

在service-mq 中添加类

配置队列

package com.atguigu.gmall.mq.config;

@Configuration
public class DelayedMqConfig {

    public static final String exchange_delay = "exchange.delay";
    public static final String routing_delay = "routing.delay";
    public static final String queue_delay_1 = "queue.delay.1";

     @Bean
    public Queue delayQeue1() {
        // 第一个参数是创建的queue的名字,第二个参数是是否支持持久化
        return new Queue(queue_delay_1, true);
    }

    @Bean
    public CustomExchange delayExchange() {
        Map<String, Object> args = new HashMap<String, Object>();
        args.put("x-delayed-type", "direct");
        return new CustomExchange(exchange_delay, "x-delayed-message", true, false, args);
    }

    @Bean
    public Binding delayBbinding1() {
        return BindingBuilder.bind(delayQeue1()).to(delayExchange()).with(routing_delay).noargs();
    }
}

发送消息:这个延迟插件,需要使用rabbitTemplate,上面的可以使用rabbitService封装的service

@GetMapping("sendelay")
public Result sendDelay() {
   SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
   this.rabbitTemplate.convertAndSend(DelayedMqConfig.exchange_delay, DelayedMqConfig.routing_delay, "我是延迟插件的消息", new MessagePostProcessor() {
      @Override
      public Message postProcessMessage(Message message) throws AmqpException {
         message.getMessageProperties().setDelay(10 * 1000);//消息的延迟时间
         System.out.println("延迟插件消息发送时间:"+sdf.format(new Date()) );
         return message;//放行消息
      }
   });
   return Result.ok();
}

接收消息

package com.atguigu.gmall.mq.receiver;


@Component
public class DelayReceiver {

    @RabbitListener(queues = DelayedMqConfig.queue_delay_1)
    public void get(String msg) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("消息接受时间: " + sdf.format(new Date()));

        System.out.println("消息内容是:"+msg)
    }

}

报错了不用管,因为我们灭有使用封装的发送消息的rabbittservice 发送消息,没有往Redis放消息,发送延迟消息发送失败,会消息回调重新发送,会获取key,没有key就会报错:

修改消息回调 

加一个为空的判断:并且在接受消息的时候加一个消息确认 

 更改后就不报错了

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

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

相关文章

游戏翻译中西班牙语的特点

由于西班牙语丰富的文化多样性和广泛的使用&#xff0c;将游戏翻译成西班牙语带来了独特的机遇和挑战。西班牙语是全球第二大使用语言&#xff0c;包括西班牙、拉丁美洲和美国部分地区在内的各个地区有超过4.6亿母语人士。然而&#xff0c;这些地区的语言和文化差异需要量身定制…

Datawhale X 李宏毅苹果书 AI夏令营-深度学习进阶task1:局部极小值与鞍点,批量和动量

一、临界点和鞍点 在做优化的时候经常会发现&#xff0c;随着参数不断更新&#xff0c;训练的损失不会再下降, 但是我们对这个损失仍然不满意或者有时模型一开始就训练不起来&#xff0c;不管我们怎么更新参数&#xff0c;损失都降不下去。 过去常见的一个猜想是我们优化到某…

GPU环境配置:1.CUDA、Anaconda、Pytorch

一、查看显卡适配CUDA型号 查看自己电脑的显卡版本&#xff1a; 在 Windows 设置中查看显卡型号&#xff1a;使用 Windows I 快捷键打开「设置」&#xff0c;依次点击「系统」-「屏幕」和「高级显示器设置」&#xff0c;在「显示器 1」旁边就可以看到显卡名称。 右键点菜单图标…

自动生成对话视频!如何使用Captions的AI视频生成与编辑API工具?

Captions公司最近发布了一套AI驱动的视频生成和编辑API工具&#xff0c;为创作者和开发者提供了一个强大的视频创作生态系统。这个系统包含AI Creator、AI Twin、AI Edit、和AI Translate四大核心功能&#xff0c;每个工具都针对不同的创作需求进行优化。下面我们就一起来详细测…

宏定义## 的使用

宏定义## 的使用 C语言中宏定义## 的使用 宏定义## 的使用 #define LV_color(x,y,z) x##y##z 文章目录 宏定义## 的使用宏定义## 的使用 宏定义## 的使用 #include<stdio.h> #include<stdlib.h>#define LV_color(x,y,z) x##y##z int main() {printf("LV_col…

SaaS行业|深入探讨五个联盟营销平台

随着数字时代的飞速发展&#xff0c;SaaS&#xff08;Software as a Service&#xff0c;软件即服务&#xff09;行业正以前所未有的速度崛起&#xff0c;成为推动全球商业变革的重要力量。本文将深入探索分析SaaS行业的五个营销联盟营销平台。 1. PartnerShare&#xff1a;Saa…

保姆级Vue项目安装配置步骤(包含vue-cli脚手架环境配置、Vue项目创建、运行)

文章目录 1. Vue-cli脚手架安装2. Vue项目创建(使用图形化界面创建步骤&#xff09;3. Vue项目-运行4. Vue项目-配置端口 此教程摘选自我的笔记&#xff1a;黑马JavaWeb开发笔记08——(保姆级Vue项目全部安装配置步骤)Vue-cli脚手架安装、NodeJS环境搭建、Vue项目的创建、运行、…

zdppy+vue3+onlyoffice文档管理系统实战 20240903 上课笔记 登录功能完成

接下来 1、注销功能&#xff1a;点击注销按钮&#xff0c;清除登录信息跳转到登录页面2、token过期 注销功能 useUser.js import storage from "../../g/storage.js"; import {useRouter} from "vue-router"; import {message} from "ant-design-…

【vue Lottie】lottie在vue项目中的使用心得

✨减少依赖体积 ●能用原生实现的动效&#xff0c;就不要切Lottie&#xff0c;提前做好切分 ●使用的时候&#xff0c;不要一股脑的复制粘贴过来&#xff0c;而是应该进行如下步骤的清洗 ○合并同样的图片依赖素材&#xff0c;减小依赖图片的大小 ○一些很大的背景图片&…

比亚迪夏亮相,枪口究竟对准了谁?

文/王俣祺 导语&#xff1a;比亚迪的MPV终于要来了&#xff0c;比亚迪夏在成都车展上正式亮相&#xff0c;据说售价会在30万级别&#xff0c;如果是这一几个区间&#xff0c;可以说是把矛头直接指向了腾势D9。作为比亚迪“宗亲”的腾势D9匆忙表示“大哥别开枪&#xff0c;自己人…

多晶透明陶瓷市场发展现状和前景:未来几年年复合增长率CAGR为15.5%

多晶透明陶瓷是一种新型先进功能材料&#xff0c;它具有独特的机械性能和透射性能&#xff0c;在战略和民用领域有着广泛的应用。陶瓷粉末合成、成型和烧结技术的进步使得先进透明陶瓷材料的微观结构、机械性能和光学性能关系的定制成为可能。透明陶瓷材料大致分为可见光、中波…

【qt】多线程实现倒计时

1.界面设计 设置右边的intvalue从10开始倒计时 2.新建Thread类 新建Thread类&#xff0c;使其继承QThread类&#xff0c;多态重写run函数&#xff0c;相当于线程执行函数 3.重写run函数 重写run函数&#xff0c;让另一个进程每隔1s发出一个信号&#xff0c;主线程使用conne…

wireshark使用攻略

简介 wireshark 是网络封包分析工具&#xff0c;可与截取各种网络数据包并且显示数据包的详细信息。 使用 打开wireshark &#xff1a; 在Linux中使用sudo wireshark 打开 打开之后选择对应的网卡&#xff0c;就可以进行网络信息的捕获&#xff0c;开始抓取网络包。 可以…

不管C盘垃圾有多少 芝麻清理就是好!彻底清理电脑垃圾!

不管C盘垃圾有多少 芝麻清理就是好&#xff01;彻底清理电脑垃圾&#xff01;让你没烦恼&#xff01;C盘垃圾是许多人的烦恼&#xff0c;如果靠手动去清理C盘垃圾是个非常麻烦的事情&#xff0c;就算有10多年电脑经验的高手&#xff0c;也未必能做到彻底清理干净C盘。 对于我们…

Allure报告下载不同格式的文件

支持类型&#xff1a; class AttachmentType(Enum):def __init__(self, mime_type, extension):self.mime_type mime_typeself.extension extensionTEXT ("text/plain", "txt")CSV ("text/csv", "csv")TSV ("text/tab-sep…

网络编程9月3日

1&#xff0c;思维导图2&#xff0c;TCP通信 服务器端 #include<myhead.h> #define JCHM 4514 #define IPDZ "192.168.0.113" #define BACKLOG 5 int main(int argc,const char *argv[]) {int oldfdsocket(AF_INET,SOCK_STREAM,0);if(oldfd-1){perror("…

猴子排序:一种理论上的排序算法

猴子排序&#xff1a;一种理论上的排序算法 在编程和算法的世界里&#xff0c;总有一些有趣的算法让人忍俊不禁&#xff0c;同时又让人深思。今天&#xff0c;我们来聊聊一种特别的排序算法——猴子排序&#xff08;Bogosort&#xff09;&#xff0c;也常被戏称为瞎子排序、波…

解放你的带宽和内存:GZIP在解决Redis大Key方面的应用

首发公众号&#xff1a;赵侠客 引用 目前主流HTTP协议接口都是使用JSON格式做数据交换的&#xff0c;JSON数据格式有着结构简单、可读性高、跨平台&#xff0c;易解析等优点&#xff0c;同时也存在着冗余数据会占用非常多的储存空间的问题&#xff0c;这大大增加了JSON格式数据…

MATLAB eig 函数简介:计算特征值和特征向量

在数据科学、工程学和数学中&#xff0c;特征值和特征向量是理解和分析矩阵行为的核心概念。MATLAB 的 eig 函数是处理这些概念的强大工具。本文将介绍 eig 函数的基本用法&#xff0c;并通过示例展示如何使用它来计算特征值和特征向量。 什么是特征值和特征向量&#xff1f; …

应用层(Web与HTTP)

目录 常见术语 1.HTTP概况 2.HTTP连接 非持久HTTP流程 响应时间模型 持久HTTP 3.HTTP报文 3.1HTTP请求报文 3.2HTTP响应报文 HTTP响应状态码 4.Cookies&#xff08;用户-服务器状态&#xff09; cookies&#xff1a;维护状态 Cookies的作用 5.Web缓冲&#xff08;…