商品和订单中使用MQ

一、将Product服务增加到配置中心

1、添加引用

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-client</artifactId>
        </dependency>

  

2、修改application.yml 为bootstrap.yml

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
spring:
  application:
    name: product
  cloud:
      config:
        discovery:
          enabled: true
          service-id: CONFIG
        profile: dev

  

3、在码云中添加product-dev.yml文件

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: 123456
    url: jdbc:mysql://127.0.0.1:3306/SpringCloud_Sell?characterEncoding=utf-8&useSSL=false
  jpa:
    show-sql: true

  

4、访问http://localhost:8080/product-dev.yml

 5、启动Product服务

二、添加消息队列到Product服务

1、添加引用

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

  

2、添加MQ配置

3、在扣库存的地方发送消息

 1)发送MQ消息

@Service
public class ProductServiceImpl  implements ProductService{

    @Autowired
    private ProductInfoRepository productInfoRepository;

    @Autowired
    private AmqpTemplate amqpTemplate;

 
    /**
     * 扣库存
     *
     * @param cartDTOList
     */
    @Override
    @Transactional  //由于扣库存是list操作,所以需要事务操作
    public void decreaseStock(List<CartDTO> cartDTOList) {
        for(CartDTO cartDTO : cartDTOList){
           Optional<ProductInfo> productInfoOptional =  productInfoRepository.findById(cartDTO.getProductId());
           //判断商品是否存在
           if(!productInfoOptional.isPresent()){
                throw new ProductException(ResultEnum.PRODUCT_NOT_EXIST);
           }
           ProductInfo productInfo = productInfoOptional.get();
           //库存是否足够  数据库里的库存-购物车中的数量
          Integer result = productInfo.getProductStock() - cartDTO.getProductQuantity();
          if(result <= 0){
                throw new ProductException(ResultEnum.PRODUCT_STOCK_ERROR);
          }
          productInfo.setProductStock(result);
          productInfoRepository.save(productInfo);

          // 发送MQ消息
            amqpTemplate.convertAndSend("productInfo", JsonUtil.toJson(productInfo));
        }
    }
}

  

之后将发送的对象改为ProductInfoOutput

         ProductInfoOutput output = new ProductInfoOutput();
          BeanUtils.copyProperties(productInfo,output);
          // 发送MQ消息
            amqpTemplate.convertAndSend("productInfo", JsonUtil.toJson(output));

  

2)建立prouductInfo队列,并观察

3、调用接口

    @PostMapping("/decreaseStock")
    public void decreaseStock(@RequestBody List<CartDTO> cartDTOList){
          productService.decreaseStock(cartDTOList);
    }

  

使用PostMan调用

最终测试结果,发现2)中的消息队列有了消息。然后查看消息的内容

三、在Order服务中接收消息

@Component
@Slf4j
public class ProductInfoReceiver {
    @RabbitListener(queuesToDeclare = @Queue("productInfo"))
    public void process(String message){
       //message 转换成 ProductInfoOutpur
       ProductInfoOutput output = (ProductInfoOutput) JsonUtil.fromJson(message,ProductInfoOutput.class);
        log.info("从队列[{}]接收到消息:{}","productInfo", output.toString());
    }
}

  接收到的结果为:

四、Order服务中将库存保存到Redis中

1)增加引用

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

  

2)增加配置

3)增加代码

4)调用减库存后,查看Reids的库存数据如下图

五、优化扣库存

1、Product服务扣库存

    @Override
    public void decreaseStock(List<CartDTO> cartDTOList) {
        List<ProductInfo> productInfoList = decreaseStockProcess(cartDTOList);
       List<ProductInfoOutput> productInfoOutputList =  productInfoList.stream().map(e -> {
            ProductInfoOutput output = new ProductInfoOutput();
            BeanUtils.copyProperties(e,output);
            return  output;
        }).collect(Collectors.toList());
        // 发送MQ消息
        amqpTemplate.convertAndSend("productInfo", JsonUtil.toJson(productInfoOutputList));
    }


    @Transactional  //由于扣库存是list操作,所以需要事务操作
    public List<ProductInfo> decreaseStockProcess(List<CartDTO> cartDTOList) {
        List<ProductInfo> productInfoList = new ArrayList<>();
        for(CartDTO cartDTO : cartDTOList){
            Optional<ProductInfo> productInfoOptional =  productInfoRepository.findById(cartDTO.getProductId());
            //判断商品是否存在
            if(!productInfoOptional.isPresent()){
                throw new ProductException(ResultEnum.PRODUCT_NOT_EXIST);
            }
            ProductInfo productInfo = productInfoOptional.get();
            //库存是否足够  数据库里的库存-购物车中的数量
            Integer result = productInfo.getProductStock() - cartDTO.getProductQuantity();
            if(result <= 0){
                throw new ProductException(ResultEnum.PRODUCT_STOCK_ERROR);
            }
            productInfo.setProductStock(result);
            productInfoRepository.save(productInfo);

           productInfoList.add(productInfo);

        }
        return  productInfoList;
    }

  

2)、订单服务接收mq消息

public class ProductInfoReceiver {

    private static final String PRODUCT_STOCK_TEMPLATE = "product_stock_%s";

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @RabbitListener(queuesToDeclare = @Queue("productInfo"))
    public void process(String message){
       //message 转换成 ProductInfoOutpur
       List<ProductInfoOutput> productInfoOutputList = ( List<ProductInfoOutput>) JsonUtil.fromJson(message,
               new TypeReference<List<ProductInfoOutput>>() {});
        log.info("从队列[{}]接收到消息:{}","productInfo", productInfoOutputList);
        //将消息存到redis
        for (ProductInfoOutput productInfoOutput : productInfoOutputList) {
            stringRedisTemplate.opsForValue().set(String.format(PRODUCT_STOCK_TEMPLATE,
                    productInfoOutput.getProductId()), productInfoOutput.getProductStock().toString());
        }


    }
}

  

原文地址:https://www.cnblogs.com/linlf03/p/10375895.html