一、将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()); } } }