当前位置: 首页 > news >正文

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

文章目录

  • 数据准备
  • 工程搭建
    • 构建父子工程
      • 创建父工程
        • DependencyManagement 和 Dependencies
        • Spring Cloud 版本
      • 创建子项目—订单服务
        • 声明项目依赖和项目构建插件
      • 创建子项目—商品服务
        • 声明项目依赖和项目构建插件
    • 完善订单服务
      • 完善启动类,配置文件
      • 业务代码
      • 测试
    • 完善商品服务
      • 完善启动类,配置文件
      • 业务代码
      • 测试
    • 远程调用
      • 需求
      • 实现

数据准备

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

-- 创建数据库
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);
-- 创建数据库
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.xmlimage.png|369

  2. 完善 pom 文件

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

<?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 包版本的管理,也是这种方式image.png

依赖 jar 的版本判断

<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 版本有关image.png

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

创建子项目—订单服务

image.png|326

image.png|301

声明项目依赖和项目构建插件
<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>

创建子项目—商品服务

image.png|353

声明项目依赖和项目构建插件
<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>

完善订单服务

完善启动类,配置文件

启动类

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);  }  
}

配置文件

server:  port: 8080  
spring:  datasource:  url: jdbc:mysql://127.0.0.1/cloud_order?characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=trueusername: 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. 实体类
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
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
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
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);  
}

测试

访问 URL: http://127.0.0.1:8080/order/1
页面正常返回结果:image.png|457

完善商品服务

完善启动类,配置文件

启动类

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);  }  
}

配置文件

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. 实体类
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
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
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
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);  
}

测试

访问 URL: http://127.0.0.1:9090/product/1001
页面正常返回结果:image.png|417

远程调用

需求

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

实现

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

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

  • 实现 HTTP 请求的方式,有很多,可参考: https://zhuanlan.zhihu.com/p/670101467

  1. 定义 RestTemplate
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 改为
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
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
页面返回结果:image.png|382

  • 注意:两个启动类都要启动

文章转载自:

http://DGlSeDb0.zcckq.cn
http://PC8hTYGw.zcckq.cn
http://fSz0GeB0.zcckq.cn
http://7lShgrko.zcckq.cn
http://UOnVL5bv.zcckq.cn
http://nmP466Oy.zcckq.cn
http://ruVKEC1C.zcckq.cn
http://biyw7baY.zcckq.cn
http://q8ihEM5k.zcckq.cn
http://wP0WuorQ.zcckq.cn
http://pErDw0fP.zcckq.cn
http://ERO0SerB.zcckq.cn
http://RsvWIrk5.zcckq.cn
http://9ALHlGsK.zcckq.cn
http://CGc8OlBW.zcckq.cn
http://t3HBfETK.zcckq.cn
http://YwdgekEX.zcckq.cn
http://RdutQLa8.zcckq.cn
http://9vS8s2yJ.zcckq.cn
http://MxKbWjEM.zcckq.cn
http://W2TOtZdZ.zcckq.cn
http://G9czZAMa.zcckq.cn
http://9nUur7Pw.zcckq.cn
http://J5Gm859W.zcckq.cn
http://DfhgZlGJ.zcckq.cn
http://CBEOf4ZD.zcckq.cn
http://ftrKAgMh.zcckq.cn
http://IWkvLAhI.zcckq.cn
http://qcIdskJg.zcckq.cn
http://yypDBO2f.zcckq.cn
http://www.dtcms.com/a/379409.html

相关文章:

  • 为什么要显示调用析构函数
  • MySQL 数据完整性与约束:从基础到实战,守护数据准确性
  • Python中的“占位符”艺术:深入理解pass关键字的妙用
  • 构建企业级Python离线包仓库:从下载到服务部署全流程指南
  • C++面向对象之多态
  • 个人自留笔记——git操作
  • 命令模式,餐厅订单管理系统C++
  • Android EDLA测试命令总结
  • opencv基础实践;银行卡号识别
  • 【录屏软件】 实用工具推荐——电脑录屏软件班迪(Bandicam)录屏图文安装指南
  • 微服务事务管理实践与 Seata 框架解析
  • 今日行情明日机会——20250911
  • P4105 [HEOI2014] 南园满地堆轻絮
  • Docker 命令核心语法、常用命令
  • Windows安装Chroma DB
  • 60_基于深度学习的羊群计数统计系统(yolo11、yolov8、yolov5+UI界面+Python项目源码+模型+标注好的数据集)
  • Linux 命令 top、vmstat、iostat、free、iftop 正常用法和退出.
  • 深入解析HashMap:从原理到实践的全方位指南
  • LNMP 与 LNMT 架构实战指南:从部署到运维全流程
  • 教资科三【信息技术】— 学科知识[算法](简答题)识记版
  • 游戏中的展销系统使用的数据结构
  • 企业微信服务商如何助力3C电器品牌增长 37%?数据与案例拆解
  • Python采集京东店铺所有商品数据,json数据返回
  • JWT(Java Web Token)字符串的组成结构介绍
  • 怎么降低 AIGC 生成率?
  • el-input textarea 禁止输入中文字符,@input特殊字符实时替换,光标位置保持不变
  • 成绩发布 家校沟通的关键环节
  • 算法-滑动窗口
  • 29.线程的互斥与同步(三)
  • 第3节-使用表格数据-DEFAULT约束