全面使用nacos,舍弃zookeeper

pull/1/head
tanghc 5 years ago
parent 90d6823693
commit 6e2a0e6c13
  1. 6
      README.md
  2. 10
      doc/docs/files/10010_快速体验.md
  3. 6
      doc/docs/files/10011_项目接入到SOP.md
  4. 10
      doc/docs/files/10050_接口交互详解.md
  5. 4
      doc/docs/files/10096_使用SpringCloudGateway.md
  6. 90
      doc/docs/files/10106_nacos注册中心.md
  7. 112
      doc/docs/files/10107_扩展其它注册中心.md
  8. 25
      doc/docs/files/90011_原理分析之路由存储.md
  9. 10
      doc/docs/files/90100_常见问题.md
  10. 6
      sop-admin/sop-admin-server/pom.xml
  11. 6
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/IsvApi.java
  12. 34
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/RouteApi.java
  13. 19
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/SopAdminConstants.java
  14. 6
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RoutePermissionService.java
  15. 11
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/SopConstants.java
  16. 7
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceConfig.java
  17. 16
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceConstants.java
  18. 13
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/BaseServiceConfiguration.java
  19. 92
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/DefaultGlobalExceptionHandler.java
  20. 27
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/ErrorController.java
  21. 87
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/GlobalExceptionHandler.java
  22. 2
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/SpringMvcServiceConfiguration.java
  23. 7
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ServiceRouteController.java
  24. 9
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ServiceRouteInfoHandler.java
  25. 37
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/route/ServiceRouteInfo.java
  26. 16
      sop-example/sop-book/sop-book-web/src/main/resources/application-dev.properties
  27. 4
      sop-example/sop-story/sop-story-web/src/main/resources/application-dev.properties
  28. 25
      sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbEnvGrayManager.java
  29. 20
      sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIPBlacklistManager.java
  30. 19
      sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvManager.java
  31. 36
      sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvRoutePermissionManager.java
  32. 19
      sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbLimitConfigManager.java
  33. 19
      sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbRouteConfigManager.java
  34. 8
      sop-gateway/src/main/resources/application-dev.properties
  35. 16
      sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/bean/WebsiteConstants.java
  36. 3
      sop-website/website-server/src/main/resources/application-dev.properties

@ -62,7 +62,7 @@ SOP封装了开放平台大部分功能包括:签名验证、统一异常处
## 工程说明
> 运行环境:JDK8,Maven3,Zookeeper
> 运行环境:JDK8,Maven3,[Nacos](https://nacos.io/zh-cn/docs/what-is-nacos.html)
- doc:开发文档
- sop-admin:后台管理
@ -76,9 +76,9 @@ SOP封装了开放平台大部分功能包括:签名验证、统一异常处
## 分支说明
- master:发版分支
- spring-cloud-gateway:Spring Cloud Gateway作为网关
- develop:日常开发分支
- registry-nacos:nacos作为注册中心
- SpringCloudGateway:SpringCloudGateway作为网关
## 相关文档

@ -1,22 +1,20 @@
# 快速体验
> 运行环境:JDK8,Maven3,Zookeeper,Mysql
> 运行环境:JDK8,Maven3,[Nacos](https://nacos.io/zh-cn/docs/what-is-nacos.html),Mysql
- 安装并启动zookeeper,[安装教程](http://zookeeper.apache.org/doc/r3.4.13/zookeeperStarted.html)
- 安装并启动Nacos,[安装教程](https://nacos.io/zh-cn/docs/quick-start.html)
- 执行Mysql脚本`sop.sql`
- IDE安装lombok插件,然后打开项目(IDEA下可以打开根pom.xml,然后open as project)
- 启动注册中心,sop-registry(运行SopRegistryApplication.java)
- 启动网关:打开sop-gateway下的`application-dev.properties`
1. 修改数据库`username/password`
2. 指定zookeeper地址,如果zookeeper安装在本机则不用改
2. 指定nacos地址,如果nacos安装在本机则不用改
3. 运行`SopGatewayApplication.java`
- 启动微服务:打开sop-story-web下的`application-dev.properties`文件
1. 指定zookeeper地址,如果zookeeper安装在本机则不用改
1. 指定nacos地址,如果nacos安装在本机则不用改
2. 运行`SopStoryApplication.java`
- 找到sop-test,打开`AllInOneTest.java`进行接口调用测试
确保注册中心先启动
## 使用admin
- 找到`sop-admin/sop-admin-server`工程,打开sop-admin-server下的`application-dev.properties`,修改相关配置

@ -39,10 +39,8 @@
server.port=2222
# 服务名称
spring.application.name=story-service
# eureka注册中心
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
# zookeeper配置
spring.cloud.zookeeper.connect-string=localhost:2181
# nacos注册中心
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
```
- 在springboot启动类上添加`@EnableDiscoveryClient`

@ -7,8 +7,8 @@
SOP也是采用这种方式实现,大致步骤如下:
- 每个服务注册到注册中心,在启动的时候把自己的路由信息上传到zookeeper,并且保证每一个接口都能对应到哪个服务。
- 网关启动时同样注册到注册中心,获取zookeeper上的接口信息,保存到本地,并监听zookeeper上的接口信息,一旦接口信息有修改,网关这边能及时进行更新。
- 每个服务注册到nacos
- 网关启动时同样注册到nacos,然后从各服务中拉取路由信息
- 网关收到客户端请求后,先进行签名校验,通过之后根据接口信息找到对应的服务,然后进行路由
- 网关对返回结果进行处理(或不处理),返回给客户端。
@ -16,10 +16,10 @@ SOP也是采用这种方式实现,大致步骤如下:
在网关定义一个`Map<String, RouteInfo> routeMap = ...`,key为接口名+版本号。
网关启动时,从zookeeper中获取路由信息,并保存到routeMap中
网关启动时,从各微服务中获取路由信息,并保存到routeMap中
```java
routeMap = buildFromZookeeper();
routeMap = requestFormServices();
```
接口请求进来后,根据`方法名+版本号`获取路由信息,然后进行路由转发。
@ -33,7 +33,7 @@ RouteInfo routeInfo = routeMap.get(method + version);
doRoute(routeInfo);
```
因为有多个服务把路由信息注册到zookeeper,我们要确保接口名唯一,即`method`全局唯一。
因为nacos需要拉取各个微服务的路由信息,接口名有可能会冲突,因此需要确保接口名唯一,即`method`全局唯一。
我们推荐接口名的命名规则应该是:`服务模块.业务模块.功能模块.行为`,如:

@ -1,8 +1,6 @@
# 使用SpringCloudGateway
SOP默认网关是使用Spring Cloud Zuul,您也可以切换成Spring Cloud Gateway,完整代码见`SpringCloudGateway`分支。
**注:**:SOP对Spring Cloud Gateway的支持目前处于beta阶段,推荐使用zuul。
SOP默认网关是使用Spring Cloud Zuul,您也可以切换成Spring Cloud Gateway,完整代码见`spring-cloud-gateway`分支。
步骤如下:

@ -1,90 +0,0 @@
# nacos注册中心
使用nacos作为注册中心,源码在`registry-nacos`分支
这里演示如何将默认的eureka注册中心替换成nacos,步骤如下:
- 准备工作
1.安装nacos,前往[最新稳定版本](https://github.com/alibaba/nacos/releases),下载最新版nacos
2.启动nacos服务器,cd nacos/bin
Linux/Unix/Mac,启动命令(standalone代表着单机模式运行,非集群模式):
`sh startup.sh -m standalone`
Windows,启动命令:
`cmd startup.cmd`
或者双击startup.cmd运行文件。
更多访问:https://nacos.io/zh-cn/docs/quick-start.html
- 微服务端修改
1.修改微服务应用pom,打开`sop-example/sop-story/sop-story-web/pom.xml`,注释eureka服务发现依赖,添加nacos服务发现依赖
```xml
<!-- 注册中心【只能用一个,不用的注释掉】 -->
<!-- 使用eureka注册中心
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
-->
<!-- 使用nacos注册中心
版本 0.2.x.RELEASE 对应的是 Spring Boot 2.x 版本,版本 0.1.x.RELEASE 对应的是 Spring Boot 1.x 版本。
https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-alibaba-nacos-discovery
-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>0.2.2.RELEASE</version>
</dependency>
<!-- 注册中心end -->
```
2.yml文件新增nacos配置,并注释掉eureka相关配置
```yaml
spring:
cloud:
# nacos注册中心,和eureka只能用一个
nacos:
discovery:
server-addr: 127.0.0.1:8848
```
- 网关修改
找到`sop-gateway`工程,步骤同上
- SOP-admin修改
修改yml文件,设置nacos服务器地址,`registry.name`填nacos
```yaml
# 注册中心地址,根据实际情况改,这里只是参数,并不会去注册
registry:
eureka-server-addr: http://localhost:1111/eureka/
# nacos服务器地址
nacos-server-addr: 127.0.0.1:8848
# 使用eureka,填:eureka,使用nacos填:nacos
name: nacos
```
- website-server修改
步骤同`SOP-admin修改`
如果要改成consul注册中心,可参照以上步骤。
- 参考资料
1.[nacos介绍及安装](https://nacos.io/zh-cn/docs/quick-start.html)
2.[nacos spring cloud注册发现](https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html)

@ -1,112 +0,0 @@
# 扩展其它注册中心
**注: nacos注册中心已经实现,本篇以nacos为例介绍如何扩展,如果要改成consul,可按照此方式进行修改**
SOP默认使用eureka注册中心,如果要换成nacos注册中心,步骤如下:
- 实现`com.gitee.sop.registryapi.service.RegistryService`接口
1.找到`SOP/sop-common/sop-registry-api`工程,在service.impl包下新建一个类,实现RegistryService接口
```java
public class RegistryServiceNacos implements RegistryService {
@Override
public List<ServiceInfo> listAllService(int pageNo, int pageSize) throws Exception {
// TODO: 返回服务实例
}
@Override
public void onlineInstance(ServiceInstance serviceInstance) throws Exception {
// TODO: 实例上线
}
@Override
public void offlineInstance(ServiceInstance serviceInstance) throws Exception {
// TODO: 实例下线
}
}
```
2.在`com.gitee.sop.registryapi.config.BaseRegistryConfig`中新增
```java
/**
* 当配置了registry.name=nacos生效
*
* @return
*/
@Bean
@ConditionalOnProperty(prefix = "registry", name = "name", havingValue = "nacos")
RegistryService registryServiceNacos() {
return new RegistryServiceNacos();
}
```
其中`@ConditionalOnProperty(prefix = "registry", name = "name", havingValue = "nacos")`
表示`application.properties`配置了`registry.name=nacos`参数才能生效,registry.name=nacos下文会讲到。
- 微服务端修改
1.修改微服务应用pom.xml,注释eureka服务发现依赖,添加nacos服务发现依赖
```xml
<!-- 注册中心【只能用一个,不用的注释掉】 -->
<!-- 使用eureka注册中心
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
-->
<!-- 使用nacos注册中心
版本 0.2.x.RELEASE 对应的是 Spring Boot 2.x 版本,版本 0.1.x.RELEASE 对应的是 Spring Boot 1.x 版本。
https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-alibaba-nacos-discovery
-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>0.2.2.RELEASE</version>
</dependency>
<!-- 注册中心end -->
```
2.yml文件新增nacos配置,并注释掉eureka相关配置
```yaml
spring:
cloud:
# nacos注册中心,和eureka只能用一个
nacos:
discovery:
server-addr: 127.0.0.1:8848
```
- 网关修改
找到`sop-gateway`工程,步骤同上
- SOP-admin修改
修改yml文件,新增nacos服务器地址,`registry.name`填nacos
```yaml
# 注册中心地址,根据实际情况改,这里只是参数,并不会去注册
registry:
# 使用eureka,填:eureka,使用nacos填:nacos
name: nacos
eureka-server-addr: http://localhost:1111/eureka/
nacos-server-addr: 127.0.0.1:8848
```
- website-server修改
步骤同`SOP-admin修改`
- 参考资料
1.[nacos介绍及安装](https://nacos.io/zh-cn/docs/quick-start.html)
2.[nacos spring cloud注册发现](https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html)

@ -1,25 +0,0 @@
# 原理分析之路由存储
SOP将路由信息存到了zookeeper当中,服务在启动时,将自己的路由信息上传到zookeeper中。
网关监听存放路由的节点,动态更新到本地。
zookeeper存储路由的结构如下:
```xml
/com.gitee.sop.route 根节点
/serviceId 服务节点,名字为服务名
/route1 路由节点,名字为:name+version,存放路由信息
/route2
/...
```
服务启动时,创建`/serviceId`节点,然后遍历创建`/routeN`节点
同时,网关监听`服务节点`和`路由节点`,当有新服务加入时,网关会获取到新加入的路由节点信息,
同时路由节点下面的子节点也会被监听到。后续子节点的增删改都会被网关监听到,然后更新到本地。
服务上传路由相关代码在`com.gitee.sop.servercommon.manager.ServiceZookeeperApiMetaManager`类中
网关监听相关代码在`com.gitee.sop.gatewaycommon.manager.BaseRouteManager`中

@ -19,16 +19,6 @@ OpenContext openContext = ServiceContext.getCurrentContext().getOpenContext();
Story bizObject = openContext.getBizObject(Story.class);
```
## Socket error occurred: `localhost/0:0:0:0:0:0:0:1:2181`: Connection refused
检查本地zookeeper有没启动,如果zookeeper在其他机器上,修改application-dev.yml
```yaml
cloud:
zookeeper:
connect-string: ip:2181
```
## 如何关闭签名验证
- 针对某一个接口关闭签名验证

@ -21,8 +21,6 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<zookeeper.version>3.4.12</zookeeper.version>
<curator-recipes.version>4.0.1</curator-recipes.version>
<okhttp.version>3.11.0</okhttp.version>
</properties>
@ -30,12 +28,12 @@
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>nacos-config-spring-boot-starter</artifactId>
<version>0.2.2</version>
<version>0.2.3</version>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>nacos-discovery-spring-boot-starter</artifactId>
<version>0.2.2</version>
<version>0.2.3</version>
</dependency>
<dependency>

@ -292,10 +292,10 @@ public class IsvApi {
}
try {
routePermissionService.sendIsvRolePermissionToZookeeper(isvInfo.getAppKey(), roleCodeList);
routePermissionService.sendIsvRolePermissionMsg(isvInfo.getAppKey(), roleCodeList);
} catch (Exception e) {
log.error("保存到zookeeper中失败,isvInfo:{}, roleCodeList:{}", isvInfo, roleCodeList);
throw new BizException("同步zookeeper失败,请查看网关日志");
log.error("同步角色失败,isvInfo:{}, roleCodeList:{}", isvInfo, roleCodeList);
throw new BizException("同步角色失败,请查看网关日志");
}
}
}

@ -4,7 +4,6 @@ import com.gitee.easyopen.annotation.Api;
import com.gitee.easyopen.annotation.ApiService;
import com.gitee.easyopen.doc.annotation.ApiDoc;
import com.gitee.easyopen.doc.annotation.ApiDocMethod;
import com.gitee.easyopen.util.CopyUtil;
import com.gitee.sop.adminserver.api.isv.result.RoleVO;
import com.gitee.sop.adminserver.api.service.param.RouteAddParam;
import com.gitee.sop.adminserver.api.service.param.RouteDeleteParam;
@ -95,46 +94,19 @@ public class RouteApi {
@Api(name = "route.add")
@ApiDocMethod(description = "新增路由")
void addRoute(RouteAddParam param) {
// TODO:新增路由
String id = param.getName() + param.getVersion();
// String routePath = ZookeeperContext.buildRoutePath(param.getServiceId(), id);
GatewayRouteDefinition routeDefinition = new GatewayRouteDefinition();
CopyUtil.copyPropertiesIgnoreNull(param, routeDefinition);
routeDefinition.setId(id);
routeDefinition.setCustom(1);
// try {
// ZookeeperContext.addPath(routePath, JSON.toJSONString(routeDefinition));
// } catch (ZookeeperPathExistException e) {
// throw new BizException("路由已存在");
// }
this.updateRouteConfig(routeDefinition);
// TODO: 新增路由
}
@Api(name = "route.update")
@ApiDocMethod(description = "修改路由")
void updateRoute(RouteUpdateParam param) {
// TODO:修改路由
// String routePath = ZookeeperContext.buildRoutePath(param.getServiceId(), param.getId());
// GatewayRouteDefinition routeDefinition = this.getGatewayRouteDefinition(routePath);
// CopyUtil.copyPropertiesIgnoreNull(param, routeDefinition);
// try {
// ZookeeperContext.updatePathData(routePath, JSON.toJSONString(routeDefinition));
// } catch (ZookeeperPathNotExistException e) {
// throw new BizException("路由不存在");
// }
// this.updateRouteConfig(routeDefinition);
// TODO: 修改路由
}
@Api(name = "route.del")
@ApiDocMethod(description = "删除路由")
void delRoute(RouteDeleteParam param) {
// TODO:删除路由
/*String routePath = ZookeeperContext.buildRoutePath(param.getServiceId(), param.getId());
GatewayRouteDefinition routeDefinition = this.getGatewayRouteDefinition(routePath);
if (!BooleanUtils.toBoolean(routeDefinition.getCustom())) {
throw new BizException("非自定义路由,无法删除");
}
ZookeeperContext.deletePathDeep(routePath);*/
// TODO: 删除路由
}

@ -1,19 +0,0 @@
package com.gitee.sop.adminserver.bean;
/**
* @author tanghc
*/
public class SopAdminConstants {
/**
* zookeeper存放接口路由信息的根目录
*/
public static final String SOP_SERVICE_ROUTE_PATH = "/com.gitee.sop.route";
/**
* 消息监听路径
*/
public static final String SOP_MSG_CHANNEL_PATH = "/com.gitee.sop.channel";
public static final String RELOAD_ROUTE_PERMISSION_PATH = "/com.gitee.sop.route.permission.reload";
}

@ -58,12 +58,12 @@ public class RoutePermissionService {
}
/**
* 推送isv路由权限到zookeeper
* 推送isv路由权限
*
* @param appKey
* @param roleCodeList
*/
public void sendIsvRolePermissionToZookeeper(String appKey, List<String> roleCodeList) throws Exception {
public void sendIsvRolePermissionMsg(String appKey, List<String> roleCodeList) throws Exception {
Collections.sort(roleCodeList);
List<String> routeIdList = this.getRouteIdList(roleCodeList);
String roleCodeListMd5 = DigestUtils.md5Hex(JSON.toJSONString(routeIdList));
@ -95,7 +95,7 @@ public class RoutePermissionService {
}
/**
* 推送所有路由权限到zookeeper
* 推送所有路由权限
*/
public void sendRoutePermissionReloadMsg(RoutePermissionParam oldRoutePermission) throws Exception {
IsvRoutePermission isvRoutePermission = new IsvRoutePermission();

@ -42,17 +42,6 @@ public class SopConstants {
public static final int BIZ_ERROR_STATUS = 4000;
/**
* zookeeper存放接口路由信息的根目录
*/
public static final String SOP_SERVICE_ROUTE_PATH = "/com.gitee.sop.route";
/**
* 消息监听路径
*/
public static final String SOP_MSG_CHANNEL_PATH = "/com.gitee.sop.channel";
public static final String UNKNOWN_SERVICE= "_sop_unknown_service_";
public static final String UNKNOWN_METHOD = "_sop_unknown_method_";
public static final String UNKNOWN_VERSION = "_sop_unknown_version_";

@ -1,7 +1,5 @@
package com.gitee.sop.servercommon.bean;
import com.gitee.sop.servercommon.configuration.DefaultGlobalExceptionHandler;
import com.gitee.sop.servercommon.configuration.GlobalExceptionHandler;
import com.gitee.sop.servercommon.param.ApiArgumentResolver;
import com.gitee.sop.servercommon.param.SopHandlerMethodArgumentResolver;
import com.gitee.sop.servercommon.result.DefaultServiceResultBuilder;
@ -45,11 +43,6 @@ public class ServiceConfig {
*/
private ServiceResultBuilder serviceResultBuilder = new DefaultServiceResultBuilder();
/**
* 全局异常处理
*/
private GlobalExceptionHandler globalExceptionHandler = new DefaultGlobalExceptionHandler();
/**
* 默认版本号
*/

@ -1,16 +0,0 @@
package com.gitee.sop.servercommon.bean;
/**
* @author tanghc
*/
public class ServiceConstants {
/**
* zookeeper存放接口路由信息的根目录
*/
public static final String SOP_SERVICE_ROUTE_PATH = "/com.gitee.sop.route";
/**
* 服务临时节点
*/
public static final String SOP_SERVICE_TEMP_PATH = "/com.gitee.sop.service.tmp";
}

@ -8,6 +8,7 @@ import com.gitee.sop.servercommon.message.ServiceErrorFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
@ -70,12 +71,20 @@ public class BaseServiceConfiguration extends WebMvcConfigurationSupport
}
@Bean
@ConditionalOnMissingBean
GlobalExceptionHandler globalExceptionHandler() {
return ServiceConfig.getInstance().getGlobalExceptionHandler();
return new GlobalExceptionHandler();
}
@Bean
ServiceRouteController serviceRouteController() {
@ConditionalOnMissingBean
ErrorController errorController() {
return new ErrorController();
}
@Bean
@ConditionalOnMissingBean
ServiceRouteController serviceRouteInfoHandler() {
return new ServiceRouteController();
}

@ -1,92 +0,0 @@
package com.gitee.sop.servercommon.configuration;
import com.gitee.sop.servercommon.bean.ServiceConfig;
import com.gitee.sop.servercommon.exception.ServiceException;
import com.gitee.sop.servercommon.result.ServiceResultBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 全局异常处理
* @author tanghc
*/
@ControllerAdvice
@Slf4j
public class DefaultGlobalExceptionHandler implements GlobalExceptionHandler {
/**
* 与网关约定好的状态码表示业务出错
*/
public static final int BIZ_ERROR_CODE = 4000;
/**
* 系统错误
*/
public static final int SYSTEM_ERROR_CODE = 5050;
public static final String X_SERVICE_ERROR_CODE = "x-service-error-code";
@RequestMapping("/error")
@ResponseBody
public Object error(HttpServletRequest request, HttpServletResponse response) {
ServiceResultBuilder serviceResultBuilder = ServiceConfig.getInstance().getServiceResultBuilder();
return serviceResultBuilder.buildError(request, response, new ServiceException("系统繁忙"));
}
/**
* 捕获手动抛出的异常
* @param request
* @param response
* @param exception
* @return
*/
@ExceptionHandler(ServiceException.class)
@ResponseBody
public Object serviceExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception exception) {
response.addHeader(X_SERVICE_ERROR_CODE, String.valueOf(BIZ_ERROR_CODE));
return this.processError(request, response, exception);
}
/**
* 捕获未知异常
* @param request
* @param response
* @param exception
* @return
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public Object exceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception exception) {
response.addHeader(X_SERVICE_ERROR_CODE, String.valueOf(SYSTEM_ERROR_CODE));
log.error("系统错误", exception);
StringBuilder msg = new StringBuilder();
msg.append(exception.getMessage());
StackTraceElement[] stackTrace = exception.getStackTrace();
// 取5行错误内容
int lineCount = 5;
for (int i = 0; i < stackTrace.length && i < lineCount ; i++) {
StackTraceElement stackTraceElement = stackTrace[i];
msg.append("<br> at ").append(stackTraceElement.toString());
}
response.setHeader("x-service-error-message", msg.toString());
return this.processError(request, response, new ServiceException("系统繁忙"));
}
/**
* 处理异常
*
* @param request
* @param response
* @param exception
* @return 返回最终结果
*/
protected Object processError(HttpServletRequest request, HttpServletResponse response, Exception exception) {
ServiceResultBuilder serviceResultBuilder = ServiceConfig.getInstance().getServiceResultBuilder();
return serviceResultBuilder.buildError(request, response, exception);
}
}

@ -0,0 +1,27 @@
package com.gitee.sop.servercommon.configuration;
import com.gitee.sop.servercommon.bean.ServiceConfig;
import com.gitee.sop.servercommon.exception.ServiceException;
import com.gitee.sop.servercommon.result.ServiceResultBuilder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author tanghc
*/
@RestController
public class ErrorController {
@RequestMapping("/error")
public Object error(HttpServletRequest request, HttpServletResponse response) {
return getResult(request, response);
}
protected Object getResult(HttpServletRequest request, HttpServletResponse response) {
ServiceResultBuilder serviceResultBuilder = ServiceConfig.getInstance().getServiceResultBuilder();
return serviceResultBuilder.buildError(request, response, new ServiceException("系统繁忙"));
}
}

@ -1,7 +1,92 @@
package com.gitee.sop.servercommon.configuration;
import com.gitee.sop.servercommon.bean.ServiceConfig;
import com.gitee.sop.servercommon.exception.ServiceException;
import com.gitee.sop.servercommon.result.ServiceResultBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 全局异常处理
* @author tanghc
*/
public interface GlobalExceptionHandler {
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* 与网关约定好的状态码表示业务出错
*/
public static final int BIZ_ERROR_CODE = 4000;
/**
* 系统错误
*/
public static final int SYSTEM_ERROR_CODE = 5050;
public static final String X_SERVICE_ERROR_CODE = "x-service-error-code";
@RequestMapping("/error")
@ResponseBody
public Object error(HttpServletRequest request, HttpServletResponse response) {
ServiceResultBuilder serviceResultBuilder = ServiceConfig.getInstance().getServiceResultBuilder();
return serviceResultBuilder.buildError(request, response, new ServiceException("系统繁忙"));
}
/**
* 捕获手动抛出的异常
* @param request
* @param response
* @param exception
* @return
*/
@ExceptionHandler(ServiceException.class)
@ResponseBody
public Object serviceExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception exception) {
response.addHeader(X_SERVICE_ERROR_CODE, String.valueOf(BIZ_ERROR_CODE));
return this.processError(request, response, exception);
}
/**
* 捕获未知异常
* @param request
* @param response
* @param exception
* @return
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public Object exceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception exception) {
response.addHeader(X_SERVICE_ERROR_CODE, String.valueOf(SYSTEM_ERROR_CODE));
log.error("系统错误", exception);
StringBuilder msg = new StringBuilder();
msg.append(exception.getMessage());
StackTraceElement[] stackTrace = exception.getStackTrace();
// 取5行错误内容
int lineCount = 5;
for (int i = 0; i < stackTrace.length && i < lineCount ; i++) {
StackTraceElement stackTraceElement = stackTrace[i];
msg.append("<br> at ").append(stackTraceElement.toString());
}
response.setHeader("x-service-error-message", msg.toString());
return this.processError(request, response, new ServiceException("系统繁忙"));
}
/**
* 处理异常
*
* @param request
* @param response
* @param exception
* @return 返回最终结果
*/
protected Object processError(HttpServletRequest request, HttpServletResponse response, Exception exception) {
ServiceResultBuilder serviceResultBuilder = ServiceConfig.getInstance().getServiceResultBuilder();
return serviceResultBuilder.buildError(request, response, exception);
}
}

@ -37,7 +37,7 @@ public class SpringMvcServiceConfiguration {
@Bean
GlobalExceptionHandler globalExceptionHandler() {
return ServiceConfig.getInstance().getGlobalExceptionHandler();
return new GlobalExceptionHandler();
}
@PostConstruct

@ -3,6 +3,7 @@ package com.gitee.sop.servercommon.manager;
import com.gitee.sop.servercommon.bean.ServiceApiInfo;
import com.gitee.sop.servercommon.route.ServiceRouteInfo;
import com.gitee.sop.servercommon.util.OpenUtil;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
@ -17,6 +18,7 @@ import javax.servlet.http.HttpServletResponse;
* @author tanghc
*/
@Slf4j
@Getter
@RestController
public class ServiceRouteController {
@ -35,6 +37,10 @@ public class ServiceRouteController {
log.error("签名验证失败, params:{}", request.getQueryString());
return null;
}
return getServiceRouteInfo(request, response);
}
protected ServiceRouteInfo getServiceRouteInfo(HttpServletRequest request, HttpServletResponse response) {
String serviceId = environment.getProperty("spring.application.name");
ApiMetaBuilder apiMetaBuilder = new ApiMetaBuilder();
ServiceApiInfo serviceApiInfo = apiMetaBuilder.getServiceApiInfo(serviceId, requestMappingHandlerMapping);
@ -42,5 +48,4 @@ public class ServiceRouteController {
return serviceRouteInfoBuilder.build(serviceApiInfo);
}
}

@ -0,0 +1,9 @@
package com.gitee.sop.servercommon.manager;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author tanghc
*/
public interface ServiceRouteInfoHandler {
}

@ -1,7 +1,6 @@
package com.gitee.sop.servercommon.route;
import com.alibaba.fastjson.annotation.JSONField;
import com.gitee.sop.servercommon.bean.ServiceConstants;
import lombok.Data;
import java.util.Date;
@ -12,10 +11,10 @@ import java.util.List;
*/
@Data
public class ServiceRouteInfo {
private static final String SOP_SERVICE_ROUTE_PATH = ServiceConstants.SOP_SERVICE_ROUTE_PATH;
private static final String SOP_SERVICE_TEMP_PATH = ServiceConstants.SOP_SERVICE_TEMP_PATH;
/** 服务名称,对应spring.application.name */
/**
* 服务名称对应spring.application.name
*/
private String serviceId;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
@ -26,36 +25,12 @@ public class ServiceRouteInfo {
private String description;
/** 路由信息md5,md5(sort(routeIdList)) */
private String md5;
@JSONField(serialize = false)
private List<GatewayRouteDefinition> routeDefinitionList;
/**
* 返回zookeeper路径
* @return 返回zookeeper路径
* 路由信息md5md5(sort(routeIdList))
*/
@JSONField(serialize = false)
public String getZookeeperPath() {
return SOP_SERVICE_ROUTE_PATH + '/' + serviceId;
}
private String md5;
/**
* 返回zookeeper路径
* @return 返回zookeeper路径
*/
@JSONField(serialize = false)
public String getZookeeperTempServiceIdPath() {
return SOP_SERVICE_TEMP_PATH + '/' + serviceId;
}
private List<GatewayRouteDefinition> routeDefinitionList;
/**
* 返回zookeeper路径
* @return 返回zookeeper路径
*/
@JSONField(serialize = false)
public String getZookeeperTempServiceIdChildPath() {
return getZookeeperTempServiceIdPath() + "/" + serviceId;
}
}

@ -1,17 +1,13 @@
server.port=3333
spring.application.name=book-service
spring.application.description=book服务
# nacos注册中心
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
# zookeeper配置
spring.cloud.zookeeper.connect-string=localhost:2181
# zipkin服务跟踪
spring.zipkin.base-url=http://127.0.0.1:9411/
# 设置sleuth收集信息的比率,默认0.1,最大是1,数字越大越耗性能
spring.sleuth.sampler.probability=1
# dubbo使用zipkin过滤器
dubbo.provider.filter=tracing
dubbo.consumer.filter=tracing
#spring.zipkin.base-url=http://127.0.0.1:9411/
## 设置sleuth收集信息的比率,默认0.1,最大是1,数字越大越耗性能
#spring.sleuth.sampler.probability=1
## dubbo使用zipkin过滤器
#dubbo.provider.filter=tracing
#dubbo.consumer.filter=tracing

@ -1,13 +1,9 @@
server.port=2222
spring.application.name=story-service
spring.application.description=story服务
# nacos注册中心
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
# zookeeper配置
spring.cloud.zookeeper.connect-string=localhost:2181
# dubbo配置
dubbo.protocol.name=dubbo
dubbo.protocol.port=12345

@ -100,31 +100,6 @@ public class DbEnvGrayManager extends DefaultEnvGrayManager {
@PostConstruct
protected void after() throws Exception {
/*ZookeeperContext.setEnvironment(environment);
String isvChannelPath = ZookeeperContext.getServiceGrayChannelPath();
ZookeeperContext.listenPath(isvChannelPath, nodeCache -> {
String nodeData = new String(nodeCache.getCurrentData().getData());
ChannelMsg channelMsg = JSON.parseObject(nodeData, ChannelMsg.class);
String data = channelMsg.getData();
ServiceGrayDefinition userKeyDefinition = JSON.parseObject(data, ServiceGrayDefinition.class);
String serviceId = userKeyDefinition.getServiceId();
switch (channelMsg.getOperation()) {
case "set":
ConfigGray configGray = configGrayMapper.getByColumn("service_id", serviceId);
this.setServiceGrayConfig(configGray);
break;
case "open":
openGray(userKeyDefinition.getInstanceId(), serviceId);
break;
case "close":
closeGray(userKeyDefinition.getInstanceId());
break;
default:
}
});*/
// nacos
ConfigService configService = nacosConfigProperties.configServiceInstance();
configService.addListener(NacosConfigs.DATA_ID_GRAY, NacosConfigs.GROUP_CHANNEL, new AbstractListener() {
@Override

@ -41,26 +41,6 @@ public class DbIPBlacklistManager extends DefaultIPBlacklistManager {
@PostConstruct
protected void after() throws Exception {
/*ZookeeperContext.setEnvironment(environment);
String path = ZookeeperContext.getIpBlacklistChannelPath();
ZookeeperContext.listenPath(path, nodeCache -> {
String nodeData = new String(nodeCache.getCurrentData().getData());
ChannelMsg channelMsg = JSON.parseObject(nodeData, ChannelMsg.class);
final IPDto ipDto = JSON.parseObject(channelMsg.getData(), IPDto.class);
String ip = ipDto.getIp();
switch (channelMsg.getOperation()) {
case "add":
log.info("添加IP黑名单,ip:{}", ip);
add(ip);
break;
case "delete":
log.info("移除IP黑名单,ip:{}", ip);
remove(ip);
break;
default:
}
});*/
// nacos
ConfigService configService = nacosConfigProperties.configServiceInstance();
configService.addListener(NacosConfigs.DATA_ID_IP_BLACKLIST, NacosConfigs.GROUP_CHANNEL, new AbstractListener() {
@Override

@ -46,25 +46,6 @@ public class DbIsvManager extends CacheIsvManager {
@PostConstruct
protected void after() throws Exception {
ApiConfig.getInstance().setIsvManager(this);
/*ZookeeperContext.setEnvironment(environment);
String isvChannelPath = ZookeeperContext.getIsvInfoChannelPath();
ZookeeperContext.listenPath(isvChannelPath, nodeCache -> {
String nodeData = new String(nodeCache.getCurrentData().getData());
ChannelMsg channelMsg = JSON.parseObject(nodeData, ChannelMsg.class);
final IsvDefinition isvDefinition = JSON.parseObject(channelMsg.getData(), IsvDefinition.class);
switch (channelMsg.getOperation()) {
case "update":
log.info("更新ISV信息,isvDefinition:{}", isvDefinition);
update(isvDefinition);
break;
case "remove":
log.info("删除ISV,isvDefinition:{}", isvDefinition);
remove(isvDefinition.getAppKey());
break;
default:
}
});*/
ConfigService configService = nacosConfigProperties.configServiceInstance();
configService.addListener(NacosConfigs.DATA_ID_ISV, NacosConfigs.GROUP_CHANNEL, new AbstractListener() {

@ -127,42 +127,6 @@ public class DbIsvRoutePermissionManager extends DefaultIsvRoutePermissionManage
@PostConstruct
protected void after() throws Exception {
/*ZookeeperContext.setEnvironment(environment);
String isvChannelPath = ZookeeperContext.getIsvRoutePermissionChannelPath();
ZookeeperContext.listenPath(isvChannelPath, nodeCache -> {
String nodeData = new String(nodeCache.getCurrentData().getData());
ChannelMsg channelMsg = JSON.parseObject(nodeData, ChannelMsg.class);
final IsvRoutePermission isvRoutePermission = JSON.parseObject(channelMsg.getData(), IsvRoutePermission.class);
switch (channelMsg.getOperation()) {
case "reload":
log.info("重新加载路由权限信息,isvRoutePermission:{}", isvRoutePermission);
String listenPath = isvRoutePermission.getListenPath();
String code = "";
try {
load();
} catch (Exception e) {
log.error("重新加载路由权限失败, channelMsg:{}", channelMsg, e);
code = e.getMessage();
}
try {
ZookeeperContext.updatePath(listenPath, code);
} catch (Exception e1) {
log.error("重新加载路由权限信息, zookeeper操作失败, path: {}", listenPath, e1);
}
break;
case "update":
log.info("更新ISV路由权限信息,isvRoutePermission:{}", isvRoutePermission);
update(isvRoutePermission);
break;
case "remove":
log.info("删除ISV路由权限信息,isvRoutePermission:{}", isvRoutePermission);
remove(isvRoutePermission.getAppKey());
break;
default:
}
});*/
ConfigService configService = nacosConfigProperties.configServiceInstance();
configService.addListener(NacosConfigs.DATA_ID_ROUTE_PERMISSION, NacosConfigs.GROUP_CHANNEL, new AbstractListener() {
@Override

@ -53,25 +53,6 @@ public class DbLimitConfigManager extends DefaultLimitConfigManager {
@PostConstruct
protected void after() throws Exception {
/*ZookeeperContext.setEnvironment(environment);
String path = ZookeeperContext.getLimitConfigChannelPath();
ZookeeperContext.listenPath(path, nodeCache -> {
String nodeData = new String(nodeCache.getCurrentData().getData());
ChannelMsg channelMsg = JSON.parseObject(nodeData, ChannelMsg.class);
final ConfigLimitDto configLimitDto = JSON.parseObject(channelMsg.getData(), ConfigLimitDto.class);
switch (channelMsg.getOperation()) {
case "reload":
log.info("重新加载限流配置信息,configLimitDto:{}", configLimitDto);
load();
break;
case "update":
log.info("更新限流配置信息,configLimitDto:{}", configLimitDto);
update(configLimitDto);
break;
default:
}
});*/
ConfigService configService = nacosConfigProperties.configServiceInstance();
configService.addListener(NacosConfigs.DATA_ID_LIMIT_CONFIG, NacosConfigs.GROUP_CHANNEL, new AbstractListener() {
@Override

@ -77,25 +77,6 @@ public class DbRouteConfigManager extends DefaultRouteConfigManager {
@PostConstruct
protected void after() throws Exception {
/*ZookeeperContext.setEnvironment(environment);
String path = ZookeeperContext.getRouteConfigChannelPath();
ZookeeperContext.listenPath(path, nodeCache -> {
String nodeData = new String(nodeCache.getCurrentData().getData());
ChannelMsg channelMsg = JSON.parseObject(nodeData, ChannelMsg.class);
final RouteConfig routeConfig = JSON.parseObject(channelMsg.getData(), RouteConfig.class);
switch (channelMsg.getOperation()) {
case "reload":
log.info("重新加载路由配置信息,routeConfigDto:{}", routeConfig);
load();
break;
case "update":
log.info("更新路由配置信息,routeConfigDto:{}", routeConfig);
update(routeConfig);
break;
default:
}
});*/
ConfigService configService = nacosConfigProperties.configServiceInstance();
configService.addListener(NacosConfigs.DATA_ID_ROUTE_CONFIG, NacosConfigs.GROUP_CHANNEL, new AbstractListener() {
@Override

@ -6,12 +6,9 @@ spring.application.name=api-gateway
mysql.username=root
mysql.password=root
# eureka注册中心地址
eureka.url=http://localhost:1111/eureka/
# zookeeper地址
zookeeper.url=localhost:2181
# nacos地址
nacos.url=127.0.0.1:8848
# zipkin服务监控地址,没有开启不用改
zipkin.url=http://127.0.0.1:9411/
@ -40,9 +37,6 @@ ribbon.OkToRetryOnAllOperations=false
# nacos cloud配置
spring.cloud.nacos.discovery.server-addr=${nacos.url}
# zookeeper配置
spring.cloud.zookeeper.connect-string=${zookeeper.url}
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/sop?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
spring.datasource.username=${mysql.username}

@ -1,16 +0,0 @@
package com.gitee.sop.websiteserver.bean;
/**
* @author tanghc
*/
public class WebsiteConstants {
/**
* zookeeper存放接口路由信息的根目录
*/
public static final String SOP_SERVICE_ROUTE_PATH = "/com.gitee.sop.route";
/**
* 服务临时节点
*/
public static final String SOP_SERVICE_TEMP_PATH = "/com.gitee.sop.service.tmp";
}

@ -2,11 +2,8 @@ server.port=8083
spring.application.name=website-server
# ------- 需要改的配置 -------
# zookeeper地址
zookeeper.url=localhost:2181
# nacos地址
nacos.url=127.0.0.1:8848
# ------- 需要改的配置end -------
# nacos cloud配置

Loading…
Cancel
Save