Section 9: 实现订单微服务 (02:42:50 - 04:40:50)

创建订单微服务 (02:42:50 - 03:04:11)

首先,让我们创建订单微服务。我们将使用 Spring Initializr 或者 IntelliJ IDEA 创建一个新的 Maven 项目,并添加以下依赖项:

  • Spring Web
  • Spring Data JPA
  • PostgreSQL Driver
  • Spring Cloud Starter Config
  • Spring Cloud Starter Netflix Eureka Client (或者 Spring Cloud Starter Discovery,取决于 Spring Cloud 版本)
  • Lombok
  • OpenFeign

创建好项目后,我们需要定义实体类。

  • Order Entity: 订单实体,包含订单的基本信息,例如订单 ID、订单编号、总金额、支付方式、客户 ID、订单明细列表、创建日期和最后修改日期。
  • OrderLine Entity: 订单明细实体,表示订单中的每一项商品,包含商品 ID、数量等信息。
  • PaymentMethod Enum: 支付方式枚举,定义了应用程式支持的支付方式,例如 PayPal、信用卡、Visa 卡、MasterCard 和 Bitcoin。

package com.alibou.ecommerce.order;

public enum PaymentMethod {
    PAYPAL,
    CREDIT_CARD,
    VISA_CARD,
    MASTERCARD,
    BITCOIN
}

实现订单控制器和服务 (03:04:11 - 04:01:07)

接下来,我们将实现订单控制器和服务。 订单控制器负责接收来自客户端的请求,并调用订单服务来处理这些请求。订单服务则负责处理订单相关的业务逻辑,例如创建订单、查询订单等。

@RestController
@RequestMapping("/api/v1/orders")
@RequiredArgsConstructor
public class OrderController {

    private final OrderService service;

    @PostMapping
    public ResponseEntity<Integer> createOrder(@RequestBody @Valid OrderRequest request) {
        return ResponseEntity.ok(service.createOrder(request));
    }

    // Other methods: findAll, findById
}

在订单服务中,我们需要实现以下步骤:

  1. 检查客户 (Check Customer): 首先,我们需要检查客户是否存在。我们将使用 OpenFeign 调用客户微服务来获取客户信息。 为了使用 OpenFeign,我们需要创建一个 CustomerClient 接口,并使用 @FeignClient 注解来指定客户微服务的服务名称和 URL。

package com.alibou.ecommerce.customer;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

import java.util.Optional;

@FeignClient(name = "customer-service", url = "${application.config.customer-url}")
public interface CustomerClient {

    @GetMapping("/api/v1/customers/{customer-id}")
    Optional<CustomerResponse> findCustomerById(@PathVariable("customer-id") String customerId);
}
2. 采购产品 (Purchase Products): 接下来,我们需要调用产品微服务来购买商品。我们将使用 RestTemplate 来实现这一功能。

@Service
@RequiredArgsConstructor
public class ProductClient {

    @Value("${application.config.product-url}")
    private String productURL;

    private final RestTemplate restTemplate;


    public List<PurchaseResponse> purchaseProducts(List<PurchaseRequest> requestBody) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        HttpEntity<List<PurchaseRequest>> requestEntity = new HttpEntity<>(requestBody, headers);
        ParameterizedTypeReference<List<PurchaseResponse>> responseType = new ParameterizedTypeReference<>() {};

        ResponseEntity<List<PurchaseResponse>> responseEntity = restTemplate.exchange(
                productURL + "/purchase",
                HttpMethod.POST,
                requestEntity,
                responseType
        );

        // Error handling
        if (responseEntity.getStatusCode().isError()) {
            throw new BusinessException("An error occurred while processing the product purchase: " + responseEntity.getStatusCode());
        }

        return responseEntity.getBody();
    }
}

Remember to create a configuration class to expose the RestTemplate as a bean:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
3. 持久化订单 (Persist Order): 我们将订单信息保存到数据库中。 4. 发送订单确认 (Send Order Confirmation): 我们将订单确认消息发送到 Kafka 消息队列。

@Service
@RequiredArgsConstructor
public class OrderProducer {

    private final KafkaTemplate<String, OrderConfirmation> kafkaTemplate;

    public void sendOrderConfirmation(OrderConfirmation orderConfirmation) {
        log.info("Sending order confirmation with body {}", orderConfirmation);

        Message<OrderConfirmation> message = MessageBuilder
                .withPayload(orderConfirmation)
                .setHeader(KafkaHeaders.TOPIC, "order-topic")
                .build();

        kafkaTemplate.send(message);
    }
}

最后,我们需要配置 Kafka,包括添加依赖、配置 Kafka 主题等。我们将在下一步中详细介绍 Kafka 的配置。

配置 Kafka:

spring:
  kafka:
    producer:
      bootstrap-servers: localhost:9092
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
    properties:
      spring.json.type.mapping: "orderConfirmation:com.alibou.ecommerce.order.OrderConfirmation" # Replace with actual package name
    trusted:
      packages: '*' #  com.alibou.ecommerce