目录

springcloud构建微服务架构

总体学习步骤:先构建一个简单的订单-支付模块微服务,然后一步一步融合springcloud各种技术组件

微服务cloud整体聚合父工程Project

  • New Project
  • Maven版本
  • 字符编码
  • 注解生效激活
  • 如果想不显示.idea,.iml,可以在File Types设置项里 ignore files and folders 添加 *.idea;*.iml,让眼睛看地清爽一些
  • 删除src文件夹

pom.xml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<?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.eh</groupId>
    <artifactId>cloud2020</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <!--统一管理jar包和版本-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <lombok.version>1.16.18</lombok.version>
        <mysql.connector.java.version>8.0.21</mysql.connector.java.version>
        <druid.verison>1.1.16</druid.verison>
        <mybatis.spring.boot.verison>2.1.3</mybatis.spring.boot.verison>
    </properties>


    <dependencyManagement>
        <dependencies>
            <!--spring boot 2.2.2-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.2.2.RELEASE</version>
                <!--默认type为jar,pom表示依赖的是一个父工程,父工程里引入了很多jar-->
                <type>pom</type>
                <!--
                在Spring boot 项目的POM文件中,我们可以通过在POM文件中继承 Spring-boot-starter-parent来引用Spring boot默认依赖的jar包
                但是,通过上面的parent继承的方法,只能继承一个 spring-boot-start-parent。
                实际开发中,用户很可能需要继承自己公司的标准parent配置,这个时候可以使用 scope=import 来实现多继承。
                -->
                <scope>import</scope>
            </dependency>
            <!--spring cloud Hoxton.SR1-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud alibaba 2.1.0.RELEASE-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- MySql -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.connector.java.version}</version>
            </dependency>
            <!-- Druid -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>${druid.verison}</version>
            </dependency>
            <!-- mybatis-springboot整合 -->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.spring.boot.verison}</version>
            </dependency>
            <!--lombok-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
        </plugins>
    </build>


</project>

设置跳过测试

20201106140640

  • 建moudle
  • 改pom
  • 写yml
  • 主启动
  • 业务类

订单模块(consumer) - > 支付模块(provider)

支付模块

改pom

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>org.eh</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-provider-payment8001</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!--mysql-connector-java-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--jdbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

写yml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
server:
  port: 8001

spring:
  application:
    name: cloud-payment-service
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: com.mysql.cj.jdbc.Driver             # mysql驱动包
    url: jdbc:mysql://localhost:3306/eden?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 333

mybatis:
  mapperLocations: classpath:mapper/*.xml

主启动

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
package com.eh.springcloud.payment8001;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@MapperScan("com.eh.springcloud.payment8001.dao")
@SpringBootApplication
public class SpringbootPayment8001Application {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootPayment8001Application.class, args);
    }
}

业务类

  • 建表sql

    1
    2
    3
    4
    5
    6
    7
    
    CREATE TABLE `payment` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
      `serial` varchar(200) COLLATE utf8_unicode_ci DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    /*Data for the table `payment` */
    insert  into `payment`(`serial`) values ('aaabbb01');
    
  • entities

    主实体Payment, 这里使用mbg自动生成

    Json封装体CommonResult

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
    package com.eh.springcloud.payment8001.entity;
      
    import lombok.Data;
      
    @Data
    public class CommonResult<T> {
        private Integer code;
        private String desc;
        private T data;
      
        public static <T> CommonResult<T> success(T data) {
            CommonResult<T> commonResult = new CommonResult<>();
            commonResult.setCode(200);
            commonResult.setDesc("处理成功");
            commonResult.setData(data);
            return commonResult;
        }
      
        public static <T> CommonResult<T> error(Integer code, String desc) {
            CommonResult<T> commonResult = new CommonResult<>();
            commonResult.setCode(code);
            commonResult.setDesc(desc);
            return commonResult;
        }
      
      
    }
    
  • dao

  • service

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    package com.eh.springcloud.payment8001.service.impl;
      
    import com.eh.springcloud.payment8001.dao.PaymentMapper;
    import com.eh.springcloud.payment8001.entity.Payment;
    import com.eh.springcloud.payment8001.service.PaymentService;
    import org.springframework.stereotype.Service;
      
    import javax.annotation.Resource;
      
    /**
     * @auther zzyy
     * @create 2020-02-18 10:40
     */
    @Service
    public class PaymentServiceImpl implements PaymentService {
        @Resource
        private PaymentMapper paymentDao;
      
        public int create(Payment payment) {
            return paymentDao.insertSelective(payment);
        }
      
        public Payment getPaymentById(Long id) {
            return paymentDao.selectByPrimaryKey(id);
        }
    }
    
  • controller

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    
    package com.eh.springcloud.payment8001.controller;
      
    import com.eh.springcloud.payment8001.entity.CommonResult;
    import com.eh.springcloud.payment8001.entity.Payment;
    import com.eh.springcloud.payment8001.service.PaymentService;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.util.Assert;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RestController;
      
    @RestController
    @Slf4j
    public class PaymentController {
      
        private final PaymentService paymentService;
      
        public PaymentController(PaymentService paymentService) {
            this.paymentService = paymentService;
        }
      
        @PostMapping("/create")
        public CommonResult<Payment> create(Payment payment) {
            log.info("开始创建订单:{}", payment);
            try {
                Assert.notNull(payment.getSerial(), "参数serial不能为空");
                paymentService.create(payment);
                return CommonResult.success(payment);
            } catch (Exception e) {
                log.error("创建订单出现异常", e);
                return CommonResult.error(444, "创建订单失败");
            }
        }
      
        @GetMapping("/{id}")
        public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
            Payment payment = paymentService.getPaymentById(id);
            if (payment != null) {
                log.info("hello");
                return CommonResult.success(payment);
            } else {
                return CommonResult.error(444, "没有对应记录, 查询ID: " + id);
            }
        }
    }
    
  • 测试:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
    GET http://localhost:8001/payment/1
      
    输出
    {
      "code": 200,
      "desc": "处理成功",
      "data": {
        "id": 1,
        "serial": "aaabbb01"
      }
    }
      
    ###
      
      
    POST http://localhost:8001/payment/create
    Content-Type: application/x-www-form-urlencoded
      
    serial=david001
      
    输出
    {
      "code": 200,
      "desc": "处理成功",
      "data": {
        "id": 2,
        "serial": "david001"
      }
    }
    

订单模块

pom.xml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>org.eh</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-consumer-order80</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

订单模块调支付模块,由于这里还没有微服务的远程调用,那么如果要调用另外一个模块,则需要使用基本的api调用,这里使用RestTemplate

RestTemplate

RestTemplate提供了多种便捷访问远程Http服务的方法,是一种简单便捷的访问restful服务的模板类,是spring提供的用于访问Rest服务的客户端模板工具集。

RestTemplate

使用RestTemplate访问restful接口非常简单,url,requestMap,ResponseBean.class这个三个参数分别代表REST请求地址,请求参数,HTTP响应转换被转换成的对象类型。

Controller

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.eh.springcloud.order80.controller;

import com.eh.springcloud.order80.entity.CommonResult;
import com.eh.springcloud.order80.entity.Payment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class OrderController {

    private final static String PAYMENT_URL = "http://localhost:8001";

    private RestTemplate restTemplate;

    public OrderController(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @GetMapping("/order/payment/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
        return restTemplate.getForObject(PAYMENT_URL + "/payment/" + id, CommonResult.class, id);
    }

    @PostMapping("/order/payment/create")
    public CommonResult<Payment> create(Payment payment) {
        return restTemplate.postForObject(PAYMENT_URL + "/payment/create", payment, CommonResult.class);
    }
}
注意

order调payment,由于是json调用(postForObject),payment对应方法参数需要加@RequestBody注解

1
2
@PostMapping("/payment/create")
public CommonResult<Payment> create(@RequestBody Payment payment) {

测试

1
2
3
4
5
6
7
8
9
GET http://localhost/order/payment/1

###

### Send POST request with body as parameters
POST http://localhost/order/payment/create
Content-Type: application/x-www-form-urlencoded

serial=david002

工程重构

新建一个common模块,将重复代码抽取到一个公共模块中

  1. 创建common模块

  2. 抽取公共pom

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    <?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">
        <parent>
            <artifactId>cloud2020</artifactId>
            <groupId>org.eh</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
       
        <artifactId>cloud-common</artifactId>
       
        <dependencies>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>5.4.7</version>
            </dependency>
        </dependencies>
       
    </project>
    
  3. 将Payment和CommonResult两个实体类放到common模块中

  4. maven clean install

  5. 其他模块引入common模块

    1
    2
    3
    4
    5
    
    <dependency>
        <groupId>org.eh</groupId>
        <artifactId>cloud-common</artifactId>
        <version>${project.version}</version>
    </dependency>
    
  6. 再次测试

至此,springcloud微服务架构学习的准备工作完毕

完整示例地址