一、SpringCloud 学习环境搭建
1.1、介绍
- 我们会使用一个Dept部门模块做一个微服务通用案例Consumer消费者(Client)通过REST调用Provider提供者(Server)提供的服务。
- 回顾Spring,SpringMVC,Mybatis等以往学习的知识。
- Maven的分包分模块架构复习。
一个简单的Maven项目结构是这样的:
-- app-parent: 一个父项目(app-parent)聚合了很多子项目(app-utilapp-daoapp-web...) |-- pom.xml | |-- app-core ||---- pom.xml | |-- app-web ||---- pom.xml ......
一个父工程带着多个Moudule子模块
MicroServiceCloud父工程(Project)下初次带着3个子模块(Module)
- microservicecloud-api 【封装的整体entity/接口/公共配置等】
- microservicecloud-consumer-dept-80 【服务提供者】
- microservicecloud-provider-dept-8001 【服务消费者】
1.2、pringCloud版本选择
大版本说明:
SpringBoot | SpringCloud | 关系 |
---|---|---|
1.2.x | Angel版本(天使) | 兼容SpringBoot1.2x |
1.3.x | Brixton版本(布里克斯顿) | 兼容SpringBoot1.3x,也兼容SpringBoot1.4x |
1.4.x | Camden版本(卡姆登) | 兼容SpringBoot1.4x,也兼容SpringBoot1.5x |
1.5.x | Dalston版本(多尔斯顿) | 兼容SpringBoot1.5x,不兼容SpringBoot2.0x |
1.5.x | Edgware版本(埃奇韦尔) | 兼容SpringBoot1.5x,不兼容SpringBoot2.0x |
2.0.x | Finchley版本(芬奇利) | 兼容SpringBoot2.0x,不兼容SpringBoot1.5x |
2.1.x | Greenwich版本(格林威治) |
实际开发版本关系:使用后两个
spring-boot-starter-parent | spring-cloud-dependencles | ||
---|---|---|---|
版本号 | 发布日期 | 版本号 | 发布日期 |
1.5.2.RELEASE | 2017-03 | Dalston.RC1 | 2017-x |
1.5.9.RELEASE | 2017-11 | Edgware.RELEASE | 2017-11 |
1.5.16.RELEASE | 2018-04 | Edgware.SR5 | 2018-10 |
1.5.20.RELEASE | 2018-09 | Edgware.SR5 | 2018-10 |
2.0.2.RELEASE | 2018-05 | Fomchiey.BULD-SNAPSHOT | 2018-x |
2.0.6.RELEASE | 2018-10 | Fomchiey-SR2 | 2018-10 |
2.1.4.RELEASE | 2019-04 | Greenwich.SR1 | 2019-03 |
1.3、创建父工程
- 新建空的maven父工程项目:springcloud,切记Packageing是pom模式、
- 主要是定义POM文件,将后续各个子模块公用的jar包等统一提取出来,类似一个抽象父类
父工程pom依赖:
<!--打包方式 pom-->
<packaging>pom</packaging>
<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>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--springCloud的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--SpringBoot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--SpringBoot 启动器-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--日志测试~-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
数据库:建立db01数据库,下面是dept表的数据
1 DROP TABLE IF EXISTS `dept`; 2 CREATE TABLE `dept` ( 3 `dno` bigint(20) NOT NULL AUTO_INCREMENT, 4 `dname` varchar(60) DEFAULT NULL, 5 `db_source` varchar(60) DEFAULT NULL, 6 PRIMARY KEY (`dno`) 7 ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; 8 9 -- ---------------------------- 10 -- Records of dept 11 -- ---------------------------- 12 INSERT INTO `dept` VALUES ('1', '开发部', 'db01'); 13 INSERT INTO `dept` VALUES ('2', '人事部', 'db01'); 14 INSERT INTO `dept` VALUES ('3', '市场部', 'db01'); 15 INSERT INTO `dept` VALUES ('4', '财务部', 'db01');
1.4、创建只管实体类的子项目 :springcloud-01-api
pom依赖
dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> /dependencies>
实体类
@Data @NoArgsConstructor @Accessors(chain = true) //链式写法 public class Dept implements Serializable { private Long dno; private String dname; //这个数据存在哪个数据库的字段,微服务,一个服务对应一个数据库,同一个信息可能存在不同的数据库 private String db_source; public Dept(String dname) { this.dname = dname; } }
1.5、创建服务提供者: springcloud-provider-dept-8001
pom
<dependencies>
<!--我们需要拿到实体类,所以要配置api moudle-->
<dependency>
<groupId>com.zhixi</groupId>
<artifactId>springcloud-01-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--junit-->
<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>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!--Eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--完善监控信息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
项目配置文件:application.yaml
1
server:
port: 8001
# mybatis配置
mybatis:
type-aliases-package: com.zhixi.pojo
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
# spring配置
spring:
application:
name: springcloud-provider-dept-8001
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/db01?userSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: xxx
dao层:提供业务接口
dao/DeptDao
@Mapper @Component public interface DeptDao { // 添加用户 boolean addDept(Dept dept); // 根据id查询用户 Dept queryDeptById(Long id); // 查询全部部门 List<Dept> queryAllDept(); }
mybatis/mapper/DempMapper.xml
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="com.zhixi.dao.DeptDao"> 6 7 <insert id="addDept" parameterType="Dept"> 8 insert into dept (dname, db_source) 9 values (#{d_name}, DATABASE()); 10 </insert> 11 12 <select id="queryDeptById" resultType="Dept" parameterType="Long"> 13 select * 14 from dept 15 where dno = #{dno}; 16 </select> 17 18 <select id="queryAllDept" resultType="Dept"> 19 select * 20 from dept; 21 </select> 22 </mapper>
service层
service/DeptService
@Service public interface DeptService { // 添加用户 boolean addDept(Dept dept); // 根据id查询用户 Dept queryDeptById(Long id); // 查询全部用户 List<Dept> queryAllDept(); }
service/DeptServiceImpl
1 @Service 2 public class DeptServiceImpl implements DeptService { 3 4 @Autowired 5 private DeptDao deptDao; 6 7 @Override 8 public boolean addDept(Dept dept) { 9 return deptDao.addDept(dept); 10 } 11 12 @Override 13 public Dept queryDeptById(Long id) { 14 return deptDao.queryDeptById(id); 15 } 16 17 @Override 18 public List<Dept> queryAllDept() { 19 return deptDao.queryAllDept(); 20 } 21 }
controller:DeptController
@RestController public class DeptController { @Autowired private DeptService deptService; @PostMapping("/dept/add") public boolean addDept(@RequestBody Dept dept) { return deptService.addDept(dept); } @GetMapping("/dept/query/{id}") public Dept queryDeptById(@PathVariable("id") Long id) { return deptService.queryDeptById(id); } @GetMapping("/dept/query/all") public List<Dept> queryDeptAll() { return deptService.queryAllDept(); } }
启动类
//启动类 @SpringBootApplication public class DeptProvider_8001 { public static void main(String[] args) { SpringApplication.run(DeptProvider_8001.class, args); } }
测试当中的业务方法:
1.7、创建服务消费者:pringcloud-provider-dept-80
代码的耦合度极大的降低,没有了service层,然后调用服务创建者的controller执行业务~
pom.xml
<dependencies> <!--实体类--> <dependency> <groupId>com.zhixi</groupId> <artifactId>springcloud-01-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--热部署--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies>
application.yaml
server:
port: 80
config/MyConfig:装配bean
@Configuration public class MyConfig { @Bean // 通过rest模板去访问服务创建者的方法 public RestTemplate restTemplate() { return new RestTemplate(); } }
controller/DeptConsumerController:执行请求
@RestController public class DeptConsumerController { // 消费者不应该有service层,这里我们直接调用 // 提供多种便捷访问http服务的方法 @Autowired private RestTemplate restTemplate; // 没有service,所以要通过http远程方式拿到请求 public static final String REST_URL_PREFIX = "http://localhost:8001"; // 根据id查询 // 通过这个请求,实际请求的是8081服务注册中的请求 @RequestMapping("/consumer/dept/query/{id}") public Dept getDeptById(@PathVariable("id") Long id) { return restTemplate.getForObject(REST_URL_PREFIX + "/dept/query/" + id, Dept.class); } // 查询所有部门 @RequestMapping("/consumer/dept/query/all") public List<Dept> getDeptAll() { return restTemplate.getForObject(REST_URL_PREFIX + "/dept/query/all", List.class); } // 添加部门 // 因为在服务创建者的形参中添加了@RequestBody注解,所以在这李添加用户时能够被成功添加的 @RequestMapping("/consumer/dept/add") public ResponseEntity<Boolean> addDept(Dept dept) { return restTemplate.postForEntity(REST_URL_PREFIX + "/dept/add", dept, boolean.class); }
启动类:
@SpringBootApplication public class ConsumerRun { public static void main(String[] args) { SpringApplication.run(ConsumerRun.class, args); } }
测试: