对接easyopen

1.x
tanghc 6 years ago
parent 3bfc5f7cc8
commit 99d90d60cc
  1. 4
      README.md
  2. 144
      sop-gateway-common/pom.xml
  3. 5
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java
  4. 5
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/BaseRouteDefinition.java
  5. 4
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/SopConstants.java
  6. 27
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/easyopen/EasyopenResultExecutor.java
  7. 34
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/easyopen/EasyopenSigner.java
  8. 26
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/easyopen/EasyopenZuulConfiguration.java
  9. 7
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/param/GatewayParamBuilder.java
  10. 35
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/BaseRouteManager.java
  11. 27
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/RouteDefinitionItemContext.java
  12. 25
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParamFactory.java
  13. 9
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/BaseExecutorAdapter.java
  14. 4
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ResultExecutor.java
  15. 3
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PostResultFilter.java
  16. 3
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreValidateFilter.java
  17. 23
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParamBuilder.java
  18. 10
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/result/ZuulResultExecutor.java
  19. 4
      sop-gateway/pom.xml
  20. 13
      sop-gateway/src/main/java/com/gitee/sop/gateway/config/ZuulConfig.java
  21. 125
      sop-service-common/pom.xml
  22. 5
      sop-service-common/src/main/java/com/gitee/sop/servercommon/annotation/ApiAbility.java
  23. 5
      sop-service-common/src/main/java/com/gitee/sop/servercommon/annotation/ApiMapping.java
  24. 2
      sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceApiInfo.java
  25. 5
      sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceConfig.java
  26. 13
      sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/BaseServiceConfiguration.java
  27. 102
      sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/EasyopenServiceConfiguration.java
  28. 72
      sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/DefaultRequestMappingEvent.java
  29. 29
      sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ServiceZookeeperApiMetaManager.java
  30. 9
      sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingHandlerMapping.java
  31. 1
      sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingInfo.java
  32. 2
      sop-service-common/src/main/java/com/gitee/sop/servercommon/route/GatewayRouteDefinition.java
  33. 93
      sop-test/src/test/java/com/gitee/sop/EasyopenClientPostTest.java

@ -35,11 +35,11 @@ SOP封装了开放平台大部分功能包括:签名验证、统一异常处
- 秘钥管理
- 微服务端自动验证(JSR-303)
- 支持Spring Cloud Gateway
- 关闭签名校验功能
- 整合[easyopen](https://gitee.com/durcframework/easyopen)
## 后期规划
- 关闭签名校验功能
- 整合[easyopen](https://gitee.com/durcframework/easyopen)
- 配置中心,Spring Cloud Config(Zookeeper)
- Admin管理平台,统一管理微服务配置,管理路由信息,微服务上下线,API文档管理等功能

@ -2,21 +2,19 @@
<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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-gateway-common</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>sop-gateway-common</name>
<description>sop-gateway-common</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
<spring-boot.version>2.1.2.RELEASE</spring-boot.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<!-- Logging -->
<logback.version>1.0.13</logback.version>
<slf4j.version>1.7.5</slf4j.version>
@ -28,28 +26,44 @@
<commons-io.version>2.5</commons-io.version>
<commons-fileupload.version>1.3.3</commons-fileupload.version>
<commons-collection.version>3.2.2</commons-collection.version>
<xstream.version>1.4.7</xstream.version>
<velocity.version>1.7</velocity.version>
<hibernate-validator.version>6.0.10.Final</hibernate-validator.version>
<oltu.version>0.31</oltu.version>
<jwt.version>3.2.0</jwt.version>
<guava.version>18.0</guava.version>
<spring-data-redis.version>1.8.8.RELEASE</spring-data-redis.version>
<netty.version>4.1.25.Final</netty.version>
<jboss-marshalling-serial.version>2.0.5.Final</jboss-marshalling-serial.version>
<itextpdf.version>5.5.12</itextpdf.version>
<xmlworker.version>5.5.8</xmlworker.version>
<itext-asian.version>5.2.0</itext-asian.version>
<asm.version>6.2</asm.version>
<commons-lang3.version>3.8.1</commons-lang3.version>
<commons-codec.version>1.11</commons-codec.version>
<xstream.version>1.4.7</xstream.version>
<zookeeper.version>3.4.12</zookeeper.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- 加了这个就不需要加版本号了 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-ribbon</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
@ -60,10 +74,6 @@
<artifactId>spring-boot-starter-webflux</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- zookeeper -->
<dependency>
@ -84,7 +94,7 @@
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.12</version>
<version>${zookeeper.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
@ -93,11 +103,17 @@
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
@ -109,15 +125,11 @@
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- commons -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
@ -151,42 +163,60 @@
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-ribbon</artifactId>
<version>2.1.0.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<!-- 打包时跳过测试 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
<!-- JDK8必须使用下面的配置 -->
<configuration>
<additionalparam>-Xdoclint:none</additionalparam>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
</project>

@ -95,6 +95,11 @@ public class ApiConfig {
*/
private boolean ignoreValidate;
/**
* 是否对结果进行合并
*/
private boolean mergeResult = true;
/**
* 超时时间
*/

@ -21,4 +21,9 @@ public class BaseRouteDefinition {
* 路由执行的顺序
*/
private int order = 0;
/**
* 是否忽略验证业务参数验证除外
*/
private boolean ignoreValidate;
}

@ -32,7 +32,7 @@ public class SopConstants {
public static final int BIZ_ERROR_STATUS = 4000;
/**
* zookeeper存放接口信息的根目录
* zookeeper存放接口路由信息的根目录
*/
public static final String SOP_SERVICE_API_PATH = "/sop-service-api";
public static final String SOP_SERVICE_ROUTE_PATH = "/sop-service-route";
}

@ -0,0 +1,27 @@
package com.gitee.sop.gatewaycommon.easyopen;
import com.alibaba.fastjson.JSON;
import com.gitee.sop.gatewaycommon.message.Error;
import com.gitee.sop.gatewaycommon.result.ApiResult;
import com.gitee.sop.gatewaycommon.result.ResultExecutor;
import com.gitee.sop.gatewaycommon.zuul.result.ZuulResultExecutor;
import com.netflix.zuul.context.RequestContext;
/**
* @author tanghc
*/
public class EasyopenResultExecutor implements ResultExecutor<RequestContext, String> {
@Override
public String mergeResult(RequestContext request, String serviceResult) {
return serviceResult;
}
@Override
public String buildErrorResult(RequestContext request, Throwable ex) {
ApiResult apiResult = new ApiResult();
Error error = ZuulResultExecutor.getError(ex);
apiResult.setCode(error.getSub_code());
apiResult.setMsg(error.getSub_msg());
return JSON.toJSONString(apiResult);
}
}

@ -0,0 +1,34 @@
package com.gitee.sop.gatewaycommon.easyopen;
import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.validate.AbstractSigner;
import com.gitee.sop.gatewaycommon.validate.taobao.TaobaoSigner;
import org.apache.commons.codec.digest.DigestUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* @author tanghc
*/
public class EasyopenSigner extends AbstractSigner {
@Override
protected String buildServerSign(ApiParam params, String secret) {
Set<String> keySet = params.keySet();
List<String> paramNames = new ArrayList<String>(keySet);
Collections.sort(paramNames);
StringBuilder paramNameValue = new StringBuilder();
for (String paramName : paramNames) {
paramNameValue.append(paramName).append(params.get(paramName));
}
String source = secret + paramNameValue.toString() + secret;
return DigestUtils.md5Hex(source).toUpperCase();
}
}

@ -0,0 +1,26 @@
package com.gitee.sop.gatewaycommon.easyopen;
import com.gitee.sop.gatewaycommon.bean.ApiConfig;
import com.gitee.sop.gatewaycommon.bean.ApiContext;
import com.gitee.sop.gatewaycommon.gateway.configuration.BaseGatewayConfiguration;
import com.gitee.sop.gatewaycommon.param.ParamNames;
import com.gitee.sop.gatewaycommon.validate.taobao.TaobaoSigner;
import com.gitee.sop.gatewaycommon.zuul.configuration.BaseZuulConfiguration;
/**
* @author tanghc
*/
public class EasyopenZuulConfiguration extends BaseZuulConfiguration {
static {
ParamNames.APP_KEY_NAME = "app_key";
ParamNames.API_NAME = "name";
ParamNames.SIGN_TYPE_NAME = "sign_type";
ParamNames.APP_AUTH_TOKEN_NAME = "access_token";
ApiConfig apiConfig = ApiContext.getApiConfig();
apiConfig.setSigner(new EasyopenSigner());
apiConfig.setZuulResultExecutor(new EasyopenResultExecutor());
apiConfig.setMergeResult(false);
}
}

@ -2,6 +2,7 @@ package com.gitee.sop.gatewaycommon.gateway.param;
import com.gitee.sop.gatewaycommon.bean.SopConstants;
import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.param.ApiParamFactory;
import com.gitee.sop.gatewaycommon.param.ParamBuilder;
import org.springframework.web.server.ServerWebExchange;
@ -14,11 +15,7 @@ public class GatewayParamBuilder implements ParamBuilder<ServerWebExchange> {
@Override
public ApiParam build(ServerWebExchange exchange) {
Map<String, String> params = exchange.getAttribute(SopConstants.CACHE_REQUEST_BODY_FOR_MAP);
ApiParam apiParam = new ApiParam();
for (Map.Entry<String, String> entry : params.entrySet()) {
apiParam.put(entry.getKey(), entry.getValue());
}
return apiParam;
return ApiParamFactory.build(params);
}

@ -16,7 +16,7 @@ import org.springframework.util.StringUtils;
import java.util.List;
import static com.gitee.sop.gatewaycommon.bean.SopConstants.SOP_SERVICE_API_PATH;
import static com.gitee.sop.gatewaycommon.bean.SopConstants.SOP_SERVICE_ROUTE_PATH;
/**
@ -30,7 +30,7 @@ import static com.gitee.sop.gatewaycommon.bean.SopConstants.SOP_SERVICE_API_PATH
@Slf4j
public abstract class BaseRouteManager<R extends BaseServiceRouteInfo<E>, E extends BaseRouteDefinition, T> implements RouteManager {
protected String sopServiceApiPath = SOP_SERVICE_API_PATH;
protected String sopServiceApiPath = SOP_SERVICE_ROUTE_PATH;
protected Environment environment;
@ -93,10 +93,7 @@ public abstract class BaseRouteManager<R extends BaseServiceRouteInfo<E>, E exte
String nodeData = new String(childData.getData());
log.info("\t* 子节点路径:" + childData.getPath() + ",该节点的数据为:" + nodeData);
R serviceRouteInfo = JSON.parseObject(nodeData, getServiceRouteInfoClass());
for (E routeDefinitionItem : serviceRouteInfo.getRouteDefinitionList()) {
T routeDefinition = buildRouteDefinition(serviceRouteInfo, routeDefinitionItem);
routeRepository.add(serviceRouteInfo, routeDefinition);
}
saveRouteDefinitionList(serviceRouteInfo);
}
// 添加事件监听器
childrenCache.getListenable().addListener(new PathChildrenCacheListener() {
@ -110,10 +107,7 @@ public abstract class BaseRouteManager<R extends BaseServiceRouteInfo<E>, E exte
R serviceRouteInfo = JSON.parseObject(nodeData, getServiceRouteInfoClass());
// 添加子节点时触发
log.info("子节点:{}添加,数据为:{}", event.getData().getPath(), nodeData);
for (E routeDefinitionItem : serviceRouteInfo.getRouteDefinitionList()) {
T routeDefinition = buildRouteDefinition(serviceRouteInfo, routeDefinitionItem);
routeRepository.add(serviceRouteInfo, routeDefinition);
}
saveRouteDefinitionList(serviceRouteInfo);
} else if (PathChildrenCacheEvent.Type.CHILD_UPDATED.equals(type)) {
String nodeData = new String(event.getData().getData());
R serviceRouteInfo = JSON.parseObject(nodeData, getServiceRouteInfoClass());
@ -122,20 +116,31 @@ public abstract class BaseRouteManager<R extends BaseServiceRouteInfo<E>, E exte
// 删除下面所有节点
routeRepository.deleteAll(serviceRouteInfo);
// 添加新节点
for (E routeDefinitionItem : serviceRouteInfo.getRouteDefinitionList()) {
T routeDefinition = buildRouteDefinition(serviceRouteInfo, routeDefinitionItem);
routeRepository.add(serviceRouteInfo, routeDefinition);
}
saveRouteDefinitionList(serviceRouteInfo);
} else if (PathChildrenCacheEvent.Type.CHILD_REMOVED.equals(type)) {
String nodeData = new String(event.getData().getData());
log.info("子节点:{}删除,数据为:{}", event.getData().getPath(), nodeData);
R serviceRouteInfo = JSON.parseObject(nodeData, getServiceRouteInfoClass());
routeRepository.deleteAll(serviceRouteInfo);
deleteRouteDefinitionList(serviceRouteInfo);
}
}
}
});
}
protected void saveRouteDefinitionList(R serviceRouteInfo) {
for (E routeDefinitionItem : serviceRouteInfo.getRouteDefinitionList()) {
RouteDefinitionItemContext.add(routeDefinitionItem);
T routeDefinition = buildRouteDefinition(serviceRouteInfo, routeDefinitionItem);
routeRepository.add(serviceRouteInfo, routeDefinition);
}
}
protected void deleteRouteDefinitionList(R serviceRouteInfo) {
for (E routeDefinitionItem : serviceRouteInfo.getRouteDefinitionList()) {
RouteDefinitionItemContext.delete(routeDefinitionItem);
}
routeRepository.deleteAll(serviceRouteInfo);
}
}

@ -0,0 +1,27 @@
package com.gitee.sop.gatewaycommon.manager;
import com.gitee.sop.gatewaycommon.bean.BaseRouteDefinition;
import java.util.HashMap;
import java.util.Map;
/**
* @author tanghc
*/
public class RouteDefinitionItemContext {
// key:id
private static Map<String, BaseRouteDefinition> routeDefinitionMap = new HashMap<>(64);
public static void add(BaseRouteDefinition routeDefinition) {
routeDefinitionMap.put(routeDefinition.getId(), routeDefinition);
}
public static BaseRouteDefinition getRouteDefinition(String id) {
return routeDefinitionMap.get(id);
}
public static void delete(BaseRouteDefinition routeDefinition) {
routeDefinitionMap.remove(routeDefinition.getId());
}
}

@ -0,0 +1,25 @@
package com.gitee.sop.gatewaycommon.param;
import com.gitee.sop.gatewaycommon.bean.BaseRouteDefinition;
import com.gitee.sop.gatewaycommon.manager.RouteDefinitionItemContext;
import com.gitee.sop.gatewaycommon.message.ErrorEnum;
import java.util.Map;
/**
* @author tanghc
*/
public class ApiParamFactory {
public static ApiParam build(Map<String, ?> params) {
ApiParam apiParam = new ApiParam();
for (Map.Entry<String, ?> entry : params.entrySet()) {
apiParam.put(entry.getKey(), entry.getValue());
}
BaseRouteDefinition routeDefinition = RouteDefinitionItemContext.getRouteDefinition(apiParam.fetchNameVersion());
if (routeDefinition == null) {
throw ErrorEnum.ISV_INVALID_METHOD.getErrorMeta().getException();
}
apiParam.setIgnoreValidate(routeDefinition.isIgnoreValidate());
return apiParam;
}
}

@ -2,10 +2,14 @@ package com.gitee.sop.gatewaycommon.result;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gitee.sop.gatewaycommon.bean.ApiContext;
import com.gitee.sop.gatewaycommon.bean.SopConstants;
import com.gitee.sop.gatewaycommon.exception.ApiException;
import com.gitee.sop.gatewaycommon.message.Error;
import com.gitee.sop.gatewaycommon.message.ErrorEnum;
import com.gitee.sop.gatewaycommon.message.ErrorMeta;
import com.gitee.sop.gatewaycommon.param.ParamNames;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
@ -45,6 +49,10 @@ public abstract class BaseExecutorAdapter<T, R> implements ResultExecutor<T, R>
@Override
public String mergeResult(T request, String serviceResult) {
boolean isMergeResult = ApiContext.getApiConfig().isMergeResult();
if (!isMergeResult) {
return serviceResult;
}
serviceResult = wrapResult(serviceResult);
int responseStatus = this.getBizHeaderCode(request);
JSONObject jsonObjectService;
@ -99,4 +107,5 @@ public abstract class BaseExecutorAdapter<T, R> implements ResultExecutor<T, R>
ret.put(ParamNames.SIGN_NAME, sign);
return ret.toJSONString();
}
}

@ -37,7 +37,7 @@ public interface ResultExecutor<T, R> {
* 合并结果
* @param request
* @param serviceResult
* @return
* @return 返回最终输出结果
*/
String mergeResult(T request, String serviceResult);
@ -45,7 +45,7 @@ public interface ResultExecutor<T, R> {
* 合并错误结果
* @param request
* @param ex
* @return
* @return 返回最终输出结果
*/
R buildErrorResult(T request, Throwable ex);
}

@ -30,6 +30,9 @@ public class PostResultFilter extends BaseZuulFilter {
@Override
protected Object doRun(RequestContext requestContext) throws ZuulException {
if (requestContext.getResponse().isCommitted()) {
return null;
}
InputStream responseDataStream = requestContext.getResponseDataStream();
ApiConfig apiConfig = ApiContext.getApiConfig();
ResultExecutor<RequestContext, String> resultExecutor = apiConfig.getZuulResultExecutor();

@ -2,10 +2,13 @@ package com.gitee.sop.gatewaycommon.zuul.filter;
import com.gitee.sop.gatewaycommon.bean.ApiContext;
import com.gitee.sop.gatewaycommon.bean.ApiConfig;
import com.gitee.sop.gatewaycommon.bean.BaseRouteDefinition;
import com.gitee.sop.gatewaycommon.exception.ApiException;
import com.gitee.sop.gatewaycommon.manager.RouteDefinitionItemContext;
import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.validate.Validator;
import com.gitee.sop.gatewaycommon.zuul.ZuulContext;
import com.gitee.sop.gatewaycommon.zuul.route.ZuulRouteDefinition;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;

@ -1,14 +1,17 @@
package com.gitee.sop.gatewaycommon.zuul.param;
import com.alibaba.fastjson.JSON;
import com.gitee.sop.gatewaycommon.bean.SopConstants;
import com.gitee.sop.gatewaycommon.message.ErrorEnum;
import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.param.ApiParamFactory;
import com.gitee.sop.gatewaycommon.param.ApiUploadContext;
import com.gitee.sop.gatewaycommon.param.ParamBuilder;
import com.gitee.sop.gatewaycommon.util.RequestUtil;
import com.gitee.sop.gatewaycommon.zuul.ZuulContext;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.http.HttpServletRequestWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
@ -24,6 +27,7 @@ import java.util.Set;
*
* @author tanghc
*/
@Slf4j
public class ZuulParamBuilder implements ParamBuilder<RequestContext> {
private static final String CONTENT_TYPE_MULTIPART = MediaType.MULTIPART_FORM_DATA_VALUE;
@ -33,16 +37,12 @@ public class ZuulParamBuilder implements ParamBuilder<RequestContext> {
@Override
public ApiParam build(RequestContext ctx) {
try {
HttpServletRequest request = ctx.getRequest();
Map<String, Object> params = this.getJson(request);
return new ApiParam(params);
} catch (Exception e) {
throw ErrorEnum.ISV_INVALID_PARAMETER.getErrorMeta().getException();
}
HttpServletRequest request = ctx.getRequest();
Map<String, Object> params = this.getParams(request);
return ApiParamFactory.build(params);
}
public Map<String, Object> getJson(HttpServletRequest request) throws Exception {
public Map<String, Object> getParams(HttpServletRequest request) {
// zuul会做一层包装
if (request instanceof HttpServletRequestWrapper) {
HttpServletRequestWrapper req = (HttpServletRequestWrapper) request;
@ -63,7 +63,12 @@ public class ZuulParamBuilder implements ParamBuilder<RequestContext> {
// json或者纯文本形式
if (contectType.contains(CONTENT_TYPE_JSON) || contectType.contains(CONTENT_TYPE_TEXT)) {
String txt = RequestUtil.getText(request);
String txt = SopConstants.EMPTY_JSON;
try {
txt = RequestUtil.getText(request);
} catch (Exception e) {
log.error("获取纯文本内容失败", e);
}
params = JSON.parseObject(txt);
} else if (contectType.contains(CONTENT_TYPE_MULTIPART)) {
// 上传文件形式

@ -40,6 +40,12 @@ public class ZuulResultExecutor extends BaseExecutorAdapter<RequestContext, Stri
@Override
public String buildErrorResult(RequestContext request, Throwable throwable) {
Error error = getError(throwable);
JSONObject jsonObject = (JSONObject) JSON.toJSON(error);
return this.merge(request, jsonObject);
}
public static Error getError(Throwable throwable) {
Error error = null;
if (throwable instanceof ZuulException) {
ZuulException ex = (ZuulException) throwable;
@ -52,8 +58,6 @@ public class ZuulResultExecutor extends BaseExecutorAdapter<RequestContext, Stri
if (error == null) {
error = ErrorEnum.AOP_UNKNOW_ERROR.getErrorMeta().getError();
}
JSONObject jsonObject = (JSONObject) JSON.toJSON(error);
return this.merge(request, jsonObject);
return error;
}
}

@ -43,6 +43,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
-->
<!-- ↑↑↑ 使用spring cloud gateway ↑↑↑ -->

@ -1,6 +1,7 @@
package com.gitee.sop.gateway.config;
import com.gitee.sop.gatewaycommon.bean.ApiContext;
import com.gitee.sop.gatewaycommon.easyopen.EasyopenZuulConfiguration;
import com.gitee.sop.gatewaycommon.zuul.configuration.AlipayZuulConfiguration;
import com.gitee.sop.gatewaycommon.zuul.configuration.TaobaoZuulConfiguration;
import org.springframework.context.annotation.Configuration;
@ -42,4 +43,14 @@ public class ZuulConfig extends AlipayZuulConfiguration {
// }
//}
/**
* 对接easyopen
*/
//@Configuration
//public class ZuulConfig extends EasyopenZuulConfiguration {
// {
// Map<String, String> appSecretStore = new HashMap();
// appSecretStore.put("easyopen_test", "G9w0BAQEFAAOCAQ8AMIIBCgKCA");
// ApiContext.getApiConfig().addAppSecret(appSecretStore);
// }
//}

@ -3,27 +3,53 @@
<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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-service-common</artifactId>
<name>sop-service-common</name>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
<spring-boot.version>2.1.2.RELEASE</spring-boot.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring-data-redis.version>1.8.8.RELEASE</spring-data-redis.version>
<fastjson.version>1.2.15</fastjson.version>
<zookeeper.version>3.4.12</zookeeper.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- 加了这个就不需要加版本号了 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
@ -49,7 +75,7 @@
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.12</version>
<version>${zookeeper.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
@ -59,26 +85,25 @@
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<groupId>net.oschina.durcframework</groupId>
<artifactId>easyopen</artifactId>
<version>1.16.0</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>9.0.14</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
@ -89,23 +114,55 @@
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<!-- 打包时跳过测试 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
<!-- JDK8必须使用下面的配置 -->
<configuration>
<additionalparam>-Xdoclint:none</additionalparam>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

@ -20,4 +20,9 @@ public @interface ApiAbility {
* 版本号1.0
*/
String version() default "";
/**
* 忽略验证业务参数除外
*/
boolean ignoreValidate() default false;
}

@ -27,6 +27,11 @@ public @interface ApiMapping {
*/
String version() default "";
/**
* 忽略验证业务参数除外
*/
boolean ignoreValidate() default false;
/**
* 接口名
* Alias for {@link RequestMapping#value}.

@ -24,6 +24,8 @@ public class ServiceApiInfo {
private String path;
/** 版本号 */
private String version;
/** 是否忽略验证 */
private boolean ignoreValidate;
public ApiMeta() {
}

@ -47,6 +47,11 @@ public class ServiceConfig {
*/
private GlobalExceptionHandler globalExceptionHandler = new DefaultGlobalExceptionHandler();
/**
* 设置为true所有接口不进行校验
*/
private boolean ignoreValidate;
public static ServiceConfig getInstance() {
return instance;
}

@ -4,6 +4,7 @@ import com.gitee.sop.servercommon.bean.ServiceConfig;
import com.gitee.sop.servercommon.interceptor.ServiceContextInterceptor;
import com.gitee.sop.servercommon.manager.ApiMetaManager;
import com.gitee.sop.servercommon.manager.DefaultRequestMappingEvent;
import com.gitee.sop.servercommon.manager.RequestMappingEvent;
import com.gitee.sop.servercommon.manager.ServiceZookeeperApiMetaManager;
import com.gitee.sop.servercommon.mapping.ApiMappingHandlerMapping;
import com.gitee.sop.servercommon.message.ServiceErrorFactory;
@ -41,11 +42,19 @@ public class BaseServiceConfiguration extends WebMvcConfigurationSupport {
*/
@Override
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
ApiMetaManager apiMetaManager = new ServiceZookeeperApiMetaManager(environment);
DefaultRequestMappingEvent requestMappingEvent = new DefaultRequestMappingEvent(apiMetaManager, environment);
ApiMetaManager apiMetaManager = getApiMetaManager(environment);
RequestMappingEvent requestMappingEvent = getRequestMappingEvent(apiMetaManager, environment);
return new ApiMappingHandlerMapping(requestMappingEvent);
}
protected RequestMappingEvent getRequestMappingEvent(ApiMetaManager apiMetaManager, Environment environment) {
return new DefaultRequestMappingEvent(apiMetaManager, environment);
}
protected ApiMetaManager getApiMetaManager(Environment environment) {
return new ServiceZookeeperApiMetaManager(environment);
}
@Bean
GlobalExceptionHandler globalExceptionHandler() {
return ServiceConfig.getInstance().getGlobalExceptionHandler();

@ -0,0 +1,102 @@
package com.gitee.sop.servercommon.configuration;
import com.gitee.easyopen.ApiContext;
import com.gitee.easyopen.annotation.Api;
import com.gitee.easyopen.annotation.ApiService;
import com.gitee.easyopen.util.ReflectionUtil;
import com.gitee.sop.servercommon.bean.ServiceApiInfo;
import com.gitee.sop.servercommon.manager.ApiMetaManager;
import com.gitee.sop.servercommon.manager.DefaultRequestMappingEvent;
import com.gitee.sop.servercommon.manager.RequestMappingEvent;
import com.gitee.sop.servercommon.mapping.ApiMappingHandlerMapping;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.Environment;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
/**
* 提供给easyopen项目使用
* @author tanghc
*/
public class EasyopenServiceConfiguration extends BaseServiceConfiguration {
@Override
protected RequestMappingEvent getRequestMappingEvent(ApiMetaManager apiMetaManager, Environment environment) {
return new EasyopenRequestMappingEvent(apiMetaManager, environment);
}
class EasyopenRequestMappingEvent extends DefaultRequestMappingEvent {
String prefixPath;
public EasyopenRequestMappingEvent(ApiMetaManager apiMetaManager, Environment environment) {
super(apiMetaManager, environment);
String prefixPath = getEnvironment().getProperty("easyopen.prefix-path");
if (prefixPath == null) {
throw new IllegalArgumentException("请在application.propertis中设置easyopen.prefix-path属性,填IndexController上面的@RequestMapping()中的值");
}
this.prefixPath = prefixPath;
}
@Override
protected List<ServiceApiInfo.ApiMeta> buildApiMetaList(ApiMappingHandlerMapping apiMappingHandlerMapping) {
ApplicationContext ctx = getApplicationContext();
String[] apiServiceNames = ReflectionUtil.findApiServiceNames(ctx);
List<ServiceApiInfo.ApiMeta> apiMetaList = new ArrayList<>();
for (String apiServiceName : apiServiceNames) {
Object bean = ctx.getBean(apiServiceName);
doWithMethods(bean.getClass(), method -> {
Api api = AnnotationUtils.findAnnotation(method, Api.class);
ServiceApiInfo.ApiMeta apiMeta = new ServiceApiInfo.ApiMeta();
apiMeta.setName(api.name());
apiMeta.setVersion(api.version());
apiMeta.setIgnoreValidate(api.ignoreValidate());
// /api/goods.get/
String servletPath = this.buildPath(api);
apiMeta.setPath(servletPath);
apiMetaList.add(apiMeta);
});
}
return apiMetaList;
}
protected void doWithMethods(Class<?> clazz, Consumer<Method> consumer) {
// Keep backing up the inheritance hierarchy.
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
boolean match = !method.isSynthetic() && AnnotationUtils.findAnnotation(method, Api.class) != null;
if (match) {
consumer.accept(method);
}
}
}
protected String buildPath(Api api) {
// /api/goods.get/
String servletPath = prefixPath + "/" + api.name() + "/";
String version = api.version();
if (StringUtils.hasLength(version)) {
// /api/goods.get/1.0/
servletPath = servletPath + version + "/";
}
return servletPath;
}
}
@Override
public void after() {
super.after();
// 取消验证
// todo:需要在easyopen端修改
//ApiContext.getApiConfig().setIgnoreValidate(true);
}
}

@ -35,38 +35,11 @@ public class DefaultRequestMappingEvent implements RequestMappingEvent {
@Override
public void onRegisterSuccess(ApiMappingHandlerMapping apiMappingHandlerMapping) {
Map<RequestMappingInfo, HandlerMethod> handlerMethods = apiMappingHandlerMapping.getHandlerMethods();
Set<RequestMappingInfo> requestMappingInfos = handlerMethods.keySet();
List<String> store = new ArrayList<>(requestMappingInfos.size());
List<ServiceApiInfo.ApiMeta> apis = new ArrayList<>(requestMappingInfos.size());
for (RequestMappingInfo requestMappingInfo : requestMappingInfos) {
Set<String> patterns = requestMappingInfo.getPatternsCondition().getPatterns();
RequestCondition<?> customCondition = requestMappingInfo.getCustomCondition();
if (customCondition instanceof ApiMappingRequestCondition) {
ApiMappingRequestCondition condition = (ApiMappingRequestCondition) customCondition;
ApiMappingInfo apiMappingInfo = condition.getApiMappingInfo();
String name = apiMappingInfo.getName();
String version = apiMappingInfo.getVersion();
String path = patterns.iterator().next();
// 不是ApiMapping注解的接口,name属性是null
if (name == null) {
name = buildName(path);
}
String key = path + version;
if (store.contains(key)) {
throw new RuntimeException("重复申明接口,请检查path和version,path:" + path + ", version:" + version);
} else {
store.add(key);
}
apis.add(new ServiceApiInfo.ApiMeta(name, path, version));
}
}
String appName = environment.getProperty("spring.application.name");
if (appName == null) {
throw new RuntimeException("请在application.properties中指定spring.application.name属性");
}
List<ServiceApiInfo.ApiMeta> apis = this.buildApiMetaList(apiMappingHandlerMapping);
// 排序
Collections.sort(apis, new Comparator<ServiceApiInfo.ApiMeta>() {
@Override
@ -83,6 +56,49 @@ public class DefaultRequestMappingEvent implements RequestMappingEvent {
apiMetaManager.uploadApi(serviceApiInfo);
}
protected List<ServiceApiInfo.ApiMeta> buildApiMetaList(ApiMappingHandlerMapping apiMappingHandlerMapping) {
Map<RequestMappingInfo, HandlerMethod> handlerMethods = apiMappingHandlerMapping.getHandlerMethods();
Set<RequestMappingInfo> requestMappingInfos = handlerMethods.keySet();
List<String> store = new ArrayList<>();
List<ServiceApiInfo.ApiMeta> apis = new ArrayList<>(requestMappingInfos.size());
for (Map.Entry<RequestMappingInfo, HandlerMethod> handlerMethodEntry : handlerMethods.entrySet()) {
ServiceApiInfo.ApiMeta apiMeta = this.buildApiMeta(handlerMethodEntry);
if (apiMeta == null) {
continue;
}
String key = apiMeta.fetchNameVersion();
if (store.contains(key)) {
throw new RuntimeException("重复申明接口,请检查path和version,path:" + apiMeta.getPath() + ", version:" + apiMeta.getVersion());
} else {
store.add(key);
}
apis.add(apiMeta);
}
return apis;
}
protected ServiceApiInfo.ApiMeta buildApiMeta(Map.Entry<RequestMappingInfo, HandlerMethod> handlerMethodEntry) {
RequestMappingInfo requestMappingInfo = handlerMethodEntry.getKey();
Set<String> patterns = requestMappingInfo.getPatternsCondition().getPatterns();
RequestCondition<?> customCondition = requestMappingInfo.getCustomCondition();
if (customCondition instanceof ApiMappingRequestCondition) {
ApiMappingRequestCondition condition = (ApiMappingRequestCondition) customCondition;
ApiMappingInfo apiMappingInfo = condition.getApiMappingInfo();
String name = apiMappingInfo.getName();
String version = apiMappingInfo.getVersion();
String path = patterns.iterator().next();
// 不是ApiMapping注解的接口,name属性是null
if (name == null) {
name = buildName(path);
}
ServiceApiInfo.ApiMeta apiMeta = new ServiceApiInfo.ApiMeta(name, path, version);
apiMeta.setIgnoreValidate(apiMappingInfo.isIgnoreValidate());
return apiMeta;
}
return null;
}
protected String buildName(String path) {
path = StringUtils.trimLeadingCharacter(path, '/');
path = StringUtils.trimTrailingCharacter(path, '/');

@ -27,6 +27,11 @@ import java.util.List;
@Setter
public class ServiceZookeeperApiMetaManager implements ApiMetaManager {
/**
* zookeeper存放接口路由信息的根目录
*/
public static final String SOP_SERVICE_ROUTE_PATH = "/sop-service-route";
public static final String PATH_START_CHAR = "/";
/**
* NameVersion=alipay.story.get1.0
@ -36,8 +41,6 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager {
private static ServiceApiInfo.ApiMeta FIRST_API_META = new ServiceApiInfo.ApiMeta("_" + System.currentTimeMillis() + "_", "/", "0.0");
private String sopServiceApiPath = "/sop-service-api";
private Environment environment;
public ServiceZookeeperApiMetaManager(Environment environment) {
@ -97,11 +100,27 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager {
List<GatewayPredicateDefinition> predicates = Arrays.asList(this.buildNameVersionPredicateDefinition(apiMeta));
gatewayRouteDefinition.setPredicates(predicates);
// lb://story-service#/alipay.story.get/
String servletPath = "#" + apiMeta.getPath();
gatewayRouteDefinition.setUri("lb://" + serviceApiInfo.getAppName() + servletPath);
String uri = this.buildUri(serviceApiInfo, apiMeta);
gatewayRouteDefinition.setUri(uri);
gatewayRouteDefinition.setIgnoreValidate(apiMeta.isIgnoreValidate());
return gatewayRouteDefinition;
}
protected String buildUri(ServiceApiInfo serviceApiInfo, ServiceApiInfo.ApiMeta apiMeta) {
String servletPath = getServletPath(serviceApiInfo, apiMeta);
if (servletPath == null) {
servletPath = PATH_START_CHAR;
}
if (!servletPath.startsWith(PATH_START_CHAR)) {
servletPath = PATH_START_CHAR + servletPath;
}
return "lb://" + serviceApiInfo.getAppName() + "#" + servletPath;
}
protected String getServletPath(ServiceApiInfo serviceApiInfo, ServiceApiInfo.ApiMeta apiMeta) {
return apiMeta.getPath();
}
protected GatewayPredicateDefinition buildNameVersionPredicateDefinition(ServiceApiInfo.ApiMeta apiMeta) {
return new GatewayPredicateDefinition(String.format(QUERY_PREDICATE_DEFINITION_TPL, apiMeta.fetchNameVersion()));
}
@ -120,7 +139,7 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager {
CuratorFramework client = null;
try {
// 保存路径
String savePath = sopServiceApiPath + "/" + serviceRouteInfo.getAppName();
String savePath = SOP_SERVICE_ROUTE_PATH + "/" + serviceRouteInfo.getAppName();
client = CuratorFrameworkFactory.builder()
.connectString(zookeeperServerAddr)

@ -3,6 +3,7 @@ package com.gitee.sop.servercommon.mapping;
import com.gitee.sop.servercommon.annotation.ApiMapping;
import com.gitee.sop.servercommon.annotation.ApiAbility;
import com.gitee.sop.servercommon.bean.ServiceConfig;
import com.gitee.sop.servercommon.bean.ServiceContext;
import com.gitee.sop.servercommon.manager.RequestMappingEvent;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.annotation.AnnotationUtils;
@ -42,14 +43,17 @@ public class ApiMappingHandlerMapping extends RequestMappingHandlerMapping imple
method.setAccessible(true);
String name = null;
String version;
boolean ignoreValidate = false;
ApiMapping apiMapping = method.getAnnotation(ApiMapping.class);
if (apiMapping != null) {
name = apiMapping.value()[0];
version = apiMapping.version();
ignoreValidate = apiMapping.ignoreValidate();
} else {
ApiAbility apiAbility = this.findApiAbilityAnnotation(method);
if (apiAbility != null) {
version = apiAbility.version();
ignoreValidate = apiAbility.ignoreValidate();
} else {
return super.getCustomMethodCondition(method);
}
@ -58,6 +62,11 @@ public class ApiMappingHandlerMapping extends RequestMappingHandlerMapping imple
version = ServiceConfig.getInstance().getDefaultVersion();
}
ApiMappingInfo apiMappingInfo = new ApiMappingInfo(name, version);
// 如果是默认配置,则采用全局配置
if (!ignoreValidate) {
ignoreValidate = ServiceConfig.getInstance().isIgnoreValidate();
}
apiMappingInfo.setIgnoreValidate(ignoreValidate);
logger.info("注册接口,method:" + method + ", version:" + version);
return new ApiMappingRequestCondition(apiMappingInfo);
}

@ -9,6 +9,7 @@ import lombok.Data;
public class ApiMappingInfo {
private String name;
private String version;
private boolean ignoreValidate;
public ApiMappingInfo(String name, String version) {
this.name = name;

@ -20,4 +20,6 @@ public class GatewayRouteDefinition {
private String uri;
/** 路由执行的顺序 */
private int order = 0;
/** 是否忽略验证,业务参数验证除外 */
private boolean ignoreValidate;
}

@ -0,0 +1,93 @@
package com.gitee.sop;
import com.alibaba.fastjson.JSON;
import junit.framework.TestCase;
import org.apache.commons.codec.digest.DigestUtils;
import org.junit.Test;
import java.io.IOException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author tanghc
*/
public class EasyopenClientPostTest extends TestBase {
String url = "http://localhost:8081/api";
String appKey = "easyopen_test";
String secret = "G9w0BAQEFAAOCAQ8AMIIBCgKCA";
@Test
public void testPost() throws IOException {
// 业务参数
Map<String, String> bizParams = new HashMap<String, String>();
bizParams.put("goods_name", "iphoneX");
String json = JSON.toJSONString(bizParams);
json = URLEncoder.encode(json, "utf-8");
// 系统参数
Map<String, String> params = new HashMap<>();
params.put("name", "goods.get");
params.put("app_key", appKey);
params.put("data", json);
params.put("timestamp", getTime());
params.put("version", "");
String sign = buildSign(params, secret);
params.put("sign", sign);
System.out.println("=====请求数据=====");
System.out.println(JSON.toJSONString(params));
System.out.println("=====返回结果=====");
String resp = post(url, params);
System.out.println(resp);
}
/**
* 构建签名串
* @param paramsMap 请求参数
* @param secret 秘钥
* @return
* @throws IOException
*/
public String buildSign(Map<String, ?> paramsMap, String secret) throws IOException {
Set<String> keySet = paramsMap.keySet();
List<String> paramNames = new ArrayList<String>(keySet);
Collections.sort(paramNames);
StringBuilder paramNameValue = new StringBuilder();
for (String paramName : paramNames) {
paramNameValue.append(paramName).append(paramsMap.get(paramName));
}
String source = secret + paramNameValue.toString() + secret;
return md5(source);
}
/**
* 生成md5,全部大写
*
* @param source
* @return
*/
public static String md5(String source) {
return DigestUtils.md5Hex(source).toUpperCase();
}
public String getTime() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
}
}
Loading…
Cancel
Save