改的地方实在太多了,所以过程记录不下去了,但是业务模块跟Boot是一毛一样的没有变化,直接发项目代码,包括了nacos中的配置文件在对应的模块,运行大概是没有问题。
成果:
链接:https://pan.baidu.com/s/10ccshvY6sjYtrbRS8AhZpA
提取码:4pdr
PS:其实过年前就已经改造结束了,但是因为带娃没空整理(借口)。前阵子看到了篇文章《Spring Boot 单体应用一键升级成 Spring Cloud Alibaba》,感觉再不发就没机会了!
引入模块:
正文结束!下面都是一些杂乱的笔记,不保证正确。
经历了三个阶段:pom整理 => cloud模块引入 => 业务模块调试
day1
原项目拆解出来的模块。
day2
迁移后引用报错解决,pom拆分。
引入spring cloud alibaba依赖
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-dependenciesartifactId>
<version>${spring-cloud-alibaba.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
pom引入nacos
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
docker安装nacos
#拉取镜像
docker pull nacos/nacos-server
#创建映射文件
mkdir -p /root/nacos/init.d /root/nacos/logs
touch /root/nacos/init.d/custom.properties
#在文件中写入
management.endpoints.web.exposure.include=*
#创建容器并启动提供a、b两种方案
#a.创建容器:使用standalone模式并开放8848端口,并映射配置文件和日志目录,数据库默认使用 Derby
docker run -d -p 8848:8848 -e MODE=standalone -e PREFER_HOST_MODE=hostname -v /root/nacos/init.d/custom.properties:/home/nacos/init.d/custom.properties -v /root/nacos/logs:/home/nacos/logs --restart always --name nacos nacos/nacos-server
访问http://nacos.dinganwang.top/nacos可以打开nacos管理页面,默认账号密码nacos/nacos。
新建命名空间dev、pro区分一下开发环境还是正式环境。如果项目够大,项目粒度够多,可以根据模块创建命名空间。
Data ID需要与应用名称保持一致。
新建配置文件bootstrap.yml,增加配置。
spring:
application:
#应用名称
name: dingx-web
cloud:
nacos:
discovery:
server-addr: nacos.dinganwang.top
# 命名空间
namespace: 命名空间ID
在启动类上使用**@EnableDiscoveryClient** 开启服务注册发现功能。
引入gateway
<!-- SpringCloud Gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
报错:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method modifyRequestBodyGatewayFilterFactory in org.springframework.cloud.gateway.config.GatewayAutoConfiguration required a bean of type 'org.springframework.http.codec.ServerCodecConfigurer' that could not be found.
Action:
Consider defining a bean of type 'org.springframework.http.codec.ServerCodecConfigurer' in your configuration.
原因:gateWay 工程中同时引入了 Web依赖 和 webflux依赖,或者是父工程中有Web依赖,二当前微服务中有webflux依赖,这样会出现冲突。
查找了下是sa-token-spring-boot-starter
中存在spring-boot-starter-web
的依赖,排除掉即可。
<dependency>
<groupId>com.dingxgroupId>
<artifactId>common-redisartifactId>
<version>1.0-SNAPSHOTversion>
<exclusions>
<exclusion>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
exclusion>
exclusions>
dependency>
根据nacos的配置方式加入配置后启动,服务列表出现一例服务实例,表示成功。
最后的目录结构:
从上到下依次介绍:
api:统一管理feign远程调用,对应modules中的业务模块,比如api-admin中存放的是对
/modules/admin
模块下接口的调用。
auth:统一权限管理,包括用户登录注销,生成token等。
common:所有可以拆解的工具模块。
┗━common-code:代码生成器模块。
┗━common-core:核心配置类,包括业务模块依赖包引入pom、工具类、全局变量、全局枚举、全局异常处理等等。业务模块必须引用。
┗━common-datasource:数据库连接模块,包括拦截器等。
┗━common-elasticsearch:es工具模块。
┗━common-log:日志切面处理。
┗━common-redis:redis工具模块。
┗━common-security:鉴权相关,主要给auth模块提供支持。
┗━common-swagger:swagger模块。
gateway:网关。
modules:业务模块统一管理。
┗━modules-admin:后台管理。
┗━modules-file:文件管理。
┗━modules-job:定时任务模块。
┗━modules-web:前台页面。
monitor:监控模块。
引入feign
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
<version>${feign.version}version>
dependency>
新建模块统一管理。
模块下创建service。
@FeignClient(contextId = "remoteAdminLogService" ,value = ServiceNameConstants.ADMIN_SERVICE)
public interface RemoteAdminLogService {
@PostMapping(value = "/system/adminLog/insert")
ResponseResult insert(@RequestBody AdminLog log);
}
鉴权中心模块,由业务登录校验抽离。
报错
Caused by: java.lang.IllegalStateException: No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?
由于SpringCloud Feign在Hoxton.M2 RELEASED版本之后不再使用Ribbon而是使用spring-cloud-loadbalancer,所以不引入spring-cloud-loadbalancer会报错
引入pom
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-loadbalancerartifactId>
dependency>
报错:Parameter 0 of constructor in com.dingx.modules.admin.service.article.impl.ArticleServiceImpl required a bean of type ‘*.mapper’ that could not be found.
原因:Mapper未扫描到。
解决方案:在MybatisPlusConfig上加@MapperScan("com.dingx.modules.**.mapper.**")
注解
报错:Parameter 2 of constructor in com.dingx.modules.admin.service.article.impl.ArticleServiceImpl required a bean of type ‘org.springframework.web.client.RestTemplate’ that could not be found.
原因:错误提示说RestTemplate没找到,这是因为在 Spring Boot 1.3版本中,会默认提供一个RestTemplate的实例Bean,而在 Spring Boot 1.4以及以后的版本中,这个默认的bean不再提供了,我们需要在Application启动时,手动创建一个RestTemplate的配置。
解决方案:写个通用BeanConfig,再遇到同类问题统一管理
@Configuration
public class BeanConfig {
@Bean
RestTemplate restTemplate(){
return new RestTemplate();
}
}
报错:Caused by: com.baomidou.dynamic.datasource.exception.CannotFindDataSourceException: dynamic-datasource can not find primary datasource
原因:引入了多数据源配置。
解决方案:暂时没用,先注释。
报错:[RemoteUserService#updateLoginInfo(LoginInfoVO)]: [{“timestamp”:“2022-12-07T10:28:10.782+00:00”,“status”:405,“error”:“Method Not Allowed”,“message”:“”,“path”:“/system/user/updateLoginInfo”}]
解决方案:加入依赖
<dependency>
<groupId>io.github.openfeigngroupId>
<artifactId>feign-httpclientartifactId>
dependency>
异常:feign调用参数未传递
解决方案:指定调用方式consumes
@PostMapping(value = "/system/user/selectNameAndPassword", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
<dependency>
<groupId>cn.dev33groupId>
<artifactId>sa-token-reactor-spring-boot-starterartifactId>
<version>1.33.0version>
dependency>
<dependency>
<groupId>cn.dev33groupId>
<artifactId>sa-token-dao-redis-jacksonartifactId>
<version>1.33.0version>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-pool2artifactId>
dependency>
/**
* 自定义权限验证接口扩展
*/
@Component
public class StpInterfaceImpl implements StpInterface {
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
// 返回此 loginId 拥有的权限列表
return ...;
}
@Override
public List<String> getRoleList(Object loginId, String loginType) {
// 返回此 loginId 拥有的角色列表
return ...;
}
}
/**
* [Sa-Token 权限认证] 配置类
* @author kong
*/
@Configuration
public class SaTokenConfigure {
// 注册 Sa-Token全局过滤器
@Bean
public SaReactorFilter getSaReactorFilter() {
return new SaReactorFilter()
// 拦截地址
.addInclude("/**") /* 拦截全部path */
// 开放地址
.addExclude("/favicon.ico")
// 鉴权方法:每次访问进入
.setAuth(obj -> {
// 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
SaRouter.match("/**", "/user/doLogin", r -> StpUtil.checkLogin());
// 权限认证 -- 不同模块, 校验不同权限
SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));
// 更多匹配 ... */
})
// 异常处理方法:每次setAuth函数出现异常时进入
.setError(e -> {
return SaResult.error(e.getMessage());
})
;
}
}
注意:sa-token-spring-boot-starter与sa-token-reactor-spring-boot-starter存在冲突,不可同时引用。
直接访问需要鉴权