pull/1/MERGE
tanghc 5 years ago
parent c12eac02e6
commit 5a773745f9
  1. 5
      changelog.md
  2. 11
      sop-common/sop-bridge-gateway/src/main/resources/sop-bridge.properties
  3. 11
      sop-common/sop-bridge-zuul/src/main/resources/sop-bridge.properties
  4. 5
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/RouteDefinition.java
  5. 30
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java
  6. 8
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/configuration/BaseGatewayConfiguration.java
  7. 3
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/EnvGrayFilter.java
  8. 25
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/IndexFilter.java
  9. 16
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/GatewayForwardChooser.java
  10. 54
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/BaseForwardChooser.java
  11. 16
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/ForwardChooser.java
  12. 13
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/ForwardInfo.java
  13. 30
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java
  14. 3
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreEnvGrayFilter.java
  15. 18
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/SopRouteLocator.java
  16. 18
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/ZuulForwardChooser.java
  17. 2
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceApiInfo.java
  18. 1
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ApiMetaBuilder.java
  19. 12
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingHandlerMapping.java
  20. 2
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingInfo.java
  21. 5
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingRequestCondition.java
  22. 25
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingStringValueResolverVersion.java
  23. 5
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/route/RouteDefinition.java
  24. 3
      sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/AlipayController.java
  25. 0
      sop-gateway/src/main/resources/META-INF/spring.factories
  26. 15
      sop-gateway/src/main/resources/application-dev.properties
  27. 26
      sop-website/src/main/resources/public/pages/doc/doc.html
  28. 2
      sop-website/src/main/resources/public/pages/doc/doc.js
  29. 27
      sop-website/src/main/resources/public/pages/sandbox/sandbox.html

@ -1,10 +1,11 @@
# changelog # changelog
## 2.6.0 ## 3.0.0
- 重构spring cloud gateway网关 - 重构spring cloud gateway网关
- zuul和gateway网关二合一 - zuul和gateway网关二合一
- 代码优化 - 精简配置文件
- 优化文档中心页面
## 2.5.10 ## 2.5.10

@ -1,6 +1,17 @@
# 固定不变,不能改
spring.application.name=sop-gateway
# 不用改,如果要改,请全局替换修改 # 不用改,如果要改,请全局替换修改
sop.secret=MZZOUSTua6LzApIWXCwEgbBmxSzpzC sop.secret=MZZOUSTua6LzApIWXCwEgbBmxSzpzC
# nacos cloud配置
spring.cloud.nacos.discovery.server-addr=${nacos.url}
# 数据库配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://${mysql.host}/sop?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
spring.datasource.username=${mysql.username}
spring.datasource.password=${mysql.password}
# https://blog.csdn.net/qq_36872046/article/details/81058045 # https://blog.csdn.net/qq_36872046/article/details/81058045
# 路由转发超时时间,毫秒,默认值1000,详见:RibbonClientConfiguration.DEFAULT_READ_TIMEOUT。 # 路由转发超时时间,毫秒,默认值1000,详见:RibbonClientConfiguration.DEFAULT_READ_TIMEOUT。
# 如果微服务端 处理时间过长,会导致ribbon read超时,解决办法将这个值调大一点 # 如果微服务端 处理时间过长,会导致ribbon read超时,解决办法将这个值调大一点

@ -1,3 +1,5 @@
# 固定不变,不能改
spring.application.name=sop-gateway
# 入口地址,不用改,默认是/zuul # 入口地址,不用改,默认是/zuul
zuul.servlet-path=/api zuul.servlet-path=/api
# 禁用默认的过滤器,不能删,不用改 # 禁用默认的过滤器,不能删,不用改
@ -6,6 +8,15 @@ zuul.Servlet30WrapperFilter.pre.disable=true
# 不用改,如果要改,请全局替换修改 # 不用改,如果要改,请全局替换修改
sop.secret=MZZOUSTua6LzApIWXCwEgbBmxSzpzC sop.secret=MZZOUSTua6LzApIWXCwEgbBmxSzpzC
# nacos cloud配置
spring.cloud.nacos.discovery.server-addr=${nacos.url}
# 数据库配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://${mysql.host}/sop?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
spring.datasource.username=${mysql.username}
spring.datasource.password=${mysql.password}
# https://blog.csdn.net/qq_36872046/article/details/81058045 # https://blog.csdn.net/qq_36872046/article/details/81058045
# 路由转发超时时间,毫秒,默认值1000,详见:RibbonClientConfiguration.DEFAULT_READ_TIMEOUT。 # 路由转发超时时间,毫秒,默认值1000,详见:RibbonClientConfiguration.DEFAULT_READ_TIMEOUT。
# 如果微服务端 处理时间过长,会导致ribbon read超时,解决办法将这个值调大一点 # 如果微服务端 处理时间过长,会导致ribbon read超时,解决办法将这个值调大一点

@ -75,4 +75,9 @@ public class RouteDefinition {
* 是否需要token * 是否需要token
*/ */
private int needToken; private int needToken;
/**
* 是否是兼容模式即使用了@ApiAbility注解
*/
private int compatibleMode;
} }

@ -8,6 +8,8 @@ import com.gitee.sop.gatewaycommon.gateway.common.RequestContentDataExtractor;
import com.gitee.sop.gatewaycommon.gateway.common.SopServerHttpRequestDecorator; import com.gitee.sop.gatewaycommon.gateway.common.SopServerHttpRequestDecorator;
import com.gitee.sop.gatewaycommon.param.ApiParam; import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.param.FormHttpOutputMessage; import com.gitee.sop.gatewaycommon.param.FormHttpOutputMessage;
import com.gitee.sop.gatewaycommon.route.ForwardInfo;
import com.gitee.sop.gatewaycommon.param.ParamNames;
import com.gitee.sop.gatewaycommon.util.RequestUtil; import com.gitee.sop.gatewaycommon.util.RequestUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -57,20 +59,17 @@ public class ServerWebExchangeUtil {
* 重定向 * 重定向
* *
* @param exchange exchange * @param exchange exchange
* @param apiParam apiParam * @param forwardInfo forwardInfo
* @return 返回新的ServerWebExchange配合chain.filter(newExchange);使用 * @return 返回新的ServerWebExchange配合chain.filter(newExchange);使用
*/ */
public static ServerWebExchange getForwardExchange(ServerWebExchange exchange, ApiParam apiParam) { public static ServerWebExchange getForwardExchange(ServerWebExchange exchange, ForwardInfo forwardInfo) {
ServerHttpRequest newRequest = getForwardRequest(exchange.getRequest(), apiParam); ServerHttpRequest newRequest = exchange.getRequest()
.mutate()
.header(ParamNames.HEADER_VERSION_NAME, forwardInfo.getVersion())
.path(forwardInfo.getPath()).build();
return exchange.mutate().request(newRequest).build(); return exchange.mutate().request(newRequest).build();
} }
public static ServerHttpRequest getForwardRequest(ServerHttpRequest request, ApiParam apiParam) {
return request
.mutate()
.header(SopConstants.REDIRECT_VERSION_KEY, apiParam.fetchVersion())
.path(getForwardPath(apiParam)).build();
}
/** /**
* 构建一个接受请求体的request * 构建一个接受请求体的request
@ -113,19 +112,6 @@ public class ServerWebExchangeUtil {
return chain.filter(newExchange); return chain.filter(newExchange);
} }
private static String getForwardPath(ApiParam apiParam) {
// 如果有异常,则重定向到这个path
if (apiParam.getThrowable() != null) {
return VALIDATE_ERROR_PATH;
}
String forwardPath = UNKNOWN_PATH;
String method = apiParam.fetchName();
if (org.springframework.util.StringUtils.hasText(method)) {
forwardPath = "/" + method + "/";
}
return forwardPath;
}
public static ApiParam getApiParam(ServerWebExchange exchange, String body) { public static ApiParam getApiParam(ServerWebExchange exchange, String body) {
MediaType contentType = exchange.getRequest().getHeaders().getContentType(); MediaType contentType = exchange.getRequest().getHeaders().getContentType();
if (contentType == null) { if (contentType == null) {

@ -4,12 +4,12 @@ import com.gitee.sop.gatewaycommon.bean.ApiConfig;
import com.gitee.sop.gatewaycommon.gateway.controller.ConfigChannelController; import com.gitee.sop.gatewaycommon.gateway.controller.ConfigChannelController;
import com.gitee.sop.gatewaycommon.gateway.controller.ErrorLogController; import com.gitee.sop.gatewaycommon.gateway.controller.ErrorLogController;
import com.gitee.sop.gatewaycommon.gateway.controller.GatewayController; import com.gitee.sop.gatewaycommon.gateway.controller.GatewayController;
import com.gitee.sop.gatewaycommon.gateway.filter.EnvGrayFilter;
import com.gitee.sop.gatewaycommon.gateway.filter.GatewayModifyResponseGatewayFilter; import com.gitee.sop.gatewaycommon.gateway.filter.GatewayModifyResponseGatewayFilter;
import com.gitee.sop.gatewaycommon.gateway.filter.IndexFilter; import com.gitee.sop.gatewaycommon.gateway.filter.IndexFilter;
import com.gitee.sop.gatewaycommon.gateway.filter.LimitFilter; import com.gitee.sop.gatewaycommon.gateway.filter.LimitFilter;
import com.gitee.sop.gatewaycommon.gateway.filter.ParameterFormatterFilter; import com.gitee.sop.gatewaycommon.gateway.filter.ParameterFormatterFilter;
import com.gitee.sop.gatewaycommon.gateway.handler.GatewayExceptionHandler; import com.gitee.sop.gatewaycommon.gateway.handler.GatewayExceptionHandler;
import com.gitee.sop.gatewaycommon.gateway.route.GatewayForwardChooser;
import com.gitee.sop.gatewaycommon.gateway.route.GatewayRouteCache; import com.gitee.sop.gatewaycommon.gateway.route.GatewayRouteCache;
import com.gitee.sop.gatewaycommon.gateway.route.GatewayRouteRepository; import com.gitee.sop.gatewaycommon.gateway.route.GatewayRouteRepository;
import com.gitee.sop.gatewaycommon.manager.AbstractConfiguration; import com.gitee.sop.gatewaycommon.manager.AbstractConfiguration;
@ -107,10 +107,8 @@ public class BaseGatewayConfiguration extends AbstractConfiguration {
return gatewayRouteRepository; return gatewayRouteRepository;
} }
@Bean @Bean
EnvGrayFilter envGrayFilter() { GatewayForwardChooser gatewayForwardChooser() {
return new EnvGrayFilter(); return new GatewayForwardChooser();
} }
} }

@ -15,7 +15,10 @@ import reactor.core.publisher.Mono;
/** /**
* @author tanghc * @author tanghc
* @deprecated
* @see com.gitee.sop.gatewaycommon.gateway.route.GatewayForwardChooser
*/ */
@Deprecated
public class EnvGrayFilter implements GlobalFilter, Ordered { public class EnvGrayFilter implements GlobalFilter, Ordered {
@Autowired @Autowired

@ -1,11 +1,11 @@
package com.gitee.sop.gatewaycommon.gateway.filter; package com.gitee.sop.gatewaycommon.gateway.filter;
import com.gitee.sop.gatewaycommon.bean.SopConstants;
import com.gitee.sop.gatewaycommon.exception.ApiException; import com.gitee.sop.gatewaycommon.exception.ApiException;
import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil; import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil;
import com.gitee.sop.gatewaycommon.manager.EnvironmentContext; import com.gitee.sop.gatewaycommon.gateway.route.GatewayForwardChooser;
import com.gitee.sop.gatewaycommon.manager.EnvironmentKeys; import com.gitee.sop.gatewaycommon.manager.EnvironmentKeys;
import com.gitee.sop.gatewaycommon.param.ApiParam; import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.route.ForwardInfo;
import com.gitee.sop.gatewaycommon.validate.Validator; import com.gitee.sop.gatewaycommon.validate.Validator;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -16,12 +16,10 @@ import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator; import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.web.reactive.function.BodyInserter; import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilter;
@ -30,8 +28,6 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.net.URI; import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.Objects; import java.util.Objects;
/** /**
@ -50,6 +46,9 @@ public class IndexFilter implements WebFilter {
@Autowired @Autowired
private Validator validator; private Validator validator;
@Autowired
private GatewayForwardChooser gatewayForwardChooser;
@Override @Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
ServerHttpRequest request = exchange.getRequest(); ServerHttpRequest request = exchange.getRequest();
@ -92,9 +91,11 @@ public class IndexFilter implements WebFilter {
exchange, headers); exchange, headers);
return bodyInserter.insert(outputMessage, new BodyInserterContext()) return bodyInserter.insert(outputMessage, new BodyInserterContext())
.then(Mono.defer(() -> { .then(Mono.defer(() -> {
ForwardInfo forwardInfo = gatewayForwardChooser.getForwardInfo(exchange);
ServerHttpRequest decorator = decorate(exchange, headers, outputMessage); ServerHttpRequest decorator = decorate(exchange, headers, outputMessage);
ServerWebExchange newExchange = exchange.mutate().request(decorator).build(); ServerWebExchange newExchange = exchange.mutate().request(decorator).build();
return chain.filter(newExchange); ServerWebExchange forwardExchange = ServerWebExchangeUtil.getForwardExchange(newExchange, forwardInfo);
return chain.filter(forwardExchange);
})); }));
} else { } else {
@ -105,8 +106,9 @@ public class IndexFilter implements WebFilter {
ApiParam apiParam = ServerWebExchangeUtil.getApiParam(exchange, originalQuery); ApiParam apiParam = ServerWebExchangeUtil.getApiParam(exchange, originalQuery);
// 签名验证 // 签名验证
doValidate(apiParam); doValidate(apiParam);
ServerWebExchange newExchange = ServerWebExchangeUtil.getForwardExchange(exchange, apiParam); ForwardInfo forwardInfo = gatewayForwardChooser.getForwardInfo(exchange);
return chain.filter(newExchange); ServerWebExchange forwardExchange = ServerWebExchangeUtil.getForwardExchange(exchange, forwardInfo);
return chain.filter(forwardExchange);
} }
} else { } else {
return ServerWebExchangeUtil.forwardUnknown(exchange, chain); return ServerWebExchangeUtil.forwardUnknown(exchange, chain);
@ -127,9 +129,7 @@ public class IndexFilter implements WebFilter {
, HttpHeaders headers , HttpHeaders headers
, CachedBodyOutputMessage outputMessage , CachedBodyOutputMessage outputMessage
) { ) {
ApiParam apiParam = ServerWebExchangeUtil.getApiParam(exchange); return new ServerHttpRequestDecorator(exchange.getRequest()) {
ServerHttpRequest newRequest = ServerWebExchangeUtil.getForwardRequest(exchange.getRequest(), apiParam);
return new ServerHttpRequestDecorator(newRequest) {
@Override @Override
public HttpHeaders getHeaders() { public HttpHeaders getHeaders() {
long contentLength = headers.getContentLength(); long contentLength = headers.getContentLength();
@ -140,7 +140,6 @@ public class IndexFilter implements WebFilter {
} else { } else {
httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
} }
httpHeaders.set(SopConstants.REDIRECT_VERSION_KEY, apiParam.fetchVersion());
return httpHeaders; return httpHeaders;
} }

@ -0,0 +1,16 @@
package com.gitee.sop.gatewaycommon.gateway.route;
import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil;
import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.route.BaseForwardChooser;
import org.springframework.web.server.ServerWebExchange;
/**
* @author tanghc
*/
public class GatewayForwardChooser extends BaseForwardChooser<ServerWebExchange> {
@Override
protected ApiParam getApiParam(ServerWebExchange exchange) {
return ServerWebExchangeUtil.getApiParam(exchange);
}
}

@ -0,0 +1,54 @@
package com.gitee.sop.gatewaycommon.route;
import com.gitee.sop.gatewaycommon.bean.RouteDefinition;
import com.gitee.sop.gatewaycommon.bean.TargetRoute;
import com.gitee.sop.gatewaycommon.manager.EnvGrayManager;
import com.gitee.sop.gatewaycommon.manager.RouteRepositoryContext;
import com.gitee.sop.gatewaycommon.param.ApiParam;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @author tanghc
*/
public abstract class BaseForwardChooser<T> implements ForwardChooser<T> {
@Autowired
private EnvGrayManager envGrayManager;
protected abstract ApiParam getApiParam(T t);
@Override
public ForwardInfo getForwardInfo(T t) {
ApiParam apiParam = getApiParam(t);
ForwardInfo forwardInfo = new ForwardInfo();
String nameVersion = apiParam.fetchNameVersion();
TargetRoute targetRoute = RouteRepositoryContext.getRouteRepository().get(nameVersion);
RouteDefinition routeDefinitionOrig = targetRoute.getRouteDefinition();
String path = routeDefinitionOrig.getPath();
String versionInHead = apiParam.fetchVersion();
String serviceId = targetRoute.getServiceRouteInfo().fetchServiceIdLowerCase();
// 如果服务在灰度阶段,返回一个灰度版本号
String grayVersion = envGrayManager.getVersion(serviceId, nameVersion);
// 如果是灰度环境
if (grayVersion != null && envGrayManager.containsKey(serviceId, apiParam.fetchAppKey())) {
String newNameVersion = apiParam.fetchName() + grayVersion;
TargetRoute targetRouteDest = RouteRepositoryContext.getRouteRepository().get(newNameVersion);
if (targetRouteDest != null) {
if (BooleanUtils.toBoolean(routeDefinitionOrig.getCompatibleMode())) {
versionInHead = grayVersion;
} else {
// 获取灰度接口
RouteDefinition routeDefinition = targetRouteDest.getRouteDefinition();
path = routeDefinition.getPath();
}
}
}
forwardInfo.setPath(path);
forwardInfo.setVersion(versionInHead);
return forwardInfo;
}
}

@ -0,0 +1,16 @@
package com.gitee.sop.gatewaycommon.route;
/**
* 转发选择
* @author tanghc
*/
public interface ForwardChooser<T> {
/**
* 返回转发信息
* @param t 上下文
* @return 返回转发信息
*/
ForwardInfo getForwardInfo(T t);
}

@ -0,0 +1,13 @@
package com.gitee.sop.gatewaycommon.route;
import lombok.Data;
/**
* @author tanghc
*/
@Data
public class ForwardInfo {
private String path;
private String version;
private String domain;
}

@ -12,13 +12,13 @@ import com.gitee.sop.gatewaycommon.zuul.controller.ZuulIndexController;
import com.gitee.sop.gatewaycommon.zuul.filter.ErrorFilter; import com.gitee.sop.gatewaycommon.zuul.filter.ErrorFilter;
import com.gitee.sop.gatewaycommon.zuul.filter.FormBodyWrapperFilterExt; import com.gitee.sop.gatewaycommon.zuul.filter.FormBodyWrapperFilterExt;
import com.gitee.sop.gatewaycommon.zuul.filter.PostResultFilter; import com.gitee.sop.gatewaycommon.zuul.filter.PostResultFilter;
import com.gitee.sop.gatewaycommon.zuul.filter.PreEnvGrayFilter;
import com.gitee.sop.gatewaycommon.zuul.filter.PreHttpServletRequestWrapperFilter; import com.gitee.sop.gatewaycommon.zuul.filter.PreHttpServletRequestWrapperFilter;
import com.gitee.sop.gatewaycommon.zuul.filter.PreLimitFilter; import com.gitee.sop.gatewaycommon.zuul.filter.PreLimitFilter;
import com.gitee.sop.gatewaycommon.zuul.filter.PreParameterFormatterFilter; import com.gitee.sop.gatewaycommon.zuul.filter.PreParameterFormatterFilter;
import com.gitee.sop.gatewaycommon.zuul.filter.PreValidateFilter; import com.gitee.sop.gatewaycommon.zuul.filter.PreValidateFilter;
import com.gitee.sop.gatewaycommon.zuul.filter.Servlet30WrapperFilterExt; import com.gitee.sop.gatewaycommon.zuul.filter.Servlet30WrapperFilterExt;
import com.gitee.sop.gatewaycommon.zuul.route.SopRouteLocator; import com.gitee.sop.gatewaycommon.zuul.route.SopRouteLocator;
import com.gitee.sop.gatewaycommon.zuul.route.ZuulForwardChooser;
import com.gitee.sop.gatewaycommon.zuul.route.ZuulRouteCache; import com.gitee.sop.gatewaycommon.zuul.route.ZuulRouteCache;
import com.gitee.sop.gatewaycommon.zuul.route.ZuulRouteRepository; import com.gitee.sop.gatewaycommon.zuul.route.ZuulRouteRepository;
import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.context.RequestContext;
@ -26,7 +26,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper; import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties; import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter; import org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -89,22 +88,28 @@ public class BaseZuulConfiguration extends AbstractConfiguration {
return new Servlet30WrapperFilterExt(); return new Servlet30WrapperFilterExt();
} }
@Bean
SopRouteLocator sopRouteLocator() {
return new SopRouteLocator();
}
/** /**
* 选取路由 * 选取路由
* @param zuulRouteRepository * @param sopRouteLocator
* @param proxyRequestHelper * @param proxyRequestHelper
* @return * @return
*/ */
@Bean @Bean
PreDecorationFilter preDecorationFilter(ZuulRouteRepository zuulRouteRepository, ProxyRequestHelper proxyRequestHelper) { PreDecorationFilter preDecorationFilter(SopRouteLocator sopRouteLocator, ProxyRequestHelper proxyRequestHelper) {
// 自定义路由 // 自定义路由
RouteLocator routeLocator = new SopRouteLocator(zuulRouteRepository); return new PreDecorationFilter(sopRouteLocator,
return new PreDecorationFilter(routeLocator,
this.server.getServlet().getContextPath(), this.server.getServlet().getContextPath(),
this.zuulProperties, this.zuulProperties,
proxyRequestHelper); proxyRequestHelper);
} }
/** /**
* 路由管理 * 路由管理
* @param zuulRouteRepository 路由仓库 * @param zuulRouteRepository 路由仓库
@ -140,14 +145,6 @@ public class BaseZuulConfiguration extends AbstractConfiguration {
return new PreLimitFilter(); return new PreLimitFilter();
} }
/**
* 决定版本号
*/
@Bean
PreEnvGrayFilter preEnvGrayFilter() {
return new PreEnvGrayFilter();
}
/** /**
* 错误处理扩展 * 错误处理扩展
*/ */
@ -173,4 +170,9 @@ public class BaseZuulConfiguration extends AbstractConfiguration {
return ApiContext.getApiConfig().getZuulErrorController(); return ApiContext.getApiConfig().getZuulErrorController();
} }
@Bean
ZuulForwardChooser zuulForwardChooser() {
return new ZuulForwardChooser();
}
} }

@ -14,7 +14,10 @@ import org.springframework.beans.factory.annotation.Autowired;
* 灰度发布判断改变版本号 * 灰度发布判断改变版本号
* *
* @author tanghc * @author tanghc
* @deprecated
* @see com.gitee.sop.gatewaycommon.zuul.route.ZuulForwardChooser
*/ */
@Deprecated
public class PreEnvGrayFilter extends BaseZuulFilter { public class PreEnvGrayFilter extends BaseZuulFilter {
@Autowired @Autowired

@ -2,7 +2,11 @@ package com.gitee.sop.gatewaycommon.zuul.route;
import com.gitee.sop.gatewaycommon.bean.AbstractTargetRoute; import com.gitee.sop.gatewaycommon.bean.AbstractTargetRoute;
import com.gitee.sop.gatewaycommon.param.ApiParam; import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.route.ForwardInfo;
import com.gitee.sop.gatewaycommon.param.ParamNames;
import com.gitee.sop.gatewaycommon.zuul.ZuulContext; import com.gitee.sop.gatewaycommon.zuul.ZuulContext;
import com.netflix.zuul.context.RequestContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.Route; import org.springframework.cloud.netflix.zuul.filters.Route;
import org.springframework.cloud.netflix.zuul.filters.RouteLocator; import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
@ -19,11 +23,11 @@ import java.util.stream.Collectors;
*/ */
public class SopRouteLocator implements RouteLocator, Ordered { public class SopRouteLocator implements RouteLocator, Ordered {
@Autowired
private ZuulRouteRepository zuulRouteRepository; private ZuulRouteRepository zuulRouteRepository;
public SopRouteLocator(ZuulRouteRepository zuulRouteRepository) { @Autowired
this.zuulRouteRepository = zuulRouteRepository; private ZuulForwardChooser zuulForwardChooser;
}
@Override @Override
public Collection<String> getIgnoredPaths() { public Collection<String> getIgnoredPaths() {
@ -52,7 +56,13 @@ public class SopRouteLocator implements RouteLocator, Ordered {
if (zuulTargetRoute == null) { if (zuulTargetRoute == null) {
return null; return null;
} }
return zuulTargetRoute.getTargetRouteDefinition(); Route targetRouteDefinition = zuulTargetRoute.getTargetRouteDefinition();
ForwardInfo forwardInfo = zuulForwardChooser.getForwardInfo(RequestContext.getCurrentContext());
String forwardPath = forwardInfo.getPath();
targetRouteDefinition.setPath(forwardPath);
String versionInHead = forwardInfo.getVersion();
RequestContext.getCurrentContext().addZuulRequestHeader(ParamNames.HEADER_VERSION_NAME, versionInHead);
return targetRouteDefinition;
} }
@Override @Override

@ -0,0 +1,18 @@
package com.gitee.sop.gatewaycommon.zuul.route;
import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.route.BaseForwardChooser;
import com.gitee.sop.gatewaycommon.zuul.ZuulContext;
import com.netflix.zuul.context.RequestContext;
/**
* @author tanghc
*/
public class ZuulForwardChooser extends BaseForwardChooser<RequestContext> {
@Override
protected ApiParam getApiParam(RequestContext requestContext) {
return ZuulContext.getApiParam();
}
}

@ -34,6 +34,8 @@ public class ServiceApiInfo {
private int permission; private int permission;
/** 是否需要token */ /** 是否需要token */
private int needToken; private int needToken;
/** 是否是兼容模式,即使用了@ApiAbility注解 */
private int compatibleMode;
/** 是否是原始Mapping */ /** 是否是原始Mapping */
private boolean originalMapping; private boolean originalMapping;

@ -95,6 +95,7 @@ public class ApiMetaBuilder {
apiMeta.setMergeResult(BooleanUtils.toInteger(apiMappingInfo.isMergeResult())); apiMeta.setMergeResult(BooleanUtils.toInteger(apiMappingInfo.isMergeResult()));
apiMeta.setPermission(BooleanUtils.toInteger(apiMappingInfo.isPermission())); apiMeta.setPermission(BooleanUtils.toInteger(apiMappingInfo.isPermission()));
apiMeta.setNeedToken(BooleanUtils.toInteger(apiMappingInfo.isNeedToken())); apiMeta.setNeedToken(BooleanUtils.toInteger(apiMappingInfo.isNeedToken()));
apiMeta.setCompatibleMode(BooleanUtils.toInteger(apiMappingInfo.isCompatibleMode()));
return apiMeta; return apiMeta;
} else { } else {
if (!ServiceContext.getCurrentContext().getBoolean(ServiceContext.RESTFUL_KEY, false)) { if (!ServiceContext.getCurrentContext().getBoolean(ServiceContext.RESTFUL_KEY, false)) {

@ -5,6 +5,7 @@ import com.gitee.sop.servercommon.annotation.ApiMapping;
import com.gitee.sop.servercommon.bean.ServiceConfig; import com.gitee.sop.servercommon.bean.ServiceConfig;
import com.gitee.sop.servercommon.bean.ServiceContext; import com.gitee.sop.servercommon.bean.ServiceContext;
import com.gitee.sop.servercommon.util.OpenUtil; import com.gitee.sop.servercommon.util.OpenUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.core.PriorityOrdered; import org.springframework.core.PriorityOrdered;
import org.springframework.util.StringValueResolver; import org.springframework.util.StringValueResolver;
import org.springframework.web.servlet.mvc.condition.RequestCondition; import org.springframework.web.servlet.mvc.condition.RequestCondition;
@ -29,7 +30,11 @@ public class ApiMappingHandlerMapping extends RequestMappingHandlerMapping imple
ApiAbility apiAbility = OpenUtil.getAnnotationFromMethodOrClass(method, ApiAbility.class); ApiAbility apiAbility = OpenUtil.getAnnotationFromMethodOrClass(method, ApiAbility.class);
StringValueResolver valueResolver = null; StringValueResolver valueResolver = null;
if (apiMapping != null) { if (apiMapping != null) {
valueResolver = stringValueResolver; String version = apiMapping.version();
if (StringUtils.isBlank(version)) {
version = ServiceConfig.getInstance().getDefaultVersion();
}
valueResolver = new ApiMappingStringValueResolverVersion(version);
} }
if (isMvc || apiAbility != null) { if (isMvc || apiAbility != null) {
valueResolver = stringValueResolverMVC; valueResolver = stringValueResolverMVC;
@ -46,7 +51,8 @@ public class ApiMappingHandlerMapping extends RequestMappingHandlerMapping imple
boolean ignoreValidate; boolean ignoreValidate;
boolean mergeResult; boolean mergeResult;
boolean permission; boolean permission;
boolean needToken = false; boolean needToken;
boolean compatibleMode = false;
ApiMapping apiMapping = method.getAnnotation(ApiMapping.class); ApiMapping apiMapping = method.getAnnotation(ApiMapping.class);
if (apiMapping != null) { if (apiMapping != null) {
name = apiMapping.value()[0]; name = apiMapping.value()[0];
@ -63,6 +69,7 @@ public class ApiMappingHandlerMapping extends RequestMappingHandlerMapping imple
mergeResult = apiAbility.mergeResult(); mergeResult = apiAbility.mergeResult();
permission = apiAbility.permission(); permission = apiAbility.permission();
needToken = apiAbility.needToken(); needToken = apiAbility.needToken();
compatibleMode = true;
} else { } else {
return super.getCustomMethodCondition(method); return super.getCustomMethodCondition(method);
} }
@ -87,6 +94,7 @@ public class ApiMappingHandlerMapping extends RequestMappingHandlerMapping imple
apiMappingInfo.setMergeResult(mergeResult); apiMappingInfo.setMergeResult(mergeResult);
apiMappingInfo.setPermission(permission); apiMappingInfo.setPermission(permission);
apiMappingInfo.setNeedToken(needToken); apiMappingInfo.setNeedToken(needToken);
apiMappingInfo.setCompatibleMode(compatibleMode);
logger.info("注册接口,name:" + method + ", version:" + version); logger.info("注册接口,name:" + method + ", version:" + version);
return new ApiMappingRequestCondition(apiMappingInfo); return new ApiMappingRequestCondition(apiMappingInfo);
} }

@ -13,6 +13,8 @@ public class ApiMappingInfo {
private boolean mergeResult; private boolean mergeResult;
private boolean permission; private boolean permission;
private boolean needToken; private boolean needToken;
private boolean compatibleMode;
public ApiMappingInfo(String name, String version) { public ApiMappingInfo(String name, String version) {
this.name = name; this.name = name;

@ -37,6 +37,11 @@ public class ApiMappingRequestCondition implements RequestCondition<ApiMappingRe
*/ */
@Override @Override
public ApiMappingRequestCondition getMatchingCondition(HttpServletRequest request) { public ApiMappingRequestCondition getMatchingCondition(HttpServletRequest request) {
String servletPath = request.getServletPath();
String path = apiMappingInfo.getName() + "/" + apiMappingInfo.getVersion() + "/";
if (servletPath.contains(path)) {
return this;
}
String version = this.getVersion(request); String version = this.getVersion(request);
if (version.equals(this.apiMappingInfo.getVersion())) { if (version.equals(this.apiMappingInfo.getVersion())) {
return this; return this;

@ -0,0 +1,25 @@
package com.gitee.sop.servercommon.mapping;
import org.springframework.util.StringValueResolver;
/**
* @author tanghc
*/
public class ApiMappingStringValueResolverVersion implements StringValueResolver {
private static final String SPLIT = "/";
private String version;
public ApiMappingStringValueResolverVersion(String version) {
this.version = version;
}
@Override
public String resolveStringValue(String strVal) {
if (strVal == null) {
return null;
}
return strVal + SPLIT + version + SPLIT;
}
}

@ -73,4 +73,9 @@ public class RouteDefinition {
* 是否需要token * 是否需要token
*/ */
private int needToken; private int needToken;
/**
* 是否是兼容模式即使用了@ApiAbility注解
*/
private int compatibleMode;
} }

@ -180,7 +180,7 @@ public class AlipayController {
} }
// http://localhost:2222/alipay.story.get/ // http://localhost:2222/alipay.story.get/
@ApiOperation(value="获取故事信息2", notes = "获取故事信息2的详细信息") @ApiOperation(value="获取故事信息", notes = "获取故事信息的详细信息")
@ApiMapping(value = "alipay.story.get") @ApiMapping(value = "alipay.story.get")
public StoryResult getStory(StoryParam param) { public StoryResult getStory(StoryParam param) {
StoryResult story = new StoryResult(); StoryResult story = new StoryResult();
@ -193,6 +193,7 @@ public class AlipayController {
* @param param 对应biz_content中的内容并自动JSR-303校验 * @param param 对应biz_content中的内容并自动JSR-303校验
* @return * @return
*/ */
@ApiOperation(value="获取故事信息", notes = "获取故事信息的详细信息")
@ApiMapping(value = "alipay.story.get", version = "1.2") @ApiMapping(value = "alipay.story.get", version = "1.2")
public StoryResult getStory11(StoryParam param) { public StoryResult getStory11(StoryParam param) {
StoryResult story2 = new StoryResult(); StoryResult story2 = new StoryResult();

@ -1,24 +1,11 @@
server.port=8081 server.port=8081
# 固定不变,不能改
spring.application.name=sop-gateway
# ------- 需要改的配置 ------- # mysql数据库配置
# mysql数据库账号
mysql.host=localhost:3306 mysql.host=localhost:3306
mysql.username=root mysql.username=root
mysql.password=root mysql.password=root
# nacos地址 # nacos地址
nacos.url=127.0.0.1:8848 nacos.url=127.0.0.1:8848
# ------- 需要改的配置end -------
# nacos cloud配置
spring.cloud.nacos.discovery.server-addr=${nacos.url}
# 数据库配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://${mysql.host}/sop?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
spring.datasource.username=${mysql.username}
spring.datasource.password=${mysql.password}
logging.level.com.gitee=debug logging.level.com.gitee=debug

@ -96,12 +96,30 @@
</div> </div>
<div class="site-content"> <div class="site-content">
<h1 class="site-h1"><i class="layui-icon layui-icon-slider"></i> <span class="sop-name"></span>(<span <h1 class="site-h1">
class="sop-summary"></span>) <i class="layui-icon layui-icon-slider"></i><span class="sop-summary"></span> <span class="sop-version"></span>
</h1> </h1>
<blockquote class="layui-elem-quote layui-text sop-description">
</blockquote>
<div class="site-text">
<table class="layui-table">
<tbody>
<tr>
<td style="width: 60px;background-color: #f2f2f2;">接口名</td>
<td><span class="sop-name"></span></td>
<td style="width: 60px;background-color: #f2f2f2;">版本号</td>
<td style="width: 40px;"><span class="sop-version"></span></td>
</tr>
</tbody>
</table>
</div>
<div class="site-title">
<fieldset class="layui-elem-field layui-field-title site-title">
<legend>接口描述</legend>
</fieldset>
</div>
<!-- 接口描述 -->
<div class="site-text sop-description"></div>
<div class="site-title"> <div class="site-title">
<fieldset class="layui-elem-field layui-field-title site-title"> <fieldset class="layui-elem-field layui-field-title site-title">

@ -61,7 +61,7 @@ layui.config({
</li> </li>
*/ */
html.push('<li class="site-tree-noicon" nameversion="'+docItem.nameVersion+'">'); html.push('<li class="site-tree-noicon" nameversion="'+docItem.nameVersion+'">');
html.push('<a href="#"><cite>' + docItem['summary'] + '</cite></a>') html.push('<a href="#"><cite>' + docItem['summary'] + ' ' + docItem.version + '</cite></a>')
} }
} }

@ -77,11 +77,30 @@
</div> </div>
<div class="site-content"> <div class="site-content">
<h1 class="site-h1"><i class="layui-icon layui-icon-slider"></i> <span class="sop-name"></span>(<span <h1 class="site-h1">
class="sop-summary"></span>) <i class="layui-icon layui-icon-slider"></i><span class="sop-summary"></span> <span class="sop-version"></span>
</h1> </h1>
<blockquote class="layui-elem-quote layui-text sop-description">
</blockquote> <div class="site-text">
<table class="layui-table">
<tbody>
<tr>
<td style="width: 60px;background-color: #f2f2f2;">接口名</td>
<td><span class="sop-name"></span></td>
<td style="width: 60px;background-color: #f2f2f2;">版本号</td>
<td style="width: 40px;"><span class="sop-version"></span></td>
</tr>
</tbody>
</table>
</div>
<div class="site-title">
<fieldset class="layui-elem-field layui-field-title site-title">
<legend>接口描述</legend>
</fieldset>
</div>
<!-- 接口描述 -->
<div class="site-text sop-description"></div>
<div class="site-title"> <div class="site-title">
<fieldset class="layui-elem-field layui-field-title site-title"> <fieldset class="layui-elem-field layui-field-title site-title">

Loading…
Cancel
Save