multi-service-demo模板项目创建

本节将结合第 5~7 章中的知识点,构建一个 Spring Cloud Alibaba 整合服务治理后的多模块模板项目。业务场景就是商城中的订单生成流程。用户在商品详情页将商品添加至购物车页面,之后在购物车页面单击 “结算” 按钮生成订单。在这个场景中包括三个功能模块:商品、购物车、订单。按照前文中讲解的知识将这三个功能模块抽象为三个服务:商品服务、购物车服务、订单服务。三个服务间的调用方式如图 7-11 所示。

image 2025 04 16 16 19 46 556
Figure 1. 图7-11 商品服务、购物车服务、订单服务间的调用方式

下面笔者结合三个模块的调用方式做一个简单的演示,供后续章节使用。过程并不复杂,就是在本章代码的基础上进行修改。

先修改项目名称为 spring-cloud-alibaba-multi-service-demo,然后将 nacos-consumer-demo 修改为 order-service-demo、将 nacos-provider-demo 修改为 shopcart-service-demo、将 nacos-provider-demo2 修改为 goods-service-demo,再依次修改项目中的启动类名称和 application.properties 配置文件(主要是端口号和应用名称)。下面修改 root 节点的 pom.xml 配置文件,代码如下:

<modelVersion>4.0.0</modelVersion>
<groupId>ltd.newbee.cloud</groupId>
<artifactId>spring-cloud-alibaba-multi-service-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-cloud-alibaba-multi-service-demo</name>
<packaging>pom</packaging>
<description>Spring Cloud Alibaba Demo</description>
<modules>
  <module>goods-service-demo</module>
  <module>shopcart-service-demo</module>
  <module>order-service-demo</module>
</modules>

goods-service-demo 项目中新建 NewBeeCloudGoodsAPI 类,代码及注释如下:

package ltd.goods.cloud.newbee.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class NewBeeCloudGoodsAPI {

    @Value("${server.port}")
    private String applicationServerPort; // 获取当前应用的启动端口

    @GetMapping("/goods/{goodsId}")
    public String goodsDetail(@PathVariable("goodsId") int goodsId) {
        // 根据id查询商品并返回调用端
        if (goodsId < 1 || goodsId > 100000) {
            return "查询商品为空,当前服务的端口号为:" + applicationServerPort;
        }
        String goodsName = "商品" + goodsId;
        // 返回信息给调用端
        return goodsName + ",当前服务的端口号为:" + applicationServerPort;
    }
}

shopcart-service-demo 项目中新建 NewBeeCloudShopCartAPI 类,代码及注释如下:

package ltd.shopcart.cloud.newbee.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class NewBeeCloudShopCartAPI {

    @Value("${server.port}")
    private String applicationServerPort; // 读取当前应用的启动端口

    @GetMapping("/shop-cart/{cartId}")
    public String cartItemDetail(@PathVariable("cartId") int cartId) {
        // 根据id查询商品并返回调用端
        if (cartId < 0 || cartId > 100000) {
            return "查询购物项为空,当前服务的端口号为:" + applicationServerPort;
        }

        String cartItem = "购物项" + cartId;
        // 返回信息给调用端
        return cartItem + ", 当前服务的端口号为:" + applicationServerPort;
    }
}

order-service-demo 项目中新建 NewBeeCloudOrderAPI 类,使用 RestTemplate 工具调用另外两个服务,代码及注释如下:

package ltd.order.cloud.newbee.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
public class NewBeeCloudOrderAPI {

    @Resource
    private RestTemplate restTemplate;

    // 商品服务调用地址
    private final String CLOUD_GOODS_SERVICE_URL =
            "http://newbee-cloud-goods-service";

    // 购物车服务调用地址
    private final String CLOUD_SHOPCART_SERVICE_URL =
            "http://newbee-cloud-shopcart-service";

    @GetMapping("/order/saveOrder")
    public String saveOrder(@RequestParam("cartId") int cartId,
                            @RequestParam("goodsId") int goodsId) {
        // 简单地模拟下单流程,包括服务间的调用流程。后续与 OpenFeign 相关的改造和优化
        // 将基于当前项目

        // 调用商品服务
        String goodsResult = restTemplate.getForObject(CLOUD_GOODS_SERVICE_URL
                + "/goods/" + goodsId, String.class);

        // 调用购物车服务
        String cartResult = restTemplate.getForObject(CLOUD_SHOPCART_SERVICE_URL
                + "/cart/" + cartId, String.class);
        SERVICE_URL + "/shop-cart/" + cartId, String.class);

        // 执行下单逻辑

        return "success! goodsResult={" + goodsResult + "},cartResult={" +
                cartResult + "}";
    }
}

编码完成后,spring-cloud-alibaba-multi-service-demo 项目的最终目录结构如图 7-12 所示。

image 2025 04 16 16 26 41 407
Figure 2. 图7-12 spring-cloud-alibaba-multi-service-demo 项目的最终目录结构

下面需要启动 Nacos Server,之后依次启动这三个项目。如果未能成功启动,则开发人员需要查看控制台中的日志是否报错,并及时确认问题和修复。启动成功后进入 Nacos 控制台,单击 “服务管理” 中的服务列表,可以看到列表中已经存在这三个服务的服务信息,如图 7-13 所示。

image 2025 04 16 16 31 18 204
Figure 3. 图7-13 Nacos 控制台中的服务列表

打开浏览器并在地址栏中输入如下地址:

http://localhost:8117/order/saveOrder?cartId=13U&goodsId=2022

响应结果如图 7-14 所示。

image 2025 04 16 16 32 23 324
Figure 4. 图7-14/order/saveOrder 请求的访问结果

order-service-demo 项目中对另外两个服务的远程调用没有问题,测试成功!

与第 4 章中简单的 Spring Cloud Alibaba 代码模板相比,spring-cloud-alibaba-multi-service-demo 项目更加复杂一些,整合了更多的内容,如 RestTemplateNacosLoadBalancer,此时的项目就有了微服务架构的雏形了,后续章节中将会以 spring-cloud-alibaba-multi-service-demo 多模块项目为模板进行其他组件的整合和功能演示。