├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── wilson │ │ └── rabbitmq │ │ ├── RabbitmqApplication.java │ │ ├── config │ │ └── RabbitConfig.java │ │ ├── controller │ │ ├── DelayController.java │ │ └── OrderController.java │ │ ├── enums │ │ └── ErrorCodeEnum.java │ │ ├── exception │ │ └── SystemException.java │ │ ├── model │ │ └── CreateOrderVo.java │ │ ├── receives │ │ └── OrderDelayConsumer.java │ │ ├── service │ │ ├── DelaySendService.java │ │ └── OrderService.java │ │ └── utils │ │ └── Message.java └── resources │ └── application.properties └── test └── java └── com └── wilson └── rabbitmq └── RabbitmqApplicationTests.java /README.md: -------------------------------------------------------------------------------- 1 | # RabbitMQ 延迟队列 2 | 3 | > 结合rabbitmq 的延迟队列实现类似未支付订单三十分钟自动取消功能,替代传统的采用后台定时任务方式取消过期订单的功能 4 | 5 | # 前言 6 | > 了解一下rabbitmq中的基本术语 7 | + 交换器 exchange: 消息首先到达mq中的地方 8 | + 队列 queue: 消息最终落地mq的地方 9 | + 路由键 routingKey: 消息到达exchange之后怎么知道需要去哪个队列中,就是根据路由键去匹配 10 | 11 | ## 何为绑定 12 | > 在rabbitmq中,队列和交换器是需要绑定的,绑定的时候需要指定前面说的路由键 13 | 14 | ## Exchange种类 15 | > rabbitmq中分为四种交换器,分别为Direct, Fanout, Topic, Header 下面分别简述一下 16 | 17 | + Direct 直接交换器,顾名思义,就是单一的路由规则,rabbitmq内置了一个Default Exchange 就是Direct类型的,当你申明一个队列未绑定交换器时,rmq会自动将该交换器绑定到默认的交换器,并指定路由键就是队列的名字。 18 | 19 | + Fanout 广播交换器,可以理解为一个消息到达该交换器后,会由该交换器将消息广播到所有绑定该交换器的队列中,且队列绑定时不需要指定路由键 20 | 21 | + Topic 通配符交换器,可以理解为该队列存在的意义就是可以将多种路由键的消息通配到一个队列中,比如你申明一个Topic 交换器,同时申明一个队列为ErrorQueue,绑定交换器时指定路由键为*.log,则所有生产的消息指定的路由键为a.log,b.log,c.log的消息都会进入该ErrorQueue队列。 22 | 23 | + Header 此交换器已经基本不再使用 24 | 25 | # 延迟队列 26 | > rabbitmq中延迟分为两种 27 | 28 | 1: 每一条消息上设置过期时间 29 | 30 | 2: 整个队列设置过期时间 31 | 32 | ## 图解延迟队列 33 | > 此处引用vector4wang的一张关于延迟队列的图解,很到位,也很容易理解 34 | ![图解延迟队列](D:\wilson\study\1.png) 35 | 36 | ## 最后奉上代码示例 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.wilson 7 | rabbitmq 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | rabbitmq 12 | rabbitmq delay queue 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.4.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-web 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-amqp 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-test 46 | test 47 | 48 | 49 | 50 | com.spring4all 51 | swagger-spring-boot-starter 52 | 1.7.1.RELEASE 53 | 54 | 55 | 56 | 57 | org.projectlombok 58 | lombok 59 | 1.16.18 60 | 61 | 62 | 63 | 64 | com.alibaba 65 | fastjson 66 | 1.2.3 67 | 68 | 69 | 70 | 71 | 72 | 73 | org.springframework.boot 74 | spring-boot-maven-plugin 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /src/main/java/com/wilson/rabbitmq/RabbitmqApplication.java: -------------------------------------------------------------------------------- 1 | package com.wilson.rabbitmq; 2 | 3 | import com.spring4all.swagger.EnableSwagger2Doc; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @EnableSwagger2Doc 8 | @SpringBootApplication 9 | public class RabbitmqApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(RabbitmqApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/wilson/rabbitmq/config/RabbitConfig.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @Copyright (c) 2018/8/17, Lianjia Group All Rights Reserved. 3 | */ 4 | package com.wilson.rabbitmq.config; 5 | 6 | import org.springframework.amqp.core.*; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | /** 11 | * rabbitmq config 12 | * 所有声明的这些queue,exchange,以及绑定关系会在第一次发送消息时建立在rabbitmq中。 13 | * @author wilson wei 14 | * @version 1.0 15 | * @since 2018/8/17 17:22 16 | */ 17 | @Configuration 18 | public class RabbitConfig { 19 | 20 | /******************************************************** 声明交换器 ************************************************************/ 21 | /** 22 | * 该交换器为直接交换器,定义了绑定delay_queue队列 23 | */ 24 | public final static String DELAY_EXCHANGE = "delay_exchange"; 25 | 26 | /** 27 | * 延迟消息队列交换器 28 | * 29 | * @return org.springframework.amqp.core.Exchange 30 | * @author wilson wei 31 | * @date 17:55 2018/8/17 32 | */ 33 | @Bean 34 | public Exchange delayExchange() { 35 | return ExchangeBuilder 36 | .directExchange(DELAY_EXCHANGE) 37 | .durable(true) 38 | .build(); 39 | } 40 | 41 | /** 42 | * 该交换器为直接交换器,定义了绑定process_queue队列 43 | */ 44 | public final static String PROCESS_EXCHANGE = "process_exchange"; 45 | 46 | /** 47 | * 正常处理队列交换器 48 | * 49 | * @return org.springframework.amqp.core.Exchange 50 | * @author wilson wei 51 | * @date 17:55 2018/8/17 52 | */ 53 | @Bean 54 | public Exchange processExchange() { 55 | return ExchangeBuilder 56 | .directExchange(PROCESS_EXCHANGE) 57 | .durable(true) 58 | .build(); 59 | } 60 | 61 | /** 62 | * 该交换器为直接交换器,定义了绑定delay_queue_queue队列 63 | * 此交换器对应的队列设置为固定过期时间的,不是每个消息自带过期时间 64 | */ 65 | public final static String DELAY_QUEUE_EXCHANGE = "delay_queue_exchange"; 66 | 67 | /** 68 | * 延迟队列交换器 69 | * 此交换器对应的队列设置为固定过期时间的,不是每个消息自带过期时间 70 | * 71 | * @return org.springframework.amqp.core.Exchange 72 | * @author wilson wei 73 | * @date 17:55 2018/8/17 74 | */ 75 | @Bean 76 | public Exchange delayQueueExchange() { 77 | return ExchangeBuilder 78 | .directExchange(DELAY_QUEUE_EXCHANGE) 79 | .durable(true) 80 | .build(); 81 | } 82 | /******************************************************** 声明队列 ************************************************************/ 83 | 84 | /** 85 | * 该队列没有直接消费者:而是定义了到达该队列的消息会在一定时间后过期,并在过期后进入到process queue队列中,每个消息都可以自定义自己的过期时间 86 | */ 87 | public final static String DELAY_QUEUE_MSG = "delay_queue"; 88 | 89 | /** 90 | * 延迟队列, 每个消息过期了都会自动发送给withArgument指定的exchange和指定的routing-key 91 | * 92 | * @return org.springframework.amqp.core.Queue 93 | * @author wilson wei 94 | * @date 18:02 2018/8/17 95 | */ 96 | @Bean 97 | public Queue delayQueue() { 98 | return QueueBuilder.durable(DELAY_QUEUE_MSG) 99 | // 延迟队列需要设置的消息过期后会发往的交换器名称 100 | .withArgument("x-dead-letter-exchange", PROCESS_EXCHANGE) 101 | // 延迟队列需要设置的消息过期后会发往的路由键名称 102 | .withArgument("x-dead-letter-routing-key", DELAY_ROUTING_KEY) 103 | .build(); 104 | } 105 | 106 | /** 107 | * 正常消费过期消息的队列,只有该队列有消费者 108 | */ 109 | public final static String PROCESS_QUEUE = "process_queue"; 110 | 111 | /** 112 | * 正常处理消息队列, 每个消息过期了都会自动路由到该队列绑定的交换器上 113 | * 普通队列声明只需要设置队列名称以及是否持久化等信息 114 | * 115 | * @return org.springframework.amqp.core.Queue 116 | * @author wilson wei 117 | * @date 18:02 2018/8/17 118 | */ 119 | @Bean 120 | public Queue processQueue() { 121 | return QueueBuilder.durable(PROCESS_QUEUE) 122 | .build(); 123 | } 124 | 125 | /** 126 | * 定义延迟队列,有固定过期时间的队列,指定名称为delay_queue_queue 127 | */ 128 | public static final String DELAY_QUEUE_QUEUE = "delay_queue_queue"; 129 | 130 | /** 131 | * 过期队列,指拥有固定过期时间的队列,其中的消息,每过30秒过期一次,全部转入到指定的x-dead-letter-xx 参数指定的交换器和路由键的队列中。 132 | * 133 | * @return org.springframework.amqp.core.Queue 134 | * @author wilson wei 135 | * @date 10:36 2018/8/19 136 | */ 137 | @Bean 138 | public Queue delayQueueQueue() { 139 | return QueueBuilder.durable(DELAY_QUEUE_QUEUE) 140 | .withArgument("x-dead-letter-exchange", PROCESS_EXCHANGE) 141 | .withArgument("x-dead-letter-routing-key", DELAY_ROUTING_KEY) 142 | .withArgument("x-message-ttl", 30000) 143 | .build(); 144 | } 145 | /******************************************************** 声明路由键 ************************************************************/ 146 | 147 | /** 148 | * 定义路由键,指定delay_queue 和 process_queue的路由规则 149 | */ 150 | public final static String DELAY_ROUTING_KEY = "delay"; 151 | 152 | /******************************************************** 声明绑定 ************************************************************/ 153 | // 当队列声明完成,交换器声明完成后,就需要进行二者的绑定,并制定路由键绑定的路由规则 154 | 155 | /** 156 | * 延迟队列绑定到延迟交换器,并制定路由键为 DELAY_ROUTING_KEY 157 | * 谁绑定到谁,并指定路由键 158 | * 159 | * @return org.springframework.amqp.core.Binding 160 | * @author wilson wei 161 | * @date 18:12 2018/8/17 162 | */ 163 | @Bean 164 | public Binding delayBiding() { 165 | return BindingBuilder.bind(delayQueue()) 166 | .to(delayExchange()) 167 | .with(DELAY_ROUTING_KEY).noargs(); 168 | } 169 | 170 | /** 171 | * 正常处理队列绑定到正常处理交换器,并制定路由键为 DELAY_ROUTING_KEY 172 | * 谁绑定到谁,并指定路由键 173 | * 174 | * @return org.springframework.amqp.core.Binding 175 | * @author wilson wei 176 | * @date 18:12 2018/8/17 177 | */ 178 | @Bean 179 | public Binding processBiding() { 180 | return BindingBuilder.bind(processQueue()) 181 | .to(processExchange()) 182 | .with(DELAY_ROUTING_KEY).noargs(); 183 | } 184 | 185 | /** 186 | * 功能描述 将过期队列绑定到过期队列交换器上,并指定路由键 187 | * @return org.springframework.amqp.core.Binding 188 | * @author wilson wei 189 | * @date 10:39 2018/8/19 190 | */ 191 | @Bean 192 | public Binding delayQueueBinding() { 193 | return BindingBuilder.bind(delayQueueQueue()) 194 | .to(delayQueueExchange()) 195 | .with(DELAY_ROUTING_KEY).noargs(); 196 | } 197 | /******************************************************* ********************************/ 198 | 199 | 200 | } 201 | -------------------------------------------------------------------------------- /src/main/java/com/wilson/rabbitmq/controller/DelayController.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @Copyright (c) 2018/8/19, Lianjia Group All Rights Reserved. 3 | */ 4 | package com.wilson.rabbitmq.controller; 5 | 6 | import com.wilson.rabbitmq.service.DelaySendService; 7 | import com.wilson.rabbitmq.utils.Message; 8 | import io.swagger.annotations.Api; 9 | import io.swagger.annotations.ApiOperation; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Controller; 12 | import org.springframework.web.bind.annotation.RequestBody; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.RequestMethod; 15 | import org.springframework.web.bind.annotation.RestController; 16 | 17 | /** 18 | * 延迟队列,每个消息发送时需要指定消息的过期时间 19 | * @author wilson wei 20 | * @version 1.0 21 | * @since 2018/8/19 9:56 22 | */ 23 | @Api(value = "1.0") 24 | @RestController 25 | @RequestMapping(value = "/api/delay") 26 | public class DelayController { 27 | 28 | @Autowired 29 | private DelaySendService delaySendService; 30 | 31 | @ApiOperation(value = "发送延时消息,每个消息都有自己的过期时间", notes = "消息自带过期时间") 32 | @RequestMapping(value = "/msg", method = RequestMethod.POST) 33 | public String sendDelayMessage(@RequestBody Message message) { 34 | 35 | delaySendService.sendDelayMessage(message); 36 | return "success"; 37 | } 38 | 39 | @ApiOperation(value = "发送延时消息队列,整个队列有自己的过期时间", notes = "队列整体有固定的过期时间") 40 | @RequestMapping(value = "/queue/msg", method = RequestMethod.POST) 41 | public String sendDelayQueueMessage(@RequestBody Message message) { 42 | 43 | delaySendService.sendDelayQueueMessage(message); 44 | return "success"; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/wilson/rabbitmq/controller/OrderController.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @Copyright (c) 2018/8/19, Lianjia Group All Rights Reserved. 3 | */ 4 | package com.wilson.rabbitmq.controller; 5 | 6 | import com.wilson.rabbitmq.model.CreateOrderVo; 7 | import com.wilson.rabbitmq.service.OrderService; 8 | import com.wilson.rabbitmq.utils.Message; 9 | import io.swagger.annotations.Api; 10 | import io.swagger.annotations.ApiOperation; 11 | import io.swagger.annotations.ApiParam; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.web.bind.annotation.RequestBody; 14 | import org.springframework.web.bind.annotation.RequestMapping; 15 | import org.springframework.web.bind.annotation.RequestMethod; 16 | import org.springframework.web.bind.annotation.RestController; 17 | 18 | import javax.servlet.http.HttpServletRequest; 19 | 20 | /** 21 | * 订单控制器 22 | * @author wilson wei 23 | * @version 1.0 24 | * @since 2018/8/19 11:17 25 | */ 26 | @Api(value = "1.0") 27 | @RestController 28 | @RequestMapping(value = "/api/order") 29 | public class OrderController { 30 | 31 | @Autowired 32 | private OrderService orderService; 33 | 34 | @ApiOperation(value = "模拟用户下单", notes = "下单后三十分钟未支付,系统自动取消订单") 35 | @RequestMapping(value = "", method = RequestMethod.POST) 36 | public String sendDelayMessage(@ApiParam(name = "订单", value = "order", required = true) @RequestBody CreateOrderVo order, HttpServletRequest request) { 37 | 38 | orderService.createOrder(order); 39 | String token = request.getHeaders("token").nextElement().toString(); 40 | System.out.println(token); 41 | return "success"; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/wilson/rabbitmq/enums/ErrorCodeEnum.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @Copyright (c) 2018/8/19, Lianjia Group All Rights Reserved. 3 | */ 4 | package com.wilson.rabbitmq.enums; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * 枚举注释 10 | * @author wilson wei 11 | * @version 1.0 12 | * @since 2018/8/19 11:47 13 | */ 14 | public enum ErrorCodeEnum { 15 | 16 | UNKNOWING_ERROR("000001", "服务器未知异常"), 17 | ; 18 | 19 | private String message; 20 | 21 | private String code; 22 | 23 | ErrorCodeEnum(String message, String code) { 24 | this.message = message; 25 | this.code = code; 26 | } 27 | 28 | public String getMessage() { 29 | return message; 30 | } 31 | 32 | public String getCode() { 33 | return code; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/wilson/rabbitmq/exception/SystemException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @Copyright (c) 2018/8/19, Lianjia Group All Rights Reserved. 3 | */ 4 | package com.wilson.rabbitmq.exception; 5 | 6 | import com.wilson.rabbitmq.enums.ErrorCodeEnum; 7 | 8 | /** 9 | * 系统类异常,如数据库崩溃,mq崩溃 10 | * @author wilson wei 11 | * @version 1.0 12 | * @since 2018/8/19 11:44 13 | */ 14 | public class SystemException extends RuntimeException { 15 | 16 | /** 错误码 */ 17 | private ErrorCodeEnum errorCode; 18 | 19 | /** 是否打印ERROR 级别日志 */ 20 | private Boolean printError; 21 | 22 | public SystemException(ErrorCodeEnum errorCode){ 23 | super(errorCode.getMessage()); 24 | this.errorCode = errorCode; 25 | this.printError = true; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/wilson/rabbitmq/model/CreateOrderVo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @Copyright (c) 2018/8/19, Lianjia Group All Rights Reserved. 3 | */ 4 | package com.wilson.rabbitmq.model; 5 | 6 | import io.swagger.annotations.ApiModelProperty; 7 | import lombok.Data; 8 | 9 | /** 10 | * 下订单 11 | * @author wilson wei 12 | * @version 1.0 13 | * @since 2018/8/19 11:19 14 | */ 15 | @Data 16 | public class CreateOrderVo { 17 | 18 | @ApiModelProperty(name = "所购买图书id", required = true, dataType = "Long", example = "1008") 19 | private Long bookId; 20 | 21 | @ApiModelProperty(name = "所购买图书名称", required = true, dataType = "String", example = "红楼梦") 22 | private String bookName; 23 | 24 | @ApiModelProperty(name = "图书价格", hidden = true) 25 | private String price; 26 | 27 | @ApiModelProperty(name = "订单编号", hidden = true) 28 | private String orderNo; 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/wilson/rabbitmq/receives/OrderDelayConsumer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @Copyright (c) 2018/8/19, Lianjia Group All Rights Reserved. 3 | */ 4 | package com.wilson.rabbitmq.receives; 5 | 6 | import com.alibaba.fastjson.JSONObject; 7 | import com.wilson.rabbitmq.model.CreateOrderVo; 8 | import com.wilson.rabbitmq.utils.Message; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.amqp.rabbit.annotation.RabbitHandler; 11 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 12 | import org.springframework.stereotype.Component; 13 | 14 | /** 15 | * 类注释 16 | * @author wilson wei 17 | * @version 1.0 18 | * @since 2018/8/19 11:53 19 | */ 20 | @Component 21 | @RabbitListener(queues = "process_queue") 22 | @Slf4j 23 | public class OrderDelayConsumer { 24 | 25 | @RabbitHandler 26 | public void orderConsumer(Message message){ 27 | 28 | // 接收到处理队列中的消息的,就是指定时间过期的消息 29 | // 这里处理每一条消息中的订单编号,去查询对应的订单支付状态,如果处于未支付状态,就取消用户的订单 30 | try { 31 | CreateOrderVo orderVo = JSONObject.parseObject(message.getContent(), CreateOrderVo.class); 32 | // 获取订单编号,去查询对应的支付结果 33 | log.info("订单编号为: {}", orderVo.getOrderNo()); 34 | } catch (Exception e) { 35 | log.error("订单消息解析异常,请检查消息格式是否正确", message.getContent()); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/wilson/rabbitmq/service/DelaySendService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @Copyright (c) 2018/8/19, Lianjia Group All Rights Reserved. 3 | */ 4 | package com.wilson.rabbitmq.service; 5 | 6 | import com.alibaba.fastjson.JSONObject; 7 | import com.wilson.rabbitmq.config.RabbitConfig; 8 | import com.wilson.rabbitmq.enums.ErrorCodeEnum; 9 | import com.wilson.rabbitmq.exception.SystemException; 10 | import com.wilson.rabbitmq.utils.Message; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.springframework.amqp.AmqpException; 13 | import org.springframework.amqp.core.AmqpTemplate; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.stereotype.Service; 16 | 17 | import java.text.SimpleDateFormat; 18 | import java.util.Date; 19 | 20 | /** 21 | * 延迟消息service 22 | * 23 | * @author wilson wei 24 | * @version 1.0 25 | * @since 2018/8/19 10:02 26 | */ 27 | @Service 28 | @Slf4j 29 | public class DelaySendService { 30 | 31 | @Autowired 32 | private AmqpTemplate rabbitTemplate; 33 | 34 | /** 35 | * 发送延时消息,每个消息都自己有自己的过期时间 36 | * 37 | * @param msg 消息 38 | * @author wilson wei 39 | * @date 10:03 2018/8/19 40 | */ 41 | public void sendDelayMessage(Message msg) { 42 | 43 | // 消息发送时间 44 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 45 | log.info("消息发送时间为: {}", sdf.format(new Date())); 46 | 47 | // 设置发送时间,开始发送 48 | try { 49 | rabbitTemplate.convertAndSend(RabbitConfig.DELAY_EXCHANGE, RabbitConfig.DELAY_ROUTING_KEY, msg, 50 | message -> { 51 | message.getMessageProperties().setExpiration(String.valueOf(msg.getTtl())); 52 | return message; 53 | }); 54 | } catch (AmqpException e) { 55 | log.error("消息发送失败,请检查消息中间件是否正常", JSONObject.toJSONString(msg)); 56 | throw new SystemException(ErrorCodeEnum.UNKNOWING_ERROR); 57 | } 58 | } 59 | 60 | /** 61 | * 发送消息,至指定过期时间的队列中。 62 | * 适用于一些定时任务 63 | * @param msg 64 | * @author wilson wei 65 | * @date 10:40 2018/8/19 66 | */ 67 | public void sendDelayQueueMessage(Message msg) { 68 | 69 | // 消息发送时间 70 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 71 | log.info("消息发送时间为: {}", sdf.format(new Date())); 72 | 73 | // 设置发送时间,开始发送 74 | try { 75 | rabbitTemplate.convertAndSend(RabbitConfig.DELAY_QUEUE_EXCHANGE, RabbitConfig.DELAY_ROUTING_KEY, msg); 76 | } catch (AmqpException e) { 77 | log.error("消息发送失败,请检查消息中间件是否正常", JSONObject.toJSONString(msg)); 78 | throw new SystemException(ErrorCodeEnum.UNKNOWING_ERROR); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/wilson/rabbitmq/service/OrderService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @Copyright (c) 2018/8/19, Lianjia Group All Rights Reserved. 3 | */ 4 | package com.wilson.rabbitmq.service; 5 | 6 | import com.alibaba.fastjson.JSONObject; 7 | import com.wilson.rabbitmq.model.CreateOrderVo; 8 | import com.wilson.rabbitmq.utils.Message; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Service; 11 | 12 | import java.util.concurrent.TimeUnit; 13 | 14 | /** 15 | * 订单service 16 | * @author wilson wei 17 | * @version 1.0 18 | * @since 2018/8/19 11:24 19 | */ 20 | @Service 21 | public class OrderService { 22 | 23 | @Autowired 24 | private DelaySendService delaySendService; 25 | 26 | /** 27 | * 功能描述 模拟用户购买图书下单 28 | * @param order 图书订单 29 | * @author wilson wei 30 | * @date 11:25 2018/8/19 31 | */ 32 | public void createOrder(CreateOrderVo order) { 33 | 34 | // 参数校验,获取图书实际价格等 35 | 36 | // 根据规则生成订单编号,下单,插入数据库中 37 | 38 | // 拿到订单编号,发送下单消息到rabbitmq中 39 | String orderNo = "100000000201808191000982091"; 40 | 41 | order.setOrderNo(orderNo); 42 | 43 | // 封装消息内容 44 | Message message = new Message(); 45 | message.setContent(JSONObject.toJSONString(order)); 46 | 47 | message.setId(1); 48 | // 三十分钟时效,自动取消订单 49 | message.setTtl(15, TimeUnit.MINUTES); 50 | delaySendService.sendDelayMessage(message); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/wilson/rabbitmq/utils/Message.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @Copyright (c) 2018/8/19, Lianjia Group All Rights Reserved. 3 | */ 4 | package com.wilson.rabbitmq.utils; 5 | 6 | import io.swagger.annotations.ApiModelProperty; 7 | import lombok.Data; 8 | 9 | import java.io.Serializable; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | /** 13 | * 消息类 14 | * @author wilson wei 15 | * @version 1.0 16 | * @since 2018/8/19 9:49 17 | */ 18 | @Data 19 | public class Message implements Serializable { 20 | 21 | @ApiModelProperty(name = "消息id") 22 | private Integer id; 23 | 24 | @ApiModelProperty(name = "消息内容", dataType = "String", required = true, example = "这是一个测试过期时间为3分钟的消息") 25 | private String content; 26 | 27 | @ApiModelProperty(name = "过期时间", dataType = "Long", required = true) 28 | private Long ttl; 29 | 30 | /** 31 | * 功能描述 设置消息过期时间 32 | * @author wilson wei 33 | * @date 11:38 2018/8/19 34 | */ 35 | public void setTtl(int number, TimeUnit unit) { 36 | this.setTtl(unit.toMillis(number)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuyuan1992/spring-boot-rabbitmq/b288cb7cb08ba49818dfd39241813102588777a8/src/main/resources/application.properties -------------------------------------------------------------------------------- /src/test/java/com/wilson/rabbitmq/RabbitmqApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.wilson.rabbitmq; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class RabbitmqApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | --------------------------------------------------------------------------------