Spring boot + RabbitMQ 整合(模块化)

数据库部分

虚拟机部分

代码部分

项目名称 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的时间是否正确

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值