基础篇:03-SpringCloud工程部署启动

news2024/11/16 6:21:02

目录

1.工程搭建部署

方案一:完整工程导入

方案二:从零开始搭建

1.工程与module创建

2.数据库导入

3.项目启动

3.1 启动并访问user-service

3.2 启动并访问order-service

4.服务远程调用

时序图说明

服务远程调用实现

注入RestTemplate

RestTemplate完成远程服务调用

重启并访问order-service

RestTemplate如何实现远程服务调用

5.总结

6.推荐阅读资料


1.工程搭建部署

方案一:完整工程导入

  • cloud.zip,如无法运行尝试换未编译版:cloud-demo.zip

  • 下载解压上述工程,ide工具导入 

方案二:从零开始搭建

1.工程与module创建

1.1 父工程创建

1.2 子module创建

  • module名称:order-service、user-service

  • 无效文件夹删除,整体结构如图2 

1.3 父pom资源引入

粘贴以下资源依赖,粘贴后maven会自动拉取依赖,如未拉取请手动刷新

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.9.RELEASE</version>
    <relativePath/>
</parent>
​
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
    <spring-cloud.version>Hoxton.SR10</spring-cloud.version>
    <mysql.version>5.1.47</mysql.version>
    <mybatis.version>2.1.1</mybatis.version>
    <lombok.version>1.18.20</lombok.version>
</properties>
​
<dependencyManagement>
    <dependencies>
        <!-- springCloud -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>${mybatis.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

1.4 子module资源引入

user-service

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!--mybatis-->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>
<build>
    <finalName>app</finalName>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

order-service

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!--mybatis-->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

1.5 业务代码编写

1.user-service

application.yml配置文件

server:
  port: 8081
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_user?useSSL=false
    username: root
    password: root123456
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS

|--mapper |-- UserMapper

package cn.itcast.user.mapper;
​
import cn.itcast.user.pojo.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
​
/**
 * 用户持久层
 *
 * @author 
 * @date 2022-12-22 14:12
 */
public interface UserMapper {
​
    /**
     * 根据ID查找用户
     * @param id    用户ID
     * @return      用户实体信息
     */
    @Select("select * from tb_user where id=#{id}")
    User findById(@Param("id") Long id);
}

|--pojo |-- User

package cn.itcast.user.pojo;
​
import lombok.Data;
​
/**
 * 用户实体
 *
 * @author 
 * @date 2022-12-22 14:07
 */
@Data
public class User {
​
    /**
     * 主键ID
     */
    private Long id;
​
    /**
     * 用户姓名
     */
    private String username;
​
    /**
     * 用户地址
     */
    private String address;
}

|--service |-- UserService

package cn.itcast.user.service;
​
import cn.itcast.user.mapper.UserMapper;
import cn.itcast.user.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
​
import java.util.Objects;
​
/**
 * 用户业务层
 *
 * @author 
 * @date 2022-12-22 14:13
 */
@Service
public class UserService {
​
    @Autowired
    private UserMapper userMapper;
​
    /**
     * 根据ID查找用户
     * @param id    用户ID
     * @return      用户实体信息
     */
    public User findById(Long id) {
        if (Objects.isNull(id)) {
            return null;
        }
        return userMapper.findById(id);
    }
​
}

|--web |-- UserController

package cn.itcast.user.web;
​
import cn.itcast.user.pojo.User;
import cn.itcast.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
​
/**
 * 用户控制层
 *
 * @author 
 * @date 2022-12-22 14:15
 */
@RestController
@RequestMapping("/user")
public class UserController {
​
    @Autowired
    private UserService userService;
​
    /**
     * 根据ID查找用户
     * @param id    ID
     * @return      用户信息
     */
    @GetMapping("/{id}")
    public User findById(@PathVariable("id") Long id) {
        return userService.findById(id);
    }
}

|--UserApplication

package cn.itcast.user;
​
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
​
/**
 * 启动类
 *
 * @author 
 * @date 2022-12-22 14:00
 */
@MapperScan("cn.itcast.user.mapper")
@SpringBootApplication
public class UserApplication {
​
    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
        System.out.println("用户工程启动成功");
    }
}

2.order-service

application.yml配置文件

server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
    username: root
    password: root123456
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  type-aliases-package: cn.itcast.order.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS

|--mapper |-- OrderMapper

package cn.itcast.order.mapper;
​
import cn.itcast.order.pojo.Order;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
​
/**
 * 订单持久层
 *
 * @author 
 * @date 2022-12-22 14:22
 */
public interface OrderMapper {
​
    /**
     * 根据ID查找订单
     * @param id    订单ID
     * @return      订单对象
     */
    @Select("select * from tb_order where id=#{id}")
    Order findById(@Param("id")Long id);
}

|--pojo |-- Order

package cn.itcast.order.pojo;
​
import lombok.Data;
​
/**
 * 订单实体(vo并非dto)
 *
 * @author 
 * @date 2022-12-22 14:19
 */
@Data
public class Order {
​
    /**
     * 主键ID
     */
    private Long id;
​
    /**
     * 用户主键ID
     */
    private Long userId;
​
    /**
     * 商品名称
     */
    private String name;
​
    /**
     * 商品价格
     */
    private Long price;
​
    /**
     * 商品数量
     */
    private Integer num;
​
    /**
     * 用户信息
     */
    private User user;
}

|-- User

package cn.itcast.order.pojo;
​
import lombok.Data;
​
/**
 * 用户实体
 *
 * @author 
 * @date 2022-12-22 14:07
 */
@Data
public class User {
​
    /**
     * 主键ID
     */
    private Long id;
​
    /**
     * 用户姓名
     */
    private String username;
​
    /**
     * 用户地址
     */
    private String address;
}

|--service |-- OrderService

package cn.itcast.order.service;
​
import cn.itcast.order.mapper.OrderMapper;
import cn.itcast.order.pojo.Order;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
​
/**
 * 订单业务层
 *
 * @author 
 * @date 2022-12-22 14:24
 */
@Service
public class OrderService {
​
    @Autowired
    private OrderMapper orderMapper;
​
    /**
     * 根据ID查找订单
     * @param id    订单ID
     * @return      订单对象
     */
    public Order findById(Long id) {
        Order order = orderMapper.findById(id);
        return order;
    }
}

|--web |-- OrderController

package cn.itcast.order.web;
​
import cn.itcast.order.pojo.Order;
import cn.itcast.order.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
​
/**
 * 订单控制层
 *
 * @author 
 * @date 2022-12-22 14:25
 */
@RestController
@RequestMapping("/order")
public class OrderController {
​
    @Autowired
    private OrderService orderService;
​
    /**
     * 根据ID查找订单
     * @param orderId    订单ID
     * @return           订单对象
     */
    @GetMapping("/{orderId}")
    public Order findById(@PathVariable("orderId")Long orderId) {
        return orderService.findById(orderId);
    }
}

|--OrderApplication

package cn.itcast.order;
​
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
​
/**
 * 启动类
 *
 * @author 
 * @date 2022-12-22 14:05
 */
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {
​
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
        System.out.println("订单工程启动成功");
​
    }
}
 

2.数据库导入

  • 需参见上图新建两个数据库,然后导入DDL语句

  • cloud-order.sql

  • cloud-user.sql

导完如下

3.项目启动

3.1 启动并访问user-service

3.2 启动并访问order-service

        观察发现,虽然order-service服务调用成功,但是里面的user对象却是空的。原因我们应该也可以了解到是因为User对象数据数存储在数据库:tb_user,而此工程连接数据库是:tb_order,查询此数据库时无法获取对应的User数据,怎么获取?获取的具体实现我们将在下一章节进一步铺开。 

4.服务远程调用

分析现有链路调用关系可以发现:

  • http://localhost:8081/user/{id} 可以获取用户信息

  • http://localhost:8081/order/{orderId} 可以获取订单信息,但是用户信息为空

想要订单信息中返回用户信息,只要在获取订单链路中追加对用户信息的获取、返回值的组装即可,由此引申出微服务之间的远程服务调用,具体调整可见下图。

时序图说明

        上述图形为时序图,一般用来描述系统与系统之间的交互流程,主要是交互API、代码顺序、参数一般忽略,时序图不同于业务流程,更关注业务实现过程中系统前后依赖,数据请求与返回,以下为笔者实际工作场景示例:

服务远程调用实现

注入RestTemplate

此处推荐一个小的优雅工具:Carbon | Create and share beautiful images of your source code

RestTemplate完成远程服务调用

在此笔者除了完成远程服务调用,同时对代码做了结构化、异常校验、函数封装。虽然此处逻辑并不复杂,但是对于主干逻辑简化和代码风格,希望能起到一个引导作用。

package cn.itcast.order.service;
​
import cn.itcast.order.mapper.OrderMapper;
import cn.itcast.order.pojo.Order;
import cn.itcast.order.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
​
import java.util.Objects;
​
/**
* 订单业务层
*
* @author 
* @date 2022-12-22 14:24
*/
@Service
public class OrderService {
​
    @Autowired
    private OrderMapper orderMapper;
​
    @Autowired
    private RestTemplate restTemplate;
​
    /**
     * 根据ID查找订单
     * @param id    订单ID
     * @return      订单对象
     */
    public Order findById(Long id) {
​
        // step 1 : 查询订单原始数据
        Order order = orderMapper.findById(id);
        if (Objects.isNull(order)) {
            return null;
        }
​
        // step 2 : 查询用户数据
        User user = queryUserInfoById(order.getUserId());
​
        // step 3 : 组装用户数据
        if (Objects.nonNull(user)) {
            order.setUser(user);
        }
​
        // step 4: 数据返回
        return order;
    }
​
    /**
     * 根据用户ID查找用户信息
     * @param userId    用户ID
     * @return          用户信息
     */
    private User queryUserInfoById(Long userId) {
        String url = "http://localhost:8081/user/" + userId;
        return restTemplate.getForObject(url, User.class);
    }
}

重启并访问order-service

RestTemplate如何实现远程服务调用

5.总结

        本节笔者带领大家完成了SpringCloud工程从0->1的搭建,当然你不想搭建也可以直接采用方案一,二者等效,至此读者们完成了一个微服务工程的搭建、部署、访问。同时在本节最后一章,笔者基于RestTemplate发起的http请求实现远程调用,实现当A系统想要获取B系统数据时的跨系统数据交互。然而RESTful API(进一步了解可移步:链接)访问并不是微服务的唯一解决方案,如Dubbo的交互一样可以实现,希望读者们能不限于此。

         在本章节,笔者希望大家对于微服务的拆分,服务调用关系有个初步认知,本例中当order-service调用user-service时,前者就充当了服务调用方,后者则是服务提供方,这种调用关系在后续我们将会大量使用。


思考问题

  • 如何实现服务远程调用?

  • 服务远程调用解决了什么问题?

  • 还有哪些技术可以实现远程服务调用?


6.推荐阅读资料

  • 了解时序图绘制:https://www.cnblogs.com/liuyitan/p/16631240.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/349649.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

自学web前端觉得好难,可能你遇到了这些困境

好多人跟我说上学的时候也学过前端&#xff0c;毕业了想从事web前端开发的工作&#xff0c;但自学起来好难&#xff0c;快要放弃了&#xff0c;所以我总结了一些大家遇到的困境&#xff0c;希望对你会有所帮助。 目录 1. 意志是否坚定 2. 没有找到合适自己的老师 3. 为了找…

论文阅读【PAMI_2022】FSGANv2: Improved Subject Agnostic Face Swapping and Reenactment

论文阅读【PAMI_2022】FSGANv2: Improved Subject Agnostic Face Swapping and Reenactment论文的缩写全拼一、摘要&#xff08;问题&#xff0c;贡献&#xff0c;效果&#xff09;二、引言&#xff08;idea&#xff09;三、方法(FSGAN)1.Detection and tracking2.Generator ar…

node学习-3:服务器渲染和客户端渲染

1. 概念 一.服务端渲染&#xff0c;后端嵌套模板&#xff0c;后端渲染模板&#xff0c;SSR&#xff08;后端把页面组装好&#xff09; 做好静态页面&#xff0c;动态效果 把前端代码提供给后端&#xff0c;后端则把静态html以及里面的假数据给删除掉 通过模板进行动态生成h…

8个让你收入翻倍的高质量免费网站

毕业几年了&#xff0c;如果你的月薪不到1w&#xff0c;还是做着重复机械的动作&#xff0c;现在马上往下看&#xff0c;今天分享6个资源网站让你的收入暴增&#xff0c;尤其是最后一个。每天花一个小时&#xff0c;让你工资翻倍&#xff0c;从此在职场横着走&#xff0c;再也不…

GEE学习笔记 八十三:【GEE之Python版教程十三】几何图形

遥感分析中用到的数据主要就是这两大类&#xff1a;矢量数据和栅格数据。在Google Earth Eninge中&#xff0c;它为我们讲这两类数据封装成为了以下几类数据。 下面几节内容我会依次讲解相关内容的详细信息&#xff0c;这一节先讲一下几何图形ee.geometry。 学习任何新的东西首…

设计模式之抽象工厂模式(C++)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 一、抽象工厂模式是什么&#xff1f; 抽象工厂模式是一种创建型的软件设计模式&#xff0c;该模式相当于升级版的工厂模式。 如果…

采集知乎评论

声明 本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! excel保存效果图: 首先我们找一个评论比较多的帖子,如下图所示有874条评论 点击评论…

算法刷刷刷| 回溯篇| 组合问题大集合

77.组合 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 输入&#xff1a;n 4, k 2 输出&#xff1a; [[2,4], [3,4], [2,3], [1,2], [1,3], [1,4],] import java.util.ArrayList; import java.util.List;clas…

可靠、稳定、安全,龙蜥云原生容器镜像正式发布!

文/云原生 SIG01背景随着云原生的蓬勃发展&#xff0c;越来越多的企业在自己的生产或者测试环境使用云原生技术&#xff0c;而容器镜像正是云原生技术中应用的实际运行环境。一个好的容器运行环境即容器镜像会真正关系到应用的体验、演进和维护。那么选择一个好的容器镜像需要考…

Flink实时同步MySQL与Doris数据

参考&#xff1a; 技术解析&#xff5c;Doris Connector 结合 Flink CDC 实现 MySQL 分库分表 Exactly Once 精准接入-阿里云开发者社区 逻辑图&#xff1a; 1. Flink环境&#xff1a; https://flink.apache.org/zh/ 下载flink-1.15.1 wget https://dlcdn.apache.org/flink…

并发编程之synchronized详解

目录 设计同步器的意义 如何解决线程并发安全问题&#xff1f; synchronized原理详解 synchronized底层原理 Monitor监视器锁 什么是monitor&#xff1f; 对象的内存布局 对象头 对象头分析工具 锁的膨胀升级过程 偏向锁 轻量级锁 自旋锁 锁消除 逃逸分析 设…

RabbitMQ学习(七):交换器

〇、前言在之前的内容中&#xff0c;我们创建了一个工作队列。我们假设的是工作队列背后&#xff0c;每个任务都恰好交付给一个消 费者(工作进程)。在今天的内容中&#xff0c;我们将做一些完全不同的事情——我们将消息传达给多个消费者。这种模式 称为 “发布/订阅”。为了说…

横板格斗类游戏实战:核心玩法介绍(一)

第一章讲解了横板格斗类游戏框架主要涉及到的一些模块设计与技术原理&#xff0c;本章节开始讲解横板格斗类游戏的玩法&#xff0c;美术资源与游戏的数值策划。我们以主要的截图为示意图&#xff0c;来把整个横板格斗类游戏的核心玩法和要实现的功能大致列一遍。对啦&#xff0…

QGIS中进行批量坡向计算

QGIS中进行坡向计算1. 坡向计算中的Z因子&#xff08;垂直单位与水平单位的比值&#xff09;2. 坡向计算步骤坡度计算的姊妹篇–坡向计算来了 1. 坡向计算中的Z因子&#xff08;垂直单位与水平单位的比值&#xff09; z 因子是一个转换因子&#xff0c;当输入表面的垂直坐标&…

BFC到底是什么?如何理解

BFC到底是什么&#xff1f; BFC全称&#xff1a;Block Formatting Context&#xff0c; 名为“块级格式化上下文”。 W3C官方解释&#xff1a;BFC 它决定了元素如何对其内容进行定位&#xff0c;以及与其他元素的关系和相互作用&#xff0c;当涉及到可视化布局时&#xff0c;B…

IMU调试方案

1.IMU 型号 QMI8658C IMU英文数据手册 参照连线与数据手册使用 类似的惯导模块开发https://www.cnblogs.com/rockyching2009/p/15071669.html 微雪 https://www.waveshare.net/wiki/RP2040-LCD-1.28 micro python &#xff1a;https://docs.micropython.org/en/latest/esp32/t…

ArcGIS API for JavaScript 4.15系列(7)——Dojo中的Ajax请求操作

1、前言 作为重要的前后端交互技术&#xff0c;Ajax被广泛应用于Web项目中。无论是jQuery时代的$.ajax还是Vue时代下的axios&#xff0c;它们都对Ajax做了良好的封装处理。而Dojo也不例外&#xff0c;开发者使用dojo/request模块可以轻松实现Ajax相关操作&#xff0c;下面开始…

UNP 简介

目录 从一个简单的时间获取客户端开始 socket 指定服务器 IP 地址与端口 与服务器建立连接并读取数据 简单的时间获取服务端 Unix 标准 从一个简单的时间获取客户端开始 接下来&#xff0c;将从一个使用 TCP 连接的获取时间的客户端开始。 // 以下代码与 UNP intro/dayt…

后台管理项目重构为vue3.0

目录前言&#xff1a;为什么要重构项目&#xff1f;重构的目的具体案例下载项目一. 为什么要重构后台管理项目二. 安装项目所需的vue3.0 插件三. 具体代码重构四. 在更改中遇到的bug总结前言&#xff1a; 我们平常玩的游戏有时需要更新出新的内容&#xff0c;我们的项目也需要…

组件化、模块化、集中式、分布式、服务化、面向服务的架构、微服务架构

目录 1.组件化与模块化 1.1.组件化 2.模块化 2.1.模块化和组件化的区别 3.集中式与分布式 3.1.集中式 3.2.分布式 4.服务化 5.面向服务的架构 5.1.什么是SOA 5.2.实现SOA 5.3.面向对象和面向服务的对比 6.微服务架构 6.1.SOA和微服务 7.总结 最近最火的词是什么…