在上一篇文章中,我们使用SpringBoot和Docker创建了第一个微服务“ ProductService”。 在这一部分中,我们将详细介绍如何使用Spring Cloud,netflix库,API网关来管理多个微服务。
假设对于我们的订单管理系统,最小关系可能是这样的:
因此,让我们以构建“ productService”的类似方式再构建两个名为“ orderService”和“ customerService”的服务。
订购服务
要创建订单,我们可以传递customerId,以及带有productId和数量的项目列表。 让我们看看如何做到这一点:
@PostMapping("/orders")
public Order save(@RequestBody CustomerOrderRequest request) {
return orderRepository.save(Order
.builder()
.customerId(request.getCustomerId())
.externalReference(request.getExternalReference())
.items(toItems(request.getItems())).build());
}
private List toItems(List items) {
return items.stream().map(item -> Item.builder().productId(item.getProductId())
.quantity(item.getQuantity()).build()).collect(Collectors.toList());
}
在这里,我们将customerId和带有productIds的项目列表保存到数据库中。
为了获取完整的订单明细,我们需要完整的客户对象和产品明细。 结果看起来像这样:
{
"orderId": "1234",
"externalReference": "234257hf",
"customer": {
"id": 123,
"firstName": "anirudh",
"lastName": "bhatnagar",
"phone": "21323",
"email": "test@test.com",
"address": {
"addressLine1": "123",
"addressLine2": "pwe",
"city": "Syd",
"state": "NSW",
"country": "Aus",
"postcode": 2000
}
},
"createdDate": "2018-11-12",
"items": [{
"product": {
"id": 123,
"name": "Nike Shoes",
"description": "Mens shoes",
"price": "100",
"sku": "1234"
},
"quantity": 3
}],
"totalOrderCost": "300.00",
"totalOrderTax": "30.00"
}
详细的订单响应应包含客户,地址,产品和订单总成本的详细信息。 为了获取此信息,订购服务将需要从产品服务和客户服务获取详细信息。
从Order Service中的ProductService获取产品详细信息
为了获取Order Service中的产品服务详细信息,我们需要一个正在运行的产品服务,以及一个orderController客户端,以对ProductService进行http GET调用。 对于httpClient,我们将使用Netflix提供的OpenFeign客户端库,它可以作为spring-cloud starter的一部分使用,因此让我们在build.gradle文件中添加该依赖项:
implementation('org.springframework.cloud:spring-cloud-starter-openfeign')
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
现在,我们已经添加了依赖项,我们将使用@FeignClient为此服务创建一个名为“ ProductServiceProxy”的代理接口:
@FeignClient(name = "product-service", url = "localhost:8001")
public interface ProductServiceProxy {
@GetMapping("/products/{id}")
Product getProduct(@PathVariable("id") Long id);
}
我们已经在界面中添加了注释@FeignClient,并配置了产品服务的名称和URL。
我们还需要通过在主类中添加另一个注释来为我们的应用程序启用Feign客户端:
@SpringBootApplication
@EnableFeignClients
public class OrderServiceApplication {
......
最后,我们需要调用在本地主机端口8001上运行的产品服务,以使用订单中提供的产品ID获取产品详细信息,并填充订单详细信息响应对象:
@GetMapping("/orders/{id}")
public CustomerOrderDetails getOrders(@PathVariable("id") Long orderId) {
final Order order = orderRepository.findById(orderId).orElse(null);
if (order == null) {
return null;
}
return toCustomerOrderDetails(order);
}
private CustomerOrderDetails toCustomerOrderDetails(Order order) {
return CustomerOrderDetails.builder()
.orderId(order.getId())
.createdDate(order.getCreatedDate())
.externalReference(order.getExternalReference())
.items(toItemList(order.getItems()))
.build();
}
private List<com.anirudhbhatnagar.orderService.dto.product.Item> toItemList(List<Item> items) {
return items.stream().map(item -> toItemDto(item)).collect(Collectors.toList());
}
private com.anirudhbhatnagar.orderService.dto.product.Item toItemDto(Item item) {
return com.anirudhbhatnagar.orderService.dto.product.Item
.builder()
.product(productServiceProxy.getProduct(item.getProductId())).build();
}
如果您仔细看一下上面的代码,
productServiceProxy.getProduct(item.getProductId())
您将看到,一旦获得获取获取给定orderId的订单详细信息的请求,我们首先将获取保存在订单服务数据库中的订单数据,然后使用每个项目或订单中提供的productId,我们将调用productService并填充orderDetails响应对象。
测试一下
一旦orderService启动并在端口8002上运行并且productService在端口8001上运行。我们可以测试我们的应用程序:确保有一些使用产品服务创建的产品,如先前的博客所述 。
记下您在产品服务中创建的productId,并使用相同的代码创建新订单:使用邮递员在http:// localhost:8002 / orders上进行POST,请求如下:
{
"customerId" : "123",
"externalReference" : "1234567",
"items" : [{
"productId" : 1,
"quantity" : 2
}]
}
这将创建一个新订单,而不是在响应中查找订单ID。 现在,使用以下订单ID获取订单详细信息:在http:// localhost / 8002 / orders / {order-id}上执行GET,这将返回以下响应:
{
"orderId": 12,
"externalReference": "1234567",
"customer": null,
"createdDate": null,
"items": [
{
"product": {
"id": "1",
"name": "Nike",
"description": "Shoes",
"price": "100",
"sku": "1234"
},
"quantity": 2
}
],
"totalOrderCost": "200"
}
因此,在这里我们看到了订单服务如何向产品服务发出请求并填充响应对象。 但是,我们仍然将客户视为“ null”,因此,为了填充客户详细信息,我们需要从客户服务获取。 为了设置客户服务,我们将执行以下操作:
1.以与我们使用Spring初始化程序进行产品或订单服务类似的方式设置客户服务。
2.在OrderService中设置代理客户端服务 3.从Order Controller调用CustomerService,以在Order Details响应对象内填充客户详细信息。 如果一切正常,我们也应该查看客户详细信息。
当前,我们已经在订单服务中对服务的URL进行了硬编码,但是理想情况下需要动态发现它们。 因此,在下一部分中,我们将为3个微服务添加“服务发现”和“负载平衡”。
整个源代码可以在这里引用。
翻译自: https://www.javacodegeeks.com/2018/11/spring-microservices-docker-kubernetes-2.html