[Spring Cloud][3]从零开始简单工程搭建实践详解,远程调用

文章目录

数据准备

根据服务自洽原则,每个服务都应有自己独立的数据库

sql 复制代码
-- 创建数据库
create database if not exists cloud_order charset utf8mb4;

use cloud_order;

-- 订单表
DROP TABLE IF EXISTS order_detail;
CREATE TABLE order_detail (
    `id` INT NOT NULL AUTO_INCREMENT COMMENT '订单id',
    `user_id` BIGINT (20) NOT NULL COMMENT '用户ID',
    `product_id` BIGINT (20) NULL COMMENT '产品id',
    `num` INT (10) NULL DEFAULT 0 COMMENT '下单数量',
    `price` BIGINT (20) NOT NULL COMMENT '实际款',
    `delete_flag` TINYINT (4) NULL DEFAULT 0,
    `create_time` DATETIME DEFAULT now(),
    `update_time` DATETIME DEFAULT now(),
    PRIMARY KEY (`id`)) ENGINE = INNODB DEFAULT CHARACTER
SET = utf8mb4 COMMENT = '订单表';

-- 数据初始化
insert into order_detail (user_id, product_id, num, price)
values
(2001, 1001, 1, 99),
(2002, 1002, 1, 30),
(2001, 1003, 1, 40),
(2003, 1004, 3, 58),
(2004, 1005, 7, 85),
(2005, 1006, 7, 94);
sql 复制代码
-- 创建数据库
create database if not exists cloud_product charset utf8mb4;

use cloud_product

-- 产品表
DROP TABLE IF EXISTS product_detail;
CREATE TABLE product_detail (
    `id` INT NOT NULL AUTO_INCREMENT COMMENT '产品id',
    `product_name` varchar (128) NULL COMMENT '产品名称',
    `product_price` BIGINT (20) NOT NULL COMMENT '产品价格',
    `state` TINYINT (4) NULL DEFAULT 0 COMMENT '产品状态-0有库存 1-下架',
    `create_time` DATETIME DEFAULT now(),
    `update_time` DATETIME DEFAULT now(),
    PRIMARY KEY (`id`)) ENGINE = INNODB DEFAULT CHARACTER
SET = utf8mb4 COMMENT = '产品表';

-- 数据初始化
insert into product_detail (id, product_name, product_price, state)
values
(1001, 'T恤', 101, 0),
(1002, '短裤', 30, 0),
(1003, '香烟', 44, 0),
(1004, '马甲', 58, 1),
(1005, '耳甲', 90, 1),
(1006, '羽绒服', 100, 0),
(1007, '裤子', 31, 0),
(1008, '鞋子', 44, 0),
(1009, '卫衣', 58, 0),
(1010, '毛衣', 98, 0);

工程搭建

构建父子工程

创建父工程

  1. 创建一个空的 Maven 项目,删除所有代码,只保留 pom.xml

  2. 完善 pom 文件

使用 properties 来进行版本号的统一管理,使用 dependencyManagement 来管理依赖,声明父工程的打包方式为 pom

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>  
<project xmlns="http://maven.apache.org/POM/4.0.0"  
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
    <modelVersion>4.0.0</modelVersion>  
  
    <groupId>org.example</groupId>  
    <artifactId>250709-spring-cloud-demo</artifactId>  
    <packaging>pom</packaging>  
    <version>1.0-SNAPSHOT</version>  
  
    <parent>        
    	<groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter-parent</artifactId>  
        <version>3.1.6</version>  
        <relativePath> <!-- lookup parent from repository --> </relativePath>  
    </parent>  
    <properties>       
    	<maven.compiler.source>17</maven.compiler.source>  
        <maven.compiler.target>17</maven.compiler.target>  
        <java.version>17</java.version>  
        <mybatis.version>3.0.3</mybatis.version>  
        <mysql.version>8.0.33</mysql.version>  
        <spring-cloud.version>2022.0.3</spring-cloud.version>  
    </properties>  
    
    <dependencies>        
    	<dependency>            
    		<groupId>org.projectlombok</groupId>  
            <artifactId>lombok</artifactId>  
            <optional>true</optional>  
        </dependency>    
    </dependencies>  
    
    <dependencyManagement>        
    	<dependencies>            
    		<dependency>               
    			<groupId>org.springframework.cloud</groupId>  
                <artifactId>spring-cloud-dependencies</artifactId>  
                <version>${spring-cloud.version}</version>  
                <type>pom</type>  
                <scope>import</scope>  
            </dependency>  
            <dependency>               
            	<groupId>org.mybatis.spring.boot</groupId>  
                <artifactId>mybatis-spring-boot-starter</artifactId>  
                <version>${mybatis.version}</version>  
            </dependency>  
            <dependency>                
            	<groupId>com.mysql</groupId>  
                <artifactId>mysql-connector-j</artifactId>  
                <version>${mysql.version}</version>  
            </dependency>        
        </dependencies>    
    </dependencyManagement>
</project>
DependencyManagement 和 Dependencies
  1. dependencies:将所依赖的 jar 直接加到项目中。子项目也会继承该依赖
  2. dependencyManagement:只是声明依赖,并不实现 jar 包引入。
    • 如果子项目需要用到相关依赖,需要显示声明
    • 如果子项目没有指定具体版本,会从父项目中读取 version
    • 如果子项目中制定了具体版本,就会使用子项目中指定的 jar 版本。
    • 此外父工程的打包方式应该是 pom,不是 jar ,这里需要手动使用 packaging 来声明

SpringBoot 实现依赖 jar 包版本的管理,也是这种方式

依赖 jar 的版本判断

xml 复制代码
<dependencies>  
    <dependency>        <groupId>org.projectlombok</groupId>  
        <artifactId>lombok</artifactId>  
        <optional>true</optional>  
    </dependency></dependencies>  
  
<dependencyManagement>  
    <dependencies>        
        <dependency>            
        	<groupId>com.mysql</groupId>  
            <artifactId>mysql-connector-j</artifactId>  
            <version>${mysql.version}</version>  
        </dependency>    
    </dependencies>
</dependencyManagement>
  • 上述代码中,lombok 会被直接引入到当前项目以及子项目中,mysql-connector-j 不会实际引入 jar,子项目继承时必须显示声明
Spring Cloud 版本

SpringCloud 是基于 SpringBoot 搭建的,所以 SpringCloud 版本与 SpringBoot 版本有关

  • 我们项目中使用的 SpringBoot 版本为 3.1.6,对应的 SpringCloud 版本应该为 2022.0.x,选择任意就可以

创建子项目---订单服务

声明项目依赖和项目构建插件
xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
    </dependency>

    <!-- mybatis -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

创建子项目---商品服务

声明项目依赖和项目构建插件
xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
    </dependency>

    <!-- mybatis -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

完善订单服务

完善启动类,配置文件

启动类

java 复制代码
package org.example.order;  
  
import org.springframework.boot.SpringApplication;  
import org.springframework.boot.autoconfigure.SpringBootApplication;  
  
@SpringBootApplication  
public class OrderServiceApplication {  
    public static void main(String[] args) {  
        SpringApplication.run(OrderServiceApplication.class, args);  
    }  
}

配置文件

yml 复制代码
server:  
  port: 8080  
spring:  
  datasource:  
    url: jdbc:mysql://127.0.0.1/cloud_order?characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
    username: root  
    password: 20230153018  
    driver-class-name: com.mysql.cj.jdbc.Driver  
mybatis:  
  configuration: # 配置打印 mybatis 日志  
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  
    map-underscore-to-camel-case: true  # 配置驼峰自动转换

业务代码

  1. 实体类
java 复制代码
package org.example.order.model;  
  
import lombok.Data;  
  
import java.util.Date;  
  
@Data  
public class OrderInfo {  
    private Integer id;  
    private Integer userId;  
    private Integer productId;  
    private Integer num;  
    private Integer price;  
    private Integer deleteFlag;  
    private Date createTime;  
    private Date updateTime;  
}
  1. controller
java 复制代码
package org.example.order.controller;  
  
import org.example.order.model.OrderInfo;  
import org.example.order.service.OrderService;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.web.bind.annotation.PathVariable;  
import org.springframework.web.bind.annotation.RequestMapping;  
import org.springframework.web.bind.annotation.RestController;  
  
@RestController  
@RequestMapping("/order")  
public class OrderController {  
    @Autowired  
    private OrderService orderService;  
  
    @RequestMapping("/{orderId}")  
    public OrderInfo getOrderById(@PathVariable("orderId") Integer orderId) {  
        return orderService.selectOrderById(orderId);  
    }  
}
  1. Service
java 复制代码
package org.example.order.service;  
  
import org.example.order.mapper.OrderMapper;  
import org.example.order.model.OrderInfo;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Service;  
  
@Service  
public class OrderService {  
  
    @Autowired  
    private OrderMapper orderMapper;  
  
    public OrderInfo selectOrderById(Integer orderId) {  
        OrderInfo orderInfo = orderMapper.selectOrderById(orderId);  
        return orderInfo;  
    }  
}
  1. Mapper
java 复制代码
package org.example.order.mapper;  
  
import org.apache.ibatis.annotations.Mapper;  
import org.apache.ibatis.annotations.Select;  
import org.example.order.model.OrderInfo;  
  
@Mapper  
public interface OrderMapper {  
    @Select("select * from order_detail where id = #{orderId}")  
    OrderInfo selectOrderById(Integer orderId);  
}

测试

访问 URLhttp://127.0.0.1:8080/order/1

页面正常返回结果:

完善商品服务

完善启动类,配置文件

启动类

java 复制代码
package org.example.order;  
  
import org.springframework.boot.SpringApplication;  
import org.springframework.boot.autoconfigure.SpringBootApplication;  
  
@SpringBootApplication  
public class ProductServiceApplication {  
    public static void main(String[] args) {  
        SpringApplication.run(ProductServiceApplication.class, args);  
    }  
}

配置文件

yml 复制代码
server:  
  port: 9090  
spring:  
  datasource:  
    url: jdbc:mysql://127.0.0.1:3306/cloud_product?useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true  
    username: root  
    password: 20230153018  
    driver-class-name: com.mysql.cj.jdbc.Driver  
  
mybatis:  
  configuration: # 配置打印 mybatis 日志  
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  
    map-underscore-to-camel-case: true  # 配置驼峰自动转换
  • 后面需要多个服务一起启动,所以设置为不同的端口号

业务代码

  1. 实体类
java 复制代码
package org.example.order.model;  
  
import lombok.Data;  
  
import java.util.Date;  
  
@Data  
public class ProductInfo {  
    private Integer id;  
    private String productName;  
    private Integer productPrice;  
    private Integer state;  
    private Date createTime;  
    private Date updateTime;  
}
  1. Controller
java 复制代码
package org.example.order.controller;  
  
import org.example.order.model.ProductInfo;  
import org.example.order.service.ProductService;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.web.bind.annotation.PathVariable;  
import org.springframework.web.bind.annotation.RequestMapping;  
import org.springframework.web.bind.annotation.RestController;  
  
@RestController  
@RequestMapping("/product")  
public class ProductController {  
    @Autowired  
    private ProductService productService;  
  
    @RequestMapping("/{productId}")  
    public ProductInfo getProductById(@PathVariable("productId") Integer productId) {  
        System.out.println("收到请求, Id: " + productId);  
        return productService.selectProductById(productId);  
    }  
}
  1. Service
java 复制代码
package org.example.order.service;  
  
import org.example.order.mapper.ProductMapper;  
import org.example.order.model.ProductInfo;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Service;  
  
@Service  
public class ProductService {  
    @Autowired  
    private ProductMapper productMapper;  
  
    public ProductInfo selectProductById(Integer id) {  
        return productMapper.selectProductById(id);  
    }  
}
  1. Mapper
java 复制代码
package org.example.order.mapper;  
  
import org.apache.ibatis.annotations.Mapper;  
import org.apache.ibatis.annotations.Select;  
import org.example.order.model.ProductInfo;  
  
@Mapper  
public interface ProductMapper {  
    @Select("select * from product_detail where id=#{id}")  
    ProductInfo selectProductById(Integer id);  
}

测试

访问 URLhttp://127.0.0.1:9090/product/1001

页面正常返回结果:

远程调用

需求

根据订单查询订单信息时,根据订单里产品 ID,获取产品的详细信息

实现

实现思路order_service 服务向 product_service 服务发送一个 HTTP 请求,把得到的返回结果,和订单结果融合在一起,返回给调用方

实现方式 :采用 Spring 提供的 RestTemplate


  1. 定义 RestTemplate
java 复制代码
package org.example.order.config;  
  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.web.client.RestTemplate;  
  
@Configuration  
public class BeanConfig {  
    @Bean  
    public RestTemplate restTemplate() {  
        return new RestTemplate();  
    }  
}
  1. ProductInfo 添加到 order_service.model 里面,并将 OrderInfo 改为
java 复制代码
package org.example.order.model;  
  
import lombok.Data;  
  
import java.util.Date;  
  
@Data  
public class OrderInfo {  
    private Integer id;  
    private Integer userId;  
    private Integer productId;  
    private Integer num;  
    private Integer price;  
    private Integer deleteFlag;  
    private Date createTime;  
    private Date updateTime;  
    private ProductInfo productInfo;  
}
  1. 修改 order_service 中的 OrderService
java 复制代码
package org.example.order.service;  
  
import org.example.order.mapper.OrderMapper;  
import org.example.order.model.OrderInfo;  
import org.example.order.model.ProductInfo;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Service;  
import org.springframework.web.client.RestTemplate;  
  
@Service  
public class OrderService {  
  
    @Autowired  
    private OrderMapper orderMapper;  
    @Autowired  
    private RestTemplate restTemplate;  
  
    public OrderInfo selectOrderById(Integer orderId) {  
        OrderInfo orderInfo = orderMapper.selectOrderById(orderId);  
        String url = "http://127.0.0.1:9090/product/" + orderInfo.getProductId();  
        ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);  
        orderInfo.setProductInfo(productInfo);  
        return orderInfo;  
    }  
}

RestTemplate 详细使用可参考: https://www.cnblogs.com/54chensongxia/p/11414923.html


测试

访问 URL: http://127.0.0.1:8080/order/1

页面返回结果:

  • 注意:两个启动类都要启动
相关推荐
gadiaola19 分钟前
【计算机网络面试篇】HTTP
java·后端·网络协议·计算机网络·http·面试
S90378459720 分钟前
为什么取模在除数等于2^n的时候可以用按位与替代?
java·tomcat·计算机外设·hibernate
e***09628 分钟前
SQL 中UPDATE 和 DELETE 语句的深入理解与应用
数据库·sql
7***37451 小时前
Java设计模式之工厂
java·开发语言·设计模式
程序员小白条2 小时前
你面试时吹过最大的牛是什么?
java·开发语言·数据库·阿里云·面试·职场和发展·毕设
折翅嘀皇虫2 小时前
fastdds.type_propagation 详解
java·服务器·前端
小年糕是糕手2 小时前
【C++】类和对象(二) -- 构造函数、析构函数
java·c语言·开发语言·数据结构·c++·算法·leetcode
豐儀麟阁贵2 小时前
8.2异常的抛出与捕捉
java·开发语言·python
老华带你飞2 小时前
社区养老保障|智慧养老|基于springboot+小程序社区养老保障系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·小程序·毕设·社区养老保障