数据库部分
虚拟机部分
代码部分
项目名称 rabbitmq-order,分为模块化创建了多个模块
entity : rabbitmq-order-entity
mapper: rabbitmq-order-mapper
service: rabbitmq-order-service
consumer:rabbitmq-order-consumer
根:
pom.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.etoal.et2106.rabbitmq</groupId>
<artifactId>rabbitmq-order</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<!-- 创建 module 自动生成的-->
<module>rabbitmq-order-entity</module>
<module>rabbitmq-order-mapper</module>
<module>rabbitmq-order-service</module>
<module>rabbitmq-order-delay-consumer</module>
</modules>
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.7</version>
</parent>
<dependencyManagement>
<dependencies>
<!-- 提供了springboot统一的依赖管理和插件管理 -->
<dependency>
<groupId>com.etoak.et2106.rabbitmq</groupId>
<artifactId>rabbitmq-order-entity</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 子模块提供的组件 -->
<dependency>
<groupId>com.etoal.et2106.rabbitmq</groupId>
<artifactId>rabbitmq-order-mapper</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- MyBatis-plus是一款MyBatis的增强工具,在MyBatis 基础上改的 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.4.3.1</version>
</dependency>
<!-- -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.1</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
rabbitmq-order-entity层级目录
entity的pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>rabbitmq-order</artifactId>
<groupId>com.etoal.et2106.rabbitmq</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>rabbitmq-order-entity</artifactId>
<dependencies>
<!-- 可以通过注解的方实现一大堆的 get set toSting ..... 方法 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- mybatis 的牛逼版 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<!-- 设置连个项目之间依赖不传递 -->
<optional>true</optional>
</dependency>
</dependencies>
</project>
entity下的Order
package com.etoak.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/*
* 自动生成一窝get set toString equals 啥的*/
@Data
/*绑定具体数据库的名称*/
@TableName("t_order")
public class Order {
/*指定当前列自动增长*/
@TableId(type = IdType.AUTO)
private Integer id;
private String orderNo;
private Integer orderStatus;
private Integer payStatus;
private String createTime;
private String cancelTime;
}
rabbitmq-order-mapper层级目录
mapper的pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>rabbitmq-order</artifactId>
<groupId>com.etoal.et2106.rabbitmq</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>rabbitmq-order-mapper</artifactId>
<dependencies>
<!-- 引入工程内的rabbtmq -->
<dependency>
<artifactId>rabbitmq-order-entity</artifactId>
<groupId>com.etoal.et2106.rabbitmq</groupId>
</dependency>
<!-- 牛逼版 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<optional>true</optional>
</dependency>
<!-- -->
<dependency>
<groupId>com.etoal.et2106.rabbitmq</groupId>
<artifactId>rabbitmq-order-entity</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
mapper的OrderMapper
package com.etoak.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.etoak.entity.Order;
/**
* 接口,继承BaseMapper,自定义的mapper 继承了后,可以有些简单的sql 就不用自己的写了
*/
public interface OrderMapper extends BaseMapper<Order> {
}
rabbitmq-order-service层级目录
service的xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>rabbitmq-order</artifactId>
<groupId>com.etoal.et2106.rabbitmq</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>rabbitmq-order-service</artifactId>
<dependencies>
<!-- 引入同一个项目中的子模块 -->
<dependency>
<groupId>com.etoal.et2106.rabbitmq</groupId>
<artifactId>rabbitmq-order-mapper</artifactId>
</dependency>
<!-- 引入后可以实现web场景开发,不需要从外部引入tomcat服务器,以及其他的web依赖文件,省事 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入后可以操作rabbitmq -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- 拦截数据库用的 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!-- 工具类,省事,各种get set toString equals -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 国产良心工具类,本土化发展的 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.13</version>
</dependency>
</dependencies>
</project>
resources下的application.yml
#服务
server:
port: 8003
#spring 数据源
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///et2106?serverTimezone=UTC
username: root
password: etoak
#rabbitmq 的配置
rabbitmq:
host: 192.168.132.139
port: 5672
username: et
password: etoak
virtual-host: /et
listener:
simple:
#手动确认
acknowledge-mode: manual
启动文件: OrderserverApp
package com.etoak;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;
//Spring 项目中开始spring自动配置,是springboot 的核心配置类
@SpringBootApplication
/*
对应xml文件中的配置属性,自动扫描并且加载符合条件的组件,
比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中,
basePackages,指定的扫描的基本包
* */
@MapperScan(basePackages = "com.etoak.mapper")
/*t 开启事务支持后,
然后在访问数据库的Service方法上添加注解 @Transactional
*/
@EnableTransactionManagement
public class OrderServerApp {
public static void main(String[] args) {
//SpringApplication是Springboot驱动Spring上下文的引导类,
// run() 启动spring应用,
// 实质上是为Spring应用创建并初始化Spring上下文。
SpringApplication.run(OrderServerApp.class,args);
}
}
controller下的OrderController
package com.etoak.controller;
import com.etoak.entity.Order;
import com.etoak.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @RestController注解相当于@ResponseBody + @Controller合在一起的作用
* 返回json数据不需要在方法前面加@ResponseBody注解了,
* 但使用@RestController这个注解,
* 就不能返回jsp,html页面,视图解析器无法解析jsp,html页面
*
*/
@RestController
public class OrderController {
/*1.引入 orderService 使用他的属性方法*/
@Autowired
OrderService orderService;
/* 提供外部请求访问的地址
* 后面可以跟参数额可以不跟默认 600000
*
* */
@RequestMapping("/create")
/**
* 用来添加创建Order的
* @RequestParam 把请求参数绑定指定是方法的那个参数,required:定义这个参数是否为必须 defaultValue:默认值是多少
*/
public String createOrder(@RequestParam(required = false,defaultValue = "600000")int delay) {
/**
* 调用Orderserver的方法传入一个新的Order,后期可以指定是啥样的Order
*/
orderService.createOrder(new Order(),delay);
/*到这说明执行成功了*/
return "Success";
}
}
service下的Orderservice
package com.etoak.service;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.etoak.config.OrderDelayConfig;
import com.etoak.entity.Order;
import com.etoak.mapper.OrderMapper;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
/**
* 自动把这个类注册到Spring容器
*/
@Service
public class OrderService {
//生命两个状态码 创建的,没付钱的
public static final int CREATE = 1;
public static final int NO_PAY = 1;
//引入OrderMapper
@Autowired
OrderMapper orderMapper;
//引入RabbitTemplate 负责实现rabbirt队列的类
@Autowired
RabbitTemplate rabbitTemplate;
//开启事务
@Transactional
//添加order 的方法,需要一个order,还有延迟时间
public int createOrder(Order order,int delay) {
//生成简单的id,唯一识别码
String orderNo = IdUtil.getSnowflake().nextIdStr();
//简单的方式大得到当前的时间,
String createTime = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
//对这个Order 设置 id 创建状态,支付状态,创建时间
order.setOrderNo(orderNo);
order.setOrderStatus(CREATE);
order.setPayStatus(NO_PAY);
order.setCreateTime(createTime);
//入库 添加到数据库
int result = orderMapper.insert(order);
//发送消息到延迟队列,
/*
* 发送消息,到对应交换机,
* 参数: 交换机,路由,对应id,对应消息
* */
rabbitTemplate.convertAndSend(OrderDelayConfig.EXCHANGE,OrderDelayConfig.ROUTING_KEY,orderNo,
//设置延迟事件,不是过期时间
message -> {
/* 设置消息的属性,设置延迟*/
message.getMessageProperties().setDelay(delay);
return message;
});
/* 执行到这说明没问题,返回添加数据库返回值 */
return result;
}
}
config下的OrderDelayConfig
package com.etoak.config;
import com.rabbitmq.client.BuiltinExchangeType;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.CustomExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class OrderDelayConfig {
//定义交换机 名字,队列名字,路由key
public static final String EXCHANGE = "order.exchange";
public static final String QUEUE = "order.queue";
public static final String ROUTING_KEY = "order.delay";
/**
* 使用插件,rabbitmq 安装的插件 rabbitmq_delayed_message_exchange-3.8.0
*/
@Bean
public CustomExchange orderExchange() {
/*
* 这里的Map 是参数要求的
* */
Map<String,Object> args = new HashMap<>();
//定义属性延迟
args.put("x-delayed-type", BuiltinExchangeType.DIRECT.getType());
/**
* CustomExchange()
* 1.名称
* 2.类型 设定交换机类型为延迟类型
* 3.是否持久化
* 4.是否自动删除
* 5.其他参数
*/
return new CustomExchange(EXCHANGE,"x-delayed-message",true,false,args);
}
@Bean
/*
*定义一个队列
* */
public Queue orderQueue() {
return new Queue(QUEUE);
}
@Bean
/*
* 进行绑定 BindingBuilder 也是一种绑定的方式
* */
public Binding orderBinding() {
return BindingBuilder
.bind(orderQueue())
.to(orderExchange())
.with(ROUTING_KEY)
.noargs();
}
}
rabbitmq-order-delay-consumer层级目录
comsumer的pom.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>rabbitmq-order</artifactId>
<groupId>com.etoal.et2106.rabbitmq</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>rabbitmq-order-delay-consumer</artifactId>
<dependencies>
<!--WEB 组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入后可以操作rabbitmq -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- 同工程下的子组件 -->
<dependency>
<groupId>com.etoal.et2106.rabbitmq</groupId>
<artifactId>rabbitmq-order-mapper</artifactId>
</dependency>
<!-- 数据库 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 升级版 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!-- 工具包 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.13</version>
</dependency>
</dependencies>
</project>
resources下的application.yml
#服务
server:
port: 8003
#spring 数据源
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///et2106?serverTimezone=UTC
username: root
password: etoak
#rabbitmq 的配置
rabbitmq:
host: 192.168.132.139
port: 5672
username: et
password: etoak
virtual-host: /et
listener:
simple:
acknowledge-mode: manual
启动项 ConsumerApp
package com.etoak;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/* 开启Spring boot 的自动配置*/
@SpringBootApplication
/*指定扫描的位置*/
@MapperScan(basePackages = "com.etoak.mapper")
/*开启事务*/
@EnableTransactionManagement
public class ConsumerApp {
//SpringApplication.run 核心方法,启动Spring应用
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
}
sercvice下的ConcelService
package com.etoak.service;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.etoak.entity.Order;
import com.etoak.mapper.OrderMapper;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.util.Date;
@Service
public class ConcelService {
/*
* 1.接收消息(orderNo)
* 2.根据OrderNo查询t_order表的状态
* 如果order_status =1 && pay_status =1,执行取消订单(order_status=3 自动取消)
* */
/* 引入OrderMapper 为待会的和数据库做交换做准备 */
@Autowired
OrderMapper orderMapper;
/* 指定所监听的队列 order.queue*/
@RabbitListener(queues = "order.queue")
/* 开启事务 rollbackFor有问题就回滚*/
@Transactional(rollbackFor = Exception.class)
/*
*因为是监听的队列所以是直接运行的,只要有消息就回消费,获得到消息,还有对应的channel
* */
public void handle(Message message, Channel channel) throws IOException {
//得到队列里消息的orderNo
String orderNo = new String(message.getBody());
//调用方法 得到order
Order order = this.getOrder(orderNo);
//如果是新增订单并且未支付,
if(order.getOrderStatus() == 1 && order.getPayStatus() == 1){
//3.自动取消,设置为3
order.setOrderStatus(3);
/*设置当前的修改时间*/
order.setCancelTime(DateUtil.format(new Date(),"yyyy-MM-dd HH:mm:ss"));
//对order进行修改
orderMapper.updateById(order);
}
//对当前操作的信道进行处理,手动确认: 参数 标签, :为了减少网络流量,手动确认可以被批处理,当该参数为 true 时,则可以一次性确认 delivery_tag 小于等于传入值的所有消息
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
}
public Order getOrder(String orderNo){
QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
/* 用得到的orderNo进行查询*/
queryWrapper.select("id","order_no","order_status","pay_status").eq("order_no",orderNo);
/*吧查到的Order 返回去*/
return orderMapper.selectOne(queryWrapper);
}
}
测试: 启动
rabbitmq-order-server 的启动类,然后再浏览器地输入
locathost:8002/create?delay
locathost:8002/create?delay=3000
locathost:8002/create?delay=30000
然后查看rabbitmq 的后台关于queue 的消息条数,应当是随着时间进行添加的
然后启动
rabbitmq-order-delay-consumer
然后去rabbitmq 的后台查看,队里里面的消息是否还存在.应当是被处理完毕,然后去数据库查看没一个roder 的 cancel_time的时间是否正确