博客系统案例练习-回顾
前言
服务拆分方案介绍
- 纵向拆分:从业务维度进⾏拆分.标准是按照业务的关联程度来决定,关联⽐较密切的业务适合拆分
为⼀个微服务,⽽功能相对⽐较独⽴的业务适合单独拆分为⼀个微服务. - 横向拆分:从公共且独⽴功能维度拆分,按照是否有公共的被多个其他服务调⽤,且依赖的资源独⽴
不与其他业务耦合. - 基于稳定性拆分:将系统中的业务模块按照稳定性进⾏排序.稳定的,不经常修改的划分⼀块.将不稳
定的,经常修改的划分为⼀个独⽴服务.⽐如⽇志服务,监控服务都是相对稳定的服务,可以归到⼀
起.⽐如20%经常变动的部分进⾏抽离,80%不经常变动的单独部署和管理.这样可以尽可能的减少
发布频率.减少发布产⽣的后遗症. - 基于可靠性拆分:将系统中的业务模块按照可靠性进⾏排序,对可靠性要求⽐较⾼的核⼼模块归在⼀
起,对可靠性要求不⾼的⾮核⼼模块归在⼀块.避免"⼀颗⽼⿏屎坏了⼀锅粥"的单体弊端,同时将来
要做⾼可⽤⽅案也能很好的节省机器或带宽的成本. - 基于⾼性能拆分:将系统中的业务模块按照对性能的要求进⾏优先级排序.把对性能要求较⾼的模块
独⽴成⼀个服务,对性能要求不⾼的放在⼀起.⽐如全⽂搜索,商品查询独⽴成单独的微服务拆分出
来.
博客系统拆分
业务优先是最基本,最重要的划分⽅式.博客系统的业务⽐较简单,分为两⼤块:⽤⼾模块,博客模块.
我们把博客系统拆分为⽤⼾服务和博客服务,对于公共且功能独⽴的模块,抽取出公共SDK(复杂业务场
景,也可以抽取出公共服务模块,此处选择SDK).
公共SDK就是一个jar包,公共服务提供接口
技术选型
博客系统从⼤的模块分为展⽰层,⽹关层,服务层,数据层.
展⽰层:依然采⽤课堂中讲的HTML+CSS+JavaScript+JQuery,使⽤Nginx来提供静态资源服务.
⽹关:采⽤SpringCloudGateway
服务层:采⽤SpringBoot框架进⾏开发,MyBatisPlus访问数据库,服务拆分为⽤⼾服务和博客服务,服
务之间使⽤OpenFeign进⾏远程调⽤.Nacos来处理服务注册/服务发现以及配置相关的内容.
为了提⾼⽤⼾登录的性能,使⽤Redis作为缓存.
⽤⼾注册成功后,给⽤⼾发邮箱,使⽤RabbitMQ来解耦
数据交互使⽤JSON,为了提⾼⼤家知识的⼴度,本次引⽤fastjson2
数据层:采⽤MySQL来提供数据服务
公共SDK:针对⼀些公共模块,把代码抽取出来,⽅便其他模块使⽤,⽐如发送邮件,操作Redis,Jwt,
Json处理等
工程搭建
总共三个项目:博客,用户,网关,还有一个公共SDK
博客,用户,项目又分为api和service
先创建父工程
然后是完善pom文件
现在开始创建子工程
再在blog-info里面创建api和service项目
然后完善依赖
这个是service的
给service弄上依赖,给每个api和service都弄上打包插件
代码迁移-博客服务
全部搬到blog里面
然后删掉全部user相关的
enums,exception,utils放在blog-common
config里面的拦截器和相关拦截器路径配置我们用网关来配置,所以删掉
result类放在blog-common里面的pojo里面
然后我们把request和response相关的类放在blog的api里面
blog-common:
然后我们从blog-common来看有没有报错信息
中jwt要引入依赖
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.11.5</version></dependency><!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl --><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.11.5</version><scope>runtime</scope></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred --><version>0.11.5</version><scope>runtime</scope></dependency>
还有就是日志的依赖
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId></dependency>
alter+enter可以直接引入spring的核心依赖
<dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId></dependency>
我们打一下包就知道有没有错误了
Blog-info-service:
这里的返回值类型要引入blog-api的依赖
然后就是挨着导入类
然后我们的result类要导入common的
然后删除这个异常信息
blog-api:
然后就是blog-api是给外面提供接口的,外面的服务就不要去访问service了–》用feign
服务之间用feign来发起远程调用
先加上feign的依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>
然后在blog-api里面写feign接口
声明service里面的接口
复制然后删除实现
参数校验的注解删掉,放在controller里面就可以了
然后统一添加路径blog,用FeignClient注解标志位feign
然后controller去实现它,就可以去掉requestMapping了
这个注解是spring-boot-web的
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
这个注解的依赖是
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>
然后就是写blog-service的配置文件了
能启动成功就可以了
代码迁移-用户服务
user-service:
删除博客相关代码
就和上面那个差不多的
然后还是定义feign,在user-api里面
注意的是feign中的单个参数要加上注解RequestParam
然后就是慢慢的导入包和类
最后在userService里面有远程调用
比如这里
我们要调入blog-api
先注入
但是这个还没有装入bean
只需要在user-service中声明这个feign就可以了
这样就OK了
BlogInfoResponse blogInfo = blogServiceApi.getBlogDeatail(blogId);
但是我们这个远程调用得到的不是BlogInfoResponse这个类,而是Result
,因为有ResponseAdvice这个东西封装的
所有同一结果返回在这里就不适用了
直接删掉ResponseAdvice,blog和user的都删掉
所以现在的controller返回的就都不是Result类型的了
我们先删除blog-service的ResponseAdvice
由于返回的都不是Result了
所以我们要手动写成返回Result类型的
Controller和api都要改
记得也要改user-service的结果返回
然后修改对应远程调用方法
然后是user-service的配置文件
我们这个是不能启动了,因为要远程调用,要用loadbalancer(负载均衡),就要用nacos
feign使用的基础就是nacos,
feign是用来造api的,真正要服务调用的话还是得naocs
naocs配置
找不到的原因主要是这里
这里的name找不到这个服务
其他地方都没有问题
user-service这里可以找到blog-api,因为引入了依赖,而且是其他包下的bean,就必须这样做
blog-service也可以找到blog-api,并实现接口,因为引入了依赖
但是blog-api找不到实现它的接口,意思就是不知道谁实现了它,就说了一个名字name=blog-service,是找不到的,因为没有配置naocs,它也不可能引入blog-service的依赖吧
naocs已经启动了
就是配置了
要把所有的服务都注入nacos,所以service都要配置
先添加nacos的依赖
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>
还要有loadbalancer的依赖,这个是负载均衡,当然也可以使用nacos的负载均衡,都是可以的
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>
然后就是修改配置了
我们要把服务注册到nacos,就要有服务名
这个·名称就是我们blog-api寻找的名称
这个就是naocs的配置了
然后是user-service的naocs配置
然后是启动
记住没有使用的依赖就不要添加,不然很容易会出错的,比如nacos-config和bootstrap,我没有使用,但是却添加了这个依赖,然后就启动不了了
然后就启动成功了,还可以远程调用了
网关服务
先加入网关依赖
因为网关要注册到nacos上,所以也要加入naocs依赖
然后还有loadbalancer的依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>
网关是一个服务,也要写启动类
然后就是配置,接收到什么请求,转发到什么样的服务
#Gateway 相关配置
server:port: 10030
spring:application:name: gateway-servicecloud:nacos:discovery:server-addr: 139.159.230.105:10020gateway:routes:- id: user-service #路由规则id, 随便起, 不重复即可uri: lb://user-service/ #目标服务地址predicates: #路由条件- Path=/user/**- id: blog-serviceuri: lb://blog-service/predicates:- Path=/blog/**
我们来启动网关,但是失败了,这个是因为,gateway这个依赖是webPlus的,是异步的。所以我们移除spring web和spring test
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency>
这样就可以启动了
现在我们就可以通过网关服务来访问user了
用户认证过滤
就是拦截器
网关实现拦截器,获取token
写了一个这个类,我们要排除一些路径,没有排除的然后校验路径
用户注册和登录,就可以直接放行—》白名单
不是这两个的,就校验header里面的token是不是合法的
我们用一个list来设置白名单(直接放行的路径)
这样我们的过滤器就写好了
测试过滤器
这个是token为空
postman没有前端,所以要手动添加token
这个是token非法的情况,我们乱写的token
我们可以添加合法的token
在登录的返回值里面,或者自己去测试生成也可以了
nacos配置mysql数据源
注意我们前面的白名单是写死的
新增白名单就要重新写代码了,就不太好
我们可以在naocs里面配置这个白名单
但是注意naocs的配置是存在data-》derty-data里面
我们现在存在mysql里面
官网
我们这里搞一个配置
版本OK
第二步第三步OK
nacos的数据库为云服务器上的数据,不为本地的数据库
打开Nacos配置文件conf/application.properties,进行以下配置更改:
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://你的数据库地址:端口/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=你的数据库用户名
db.password=你的数据库密码
我们找到这个信息,已经注释掉了
文档建议我们使用spring.sql.init.platform=mysql
官网建议我们使用spring.datasource.platform=mysql
这两个都可以的
原来:
变
这里配置的数据库为nacos_config,那么我们待会建库的时候,也是建nacos_config
第五步:初始化数据库
我们先看一下这个文件
就是sql语句
然后就是执行sqsl语句了
这个sql文件没有建库的语句
所以要先建库,然后执行这个sql脚本
create database if not exists nacos_config charset utf8mb4;
这个建的库名和我们配置的naocs的数据库的名字是一样的
然后是执行sql脚本
use nacos_config;
source /usr/local/src/nacos/conf/mysql-schema.sql
最后一步
重启naocs
先关闭nacos
sh shutdown.sh
bash startup.sh -m standalone
然后这里的naocs什么都没有了,因为原来的配置是存在data-》derty-data里面的,naocs重启就没了
我们现在新建一个配置
然后去看数据库
select * from config_info;
这样我们就看到了刚刚的配置了
从nacos读取配置
dataId
DataId格式介绍
在NacosSpringCloud中,
dataId 的完整格式如下:
${prefix}-${spring.profiles.active}.${file-extension} prefix
默认为spring.application.name 的值,也可以通过配置项spring.cloud.nacos.config.prefix
来配置. • s pring.profiles.active 即为当前环境对应的profile.当{prefix}.${file-extension} spring.profiles.active
为空时,对应的连接符 也将不存在,dataId的拼接格式变
成 ‘ p r e f i x . {`prefix}. ‘prefix.{file-extension}
f ile-exetension为配置内容的数据格式,可以通过配置项spring.cloud.nacos.config.file-extension 来配置。⽬前只⽀持properties 和yaml类型.默认为properties.微服务启动时,会从Nacos读取多个配置⽂件: 1.
p r e f i x − {prefix}- prefix−{spring.profiles.active}.${file-extension}` 如:product
service-dev.properties
2.
p r e f i x . {prefix}. prefix.{file-extension}
,如:product-service.properties
3.
${prefix}
如product-service
我们第三个用yaml,用properties ,配置文件就不用配置,用yaml就要配置,而且配置就真的是yaml格式了
这样就配置好了
然后是给gateway添加naocs-config的pom文件,和bootstrap
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!-- SpringCloud 2020.*之后版本需要引入bootstrap--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency>
然后是写bootstrap.yml了
这样就写好了,要写明是yaml
还有就是应用名称是gateway-service
所以nacos也要改一下
然后就是建立类开始读取naocs配置了
这样url就交给spring进行管理了,所以我们要注入它了,在filter里面注入
然后开始测试就可以了
注意这里的配置文件改一下,不要有http的前缀,这样就OK了
然后就是数据库中也有数据的