SpringBoot 集成 rabbitmq 簡單實現經過隊列進行,訂單系統與庫存系統,物流系統之間的信息交互

SpringBoot 集成 rabbitmq 簡單實現建立訂單、減小庫存、建立物流即應用解耦javascript

隊列實現方式:
訂單系統:用戶下單後,訂單系統完成持久化處理,將消息寫入消息隊列,返回用戶訂單下單成功。
庫存系統:訂閱下單的消息,採用拉/推的方式,獲取下單信息,庫存系統根據下單信息,進行庫存操做
物流系統:用戶下單後,建立用戶的物流信息
假如:在下單時庫存系統不能正常使用。也不影響正常下單,由於下單後,訂單系統寫入消息隊列就再也不關心其餘的後續操做了。實現訂單系統與庫存系統的應用解耦html

詳細代碼訪問個人github:https://github.com/ningcs/reservemqjava

項目結構:mysql

 

項目結構描述:jquery

eureka :項目註冊與發現。git

全部項目都註冊到這個地址,方便三個系統之間經過feignClient進行數據交互。(eureka詳細註冊與發現這裏不過多描述)github

eureka 配置文件:web

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:訂單系統,消費者從訂單系統發起訂單,同時告知物流和庫存系統。ajax

reserve-receiver-service:庫存系統。獲取庫存量,減小庫存等。spring

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

相關文章
相關標籤/搜索