SpringCloud工程部署启动

简介: 本文介绍SpringCloud微服务工程搭建与部署,支持完整导入或从零搭建。包含父工程与子模块(order-service、user-service)创建、POM依赖配置、数据库建表及业务代码实现,并通过RestTemplate实现服务间远程调用,初步构建微服务调用链路,帮助理解服务拆分与通信机制。(238字)

工程搭建部署
方案一:完整工程导入
● ,如无法运行尝试换未编译版:
● 下载解压上述工程,ide工具导入
方案二:从零开始搭建
1.工程与module创建
1.1 父工程创建

1.2 子module创建
● module名称:order-service、user-service
● 无效文件夹删除,整体结构如图2

1.3 父pom资源引入

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


org.springframework.boot
spring-boot-starter-parent
2.3.9.RELEASE


UTF-8
UTF-8
1.8
Hoxton.SR10
5.1.47
2.1.1
1.18.20





org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import



mysql
mysql-connector-java
${mysql.version}



org.mybatis.spring.boot
mybatis-spring-boot-starter
${mybatis.version}


org.projectlombok
lombok
${lombok.version}



1.4 子module资源引入
user-service



org.springframework.boot
spring-boot-starter-web


mysql
mysql-connector-java



org.mybatis.spring.boot
mybatis-spring-boot-starter


org.projectlombok
lombok


app


org.springframework.boot
spring-boot-maven-plugin



order-service



org.springframework.boot
spring-boot-starter-web


mysql
mysql-connector-java



org.mybatis.spring.boot
mybatis-spring-boot-starter


org.projectlombok
lombok




org.springframework.boot
spring-boot-maven-plugin



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语句


导完如下

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
此处推荐一个小的优雅工具:https://carbon.now.sh/

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

相关文章
sentinel-dashboard-1.8.0.jar开机自启动脚本
sentinel-dashboard-1.8.0.jar开机自启动脚本
603 0
|
9月前
|
消息中间件 Java 数据安全/隐私保护
RabbitMQ集群部署
本文介绍RabbitMQ集群部署与高可用方案,涵盖普通集群搭建、Erlang Cookie配置、节点发现机制及安全设置。通过静态配置实现三节点集群,并详解镜像模式(exactly、all、nodes)提升高可用性,避免单点故障。同时引入3.8版本后的仲裁队列,简化配置,实现数据冗余与自动主从切换,保障消息服务的稳定性与可靠性。
|
12月前
|
存储 NoSQL 前端开发
Redis专题-实战篇一-基于Session和Redis实现登录业务
本项目基于SpringBoot实现黑马点评系统,涵盖Session与Redis两种登录方案。通过验证码登录、用户信息存储、拦截器校验等流程,解决集群环境下Session不共享问题,采用Redis替代Session实现数据共享与自动续期,提升系统可扩展性与安全性。
639 3
Redis专题-实战篇一-基于Session和Redis实现登录业务
|
安全 前端开发 Java
Spring Boot 项目中触发 Circular View Path 错误的原理与解决方案
在Spring Boot开发中,**Circular View Path**错误常因视图解析与Controller路径重名引发。当视图名称(如`login`)与请求路径相同,Spring MVC无法区分,导致无限循环调用。解决方法包括:1) 明确指定视图路径,避免重名;2) 将视图文件移至子目录;3) 确保Spring Security配置与Controller路径一致。通过合理设定视图和路径,可有效避免该问题,确保系统稳定运行。
1020 0
|
消息中间件 监控 负载均衡
七万字整理SpringCloud + CloudAlibaba知识点总结笔记
各位小伙伴们大家好,欢迎来到这个小扎扎的[spring cloud专栏],在这个系列专栏中我对B站尚硅谷阳哥的spring cloud教程进行一个总结,鉴于 看到就是学到、学到就是赚到 精神,这波依然是血赚 ┗|`O′|┛
3222 0
七万字整理SpringCloud + CloudAlibaba知识点总结笔记
|
JavaScript 前端开发
常用的 JavaScript 框架和库
常用的 JavaScript 框架和库
542 7
|
负载均衡 Java Spring
@EnableFeignClients注解源码解析
@EnableFeignClients注解源码解析
531 14
|
JavaScript 前端开发 程序员
Vue学习之--------Vue生命周期beforeCreate、created、beforeMount、mounted、beforeDestroy 。。。(图解详细过程)(2022/7/17)
这篇文章详细介绍了Vue的生命周期和各个阶段的钩子函数,包括`beforeCreate`、`created`、`beforeMount`、`mounted`、`beforeUpdate`、`updated`、`beforeDestroy`和`destroyed`。文章通过图解、方法说明、代码实例和测试效果,阐述了每个钩子函数的作用和使用场景,帮助读者深入理解Vue实例从创建到销毁的整个过程。
Vue学习之--------Vue生命周期beforeCreate、created、beforeMount、mounted、beforeDestroy 。。。(图解详细过程)(2022/7/17)
|
SQL 算法 安全
odps是什么?
ODPS(Open Data Processing Service),原是阿里云从 09年开始自研的大规模批量计算引擎,2016 年更名为MaxCompute。2022云栖大会上,阿里云ODPS全新升级为一体化大数据平台,存储、调度、元数据一体化融合 ,从 Processing 升级为 Platform,即 Open Data Platform and Service。提供了离线计算、实时交互式分析、机器学习等可扩展的智能计算引擎,满足用户多元化数据计算需求。
79671 133
odps是什么?
|
存储 人工智能 分布式计算
【云栖2023】张治国:MaxCompute架构升级及开放性解读
本文根据2023云栖大会演讲实录整理而成,演讲信息如下 演讲人:张治国|阿里云智能计算平台研究员、阿里云MaxCompute负责人 演讲主题:MaxCompute架构升级及开放性解读 活动:2023云栖大会
62246 17

热门文章

最新文章