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

2024-09-04 21:12

本文主要是介绍尚品汇-商品上下架完善(更新ES)、延迟消息(四十四),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录:

(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 {@Autowiredprivate 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";// 定义交换机@Beanpublic DirectExchange exchange(){return new DirectExchange(exchange_dead,true,false,null);}@Beanpublic 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);}@Beanpublic Binding binding(){// 将队列一 通过routing_dead_1 key 绑定到exchange_dead 交换机上return BindingBuilder.bind(queue1()).to(exchange()).with(routing_dead_1);}// 这个队列二就是一个普通队列@Beanpublic Queue queue2(){return new Queue(queue_dead_2,true,false,false,null);}// 设置队列二的绑定规则@Beanpublic 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 {@Autowiredprivate RabbitTemplate rabbitTemplate;@Autowiredprivate 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";@Beanpublic Queue delayQeue1() {// 第一个参数是创建的queue的名字,第二个参数是是否支持持久化return new Queue(queue_delay_1, true);}@Beanpublic 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);}@Beanpublic 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() {@Overridepublic 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就会报错:

修改消息回调 

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

 更改后就不报错了

这篇关于尚品汇-商品上下架完善(更新ES)、延迟消息(四十四)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1137044

相关文章

Three.js构建一个 3D 商品展示空间完整实战项目

《Three.js构建一个3D商品展示空间完整实战项目》Three.js是一个强大的JavaScript库,专用于在Web浏览器中创建3D图形,:本文主要介绍Three.js构建一个3D商品展... 目录引言项目核心技术1. 项目架构与资源组织2. 多模型切换、交互热点绑定3. 移动端适配与帧率优化4. 可

聊聊springboot中如何自定义消息转换器

《聊聊springboot中如何自定义消息转换器》SpringBoot通过HttpMessageConverter处理HTTP数据转换,支持多种媒体类型,接下来通过本文给大家介绍springboot中... 目录核心接口springboot默认提供的转换器如何自定义消息转换器Spring Boot 中的消息

MySQL 数据库表操作完全指南:创建、读取、更新与删除实战

《MySQL数据库表操作完全指南:创建、读取、更新与删除实战》本文系统讲解MySQL表的增删查改(CURD)操作,涵盖创建、更新、查询、删除及插入查询结果,也是贯穿各类项目开发全流程的基础数据交互原... 目录mysql系列前言一、Create(创建)并插入数据1.1 单行数据 + 全列插入1.2 多行数据

linux安装、更新、卸载anaconda实践

《linux安装、更新、卸载anaconda实践》Anaconda是基于conda的科学计算环境,集成1400+包及依赖,安装需下载脚本、接受协议、设置路径、配置环境变量,更新与卸载通过conda命令... 目录随意找一个目录下载安装脚本检查许可证协议,ENTER就可以安装完毕之后激活anaconda安装更

Nginx进行平滑升级的实战指南(不中断服务版本更新)

《Nginx进行平滑升级的实战指南(不中断服务版本更新)》Nginx的平滑升级(也称为热升级)是一种在不停止服务的情况下更新Nginx版本或添加模块的方法,这种升级方式确保了服务的高可用性,避免了因升... 目录一.下载并编译新版Nginx1.下载解压2.编译二.替换可执行文件,并平滑升级1.替换可执行文件

SQL Server跟踪自动统计信息更新实战指南

《SQLServer跟踪自动统计信息更新实战指南》本文详解SQLServer自动统计信息更新的跟踪方法,推荐使用扩展事件实时捕获更新操作及详细信息,同时结合系统视图快速检查统计信息状态,重点强调修... 目录SQL Server 如何跟踪自动统计信息更新:深入解析与实战指南 核心跟踪方法1️⃣ 利用系统目录

RabbitMQ消息总线方式刷新配置服务全过程

《RabbitMQ消息总线方式刷新配置服务全过程》SpringCloudBus通过消息总线与MQ实现微服务配置统一刷新,结合GitWebhooks自动触发更新,避免手动重启,提升效率与可靠性,适用于配... 目录前言介绍环境准备代码示例测试验证总结前言介绍在微服务架构中,为了更方便的向微服务实例广播消息,

SpringBoot整合(ES)ElasticSearch7.8实践

《SpringBoot整合(ES)ElasticSearch7.8实践》本文详细介绍了SpringBoot整合ElasticSearch7.8的教程,涵盖依赖添加、客户端初始化、索引创建与获取、批量插... 目录SpringBoot整合ElasticSearch7.8添加依赖初始化创建SpringBoot项

SpringBoot中六种批量更新Mysql的方式效率对比分析

《SpringBoot中六种批量更新Mysql的方式效率对比分析》文章比较了MySQL大数据量批量更新的多种方法,指出REPLACEINTO和ONDUPLICATEKEY效率最高但存在数据风险,MyB... 目录效率比较测试结构数据库初始化测试数据批量修改方案第一种 for第二种 case when第三种

java向微信服务号发送消息的完整步骤实例

《java向微信服务号发送消息的完整步骤实例》:本文主要介绍java向微信服务号发送消息的相关资料,包括申请测试号获取appID/appsecret、关注公众号获取openID、配置消息模板及代码... 目录步骤1. 申请测试系统2. 公众号账号信息3. 关注测试号二维码4. 消息模板接口5. Java测试