【JavaEE】【SpringCloud】环境与工程搭建

目录

  • 一、环境搭建
  • 二、工程搭建
    • [2.1 案例](#2.1 案例)
    • [2.2 服务拆分原则](#2.2 服务拆分原则)
    • [2.3 父子工程搭建](#2.3 父子工程搭建)
      • [2.3.1 数据准备](#2.3.1 数据准备)
      • [2.3.2 创建⽗⼯程](#2.3.2 创建⽗⼯程)
      • [2.3.3 创建子工程](#2.3.3 创建子工程)
      • [2.3.4 订单服务](#2.3.4 订单服务)
      • [2.3.5 商品服务](#2.3.5 商品服务)
  • 三、远程调用
  • 四、RestTemplate
    • [4.1 REST](#4.1 REST)
    • [4.2 RESTful](#4.2 RESTful)

一、环境搭建

在服务器和本地都安装JDK17和MySQL。

Ubuntu安装JDK:

yml 复制代码
#更新软件包
sudo apt update 
#安装JDK
sudo apt install openjdk-17-jdk

Ubuntu安装mysql:

java 复制代码
#查找安装包
apt list |grep "mysql-server"
#安装mysql
sudo apt install mysql-server
 #安装安全设置 
sudo mysql_secure_installation
#连接mysql服务器
 sudo mysql
 --密码强度为2时, 密码要包含⼤⼩写字符, 特殊符号 
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 
'密码';

二、工程搭建

2.1 案例

我们以一个电商平台的案例来解析一下,微服务的工程搭建。

2.2 服务拆分原则

微服务的拆分主要遵循以下原则(具体的实现还是根据最适合当前架构实现):

坚持 "合适优于业界领先", 避免"过度设计"

  1. 单一职责原则
    ⼀个微服务也应该只负责⼀个功能或业务领域,每个服务应该有清晰的定义和边界,只关注⾃⼰的特定业务领域。就像写代码时一个类就专注一个功能。

电商系统拆分不同的服务

  1. 服务自治原则
    每个服务要能做到独⽴开发,独⽴测试,独⽴构建,独⽴部署,独⽴运⾏。

电商系统不同的服务,独立自治

  1. 单向依赖原则
    微服务之间需要做到单向依赖,严禁循环依赖,双向依赖。

2.3 父子工程搭建

我们使用两个服务先了解微服务: 订单服务,商品服务

订单服务: 提供订单ID,获取订单详细信息

商品服务: 根据商品ID,返回商品详细信息

2.3.1 数据准备

订单表:

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

-- 订单表 
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;

-- 产品表 
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, 0), (1005, "⻢甲",98, 0),(1006,"⽻绒服", 101, 0), 
(1007, "冲锋⾐",30, 0), (1008, "袜⼦",44, 0), (1009, "鞋⼦",58, 0),
(10010, "⽑⾐",98, 0)

2.3.2 创建⽗⼯程

创建⼀个空的Maven项⽬:

完善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>spring-cloud-demo</artifactId>
    <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 -->
    </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>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-test-autoconfigure</artifactId>
                <version>3.0.4</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>


</project>

DependencyManagement 和 Dependencies

  1. dependencies :将所依赖的jar直接加到项⽬中.⼦项⽬也会继承该依赖.
  2. dependencyManagement :只是声明依赖, 并不实现Jar包引⼊。如果⼦项⽬需要⽤到相关依赖,需要显式声明。如果⼦项⽬没有指定具体版本,会从⽗项⽬中读取version。如果⼦项⽬中指定了版本号,就会使⽤⼦项⽬中指定的jar版本。此外⽗⼯程的打包⽅式应该是pom,不是jar,这⾥需要⼿动使⽤ packaging 来声明。

2.3.3 创建子工程

订单服务:

商品服务:

2.3.4 订单服务

根据订单id,获取订单详情。

pom文件加上:

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 com.cloud.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:3306/cloud_product?characterEncoding=utf8&useSSL=false
    username: root
    password: 1234
    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 #配置驼峰⾃动转换

实体类:

java 复制代码
package com.cloud.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;

}

mapper:

java 复制代码
package com.cloud.order.mapper;

import com.cloud.order.model.OrderInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface OrderMapper {
    @Select("select * from order_detail where id=#{orderId}")
    OrderInfo selectOrderById(Integer orderId);
}

service:

java 复制代码
package com.cloud.order.service;

import com.cloud.order.mapper.OrderMapper;
import com.cloud.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;
    }

}

controller:

java 复制代码
package com.cloud.order.controller;

import com.cloud.order.model.OrderInfo;
import com.cloud.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);
    }

}

接口测试:

2.3.5 商品服务

根据商品id,获取商品详情。

pom文件加上:

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>

配置文件:

yml 复制代码
server:
  port: 9090
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/cloud_order?characterEncoding=utf8&useSSL=false
    username: root
    password: 1234
    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 #配置驼峰⾃动转换

完善启动类:

java 复制代码
package com.cloud.product;

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

实体类

java 复制代码
package com.cloud.product.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;
}

mapper:

java 复制代码
package com.cloud.product.mapper;

import com.cloud.product.model.ProductInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface ProductMapper {
 @Select("select * from product_detail where id=#{id}")
 ProductInfo selectProductById(Integer id);
}

service:

java 复制代码
package com.cloud.product.service;

import com.cloud.product.mapper.ProductMapper;
import com.cloud.product.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);
 }
}

controller:

java 复制代码
package com.cloud.product.controller;

import com.cloud.product.model.ProductInfo;
import com.cloud.product.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);
   }
}

接口测试:

三、远程调用

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

实体类:将ProductInfo 类拷贝一份进com.cloud.order.model,在OrderInfo 添加ProductInfo 作为成员。

java 复制代码
package com.cloud.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;
}

order-service 服务向product-service 服务发送⼀个http请求,把得到的返回结果,和订单结果融合在⼀起,返回给调⽤⽅。

实现⽅式:采⽤Spring 提供的RestTemplate

实现RestTemplate

java 复制代码
package com.cloud.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();
 }
}

OrderService修改:

java 复制代码
package com.cloud.order.service;

import com.cloud.order.mapper.OrderMapper;
import com.cloud.order.model.OrderInfo;
import com.cloud.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

RestTemplate 是从 Spring3.0 开始⽀持的⼀个 HTTP 请求⼯具, 它是⼀个同步的 REST API 客⼾端,提供了常⻅的REST请求⽅案的模版。

4.1 REST

REST(Representational State Transfer),表现层资源状态转移

主要有三个概念:

  1. 资源: ⽹络上的所有事物都可以抽象为资源 每个资源都有⼀个唯⼀的资源标识符(URI)
  2. 表现层: 资源的表现形式, ⽐如⽂本作为资源, 可以⽤txt格式表现, 也可以通过HTML, XML, JSON等格式来表现, 甚⾄以⼆进制的格式表现.
  3. 状态转移: 访问URI, 也就是客⼾端和服务器的交互过程. 客⼾端⽤到的⼿段,只能是HTTP协议.这个过程中, 可能会涉及到数据状态的变化. ⽐如对数据的增删改查, 都是状态的转移.

REST描述的是在⽹络中Client和Server的⼀种交互形式, REST本⾝不实⽤,实⽤的是如何设计 RESTful API(REST⻛格的⽹络接⼝)

4.2 RESTful

RESTful就是满⾜REST架构⻛格的接⼝。

RESTful ⻛格⼤致有以下⼏个主要特征:

  1. 资源: 资源可以是⼀个图⽚,⾳频,视频或者JSON格式等⽹络上的⼀个实体 除了⼀些⼆进制的资源外普通的⽂本资源更多以JSON为载体、⾯向⽤⼾的⼀组数据(通常从数据库中查询⽽得到)
  2. 统⼀接⼝:对资源的操作. ⽐如获取, 创建, 修改和删除. 这些操作正好对应HTTP协议提供的GET、POST、PUT和DELETE⽅法. 换⾔⽽知,如果使⽤RESTful⻛格的接⼝,从接⼝上你可能只能定位其资源,但是⽆法知晓它具体进⾏了什么操作,需要具体了解其发⽣了什么操作动作要从其HTTP请求⽅法类型上进⾏判断

RESTful API 缺点:

  1. 操作⽅式繁琐, RESTful API通常根据GET, POST, PUT, DELETE 来区分对资源的操作动作. 但是 HTTP Method 并不可直接⻅到, 需要通过抓包等⼯具才能观察. 如果把动作放在URL上反⽽更加直观, 更利于团队的理解和交流.
  2. ⼀些浏览器对GET, POST之外的请求⽀持不太友好, 需要额外处理.
  3. 过分强调资源. ⽽实际业务需求可能⽐较复杂, 并不能单纯使⽤增删改查就能满⾜需求, 强⾏使⽤RESTful API会增加开发难度和成本.
相关推荐
我居然是兔子8 小时前
异常练习:在试错中吃透Java异常处理的底层逻辑
java·开发语言
CC.GG9 小时前
【C++】STL容器----unordered_map和unordered_set的使用
java·数据库·c++
Overt0p10 小时前
抽奖系统(4)
java·spring boot·tomcat
想做后端的小C11 小时前
Java:接口回调
java·开发语言·接口回调
爱学习的小可爱卢11 小时前
JavaEE进阶——Spring核心设计模式深度剖析
java·spring·设计模式
毕设源码-钟学长12 小时前
【开题答辩全过程】以 个性化电影推荐网站的设计与实现为例,包含答辩的问题和答案
java·spring boot
C++业余爱好者12 小时前
Power Job 快速搭建 及通信机制介绍
java
qq_27049009612 小时前
SpringBoot药品管理系统设计实现
java·spring boot·后端
、BeYourself13 小时前
SpringAI-ChatClient Fluent API 详解
java·后端·springai