03 订单微服务与商品微服务之间的调用
应用之间的通行的主要两种方式:
- RPC – 代表 Dubbo (可以基于TCP协议,也可以基于HTTP协议)
- HTTP --代表 Spring Cloud (基于HTTP协议)
HTTP方式之RestTemplate
在order微服务调用product微服务,product作为服务端,先对外暴露个测试接口
@GetMapping("showInfo")
public String showInfo(){
return "info from product server";
}
方式一:直接使用RestTemplate访问url,url写死
@GetMapping("requestServer")
public String requestServer(){
RestTemplate restTemplate = new RestTemplate();
String message = restTemplate.getForObject("http://localhost:8080/product/showInfo", String.class);
log.info("message from server:"+message);
return message;
}
写死不够灵活
方式二 (使用LoadBalancerClient通过应用名获取url,拼装请求地址,然后再使用restTemplate)
@GetMapping("requestServer")
public String requestServer(){
RestTemplate restTemplate = new RestTemplate();
ServiceInstance serviceInstance = loadBalancerClient.choose("production");
String url = String.format("http://%s:%s", serviceInstance.getHost(), serviceInstance.getPort() + "/product/showInfo");
log.info("请求的url:{}",url);
String message = restTemplate.getForObject(url, String.class);
log.info("message from server:"+message);
return message;
}
loadBalancerClient.choose("PRODUCT"); 通过loadBalancerClient 选择 注册到Eurek Server上的ip . 需要填写注册到注册中心的名字PRODUCT。
方式三:使用@LoadBalanced注解
先初始化RestTemplate , 标注 @LoadBalanced 注解
@GetMapping("requestServer")
public String requestServer(){
String message = restTemplate.getForObject("http://production/product/showInfo", String.class);
log.info("message from server:"+message);
return message;
}
Fegin 的使用
在作为客户端的order微服务中, 步骤如下
- 添加依赖
- 添加注解@EnableFeignClients
- 开发接口
- 使用
添加依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
添加@EnableFeignClients
@SpringBootApplication @EnableEurekaClient @EnableFeignClients public class OrderApplication { public static void main(String[] args) { SpringApplication.run(OrderApplication.class, args); } }
编写接口
package com.smart.order.controller; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; @FeignClient(name="production") public interface ProductClient { @GetMapping("/product/showInfo") String getServerInfo(); }
使用
@RestController @Slf4j @RequestMapping("/order") public class FeginClientController { @Autowired private ProductClient productClient; @GetMapping("/getServerInfoByFeign") public String requestServer(){ String msg = productClient.getServerInfo(); log.info("msg from server : {}", msg); return msg; } }
Product微服务查询商品列表功能开发
* { * "name":"xxx", * "phone":"xxx", * "address":"xxx", * "openid":"xxx", * "items":[ * "productId":"xxxx", * "productQuantity":"2" * ] * }
关于商品的信息,productId是个集合,那么就需要提供一个根据传入的productId列表来返回product集合的功能。
DAO
public interface ProductRepository extends JpaRepository<Product,String>{ List<Product> findByProductStatus(Integer productStatus); /** * 根据productId查询商品列表 * @param productIds * @return */ List<Product> findByProductId(List<String> productIds); }
Service层
public interface ProductService { List<Product> getAllUpProduct(); List<Product> getProductList(List<String> productIds); }
实现类
@Override public List<Product> getProductList(List<String> productIds) { return productRepository.findByProductId(productIds); }
Controller
@PostMapping("productListForOrder")
public List<Product> productListForOrder(@RequestBody List<String> productIds){
return productService.getProductList(productIds);
}
Order微服务调用接口查询商品列表
增加接口方法
@FeignClient(name="production") public interface ProductClient { @GetMapping("/product/productListForOrder") List<Product> getProductForOrder(List<String> productIds); }
Controller层
@GetMapping("productList")
public String getProductList(){
List<Product> productList = productClient.getProductForOrder(Arrays.asList("1,2"));
log.info("获取产品:"+productList);
return JSON.toJSONString(productList);
}
Product微服务减库存功能开发
减库存的参数 DTO封装,前台会传递什么
* { * "name":"xxx", * "phone":"xxx", * "address":"xxx", * "openid":"xxx", * "items":[ * "productId":"xxxx", * "productQuantity":"2" * ] * }
某个产品 扣除多少个数量。 []可以传递多个,对于后台来讲是个集合 。
Product微服务需要两个参数 productId 和 productQuantity
package com.smart.order.dto; import lombok.Data; @Data public class CartDTO { private String productId; private Integer productQuantity; public CartDTO() { } public CartDTO(String productId, Integer productQuantity) { this.productId = productId; this.productQuantity = productQuantity; } }
Service
分析下,扣减库存,直接使用JPA内置的方法即可,DAO层可以省略
@Transactional public void decreaseProduct(List<CartDTO> cartDTOList) { for (CartDTO cartDTO : cartDTOList) { Optional<Product> productOptional = productRepository.findById(cartDTO.getProductId()); if (!productOptional.isPresent()) { throw new ProductException(ErrorCode.PRODUCT_NOT_EXIST); } Product product = productOptional.get(); Integer leftStock = product.getProductStock() - cartDTO.getProductQuantity(); if (leftStock < 0) { throw new ProductException(ErrorCode.PRODUCT_STOCK_ERROR); } product.setProductStock(leftStock); productRepository.save(product); } }
Controller层
@PostMapping("decreaseProduct")
public void decreaseProduct(@RequestBody List<CartDTO> cartDTOS){
productService.decreaseProduct(cartDTOS);
}
Order微服务调用接口扣减库存
增加接口方法
ProductClient接口新增方法
@FeignClient(name="production") public interface ProductClient { @PostMapping("/product/decreaseProduct") void decreaseProduct(List<CartDTO> cartDTOS); }
整合业务逻辑
@Override public OrderDTO createOrder(OrderDTO orderDTO) { String orderId = KeyUtil.genUniqueKey(); //查询商品信息 List<String> productIds = orderDTO.getOrderDetailList().stream() .map(OrderDetail::getProductId) .collect(Collectors.toList()); List<Product> productList = productClient.getProductForOrder(productIds); //计算订单总价 BigDecimal orderAmount = new BigDecimal(BigInteger.ZERO); for(OrderDetail orderDetail : orderDTO.getOrderDetailList()){ for(Product product : productList){ if(product.getProductId().equals(orderDetail.getProductId())){ orderAmount=product.getProductPrice() .multiply(new BigDecimal(orderDetail.getProductQuantity())) .add(orderAmount); BeanUtils.copyProperties(product,orderDetail); orderDetail.setOrderId(orderId); orderDetail.setDetailId(KeyUtil.genUniqueKey()); orderDedetailRepository.save(orderDetail); } } } //减库存 List<CartDTO> cartDTOS = orderDTO.getOrderDetailList().stream() .map(e -> new CartDTO(e.getProductId(), e.getProductQuantity())) .collect(Collectors.toList()); productClient.decreaseProduct(cartDTOS); //订单入库 Order order = new Order(); orderDTO.setOrderId(orderId); BeanUtils.copyProperties(orderDTO,order); order.setOrderAmount(new BigDecimal(100)); order.setOrderStatus(OrderStatus.NEW.getCode()); order.setPayStatus(PayStatus.WAIT.getCode()); orderRepository.save(order); return orderDTO; }
测试:

浙公网安备 33010602011771号