nacos注册中心

1.x
tanghc 5 years ago
parent de85e5aef9
commit 6fc49f2699
  1. 55
      doc/docs/_sidebar.md
  2. 113
      doc/docs/files/10106_nacos注册中心.md
  3. 22
      sop-admin/sop-admin-server/pom.xml
  4. 21
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/ServiceApi.java
  5. 10
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/result/ServiceInstanceVO.java
  6. 12
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/config/RegistryConfig.java
  7. 14
      sop-admin/sop-admin-server/src/main/resources/application-dev.yml
  8. 3
      sop-common/pom.xml
  9. 3
      sop-common/readme.md
  10. 2
      sop-common/sop-gateway-common/readme.md
  11. 74
      sop-common/sop-registry-api/pom.xml
  12. 3
      sop-common/sop-registry-api/readme.md
  13. 2
      sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/bean/EurekaApplication.java
  14. 2
      sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/bean/EurekaApplications.java
  15. 2
      sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/bean/EurekaApps.java
  16. 2
      sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/bean/EurekaInstance.java
  17. 27
      sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/bean/EurekaUri.java
  18. 13
      sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/bean/ServiceInfo.java
  19. 14
      sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/bean/ServiceInstance.java
  20. 36
      sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/config/BaseRegistryConfig.java
  21. 8
      sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/service/RegistryService.java
  22. 58
      sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/service/impl/RegistryServiceEureka.java
  23. 106
      sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/service/impl/RegistryServiceNacos.java
  24. 18
      sop-example/sop-book/sop-book-web/pom.xml
  25. 2
      sop-example/sop-book/sop-book-web/src/main/java/com/gitee/sop/bookweb/controller/ApiResult.java
  26. 16
      sop-example/sop-book/sop-book-web/src/main/resources/application-dev.yml
  27. 16
      sop-example/sop-story/sop-story-web/pom.xml
  28. 2
      sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/AlipayController.java
  29. 17
      sop-example/sop-story/sop-story-web/src/main/resources/application-dev.yml
  30. 14
      sop-gateway/pom.xml
  31. 17
      sop-gateway/src/main/resources/application-dev.yml
  32. 64
      sop-test/src/test/java/com/gitee/sop/LoadBalanceTest.java
  33. 7
      sop-website/website-server/pom.xml
  34. 12
      sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/config/RegistryConfig.java
  35. 13
      sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/controller/SandboxController.java
  36. 89
      sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/manager/DocManagerImpl.java
  37. 12
      sop-website/website-server/src/main/resources/application-dev.yml

@ -1,29 +1,30 @@
* [首页](/?t=1561689549009) * [首页](/?t=1561970396914)
* 开发文档 * 开发文档
* [快速体验](files/10010_快速体验.md?t=1561689549011) * [快速体验](files/10010_快速体验.md?t=1561970396914)
* [项目接入到SOP](files/10011_项目接入到SOP.md?t=1561689549027) * [项目接入到SOP](files/10011_项目接入到SOP.md?t=1561970396931)
* [新增接口](files/10020_新增接口.md?t=1561689549027) * [新增接口](files/10020_新增接口.md?t=1561970396931)
* [业务参数校验](files/10030_业务参数校验.md?t=1561689549028) * [业务参数校验](files/10030_业务参数校验.md?t=1561970396931)
* [错误处理](files/10040_错误处理.md?t=1561689549028) * [错误处理](files/10040_错误处理.md?t=1561970396931)
* [编写文档](files/10041_编写文档.md?t=1561689549028) * [编写文档](files/10041_编写文档.md?t=1561970396931)
* [接口交互详解](files/10050_接口交互详解.md?t=1561689549028) * [接口交互详解](files/10050_接口交互详解.md?t=1561970396931)
* [easyopen支持](files/10070_easyopen支持.md?t=1561689549028) * [easyopen支持](files/10070_easyopen支持.md?t=1561970396932)
* [使用签名校验工具](files/10080_使用签名校验工具.md?t=1561689549028) * [使用签名校验工具](files/10080_使用签名校验工具.md?t=1561970396932)
* [ISV管理](files/10085_ISV管理.md?t=1561689549028) * [ISV管理](files/10085_ISV管理.md?t=1561970396932)
* [自定义路由](files/10086_自定义路由.md?t=1561689549028) * [自定义路由](files/10086_自定义路由.md?t=1561970396932)
* [路由授权](files/10090_路由授权.md?t=1561689549028) * [路由授权](files/10090_路由授权.md?t=1561970396932)
* [接口限流](files/10092_接口限流.md?t=1561689549029) * [接口限流](files/10092_接口限流.md?t=1561970396932)
* [监控日志](files/10093_监控日志.md?t=1561689549029) * [监控日志](files/10093_监控日志.md?t=1561970396932)
* [SDK开发](files/10095_SDK开发.md?t=1561689549029) * [SDK开发](files/10095_SDK开发.md?t=1561970396932)
* [使用SpringCloudGateway](files/10096_使用SpringCloudGateway.md?t=1561689549029) * [使用SpringCloudGateway](files/10096_使用SpringCloudGateway.md?t=1561970396932)
* [应用授权](files/10097_应用授权.md?t=1561689549029) * [应用授权](files/10097_应用授权.md?t=1561970396932)
* [更改数据节点名称](files/10099_更改数据节点名称.md?t=1561689549029) * [更改数据节点名称](files/10099_更改数据节点名称.md?t=1561970396932)
* [对接前端](files/10100_对接前端.md?t=1561689549029) * [对接前端](files/10100_对接前端.md?t=1561970396933)
* [自定义过滤器](files/10102_自定义过滤器.md?t=1561689549029) * [自定义过滤器](files/10102_自定义过滤器.md?t=1561970396933)
* [文件上传](files/10104_文件上传.md?t=1561689549029) * [文件上传](files/10104_文件上传.md?t=1561970396933)
* [nacos注册中心](files/10106_nacos注册中心.md?t=1561970396933)
* 原理分析 * 原理分析
* [原理分析之@ApiMapping](files/90010_原理分析之@ApiMapping.md?t=1561689549029) * [原理分析之@ApiMapping](files/90010_原理分析之@ApiMapping.md?t=1561970396933)
* [原理分析之路由存储](files/90011_原理分析之路由存储.md?t=1561689549030) * [原理分析之路由存储](files/90011_原理分析之路由存储.md?t=1561970396933)
* [原理分析之如何路由](files/90012_原理分析之如何路由.md?t=1561689549030) * [原理分析之如何路由](files/90012_原理分析之如何路由.md?t=1561970396933)
* [原理分析之文档归纳](files/90013_原理分析之文档归纳.md?t=1561689549030) * [原理分析之文档归纳](files/90013_原理分析之文档归纳.md?t=1561970396933)
* [常见问题](files/90100_常见问题.md?t=1561689549030) * [常见问题](files/90100_常见问题.md?t=1561970396933)

@ -0,0 +1,113 @@
# nacos注册中心
完整代码在`registry-nacos`分支
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修改`
如果要改成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)

@ -13,7 +13,7 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version> <version>2.1.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository --> <relativePath /> <!-- lookup parent from repository -->
</parent> </parent>
@ -27,12 +27,12 @@
</properties> </properties>
<dependencies> <dependencies>
<!-- 将前端页面打包成webjars,然后打开注释
<dependency> <dependency>
<groupId>com.gitee.sop</groupId> <groupId>com.gitee.sop</groupId>
<artifactId>sop-admin-front</artifactId> <artifactId>sop-registry-api</artifactId>
<version>1.0.0-SNAPSHOT</version> <version>1.11.0-SNAPSHOT</version>
</dependency>--> </dependency>
<!-- easyopen starter --> <!-- easyopen starter -->
<dependency> <dependency>
<groupId>net.oschina.durcframework</groupId> <groupId>net.oschina.durcframework</groupId>
@ -78,12 +78,6 @@
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
@ -109,6 +103,12 @@
<version>1.18.4</version> <version>1.18.4</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
<version>2.1.0.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies> </dependencies>

@ -10,22 +10,21 @@ import com.gitee.sop.adminserver.api.service.param.ServiceSearchParam;
import com.gitee.sop.adminserver.api.service.result.RouteServiceInfo; import com.gitee.sop.adminserver.api.service.result.RouteServiceInfo;
import com.gitee.sop.adminserver.api.service.result.ServiceInfoVo; import com.gitee.sop.adminserver.api.service.result.ServiceInfoVo;
import com.gitee.sop.adminserver.api.service.result.ServiceInstanceVO; import com.gitee.sop.adminserver.api.service.result.ServiceInstanceVO;
import com.gitee.sop.adminserver.bean.ServiceInfo;
import com.gitee.sop.adminserver.bean.ServiceInstance;
import com.gitee.sop.adminserver.bean.ServiceRouteInfo; import com.gitee.sop.adminserver.bean.ServiceRouteInfo;
import com.gitee.sop.adminserver.bean.ZookeeperContext; import com.gitee.sop.adminserver.bean.ZookeeperContext;
import com.gitee.sop.adminserver.common.BizException; import com.gitee.sop.adminserver.common.BizException;
import com.gitee.sop.adminserver.common.ZookeeperPathExistException; import com.gitee.sop.adminserver.common.ZookeeperPathExistException;
import com.gitee.sop.adminserver.common.ZookeeperPathNotExistException; import com.gitee.sop.adminserver.common.ZookeeperPathNotExistException;
import com.gitee.sop.adminserver.service.RegistrationService; import com.gitee.sop.registryapi.bean.ServiceInfo;
import com.gitee.sop.adminserver.service.impl.RegistrationServiceEureka; import com.gitee.sop.registryapi.bean.ServiceInstance;
import com.gitee.sop.registryapi.service.RegistryService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.curator.framework.recipes.cache.ChildData; import org.apache.curator.framework.recipes.cache.ChildData;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.Resource;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -42,8 +41,8 @@ import java.util.stream.Collectors;
@Slf4j @Slf4j
public class ServiceApi { public class ServiceApi {
@Resource(type = RegistrationServiceEureka.class) @Autowired
private RegistrationService registrationService; private RegistryService registryService;
@Api(name = "zookeeper.service.list") @Api(name = "zookeeper.service.list")
@ApiDocMethod(description = "zk中的服务列表", elementClass = RouteServiceInfo.class) @ApiDocMethod(description = "zk中的服务列表", elementClass = RouteServiceInfo.class)
@ -113,10 +112,10 @@ public class ServiceApi {
@Api(name = "service.instance.list") @Api(name = "service.instance.list")
@ApiDocMethod(description = "获取注册中心的服务列表", elementClass = ServiceInfoVo.class) @ApiDocMethod(description = "获取注册中心的服务列表", elementClass = ServiceInfoVo.class)
List<ServiceInstanceVO> listService(ServiceSearchParam param) { List<ServiceInstanceVO> listService(ServiceSearchParam param) {
List<ServiceInfo> serviceInfos; List<ServiceInfo> serviceInfos;
try { try {
serviceInfos = registrationService.listAllService(1, 99999/* 获取所有实例 */); serviceInfos = registryService.listAllService(1, 99999/* 获取所有实例 */);
} catch (Exception e) { } catch (Exception e) {
log.error("获取服务实例失败", e); log.error("获取服务实例失败", e);
return Collections.emptyList(); return Collections.emptyList();
@ -156,7 +155,7 @@ public class ServiceApi {
@ApiDocMethod(description = "服务下线") @ApiDocMethod(description = "服务下线")
void serviceOffline(ServiceInstance param) { void serviceOffline(ServiceInstance param) {
try { try {
registrationService.offlineInstance(param); registryService.offlineInstance(param);
} catch (Exception e) { } catch (Exception e) {
log.error("下线失败,param:{}", param, e); log.error("下线失败,param:{}", param, e);
throw new BizException("下线失败,请查看日志"); throw new BizException("下线失败,请查看日志");
@ -167,7 +166,7 @@ public class ServiceApi {
@ApiDocMethod(description = "服务上线") @ApiDocMethod(description = "服务上线")
void serviceOnline(ServiceInstance param) throws IOException { void serviceOnline(ServiceInstance param) throws IOException {
try { try {
registrationService.onlineInstance(param); registryService.onlineInstance(param);
} catch (Exception e) { } catch (Exception e) {
log.error("上线失败,param:{}", param, e); log.error("上线失败,param:{}", param, e);
throw new BizException("上线失败,请查看日志"); throw new BizException("上线失败,请查看日志");

@ -24,6 +24,12 @@ public class ServiceInstanceVO {
@ApiDocField(description = "ipPort") @ApiDocField(description = "ipPort")
private String ipPort; private String ipPort;
@ApiDocField(description = "ip")
private String ip;
@ApiDocField(description = "port")
private int port;
@ApiDocField(description = "status,服务状态,UP:已上线,OUT_OF_SERVICE:已下线") @ApiDocField(description = "status,服务状态,UP:已上线,OUT_OF_SERVICE:已下线")
private String status; private String status;
@ -41,4 +47,8 @@ public class ServiceInstanceVO {
return new Date(Long.valueOf(lastUpdatedTimestamp)); return new Date(Long.valueOf(lastUpdatedTimestamp));
} }
public String getIpPort() {
return ip != null && port > 0 ? ip + ":" + port : "";
}
} }

@ -0,0 +1,12 @@
package com.gitee.sop.adminserver.config;
import com.gitee.sop.registryapi.config.BaseRegistryConfig;
import org.springframework.context.annotation.Configuration;
/**
* @author tanghc
*/
@Configuration
public class RegistryConfig extends BaseRegistryConfig {
}

@ -12,6 +12,8 @@ spring:
name: sop-admin name: sop-admin
cloud: cloud:
# zookeeper地址,根据实际情况修改
zookeeper: zookeeper:
connect-string: localhost:2181 connect-string: localhost:2181
baseSleepTimeMs: 3000 baseSleepTimeMs: 3000
@ -31,12 +33,12 @@ easyopen:
ignore-validate: true ignore-validate: true
# 注册中心地址,根据实际情况改,这里只是参数,并不会去注册 # 注册中心地址,根据实际情况改,这里只是参数,并不会去注册
eureka: registry:
port: 1111 eureka-server-addr: http://localhost:1111/eureka/
host: localhost nacos-server-addr: 127.0.0.1:8848
client: # 使用哪个配置中心,使用eureka,填eureka;使用nacos填nacos
serviceUrl: name: nacos
defaultZone: http://${eureka.host}:${eureka.port}/eureka/
# 根据实际情况改 # 根据实际情况改
logging: logging:

@ -37,7 +37,8 @@
<modules> <modules>
<module>sop-gateway-common</module> <module>sop-gateway-common</module>
<module>sop-service-common</module> <module>sop-service-common</module>
</modules> <module>sop-registry-api</module>
</modules>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>

@ -1,8 +1,11 @@
# sop-common # sop-common
- sop-gateway-common:提供给网关使用 - sop-gateway-common:提供给网关使用
- sop-registry-api:注册中心API
- sop-service-common:提供给微服务端使用,需要打成jar - sop-service-common:提供给微服务端使用,需要打成jar
正式开发请将这些模块上传的maven私服
- 打包成jar:`mvn clean package` - 打包成jar:`mvn clean package`
- 上传到本机仓库:`mvn clean install` - 上传到本机仓库:`mvn clean install`
- 上传到maven私服:`mvn clean deploy` - 上传到maven私服:`mvn clean deploy`

@ -1,3 +1,3 @@
# sop-gateway-common # sop-gateway-common
zuul通用组件,主要封装网关的一些功能。 网关通用组件,主要封装网关的一些功能。

@ -0,0 +1,74 @@
<?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.gitee.sop</groupId>
<artifactId>sop-registry-api</artifactId>
<version>1.11.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<okhttp.version>3.11.0</okhttp.version>
</properties>
<dependencies>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp.version}</version>
</dependency>
<!-- nacos sdk -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.1.4.RELEASE</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,3 @@
# sop-registry-api
统一各注册中心接口

@ -1,4 +1,4 @@
package com.gitee.sop.adminserver.bean; package com.gitee.sop.registryapi.bean;
import lombok.Data; import lombok.Data;

@ -1,4 +1,4 @@
package com.gitee.sop.adminserver.bean; package com.gitee.sop.registryapi.bean;
import lombok.Data; import lombok.Data;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;

@ -1,11 +1,9 @@
package com.gitee.sop.adminserver.bean; package com.gitee.sop.registryapi.bean;
import okhttp3.MediaType; import okhttp3.MediaType;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.RequestBody; import okhttp3.RequestBody;
import okhttp3.internal.http.HttpMethod; import okhttp3.internal.http.HttpMethod;
import org.apache.commons.lang.ArrayUtils;
import org.springframework.web.bind.annotation.RequestMethod;
/** /**
* https://github.com/Netflix/eureka/wiki/Eureka-REST-operations * https://github.com/Netflix/eureka/wiki/Eureka-REST-operations
@ -17,22 +15,22 @@ public enum EurekaUri {
/** /**
* 查询所有实例 Query for all instances * 查询所有实例 Query for all instances
*/ */
QUERY_APPS(RequestMethod.GET, "/apps"), QUERY_APPS("GET", "/apps"),
/** /**
* 下线 Take instance out of service * 下线 Take instance out of service
*/ */
OFFLINE_SERVICE(RequestMethod.PUT, "/apps/%s/%s/status?value=OUT_OF_SERVICE"), OFFLINE_SERVICE("PUT", "/apps/%s/%s/status?value=OUT_OF_SERVICE"),
/** /**
* 上线 Move instance back into service (remove override) * 上线 Move instance back into service (remove override)
*/ */
ONLINE_SERVICE(RequestMethod.DELETE, "/apps/%s/%s/status?value=UP"), ONLINE_SERVICE("DELETE", "/apps/%s/%s/status?value=UP"),
; ;
public static final String URL_PREFIX = "/"; public static final String URL_PREFIX = "/";
String uri; String uri;
RequestMethod requestMethod; String requestMethod;
EurekaUri(RequestMethod httpMethod, String uri) { EurekaUri(String httpMethod, String uri) {
if (!uri.startsWith(URL_PREFIX)) { if (!uri.startsWith(URL_PREFIX)) {
uri = "/" + uri; uri = "/" + uri;
} }
@ -41,10 +39,13 @@ public enum EurekaUri {
} }
public String getUri(String... args) { public String getUri(String... args) {
if (ArrayUtils.isEmpty(args)) { if (args == null || args.length == 0) {
return uri; return uri;
} }
Object[] param = ArrayUtils.clone(args); Object[] param = new Object[args.length];
for (int i = 0; i < args.length; i++) {
param[i] = args[i];
}
return String.format(uri, param); return String.format(uri, param);
} }
@ -59,12 +60,12 @@ public enum EurekaUri {
} }
public Request.Builder getBuilder() { public Request.Builder getBuilder() {
String method = requestMethod.name(); String method = requestMethod;
RequestBody requestBody = null; RequestBody requestBody = null;
if (HttpMethod.requiresRequestBody(method)) { if (HttpMethod.requiresRequestBody(method)) {
MediaType contentType = MediaType.parse(org.springframework.http.MediaType.APPLICATION_JSON_VALUE); MediaType contentType = MediaType.parse("application/json");
requestBody = RequestBody.create(contentType, "{}"); requestBody = RequestBody.create(contentType, "{}");
} }
return new Request.Builder().method(requestMethod.name(), requestBody); return new Request.Builder().method(requestMethod, requestBody);
} }
} }

@ -1,6 +1,7 @@
package com.gitee.sop.adminserver.bean; package com.gitee.sop.registryapi.bean;
import lombok.Data; import lombok.Getter;
import lombok.Setter;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -8,10 +9,16 @@ import java.util.List;
/** /**
* @author tanghc * @author tanghc
*/ */
@Data @Getter
@Setter
public class ServiceInfo { public class ServiceInfo {
/** 服务名称 */ /** 服务名称 */
private String serviceId; private String serviceId;
/** 实例列表 */ /** 实例列表 */
private List<ServiceInstance> instances = Collections.emptyList(); private List<ServiceInstance> instances = Collections.emptyList();
@Override
public String toString() {
return "服务名称: " + serviceId + ", 实例数:" + instances.size();
}
} }

@ -1,4 +1,4 @@
package com.gitee.sop.adminserver.bean; package com.gitee.sop.registryapi.bean;
import lombok.Data; import lombok.Data;
@ -15,12 +15,18 @@ public class ServiceInstance {
private String serviceId; private String serviceId;
/** /**
* IP 端口 * ip
*/ */
private String ipPort; private String ip;
/** /**
* 状态1上线2下线 * port
*/
private int port;
/**
* 服务状态UP已上线OUT_OF_SERVICE已下线
*/ */
private String status; private String status;
} }

@ -0,0 +1,36 @@
package com.gitee.sop.registryapi.config;
import com.gitee.sop.registryapi.service.RegistryService;
import com.gitee.sop.registryapi.service.impl.RegistryServiceEureka;
import com.gitee.sop.registryapi.service.impl.RegistryServiceNacos;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
/**
* @author tanghc
*/
public class BaseRegistryConfig {
/**
* 当配置了registry.name=eureka生效
*
* @return
*/
@Bean
@ConditionalOnProperty(prefix = "registry", name = "name", havingValue = "eureka")
RegistryService registryServiceEureka() {
return new RegistryServiceEureka();
}
/**
* 当配置了registry.name=nacos生效
*
* @return
*/
@Bean
@ConditionalOnProperty(prefix = "registry", name = "name", havingValue = "nacos")
RegistryService registryServiceNacos() {
return new RegistryServiceNacos();
}
}

@ -1,14 +1,14 @@
package com.gitee.sop.adminserver.service; package com.gitee.sop.registryapi.service;
import com.gitee.sop.adminserver.bean.ServiceInfo; import com.gitee.sop.registryapi.bean.ServiceInfo;
import com.gitee.sop.adminserver.bean.ServiceInstance; import com.gitee.sop.registryapi.bean.ServiceInstance;
import java.util.List; import java.util.List;
/** /**
* @author tanghc * @author tanghc
*/ */
public interface RegistrationService { public interface RegistryService {
/** /**
* 获取所有服务列表 * 获取所有服务列表
* *

@ -1,45 +1,43 @@
package com.gitee.sop.adminserver.service.impl; package com.gitee.sop.registryapi.service.impl;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.gitee.sop.adminserver.bean.EurekaApplication; import com.gitee.sop.registryapi.bean.EurekaApplication;
import com.gitee.sop.adminserver.bean.EurekaApps; import com.gitee.sop.registryapi.bean.EurekaApps;
import com.gitee.sop.adminserver.bean.EurekaInstance; import com.gitee.sop.registryapi.bean.EurekaInstance;
import com.gitee.sop.adminserver.bean.EurekaUri; import com.gitee.sop.registryapi.bean.EurekaUri;
import com.gitee.sop.adminserver.bean.ServiceInfo; import com.gitee.sop.registryapi.bean.ServiceInfo;
import com.gitee.sop.adminserver.bean.ServiceInstance; import com.gitee.sop.registryapi.bean.ServiceInstance;
import com.gitee.sop.adminserver.common.BizException; import com.gitee.sop.registryapi.service.RegistryService;
import com.gitee.sop.adminserver.service.RegistrationService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.Response; import okhttp3.Response;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
* eureka接口实现
* @author tanghc * @author tanghc
*/ */
@Slf4j @Slf4j
@Service public class RegistryServiceEureka implements RegistryService {
public class RegistrationServiceEureka implements RegistrationService {
OkHttpClient client = new OkHttpClient(); OkHttpClient client = new OkHttpClient();
@Autowired @Value("${registry.eureka-server-addr:}")
private Environment environment;
private String eurekaUrl; private String eurekaUrl;
@Override @Override
public List<ServiceInfo> listAllService(int pageNo, int pageSize) throws Exception { public List<ServiceInfo> listAllService(int pageNo, int pageSize) throws Exception {
if (StringUtils.isBlank(eurekaUrl)) {
return Collections.emptyList();
}
String json = this.requestEurekaServer(EurekaUri.QUERY_APPS); String json = this.requestEurekaServer(EurekaUri.QUERY_APPS);
EurekaApps eurekaApps = JSON.parseObject(json, EurekaApps.class); EurekaApps eurekaApps = JSON.parseObject(json, EurekaApps.class);
@ -49,13 +47,14 @@ public class RegistrationServiceEureka implements RegistrationService {
ServiceInfo serviceInfo = new ServiceInfo(); ServiceInfo serviceInfo = new ServiceInfo();
serviceInfo.setServiceId(eurekaApplication.getName()); serviceInfo.setServiceId(eurekaApplication.getName());
List<EurekaInstance> instanceList = eurekaApplication.getInstance(); List<EurekaInstance> instanceList = eurekaApplication.getInstance();
if (CollectionUtils.isNotEmpty(instanceList)) { if (!CollectionUtils.isEmpty(instanceList)) {
serviceInfo.setInstances(new ArrayList<>(instanceList.size())); serviceInfo.setInstances(new ArrayList<>(instanceList.size()));
for (EurekaInstance eurekaInstance : instanceList) { for (EurekaInstance eurekaInstance : instanceList) {
ServiceInstance serviceInstance = new ServiceInstance(); ServiceInstance serviceInstance = new ServiceInstance();
serviceInstance.setInstanceId(eurekaInstance.getInstanceId()); serviceInstance.setInstanceId(eurekaInstance.getInstanceId());
serviceInstance.setServiceId(serviceInfo.getServiceId()); serviceInstance.setServiceId(serviceInfo.getServiceId());
serviceInstance.setIpPort(eurekaInstance.getIpAddr() + ":" + eurekaInstance.fetchPort()); serviceInstance.setIp(eurekaInstance.getIpAddr());
serviceInstance.setPort(Integer.valueOf(eurekaInstance.fetchPort()));
serviceInstance.setStatus(eurekaInstance.getStatus()); serviceInstance.setStatus(eurekaInstance.getStatus());
serviceInfo.getInstances().add(serviceInstance); serviceInfo.getInstances().add(serviceInstance);
} }
@ -84,21 +83,8 @@ public class RegistrationServiceEureka implements RegistrationService {
return response.body().string(); return response.body().string();
} else { } else {
log.error("操作失败,url:{}, msg:{}, code:{}", eurekaUri.getUri(args), response.message(), response.code()); log.error("操作失败,url:{}, msg:{}, code:{}", eurekaUri.getUri(args), response.message(), response.code());
throw new BizException("操作失败", String.valueOf(response.code())); throw new RuntimeException("操作失败");
} }
} }
@PostConstruct
protected void after() {
String eurekaUrls = environment.getProperty("eureka.client.serviceUrl.defaultZone");
if (StringUtils.isBlank(eurekaUrls)) {
throw new BizException("未指定eureka.client.serviceUrl.defaultZone参数");
}
// 取第一个
String url = eurekaUrls.split("\\,")[0];
if (url.endsWith("/")) {
url = eurekaUrls.substring(0, eurekaUrls.length() - 1);
}
this.eurekaUrl = url;
}
} }

@ -0,0 +1,106 @@
package com.gitee.sop.registryapi.service.impl;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;
import com.gitee.sop.registryapi.bean.ServiceInfo;
import com.gitee.sop.registryapi.bean.ServiceInstance;
import com.gitee.sop.registryapi.service.RegistryService;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* nacos接口实现
* @author tanghc
*/
public class RegistryServiceNacos implements RegistryService {
OkHttpClient client = new OkHttpClient();
@Value("${registry.nacos-server-addr:}")
private String nacosAddr;
private NamingService namingService;
@PostConstruct
public void after() throws NacosException {
if (StringUtils.isNotBlank(nacosAddr)) {
namingService = NamingFactory.createNamingService(nacosAddr);
}
}
@Override
public List<ServiceInfo> listAllService(int pageNo, int pageSize) throws Exception {
ListView<String> servicesOfServer = namingService.getServicesOfServer(pageNo, pageSize);
List<String> serverList = servicesOfServer.getData();
List<ServiceInfo> serviceInfoList = new ArrayList<>();
for (String serviceName : serverList) {
ServiceInfo serviceInfo = new ServiceInfo();
serviceInfo.setServiceId(serviceName);
List<Instance> instanceList = namingService.getAllInstances(serviceName);
if (!CollectionUtils.isEmpty(instanceList)) {
serviceInfo.setInstances(new ArrayList<>(instanceList.size()));
for (Instance instance : instanceList) {
ServiceInstance serviceInstance = new ServiceInstance();
serviceInstance.setInstanceId(instance.getInstanceId());
serviceInstance.setServiceId(serviceInfo.getServiceId());
serviceInstance.setIp(instance.getIp());
serviceInstance.setPort(instance.getPort());
boolean isOnline = instance.getWeight() > 0;
String status = isOnline ? "UP" : "OUT_OF_SERVICE";
serviceInstance.setStatus(status);
serviceInfo.getInstances().add(serviceInstance);
}
}
serviceInfoList.add(serviceInfo);
}
return serviceInfoList;
}
@Override
public void onlineInstance(ServiceInstance serviceInstance) throws Exception {
Map<String, String> params = new HashMap<>();
// 上线,把权重设置成1
params.put("weight", "1");
this.updateInstance(serviceInstance, params);
}
@Override
public void offlineInstance(ServiceInstance serviceInstance) throws Exception {
Map<String, String> params = new HashMap<>();
// 下线,把权重设置成0
params.put("weight", "0");
this.updateInstance(serviceInstance, params);
}
private Response updateInstance(ServiceInstance serviceInstance, Map<String, String> params) throws IOException {
FormBody.Builder builder = new FormBody.Builder();
for (Map.Entry<String, String> entry : params.entrySet()) {
builder.add(entry.getKey(), String.valueOf(entry.getValue()));
}
builder.add("serviceName", serviceInstance.getServiceId())
.add("ip", serviceInstance.getIp())
.add("port", String.valueOf(serviceInstance.getPort()));
FormBody formBody = builder.build();
final Request request = new Request.Builder()
.url("http://" + nacosAddr + "/nacos/v1/ns/instance")
.put(formBody)
.build();
return client.newCall(request).execute();
}
}

@ -36,10 +36,28 @@
<artifactId>sop-story-api</artifactId> <artifactId>sop-story-api</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
</dependency> </dependency>
<!-- 注册中心【只能用一个,不用的注释掉】 -->
<!-- 使用eureka注册中心
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency> </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 -->
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId> <artifactId>spring-cloud-starter-openfeign</artifactId>

@ -1,6 +1,5 @@
package com.gitee.sop.bookweb.controller; package com.gitee.sop.bookweb.controller;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data; import lombok.Data;
/** /**
@ -48,7 +47,6 @@ import lombok.Data;
* *
* @author tanghc * @author tanghc
*/ */
@XStreamAlias("response")
@Data @Data
public class ApiResult { public class ApiResult {

@ -10,12 +10,16 @@ spring:
# zookeeper配置 # zookeeper配置
connect-string: localhost:2181 connect-string: localhost:2181
eureka: # nacos注册中心,和eureka只能用一个
port: 1111 nacos:
host: localhost discovery:
client: server-addr: 127.0.0.1:8848
serviceUrl:
defaultZone: http://${eureka.host}:${eureka.port}/eureka/ # eureka注册中心,如果使用nacos注册中心,这里要注释掉
#eureka:
# client:
# serviceUrl:
# defaultZone: http://localhost:1111/eureka/
# dubbo consumer # dubbo consumer
demo: demo:

@ -31,10 +31,26 @@
<artifactId>sop-story-api</artifactId> <artifactId>sop-story-api</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
</dependency> </dependency>
<!-- 注册中心【只能用一个,不用的注释掉】 -->
<!-- 使用eureka注册中心
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency> </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 -->
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId> <artifactId>spring-cloud-starter-openfeign</artifactId>

@ -87,7 +87,7 @@ public class AlipayController {
public Story getStory() { public Story getStory() {
Story story = new Story(); Story story = new Story();
story.setId(1); story.setId(1);
story.setName("海底小纵队(alipay.story.get)"); story.setName("海底小纵队(alipay.story.get),2222");
return story; return story;
} }

@ -10,13 +10,16 @@ spring:
zookeeper: zookeeper:
connect-string: localhost:2181 connect-string: localhost:2181
# 注册中心 # nacos注册中心,和eureka只能用一个
eureka: nacos:
port: 1111 discovery:
host: localhost server-addr: 127.0.0.1:8848
client:
serviceUrl: # eureka注册中心,如果使用nacos注册中心,这里要注释掉
defaultZone: http://${eureka.host}:${eureka.port}/eureka/ #eureka:
# client:
# serviceUrl:
# defaultZone: http://localhost:1111/eureka/
# dubbo provider # dubbo provider
dubbo: dubbo:

@ -65,10 +65,24 @@
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
<!-- 注册中心【只能用一个,不用的注释掉】 -->
<!-- 使用eureka注册中心
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency> </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 -->
<!-- test --> <!-- test -->
<dependency> <dependency>

@ -19,13 +19,6 @@ ribbon:
# 请谨慎设置,因为post请求大多都是写入请求,如果要支持重试,确保服务的幂等性 # 请谨慎设置,因为post请求大多都是写入请求,如果要支持重试,确保服务的幂等性
OkToRetryOnAllOperations: false OkToRetryOnAllOperations: false
# 注册中心,根据实际情况修改
eureka:
serverAddr: localhost:1111
client:
serviceUrl:
defaultZone: http://${eureka.serverAddr}/eureka/
spring: spring:
application: application:
name: api-gateway name: api-gateway
@ -41,6 +34,16 @@ spring:
lower-case-service-id: true lower-case-service-id: true
enabled: true enabled: true
# nacos注册中心,和eureka只能用一个
nacos:
discovery:
server-addr: 127.0.0.1:8848
# eureka注册中心,如果使用nacos注册中心,这里要注释掉
#eureka:
# client:
# serviceUrl:
# defaultZone: http://localhost:1111/eureka/
# 数据源,根据实际情况修改 # 数据源,根据实际情况修改
datasource: datasource:

@ -0,0 +1,64 @@
package com.gitee.sop;
import com.alibaba.fastjson.JSON;
import com.gitee.sop.alipay.AlipayApiException;
import com.gitee.sop.alipay.AlipaySignature;
import org.junit.Test;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class LoadBalanceTest extends TestBase {
String url = "http://localhost:8081/api"; // zuul
String appId = "2019032617262200001";
// 支付宝私钥
String privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXJv1pQFqWNA/++OYEV7WYXwexZK/J8LY1OWlP9X0T6wHFOvxNKRvMkJ5544SbgsJpVcvRDPrcxmhPbi/sAhdO4x2PiPKIz9Yni2OtYCCeaiE056B+e1O2jXoLeXbfi9fPivJZkxH/tb4xfLkH3bA8ZAQnQsoXA0SguykMRZntF0TndUfvDrLqwhlR8r5iRdZLB6F8o8qXH6UPDfNEnf/K8wX5T4EB1b8x8QJ7Ua4GcIUqeUxGHdQpzNbJdaQvoi06lgccmL+PHzminkFYON7alj1CjDN833j7QMHdPtS9l7B67fOU/p2LAAkPMtoVBfxQt9aFj7B8rEhGCz02iJIBAgMBAAECggEARqOuIpY0v6WtJBfmR3lGIOOokLrhfJrGTLF8CiZMQha+SRJ7/wOLPlsH9SbjPlopyViTXCuYwbzn2tdABigkBHYXxpDV6CJZjzmRZ+FY3S/0POlTFElGojYUJ3CooWiVfyUMhdg5vSuOq0oCny53woFrf32zPHYGiKdvU5Djku1onbDU0Lw8w+5tguuEZ76kZ/lUcccGy5978FFmYpzY/65RHCpvLiLqYyWTtaNT1aQ/9pw4jX9HO9NfdJ9gYFK8r/2f36ZE4hxluAfeOXQfRC/WhPmiw/ReUhxPznG/WgKaa/OaRtAx3inbQ+JuCND7uuKeRe4osP2jLPHPP6AUwQKBgQDUNu3BkLoKaimjGOjCTAwtp71g1oo+k5/uEInAo7lyEwpV0EuUMwLA/HCqUgR4K9pyYV+Oyb8d6f0+Hz0BMD92I2pqlXrD7xV2WzDvyXM3s63NvorRooKcyfd9i6ccMjAyTR2qfLkxv0hlbBbsPHz4BbU63xhTJp3Ghi0/ey/1HQKBgQC2VsgqC6ykfSidZUNLmQZe3J0p/Qf9VLkfrQ+xaHapOs6AzDU2H2osuysqXTLJHsGfrwVaTs00ER2z8ljTJPBUtNtOLrwNRlvgdnzyVAKHfOgDBGwJgiwpeE9voB1oAV/mXqSaUWNnuwlOIhvQEBwekqNyWvhLqC7nCAIhj3yvNQKBgQCqYbeec56LAhWP903Zwcj9VvG7sESqXUhIkUqoOkuIBTWFFIm54QLTA1tJxDQGb98heoCIWf5x/A3xNI98RsqNBX5JON6qNWjb7/dobitti3t99v/ptDp9u8JTMC7penoryLKK0Ty3bkan95Kn9SC42YxaSghzqkt+uvfVQgiNGQKBgGxU6P2aDAt6VNwWosHSe+d2WWXt8IZBhO9d6dn0f7ORvcjmCqNKTNGgrkewMZEuVcliueJquR47IROdY8qmwqcBAN7Vg2K7r7CPlTKAWTRYMJxCT1Hi5gwJb+CZF3+IeYqsJk2NF2s0w5WJTE70k1BSvQsfIzAIDz2yE1oPHvwVAoGAA6e+xQkVH4fMEph55RJIZ5goI4Y76BSvt2N5OKZKd4HtaV+eIhM3SDsVYRLIm9ZquJHMiZQGyUGnsvrKL6AAVNK7eQZCRDk9KQz+0GKOGqku0nOZjUbAu6A2/vtXAaAuFSFx1rUQVVjFulLexkXR3KcztL1Qu2k5pB6Si0K/uwQ=";
// 测试稳定性
@Test
public void testLoadBalance() throws Exception {
int i = 0;
while (i++ < 50) {
doTest();
Thread.sleep(3000);
}
}
private void doTest() throws AlipayApiException {
// 公共请求参数
Map<String, String> params = new HashMap<String, String>();
params.put("app_id", appId);
params.put("method", "alipay.story.get");
params.put("format", "json");
params.put("charset", "utf-8");
params.put("sign_type", "RSA2");
params.put("timestamp", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
params.put("version", "1.0");
// 业务参数
Map<String, String> bizContent = new HashMap<>();
bizContent.put("id", "1");
bizContent.put("name", "葫芦娃");
params.put("biz_content", JSON.toJSONString(bizContent));
// System.out.println("----------- 请求信息 -----------");
// System.out.println("请求参数:" + buildParamQuery(params));
// System.out.println("商户秘钥:" + privateKey);
String content = AlipaySignature.getSignContent(params);
// System.out.println("待签名内容:" + content);
String sign = AlipaySignature.rsa256Sign(content, privateKey, "utf-8");
// System.out.println("签名(sign):" + sign);
params.put("sign", sign);
// System.out.println("----------- 返回结果 -----------");
String responseData = get(url, params);// 发送请求
System.out.println(responseData);
}
}

@ -21,6 +21,13 @@
</properties> </properties>
<dependencies> <dependencies>
<dependency>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-registry-api</artifactId>
<version>1.11.0-SNAPSHOT</version>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>

@ -0,0 +1,12 @@
package com.gitee.sop.websiteserver.config;
import com.gitee.sop.registryapi.config.BaseRegistryConfig;
import org.springframework.context.annotation.Configuration;
/**
* @author tanghc
*/
@Configuration
public class RegistryConfig extends BaseRegistryConfig {
}

@ -3,6 +3,7 @@ package com.gitee.sop.websiteserver.controller;
import com.gitee.sop.websiteserver.sign.AlipayApiException; import com.gitee.sop.websiteserver.sign.AlipayApiException;
import com.gitee.sop.websiteserver.sign.AlipaySignature; import com.gitee.sop.websiteserver.sign.AlipaySignature;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.http.NameValuePair; import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.entity.UrlEncodedFormEntity;
@ -30,6 +31,7 @@ import java.util.stream.Collectors;
* 沙箱环境代理类 * 沙箱环境代理类
* @author tanghc * @author tanghc
*/ */
@Slf4j
@RestController @RestController
@RequestMapping("sandbox") @RequestMapping("sandbox")
public class SandboxController { public class SandboxController {
@ -45,8 +47,8 @@ public class SandboxController {
, @RequestParam String version , @RequestParam String version
, @RequestParam String bizContent) throws AlipayApiException { , @RequestParam String bizContent) throws AlipayApiException {
Assert.isTrue(StringUtils.isNotBlank(appId), "appId不能为空"); Assert.isTrue(StringUtils.isNotBlank(appId), "AppId不能为空");
Assert.isTrue(StringUtils.isNotBlank(privateKey), "privateKey不能为空"); Assert.isTrue(StringUtils.isNotBlank(privateKey), "PrivateKey不能为空");
Assert.isTrue(StringUtils.isNotBlank(method), "method不能为空"); Assert.isTrue(StringUtils.isNotBlank(method), "method不能为空");
// 公共请求参数 // 公共请求参数
@ -69,7 +71,12 @@ public class SandboxController {
String content = AlipaySignature.getSignContent(params); String content = AlipaySignature.getSignContent(params);
result.beforeSign = content; result.beforeSign = content;
String sign = AlipaySignature.rsa256Sign(content, privateKey, "utf-8"); String sign = null;
try {
sign = AlipaySignature.rsa256Sign(content, privateKey, "utf-8");
} catch (AlipayApiException e) {
throw new RuntimeException("构建签名失败");
}
result.sign = sign; result.sign = sign;
params.put("sign", sign); params.put("sign", sign);

@ -3,19 +3,13 @@ package com.gitee.sop.websiteserver.manager;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature; import com.alibaba.fastjson.parser.Feature;
import com.gitee.sop.registryapi.bean.ServiceInfo;
import com.gitee.sop.registryapi.bean.ServiceInstance;
import com.gitee.sop.registryapi.service.RegistryService;
import com.gitee.sop.websiteserver.bean.DocInfo; import com.gitee.sop.websiteserver.bean.DocInfo;
import com.gitee.sop.websiteserver.bean.DocItem; import com.gitee.sop.websiteserver.bean.DocItem;
import com.gitee.sop.websiteserver.bean.EurekaApplication;
import com.gitee.sop.websiteserver.bean.EurekaApps;
import com.gitee.sop.websiteserver.bean.EurekaInstance;
import com.gitee.sop.websiteserver.bean.EurekaUri;
import com.gitee.sop.websiteserver.bean.ZookeeperContext; import com.gitee.sop.websiteserver.bean.ZookeeperContext;
import com.gitee.sop.websiteserver.vo.ServiceInfoVO;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.lang.StringUtils;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent; import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
@ -26,8 +20,6 @@ import org.springframework.util.DigestUtils;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -53,8 +45,6 @@ public class DocManagerImpl implements DocManager {
Map<String, DocItem> docItemMap = new HashMap<>(); Map<String, DocItem> docItemMap = new HashMap<>();
OkHttpClient client = new OkHttpClient();
RestTemplate restTemplate = new RestTemplate(); RestTemplate restTemplate = new RestTemplate();
DocParser swaggerDocParser = new SwaggerDocParser(); DocParser swaggerDocParser = new SwaggerDocParser();
@ -70,33 +60,35 @@ public class DocManagerImpl implements DocManager {
@Autowired @Autowired
private Environment environment; private Environment environment;
private String eurekaUrl; @Autowired
private RegistryService registryService;
private volatile boolean listenInited; private volatile boolean listenInited;
@Override @Override
public void load() { public void load() {
try { try {
// {"STORY-SERVICE":[{"ipAddr":"10.1.30.54","name":"STORY-SERVICE","serverPort":"2222"}],"API-GATEWAY":[{"ipAddr":"10.1.30.54","name":"API-GATEWAY","serverPort":"8081"}]} List<ServiceInfo> serviceInfoList = registryService.listAllService(1, 9999);
Map<String, List<ServiceInfoVO>> listMap = this.getAllServiceList(); log.info("服务列表:{}", serviceInfoList);
log.info("服务列表:{}", JSON.toJSONString(listMap.keySet()));
listMap.entrySet() serviceInfoList
.stream() .stream()
// 网关没有文档提供,需要排除 // 网关没有文档提供,需要排除
.filter(entry -> !"API-GATEWAY".equalsIgnoreCase(entry.getKey())) .filter(serviceInfo -> !"API-GATEWAY".equalsIgnoreCase(serviceInfo.getServiceId()))
.forEach(entry -> { .filter(serviceInfo -> !serviceInfo.getInstances().isEmpty())
ServiceInfoVO serviceInfoVo = entry.getValue().get(0); .map(serviceInfo -> serviceInfo.getInstances().get(0))
loadDocInfo(serviceInfoVo); .collect(Collectors.toList())
}); .forEach(this::loadDocInfo);
} catch (Exception e) { } catch (Exception e) {
log.error("加载失败", e); log.error("加载失败", e);
} }
} }
protected void loadDocInfo(ServiceInfoVO serviceInfoVo) { protected void loadDocInfo(ServiceInstance serviceInstance) {
String query = this.buildQuery(); String query = this.buildQuery();
String url = "http://" + serviceInfoVo.getIpAddr() + ":" + serviceInfoVo.getServerPort() + "/v2/api-docs" + query; String url = "http://" + serviceInstance.getIpPort() + "/v2/api-docs" + query;
try { try {
log.info("读取swagger文档,url:{}", url);
ResponseEntity<String> entity = restTemplate.getForEntity(url, String.class); ResponseEntity<String> entity = restTemplate.getForEntity(url, String.class);
if (entity.getStatusCode() != HttpStatus.OK) { if (entity.getStatusCode() != HttpStatus.OK) {
throw new IllegalAccessException("无权访问"); throw new IllegalAccessException("无权访问");
@ -144,55 +136,8 @@ public class DocManagerImpl implements DocManager {
return docDefinitionMap.values(); return docDefinitionMap.values();
} }
protected Map<String, List<ServiceInfoVO>> getAllServiceList() throws IOException {
String json = this.requestEurekaServer(EurekaUri.QUERY_APPS);
EurekaApps eurekaApps = JSON.parseObject(json, EurekaApps.class);
List<ServiceInfoVO> serviceInfoVoList = new ArrayList<>();
List<EurekaApplication> applicationList = eurekaApps.getApplications().getApplication();
applicationList.stream()
.forEach(eurekaApplication -> {
List<EurekaInstance> instanceList = eurekaApplication.getInstance();
for (EurekaInstance instance : instanceList) {
if ("UP".equals(instance.getStatus())) {
ServiceInfoVO vo = new ServiceInfoVO();
vo.setName(eurekaApplication.getName());
vo.setIpAddr(instance.getIpAddr());
vo.setServerPort(instance.fetchPort());
serviceInfoVoList.add(vo);
}
}
});
Map<String, List<ServiceInfoVO>> listMap = serviceInfoVoList.stream()
.collect(Collectors.groupingBy(ServiceInfoVO::getName));
return listMap;
}
protected String requestEurekaServer(EurekaUri eurekaUri, String... args) throws IOException {
Request request = eurekaUri.getRequest(this.eurekaUrl, args);
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
return response.body().string();
} else {
log.error("操作失败,url:{}, msg:{}, code:{}", eurekaUri.getUri(args), response.message(), response.code());
throw new RuntimeException("操作失败");
}
}
@PostConstruct @PostConstruct
protected void after() throws Exception { protected void after() throws Exception {
String eurekaUrls = environment.getProperty("eureka.client.serviceUrl.defaultZone");
if (StringUtils.isBlank(eurekaUrls)) {
throw new IllegalArgumentException("未指定eureka.client.serviceUrl.defaultZone参数");
}
String url = eurekaUrls.split("\\,")[0];
if (url.endsWith("/")) {
url = eurekaUrls.substring(0, eurekaUrls.length() - 1);
}
this.eurekaUrl = url;
this.listenServiceId(); this.listenServiceId();
} }

@ -1,12 +1,12 @@
server: server:
port: 8083 port: 8083
# 注册中心 # 注册中心地址,根据实际情况改,这里只是参数,并不会去注册
eureka: registry:
serverAddr: localhost:1111 # 使用哪个配置中心,使用eureka,填eureka;使用nacos填nacos
client: name: nacos
serviceUrl: eureka-server-addr: http://localhost:1111/eureka/
defaultZone: http://${eureka.serverAddr}/eureka/ nacos-server-addr: 127.0.0.1:8848
spring: spring:
application: application:

Loading…
Cancel
Save