日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring Cloud【Finchley】实战-03订单微服务与商品微服务之间的调用

發(fā)布時間:2025/3/21 javascript 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Cloud【Finchley】实战-03订单微服务与商品微服务之间的调用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • Spring Cloud【Finchley】專欄
  • 概述
  • HTTP方式之RestTemplate
    • 方式一 (直接使用restTemplate訪問URL,url寫死)
    • 方式二 (使用LoadBalancerClient通過應(yīng)用名獲取url,拼裝請求地址,然后再使用restTemplate)
    • 方式三 (使用@LoadBalanced注解)
  • Fegin 的使用
  • 商品微服務(wù)獲取商品列表功能開發(fā)
    • Product微服務(wù)查詢商品列表功能開發(fā)
      • DAO層
      • Service層
      • Controller層
    • Order微服務(wù)調(diào)用接口查詢商品列表
      • 增加接口方法
  • 調(diào)用商品微服務(wù)扣庫存功能開發(fā)
    • Product微服務(wù)減庫存功能開發(fā)
      • 減庫存的參數(shù) DTO封裝
      • Service
      • Controller層
    • Order微服務(wù)調(diào)用接口扣減庫存
      • 增加接口方法
  • 整合
    • 測試
  • 知識點小結(jié)
    • 點1
    • 點2
  • Github

Spring Cloud【Finchley】專欄

如果還沒有系統(tǒng)的學(xué)過Spring Cloud ,先到我的專欄去逛逛吧

Spring Cloud 【Finchley】手札


概述

還記得上篇博文的TODO吧

這里我們先循序漸進的了解下,微服務(wù)之間調(diào)用的幾種方式

先了解下應(yīng)用之間的通行的主要兩種方式

  • RPC – 代表 Dubbo (可以基于TCP協(xié)議,也可以基于HTTP協(xié)議)
  • HTTP —代表 Spring Cloud (基于HTTP協(xié)議)

HTTP方式之RestTemplate

我們在order微服務(wù)調(diào)用product微服務(wù)。

product作為服務(wù)端,先對外暴露個測試接口

order作為客戶端調(diào)用該接口

方式一 (直接使用restTemplate訪問URL,url寫死)

訪問 http://localhost:8081/order/getServerInfoFromClient

寫死的地址,并且只能請求一個,如果有多個地址就比較麻煩了。而且還是IP地址。


方式二 (使用LoadBalancerClient通過應(yīng)用名獲取url,拼裝請求地址,然后再使用restTemplate)

package com.artisan.order.controller;import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate;@RestController @Slf4j @RequestMapping("/order") public class ClientController {@Autowiredprivate LoadBalancerClient loadBalancerClient;@GetMapping("/getServerInfoFromClient")public String requestServer(){// 方式二 (使用LoadBalancerClient通過應(yīng)用名獲取url,拼裝請求地址,然后再使用restTemplate)RestTemplate restTemplate2 = new RestTemplate();ServiceInstance serviceInstance = loadBalancerClient.choose("ARTISAN-PRODUCT");// 獲取ip port 組裝urlString url = String.format("http://%s:%s",serviceInstance.getHost(),serviceInstance.getPort() + "/product/serverMsg");log.info("url:{}",url);String msg = restTemplate2.getForObject(url,String.class);log.info("msg from server : {}", msg);return msg;} }

loadBalancerClient.choose("ARTISAN-PRODUCT"); 通過loadBalancerClient 選擇 注冊到Eurek Server上的ip . 需要填寫注冊到注冊中心的名字ARTISAN-PRODUCT。

訪問 http://localhost:8081/order/getServerInfoFromClient


方式三 (使用@LoadBalanced注解)

先初始化RestTemplate , 標(biāo)注 @LoadBalanced 注解

package com.artisan.order.config;import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate;@Configuration public class RestTemplateConfig {@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();} } package com.artisan.order.controller;import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate;@RestController @Slf4j @RequestMapping("/order") public class ClientController {@Autowiredprivate RestTemplate restTemplate;@GetMapping("/getServerInfoFromClient")public String requestServer(){// 方式三 (使用@LoadBalanced注解)String msg = restTemplate.getForObject("http://ARTISAN-PRODUCT/product/serverMsg",String.class);log.info("msg from server : {}", msg);return msg;} }

請求的地址 http://ARTISAN-PRODUCT/product/serverMsg 注冊到服務(wù)中心上的服務(wù)

訪問 http://localhost:8081/order/getServerInfoFromClient


Fegin 的使用

Spring Cloud【Finchley】-06服務(wù)消費者整合Feign

總體來說,在作為客戶端的order微服務(wù)中, 步驟如下

  • 添加依賴
  • 添加注解@EnableFeignClients
  • 開發(fā)接口
  • 使用
  • pom.xml 添加依賴


    添加注解@EnableFeignClients


    編寫client接口

    package com.artisan.order.client;import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping;// name為注冊在注冊中心上的名稱 @FeignClient(name="ARTISAN-PRODUCT") public interface ProductClient {// ARTISAN-PRODUCT微服務(wù)接口的訪問路徑@GetMapping("/product/serverMsg")String getServerInfo(); }

    調(diào)用

    package com.artisan.order.controller;import com.artisan.order.client.ProductClient; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;@RestController @Slf4j @RequestMapping("/order") public class FeginClientController {@Autowiredprivate ProductClient productClient;@GetMapping("/getServerInfoByFeign")public String requestServer(){String msg = productClient.getServerInfo();log.info("msg from server : {}", msg);return msg;} }

    訪問 http://localhost:8081/order/getServerInfoByFeign

    OK。


    商品微服務(wù)獲取商品列表功能開發(fā)

    熟悉了基本使用后,剛開始說了,我們有幾個TODO要做,那開始吧


    Product微服務(wù)查詢商品列表功能開發(fā)

    我們看下前臺會傳遞什么給我們

    關(guān)于商品的信息,productId是個集合,那么我們就需要提供一個根據(jù)傳入的productId列表來返回product集合的功能。

    DAO層

    老規(guī)矩,DAO層先


    單元測試下,

    @Testpublic void findByProductIdIn() {List<Product> list = productRepository.findByProductIdIn(Arrays.asList("1","2"));Assert.assertEquals(2,list.size());}

    結(jié)合庫表中的數(shù)據(jù)


    單元測試通過


    Service層

    緊接著Service層

    實現(xiàn)類

    單元測試


    單元測試通過


    Controller層

    /*** 根據(jù)productIdList 查詢商品列表* 提供給Order微服務(wù)用* @param productIdList* @return*/@PostMapping("/productListForOrder")private List<Product> getProductForOrder(@RequestBody List<String> productIdList){return productService.getProductList(productIdList);}

    Order微服務(wù)調(diào)用接口查詢商品列表

    增加接口方法

    返回的類型是個Product集合,我們先從product微服務(wù)那邊將Product copy一份過來。 后續(xù)會優(yōu)化這些地方

    我們寫個方法來測試下這個功能, 那就在剛才的用作測試的FeginClientController類中寫個方法吧

    當(dāng)參數(shù)中標(biāo)注了@RequestBody , 則必須使用POST方法

    啟動服務(wù),測試下 http://localhost:8081/order/getProductList


    可見功能是OK的。


    調(diào)用商品微服務(wù)扣庫存功能開發(fā)

    Product微服務(wù)減庫存功能開發(fā)

    減庫存的參數(shù) DTO封裝

    我們看下前臺會傳遞什么給我們

    肯定是 某個產(chǎn)品 扣除多少個數(shù)量。 []可以傳遞多個,對于后臺來講是個集合 。

    Product微服務(wù)需要兩個參數(shù) productId 和 productQuantity


    Service

    分析下,扣減庫存,直接使用JPA內(nèi)置的方法即可,DAO層可以省略了。

    直接來Service吧 ,直接寫實現(xiàn)類中的方法你把

    @Override// 因為是對List操作,所以加個事務(wù)控制@Transactionalpublic void decreaseProduct(List<CartDTO> cartDTOList) {// 遍歷CartDTOfor (CartDTO cartDTO : cartDTOList) {// 根據(jù)productId查詢ProductOptional<Product> productOptional = productRepository.findById(cartDTO.getProductId());// 商品是否存在if (!productOptional.isPresent()) {throw new ProductException(ResultEnum.PRODUCT_NOT_EXIST);}// 是否庫存充足Product product = productOptional.get();int leftStock = product.getProductStock() - cartDTO.getProductQuantity();if (leftStock < 0 ){throw new ProductException(ResultEnum.PRODUCT_STOCK_ERROR);}// 將剩余庫存設(shè)置到product,并更新數(shù)據(jù)庫product.setProductStock(leftStock);productRepository.save(product);}}

    因為是對List操作,所以加個事務(wù)控制 @Transactional

    單元測試

    @Testpublic void decreaseProductTest() {CartDTO cartDTO = new CartDTO();cartDTO.setProductId("3");cartDTO.setProductQuantity(2);productService.decreaseProduct(Arrays.asList(cartDTO));}

    測試前數(shù)據(jù)


    Controller層


    Order微服務(wù)調(diào)用接口扣減庫存

    增加接口方法

    ProductClient接口新增方法

    測試下 ,在 FeginClientController 新增個方法 (這個Controller和工程無關(guān)哈,僅僅是用來測試用的)

    訪問 http://localhost:8081/order/decreseProduct


    整合

    Product微服務(wù)要提供的功能及Order微服務(wù)調(diào)用都開發(fā)完了,那整合到業(yè)務(wù)邏輯中吧

    @Overridepublic OrderDTO createOrder(OrderDTO orderDTO) {String orderId = KeyUtil.genUniqueKey();// 查詢商品信息(調(diào)用商品微服務(wù))List<String> productIdList = orderDTO.getOrderDetailList().stream().map(OrderDetail::getProductId).collect(Collectors.toList());List<Product> productList = productClient.getProductForOrder(productIdList);// 計算訂單總價BigDecimal orderAmout = new BigDecimal(BigInteger.ZERO);for (OrderDetail orderDetail: orderDTO.getOrderDetailList()) {for (Product product: productList) {if (product.getProductId().equals(orderDetail.getProductId())) {//單價*數(shù)量orderAmout = product.getProductPrice().multiply(new BigDecimal(orderDetail.getProductQuantity())).add(orderAmout);BeanUtils.copyProperties(product, orderDetail);orderDetail.setOrderId(orderId);orderDetail.setDetailId(KeyUtil.genUniqueKey());//訂單詳情入庫orderDetailRepository.save(orderDetail);}}}// 扣減庫存(調(diào)用商品微服務(wù))List<CartDTO> cartDTOList = orderDTO.getOrderDetailList().stream().map(e -> new CartDTO(e.getProductId(), e.getProductQuantity())).collect(Collectors.toList());productClient.decreseProduct(cartDTOList);//訂單入庫Order order = new Order();orderDTO.setOrderId(orderId);// 復(fù)制屬性BeanUtils.copyProperties(orderDTO, order);// 設(shè)置其他屬性order.setOrderAmount(orderAmout);order.setOrderStatus(OrderStatusEnum.NEW.getCode());order.setPayStatus(PayStatusEnum.WAIT.getCode());orderRepository.save(order);return orderDTO;}

    測試

    [{"productId": "1","productQuantity": 2 }, {"productId": "2","productQuantity": 5 }, {"productId": "3","productQuantity": 10 }]

    買 1號商品 2個 ,金額 20.99乘以2 = 41.98
    買 2號商品 5個 ,金額 7.5乘以5 = 37.5
    買 3號商品 10個 ,金額 15乘以10 = 150
    總金額 229.48

    原始庫存:

    使用POSTMAN測試一把

    檢查下總金額,庫存扣減,及order_detail中的數(shù)據(jù)

    artisan_order

    order_detail 3條記錄

    庫存:

    OK


    知識點小結(jié)

    點1

    Spring MVC在接收集合請求參數(shù)時,需要在Controller方法的集合參數(shù)里前添加@RequestBody

    List<Product> getProductForOrder(@RequestBody List<String> productIdList)

    點2

    當(dāng)參數(shù)中標(biāo)注了@RequestBody , 則必須使用POST方法


    Github

    artisan-product: https://github.com/yangshangwei/springcloud-o2o/tree/master/artisan_order

    artisan_order: https://github.com/yangshangwei/springcloud-o2o/tree/master/artisan-product

    總結(jié)

    以上是生活随笔為你收集整理的Spring Cloud【Finchley】实战-03订单微服务与商品微服务之间的调用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。