1.总体介绍
- 我们会使用一个Dept部门模块做一个微服务通用案例Consumer消费者(Client)通过REST调用Provider提供者(Server)提供的服务
- 回顾Spring,SpringMVC,Mybatis等以往学习的知识
- Maven的分包分模块架构复习
一个简单的Maven模块结构是这样的: -- app-parent: 一个父项目(app-parent)聚合了很多子项目(app-util\app-dao\app-web...) |-- pom.xml | |-- app-core ||---- pom.xml | |-- app-web ||---- pom.xml ......
- 一个父工程带着多个model子模块
- MicroServiceCloud父工程(Project)下初次带着3个子模块(Module)
- microservicecloud-api 【封装的整体entity/接口/公共配置等】
- microservicecloud-consumer-dept-80 【服务提供者】
- microservicecloud-provider-dept-8001 【服务消费者】
2.SpringCloud版本选择
- 大版本说明
- 实际开发版本关系
- 使用后两个
3.创建工程
1.创建父工程
- 创建新项目
- 首先导入项目依赖,首先当然是导入核心依赖,依赖名称我们可以在官方Doc上面找
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR8</version> <type>pom</type> <scope>import</scope><!--可以直接删除,也可以改成import--> </dependency>
- 第二个需要导入的依赖为spring boot的依赖,因为spring could的使用是依赖于spring boot的,所以我们应该导入spring boot的依赖;但是我们需要spring could和spring boot之间的版本对应(版本对应网址,注意:需要使用火狐才能正常的解析查看下图样式,其他的浏览器就是正常的JSON字符串,没有样式我们可以直接搜索也可以找到对应的版本选择)
- 所以我们使用的最新稳定版sr8对应的spring boot版本需要在2.2.0-2.3.5之间,而我们前面使用的spring boot刚好为2.3.4,所以我们沿用前面的spring boot依赖即可
<!--spring boot的依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.3.4.RELEASE</version> <type>pom</type> <scope>import</scope><!--可以直接删除,也可以改成import--> </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.24</version> </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.24</version> </dependency>
- mybatis启动器
<!--spring boot中mybatis的启动器--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency>
- 其他的一些杂七杂八的依赖
<!--日志log4j依赖--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> <!--单元测试依赖--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <!--注意:该版本号我们可以不在这里写死,而是使用我们上面的properties节点中定义的参数来实现版本可变--> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency>
- 注意:上面3个依赖的版本号我都是写的${变量名}进行取值,这些变量名都写在上面的节点properties中的
<properties> <lombok.version>1.18.12</lombok.version> <junit.version>4.13</junit.version> <log4j.version>1.2.17</log4j.version> </properties>
- 这种做法可以实现我们动态的修改对应依赖的版本号,虽然我们可以直接去对应的依赖中直接修改,但是当依赖太多的时候,寻找对应的依赖就变成了一件麻烦事,所以我们可以通过自定义变量将变量的控制集中在properties节点中,后面要修改直接在properties中进行修改即可
- 还有一个log4j需要的依赖
<dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency>
- 除了上面的依赖导入,我们还需要配置一些资源导出配置过滤,主要防止maven项目约定大于配置,导致非resources文件夹下的资源文件无法导出的问题
<build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.yml</include> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.yml</include> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> </build>
- 所以完整的父工程的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>com.thhh</groupId> <artifactId>SpringCould-Study</artifactId> <version>1.0-SNAPSHOT</version> <!--导包方式 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> <lombok.version>1.18.12</lombok.version> <junit.version>4.13</junit.version> <log4j.version>1.2.17</log4j.version> </properties> <dependencyManagement> <dependencies> <!--spring could的依赖--> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR8</version> <type>pom</type> <scope>import</scope><!--可以直接删除,也可以改成import--> </dependency> <!--spring boot的依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.3.4.RELEASE</version> <type>pom</type> <scope>import</scope><!--可以直接删除,也可以改成import--> </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.24</version> </dependency> <!--spring boot中mybatis的启动器--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency> <!--日志和测试--> <!--log4j需要的依赖--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> <!--日志log4j依赖--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> <!--单元测试依赖--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <!--注意:该版本号我们可以不在这里写死,而是使用我们上面的properties节点中定义的参数来实现版本可变--> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> </dependencies> </dependencyManagement> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.yml</include> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.yml</include> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> </build> </project>
2.创建子model
- 创建一个普通的maven子model
- 配置子model中需要的依赖,注意:我们的父工程中对于依赖是使用< dependencyManagement >对于导入的依赖进行的管理,在子model创建之后,并不能直接使用父工程中已经导入的依赖,而是需要我们自己手动的导入,但是导入的依赖不需要对其版本进行管理,因为子model中导入的依赖都是从父项目中获取的,所以版本的管理都放在了父项目中;而当子model导入父项目中没有的依赖时,版本就需要自己进行管理,这和前面学习spring boot是一样的
<dependencies> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies>
- 创建该子model的数据库
- 接下来就是给数据库创建表,我们可以选择在IDEA中进行创建,因为它的可视化做的很好,创建起来很快,很方便
- 插入测试数据
insert into dept(dname, db_source) VALUES ('开发部',database()); insert into dept(dname, db_source) VALUES ('人事部',database()); insert into dept(dname, db_source) VALUES ('财务部',database()); insert into dept(dname, db_source) VALUES ('市场部',database()); insert into dept(dname, db_source) VALUES ('运维部',database());
-
编写实体类pojo
package com.thhh.springcould.pojo; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import java.io.Serializable; @Data @NoArgsConstructor @Accessors(chain = true)//开启这个类的链式写法 /*链式写法 * Dept dept = new Dept(); * dept.setDeptno().setDname().setDb_source() * */ public class Dept implements Serializable { private Long deptno; //主键 private String dname; //部门名称 private String db_source;//标识数据来自哪一个数据库 public Dept(String dname) { //注意:构造器只需要传入部门名称即可,因为部门主键是自增的,来自哪一个数据库是调用数据库函数database()获取的 this.dname = dname; } }
-
到此,这个微服务就写完了
3.服务提供者编写
- 接下来就来写服务的提供者,再创建一个model:springcould-provider-dept-8001,注意名称:springcould-provider表示这个是一个spring could中的服务提供者,dept表示提供dept服务,8001表示这个服务运行在哪一个端口上,因为后面服务一多起来,我们可以直接通过子model的名称知道它运行在哪一个端口上就很方便
- 配置子model的依赖,注意:首先这个子model是用来提供dept实体类的服务的,所以它首先就要导入pojo实体类的依赖,直接在依赖中输入我们前面写的那个子model的名称springcould-api即可导入
<dependencies> <dependency> <groupId>com.thhh</groupId> <artifactId>springcould-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
- 完整的子model的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"> <parent> <artifactId>SpringCould-Study</artifactId> <groupId>com.thhh</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>springcould-provider-dept-8001</artifactId> <dependencies> <!--实体类dept依赖--> <dependency> <groupId>com.thhh</groupId> <artifactId>springcould-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> <!--logback依赖,讲解:https://zhuanlan.zhihu.com/p/136893269--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> </dependency> <!--mybatis依赖--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <!--spring boot的web启动器--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--spring boot的测试依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-test</artifactId> </dependency> <!--jetty--> <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> </dependencies> </project>
- 编写配置文件
server: port: 8001 #端口号 #mybatis配置 mybatis: type-aliases-package: com.thhh.springcould.pojo #mybatis的别名扫描 mapper-locations: classpath:mybatis/mapper/*.xml #mybatis去哪里读取pojo对应的mapper接口的mapper.xml文件 config-location: classpath:mybatis/mybatis-config.xml #mybatis核心配置文件,可要可不要,不要就把配置写在spring配置中 #spring配置 spring: application: name: springcould-provider-dept datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/db01?useSSL=false&useUnicode=true&characterEncoding=utf-8 username: root password: 123
- 编写mybatis核心配置文件(可要可不要)
<?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"/> <!--开启mybatis二级缓存,一级缓存是默认开启的--> </settings> </configuration>
- 为pojo编写对应的mapper接口
package com.thhh.springcould.mapper; import com.thhh.springcould.pojo.Dept; import org.apache.ibatis.annotations.Mapper; import org.springframework.stereotype.Repository; import java.util.List; @Mapper //声明这是一个mapper @Repository //托管到spring容器中 public interface DeptMapper { //新增一个部门 public boolean addDept(Dept dept); //删除一个部门 public boolean deleteDeptById(long id); //修改一个部门 public boolean updateDeptById(long id); //查询一个部门 public Dept queryDeptById(long id); //查询所有部门 public List<Dept> queryDeptList(); }
- 编写mapper接口的mapper.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="com.thhh.springcould.mapper.DeptMapper"> 注意绑定namespace,且是绑定到对应的接口 <insert id="addDept" parameterType="Dept"> insert into db01.dept(dname, db_source) values (#{dname},database()) </insert> <select id="queryDeptById" resultType="Dept"> select * from db01.dept where deptno = #{deptno} </select> <select id="queryDeptList" resultType="Dept"> select * from db01.dept </select> </mapper>
- 编写service层
package com.thhh.springcould.service; import com.thhh.springcould.mapper.DeptMapper; import com.thhh.springcould.pojo.Dept; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class DeptServiceImpl implements DeptService{ @Autowired private DeptMapper deptMapper; @Override public boolean addDept(Dept dept) { return deptMapper.addDept(dept); } @Override public Dept queryDeptById(long id) { return deptMapper.queryDeptById(id); } @Override public List<Dept> queryDeptList() { return deptMapper.queryDeptList(); } }
- 编写controller,向前端提供服务接口
package com.thhh.springcould.controller; import com.thhh.springcould.pojo.Dept; import com.thhh.springcould.service.DeptService; 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.PostMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController //提供restful服务 public class DeptController { @Autowired private DeptService deptService; //controller调用service层的服务 //新增一个部门 @PostMapping("/dept/add") public boolean addDept(Dept dept){ return deptService.addDept(dept); } //查询一个部门 @GetMapping("/dept/queryById/{deptno}") public Dept queryDeptById(@PathVariable("deptno") long id){ return deptService.queryDeptById(id); } //查询所有部门 @GetMapping("/dept/queryList") public List<Dept> queryDeptList(){ return deptService.queryDeptList(); } }
- 由于我们创建的是一个普通的maven项目,并不是一个spring boot项目,所以我们需要自己手动的创建一个项目的主启动程序/入口程序DeptProvider_8001,注意:入口程序要和我们创建的文件夹平级,否则我们创建的文件夹将不会被扫描到
- 按照spring boot入口程序照猫画虎写一个入口程序
package com.thhh.springcould; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DeptProvider_8001 { public static void main(String[] args) { SpringApplication.run(DeptProvider_8001.class,args); } }
4.测试
- 启动项目测试
- 至于添加部门信息,我们写的是注解@PostMapping,所以我们需要依赖表单进行post数据提交,所以我们不能直接在url中进行部门数据的新增,但是我们可以测试一下是不是和上面的结论相符
- 至此,服务提供者已经创建编写完成,接下来就是创建服务消费者