初识SpringCloud-Rest

125 阅读6分钟

SpringCloud

简介 Spring Cloud为开发人员提供了快速构建分布式系统中的一些常见模式的工具(例如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导人选举、分布式会话、集群状态)。分布式系统的协调导致了锅炉板模式,而使用Spring Cloud开发人员可以快速建立实现这些模式的服务和应用程序。它们在任何分布式环境中都能很好地工作,包括开发人员自己的笔记本电脑、裸金属数据中心和云计算等托管平台。 优点

  • 产出于Spring大家族,Spring在企业级开发框架中无人能敌,来头很大,可以保证后续的更新、完善
  • 组件丰富,功能齐全。Spring Cloud 为微服务架构提供了非常完整的支持。例如、配置管理、服务发现、断路器、微服务网关等;
  • Spring Cloud 社区活跃度很高,教程很丰富,遇到问题很容易找到解决方案
  • 服务拆分粒度更细,耦合度比较低,有利于资源重复利用,有利于提高开发效率
  • 可以更精准的制定优化服务方案,提高系统的可维护性
  • 减轻团队的成本,可以并行开发,不用关注其他人怎么开发,先关注自己的开发
  • 微服务可以是跨平台的,可以用任何一种语言开发
  • 适于互联网时代,产品迭代周期更短

缺点

  • 微服务过多,治理成本高,不利于维护系统
  • 分布式系统开发的成本高(容错,分布式事务等)对团队挑战大

SpringCloud和SpringBoot对应版本

image.png

SpringBoot vs SpringCloud

  • SpringBoot专注于快速方便的开发单个个体微服务。
  • SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,
  • 为各个微服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务
  • SpringBoot可以离开SpringCloud独立使用开发项目, 但是SpringCloud离不开SpringBoot ,属于依赖的关系
  • SpringBoot专注于快速、方便的开发单个微服务个体,SpringCloud关注全局的服务治理框架。

其他关于SpringCloud的一些点

SpringCloud入门初体验-Rest

  1. 创建一个空的Maven项目springcloud-study作为父项目
  2. 在这个父项目的pom.xml导入依赖:这里的依赖只是被管理,如果在子项目中要使用,就需要在子项目中把依赖引进来,父项目如果已经管理了,子项目就不需要写版本
   <!-- 打包方式 pom   -->
    <packaging>pom</packaging>
    <!--版本控制,易于后期的维护-->
    <properties>
        <junit.version>4.12</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.18.10</lombok.version>
    </properties>

    <!--  依赖管理  -->
    <dependencyManagement>
        <dependencies>
            <!-- spring-cloud的依赖 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR9</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--springboot-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.3.5.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--数据库-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.12</version>
            </dependency>
            <!--数据源-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.2.5</version>
            </dependency>
            <!--springboot启动器-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.1</version>
            </dependency>
            <!--log4j-->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>1.3.0-alpha5</version>
            </dependency>
            <!--junit-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <!--lombok-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
  1. 创建一个数据库,IDEA连接数据库。 image.png

  2. 创建一个子模块springcloyd-api,在子模块导入需要用到的依赖

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
  1. 在该模块下写对应数据库的实体类,实现ORM映射
package pojo;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.io.Serializable;

//implements Serializable  序列化
@Data
@NoArgsConstructor
@Accessors(chain = true)//链式写法
public class Dept implements Serializable {
    private Long deptId;
    private String deptName;

    //判断数据是从哪个数据库中取出来的
    private String dbResource;

    public Dept(String deptName) {
        this.deptName = deptName;
    }
}

服务提供者

  1. 新建一个子模块springcloud-provider-8001,作为服务提供者,该模块的结构

image.png

  1. 为该子模块添加需要用到的依赖
   <dependencies>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>

    </dependencies>
  1. 在该模块编写mapper层DeptMapper.java
package springcloud.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import pojo.Dept;

import java.util.List;

@Mapper
@Repository
public interface DeptMapper {
    public Boolean addDept(Dept dept);

    public Dept getDeptById(Long deptId);

    public List<Dept> queryAll();
}

  1. 在该模块编写mapper层的配置文件DeptMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="springcloud.mapper.DeptMapper">
    <insert id="addDept" parameterType="dept">
        insert into db01.dept (deptName, dbResource) VALUES (#{deptName},DATABASE());
    </insert>

    <select id="getDeptById" resultType="dept" parameterType="Long">
        select * from db01.dept where deptId=#{id};
    </select>

    <select id="queryAll" resultType="dept">
        select * from db01.dept;
    </select>

</mapper>
  1. 在该模块编写service层接口DeptService.java
package springcloud.service;

import pojo.Dept;

import java.util.List;

public interface DeptService {
    public Boolean addDept(Dept dept);

    public Dept getDeptById(Long deptId);

    public List<Dept> queryAll();
}

  1. 在该模块编写service层接口实现类DeptServiceImpl.java
package springcloud.service;

import springcloud.mapper.DeptMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import pojo.Dept;

import java.util.List;

@Service
public class DeptServiceImpl implements DeptService{

    @Autowired
    private DeptMapper deptMapper;


    public Boolean addDept(Dept dept) {
        return deptMapper.addDept(dept);
    }

    public Dept getDeptById(Long deptId) {
        return deptMapper.getDeptById(deptId);
    }

    public List<Dept> queryAll() {
        return deptMapper.queryAll();
    }
}

  1. 在该模块编写controller层DeptController.java
package springcloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import pojo.Dept;
import springcloud.service.DeptService;

import java.util.List;

//提供Restful服务
@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    @PostMapping("/provider/add")
    public Boolean add(@RequestBody Dept dept){
            return deptService.addDept(dept);
    }

    @GetMapping("/provider/get/{id}")
    public Dept get(@PathVariable("id") Long id){
        return deptService.getDeptById(id);
    }

    @PostMapping("/provider/query")
    public List<Dept> query(){
        return deptService.queryAll();
    }

}

  1. 编写mybatis核心配置文件mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--开启二级缓存-->
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
</configuration>
  1. 编写application.yml配置
server:
  port: 8001
mybatis:
  type-aliases-package: pojo
  mapper-locations: classpath:mybatis/mapper/*.xml
  config-location: classpath:mybatis/mybatis-config.xml
spring:
  application:
    name: springcloud-provider
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    username: root
    password: 123456
  1. 编写主启动类DeptProvider.java
package springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

//主启动类
@SpringBootApplication
public class DeptProvider {
    public static void main(String[] args) {
        SpringApplication.run(DeptProvider.class,args);
    }

}

  1. 启动测试,保证服务提供者能够顺利提供服务

服务消费者

  1. 同样的,先创建一个子模块springcloud-consumer-80来实现服务消费者

image.png

  1. 导入依赖
<?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>springcloud-study</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-consumer-80</artifactId>
    <dependencies>
        <!--实体类-->
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--web启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

</project>
  1. 编写application.yml配置
server:
  port: 80
  1. 在config包下编写RestfulBean.java实现REST请求方案模版的配置
package springcloud.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/*
RestTemplate 是从 Spring3.0 开始支持的一个 HTTP 请求工具,它提供了常见的REST请求方案的模版,例
如 GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及 execute。
*/

@Configuration
public class RestfulBean {
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

  1. 在controller包下编写DeptController.java让消费者拿到服务
package springcloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import pojo.Dept;

import java.util.List;

@RestController
public class DeptController {

    @Autowired
    private RestTemplate restTemplate;

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


    @RequestMapping("/consumer/add")
    public boolean add(Dept dept){
        //请求的路径:REST_URL_PREFIX+"add"
        //传递的参数:dept
        //返回的对象:boolean.class
        return restTemplate.postForObject(REST_URL_PREFIX+"/provider/add",dept,boolean.class);
    }

    @RequestMapping("/consumer/get/{id}")
    public Dept get(@PathVariable("id") Long id){
        //请求的路径:REST_URL_PREFIX+"get/"+id
        //请求返回的对象:Dept.class
        return restTemplate.getForObject(REST_URL_PREFIX+"/provider/get/"+id,Dept.class);
    }

    @RequestMapping("/consumer/query")
    public List<Dept> query(){
        //请求的路径:REST_URL_PREFIX+"query"
        //传递的参数:void.class
        //返回的对象:List.class
        return restTemplate.postForObject(REST_URL_PREFIX+"/provider/query",void.class,List.class);
    }

}

  1. 编写主启动类DeptConsumer,java
package springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DeptConsumer {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer.class,args);
    }
}

这样子,我们就简单的实现了Rest学习环境的搭建,我们先启动服务提供者,再启动服务消费者,就可以进行测试了。

SpringCloud-Rest 初体验小结

  1. @Mapper和@Repository

    @Mapper:

       1. 作用在dao层接口,使得其生成代理对象bean,交给spring容器管理
       2. 相当于原来mybatis-config.xml中的
          <mappers>
               <mapper resource="com/wu/dao/UserMapper.xml"/>
          </mappers>
       3. 也就是将mapper注册到spring容器中
       4. 不需要配置扫描地址,可以单独使用,有多个mapper的话,
          可以在项目启动类中加入@MapperScan(“mapper文件所在包”),
          这样就不需要每个mapper文件都加@Mapper注解了
    

    @Repository:

       1. 也作用在dao层,但是不能单独使用
       2. 需要配置扫描地址
    
  2. @RestController=@Controller+@ResponseBody跟@RequestBody不一样

  3. @RequestBody接收请求,一篇对这个注解详细解释的Blog

  4. @ResponseBody返回响应

  5. 主启动类不能放在java包下,要在java包下再建一个包,主启动类放在这个新建的包下

  6. 主启动类只会扫描和主启动类同级的包

  7. RestTemplate 是从 Spring3.0 开始支持的一个 HTTP 请求工具,它提供了常见的REST请求方案的模版,例如 GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及 execute。

  8. 服务提供者提供访问的方式和服务消费者的访问方式要一致

image.png

  1. 使用post和get方式,返回时所需要的参数是不同的

image.png