SpringBoot 集成 rabbitmq 简单实现通过队列进行,订单系统与库存系统,物流系统之间的信息交互...

SpringBoot 集成 rabbitmq 简单实现创建订单、减少库存、创建物流即应用解耦

队列实现方式:
订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功。
库存系统:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作
物流系统:用户下单后,创建用户的物流信息
假如:在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦

详细代码访问我的github:https://github.com/ningcs/reservemq

项目结构:

 

项目结构描述:

eureka :项目注册与发现。

所有项目都注册到这个地址,方便三个系统之间通过feignClient进行数据交互。(eureka详细注册与发现这里不过多描述)

eureka 配置文件:

spring.application.name=eureka-server
server.port=1001
eureka.instance.hostname=localhost
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
##禁用自我保护模式
#eureka.server.enable-self-preservation=false
#eureka.instance.prefer-ip-address=true
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/

reserve-provider-service:订单系统,消费者从订单系统发起订单,同时告知物流和库存系统。

reserve-receiver-service:库存系统。获取库存量,减少库存等。

reserve-wuliu-receiver-service: 物流系统。订单完成,告知物流系统创建该用户的物流信息。

项目所需jar包:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
</dependency>
<!-- 添加springboot对amqp的支持 -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <scope>runtime</scope>
</dependency>
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-commons</artifactId>
   <version>1.2.4.RELEASE</version>
</dependency>
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

订单系统:

通过一个简单的购买页面,模拟用户购买时的状况。

package com.example.demo.controller;

import com.example.demo.dto.OrderInfo;
import com.example.demo.dto.ReserveInfo;
import com.example.demo.entity.Product;
import com.example.demo.service.OrderService;
import com.example.demo.service.ReserveService;
import com.example.demo.util.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

/**
 * Created by ningcs on 2017/10/30.
 */
@Controller
@RequestMapping("rabbit")
public class RabbitController {



    @Autowired
    private ReserveService reserveService;

    @Autowired
    private OrderService orderService;


//
//    @RequestMapping(value = "/hello",method = {RequestMethod.GET, RequestMethod.POST})
//    public String helloSender(){
//        helloSender.send("hello,rabbit~");
//        return "发送成功";
//    }
    @RequestMapping(value = "/createOrderPage",method = {RequestMethod.GET, RequestMethod.POST})
    public ModelAndView createOrderPage(Integer productId){
        productId=1;
        ModelAndView modelAndView =new ModelAndView("/index");
        //获取库存余量
        ReserveInfo reserve =reserveService.getReserveCount(productId);
        Product product =orderService.getProductById(productId);
        if (reserve!=null && product!=null){
            modelAndView.addObject("total",reserve.getTotalCount()-reserve.getCurrentCount());
            modelAndView.addObject("product",product);
            modelAndView.addObject("userId",2);
        }

        return modelAndView;
    }


    @RequestMapping(value = "/createOrder",method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ResponseResult createOrder(Integer productId, Integer  count,Integer userId){
        if (count==null || count<=0){
            return ResponseResult.errorResult("购买数量不能为空或为0");
        }
        DecimalFormat df   = new DecimalFormat("#.00");
        Product product =orderService.getProductById(productId);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmm");
        OrderInfo orderInfo =new OrderInfo();
        orderInfo.setProductId(productId);
        orderInfo.setBuyCount(count);
        orderInfo.setUserId(userId);
        //保留两位小数
        orderInfo.setMonetary(""+df.format(Double.parseDouble(product.getProductPrice())*count));
        orderInfo.setOrderId(getTenRandomLetter()+sdf.format(new Date())+"_"+userId+"_"+productId);
        orderInfo.setProductName(product.getProductName());
        //创建订单 向库存系统 和物流系统发送消息
        orderService.addOrder(orderInfo);
        return ResponseResult.successResult("生成订单成功");
    }

    /**
     * 从26为字母中获得一个6位随机数(纯字母)
     * ok
     */
    public static String getTenRandomLetter() {
        String word = "abcdefghijklmnopqrstuvwxyz";
        String tmp = "";

        for (int i = 0; i < 6; i++) {
            Random random = new Random();
            Integer index = random.nextInt(word.length());
            char c = word.charAt(index);
            tmp = tmp + c;
        }
        return tmp;
    }
}

service: 将订单,和mq放在一个事物里面,创建订单成功后,会通过队列告知库存系统减少库存,物流系统创建该用户的物流信息。

package com.example.demo.service.impl;

import com.example.demo.dao.OrderDao;
import com.example.demo.dto.OrderInfo;
import com.example.demo.entity.Product;
import com.example.demo.sender.HelloSender;
import com.example.demo.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * Created by ningcs on 2017/11/20.
 */
@Service
public class OrderServiceImpl implements OrderService{

    @Autowired
    private OrderDao orderDao;

    @Autowired
    private HelloSender helloSender;
    @Override
    public Product getProductById(Integer productId) {

        return orderDao.getProductById(productId);
    }

    @Override
    @Transactional
    public void addOrder(OrderInfo orderInfo) {
        orderDao.addOrder(orderInfo);
        helloSender.send(orderInfo);
    }
}

队列配置:

package com.example.demo.conf;

import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Created by ningcs on 2017/10/30.
 */
@Configuration
public class SenderConf {
    @Bean
    public Queue queueOrder() {
        return new Queue("queueOrder1");
    }

    @Bean
    public Queue queueOrder2() {
        return new Queue("queueOrder2");
    }
}

订单系统的配置文件:页面框架使用的freemark

server.port=17073
eureka.client.service-url.defaultZone=http://127.0.0.1:1001/eureka/
spring.application.name=spirng-boot-rabbitmq-sender

spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=ncs
spring.rabbitmq.password=12345678
spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.virtual-host=/

spring.rabbitmq.listener.concurrency=1
spring.rabbitmq.listener.max-concurrency=5

spring.resources.static-locations=classpath:/static/
spring.freemarker.template-loader-path=classpath:/views/templates/
spring.freemarker.cache=false
spring.freemarker.charset=UTF-8
spring.freemarker.check-template-location=true
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=true
spring.freemarker.expose-session-attributes=true
spring.freemarker.request-context-attribute=request
spring.freemarker.suffix=.ftl



spring.datasource.url=jdbc:mysql://**.**.206.***:3306/order?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
spring.datasource.username=***
spring.datasource.password=pning*****
spring.datasource.driver-class-name=com.mysql.jdbc.Driver


feign.hystrix.enabled=false

库存系统:相当于消费者 ,接收创建订单成功后,减少库存。

package com.example.demo.receiver;

import com.example.demo.dto.OrderInfo;
import com.example.demo.service.ReserveService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * Created by ningcs on 2017/10/30.
 */
@Component
public class HelloReceive {
    Log log = LogFactory.getLog(getClass());

    @Autowired
    ReserveService reserveService;
    @RabbitListener(queues="queueOrder1")    //监听器监听指定的Queue
    public void queueOrder1(OrderInfo orderInfo) {
        Integer count=0;
        if (orderInfo!=null){
            count=  reserveService.updateReserveCount(orderInfo.getBuyCount(),orderInfo.getProductId());
            log.info("Receive:队列:queueOrder1 商品名字:"+orderInfo.getProductName()+",商品购买数量:"+orderInfo.getBuyCount());
        }
    }

    @RabbitListener(queues="queueOrder2")    //监听器监听指定的Queue
    public void queueOrder2(OrderInfo orderInfo) {
        Integer count=0;
        if (orderInfo!=null){
           count=  reserveService.updateReserveCount(orderInfo.getBuyCount(),orderInfo.getProductId());
            log.info("Receive:队列:queueOrder2 商品名字:"+orderInfo.getProductName()+",商品购买数量:"+orderInfo.getBuyCount());
        }
    }

}

物流系统:相当于消费者 ,接收创建订单成功后,创建该用户的物流信息。

package com.example.demo.receiver;

import com.example.demo.dto.OrderInfo;
import com.example.demo.service.WuliuService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * Created by ningcs on 2017/10/30.
 */
@Component
public class HelloReceive {
    Log log = LogFactory.getLog(getClass());

    @Autowired
    private WuliuService wuliuService;
    @RabbitListener(queues="queueWuLiu1")    //监听器监听指定的Queue
    public void queueOrder1(OrderInfo orderInfo) {
        if (orderInfo!=null){
            wuliuService.addWuliu(orderInfo);
            log.info("Receive:队列:queueWuLiu1 商品名字:"+orderInfo.getProductName()+",商品购买数量:"+orderInfo.getBuyCount());
        }
    }

    @RabbitListener(queues="queueWuLiu2")    //监听器监听指定的Queue
    public void queueOrder2(OrderInfo orderInfo) {
        Integer count=0;
        if (orderInfo!=null){
            wuliuService.addWuliu(orderInfo);
            log.info("Receive:队列:queueWuLiu2 商品名字:"+orderInfo.getProductName()+",商品购买数量:"+orderInfo.getBuyCount());
        }
    }
}

 

 

简单购买页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <script src="/js/jquery.js"></script>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>

<form id="form">
    <div class="form-group">
        <label for="name">名称:</label>
        <input type="text" id="productName" disabled value="${product.productName}">
    </div>
    <div class="form-group">
        <label for="count">购买数量:</label>
        <input type="number" id="count"  value="">
    </div>
    <div class="form-group">
        <label for="count">单价:</label>
        <p class="form-control-static" id="price">${product.productPrice}</p>
    </div>
    <div class="form-group">
        <label for="count">库存:</label>
        <p class="form-control-static" id="total">${total}</p>
    </div>
    <div class="form-group">
        <a href="javascript:void(0);" id="sub">购买</a>
    </div>
</form>


<script>
$('#sub').click(function () {
    $.ajax({
        url: '/rabbit/createOrder',
        type: 'post',
        data: {
            productId: ${product.id},
            count: $('#count').val(),
            userId: ${userId}
        },
        dataType: 'json',
        cache: false,
        success: function (json) {
            if(json.code==0){
        window.location.reload();
            }else {
                alert(json.msg);
            }

        },
        error: function () {
            alert('出错');

        }
    });
    return false;
});

</script>
</body>
</html>

本文只是自己经过简单的构思,对Springboot和rabbitmq的集成设计的订单、物流、库存写的一个简单的例子,只是构思了大抵的思路,并通过简单的代码实现,并没有用到什么先进的技术和严密的构思。甚至还有很多缺陷,望大家多多指导,也希望对初学者有所帮助。

详细代码地址访问我的github:https://github.com/ningcs/reservemq

 

 

 

 

 

转载于:https://my.oschina.net/u/2851681/blog/1576927

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值