diff --git a/pom.xml b/pom.xml index 7804453f..8cdce044 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ sop-registry sop-gateway sop-gateway-common - sop-server-common + sop-service-common sop-story sop-book sop-test diff --git a/sop-gateway-common/pom.xml b/sop-gateway-common/pom.xml index 9c1c6bf9..c134af45 100644 --- a/sop-gateway-common/pom.xml +++ b/sop-gateway-common/pom.xml @@ -45,10 +45,52 @@ + + + + + org.springframework.cloud - spring-cloud-starter-netflix-zuul + spring-cloud-starter-gateway + + + org.springframework.boot + spring-boot-starter-webflux + + org.springframework.boot + spring-boot-starter-actuator + + + + + org.springframework.cloud + spring-cloud-starter-zookeeper-all + + + + org.springframework.cloud + spring-cloud-starter-zookeeper-discovery + + + org.apache.zookeeper + zookeeper + + + + + org.apache.zookeeper + zookeeper + 3.4.12 + + + org.slf4j + slf4j-log4j12 + + + + org.springframework.boot spring-boot-starter-test @@ -70,6 +112,11 @@ spring-boot-starter-data-redis + + org.apache.commons + commons-lang3 + 3.8.1 + commons-collections commons-collections @@ -96,6 +143,18 @@ 1.18.4 provided + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + org.springframework.cloud + spring-cloud-netflix-ribbon + 2.1.0.RELEASE + compile + diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java index 47168791..a169989c 100644 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java @@ -1,13 +1,9 @@ package com.gitee.sop.gatewaycommon.bean; -import com.gitee.sop.gatewaycommon.configuration.BaseZuulController; -import com.gitee.sop.gatewaycommon.param.ApiParamParser; -import com.gitee.sop.gatewaycommon.param.ParamParser; +import com.gitee.sop.gatewaycommon.param.ApiParamBuilder; +import com.gitee.sop.gatewaycommon.param.ParamBuilder; import com.gitee.sop.gatewaycommon.result.ApiResultExecutor; -import com.gitee.sop.gatewaycommon.result.JsonResultSerializer; import com.gitee.sop.gatewaycommon.result.ResultExecutor; -import com.gitee.sop.gatewaycommon.result.ResultSerializer; -import com.gitee.sop.gatewaycommon.result.XmlResultSerializer; import com.gitee.sop.gatewaycommon.secret.AppSecretManager; import com.gitee.sop.gatewaycommon.secret.CacheAppSecretManager; import com.gitee.sop.gatewaycommon.session.ApiSessionManager; @@ -40,15 +36,6 @@ public class ApiConfig { */ private ResultExecutor resultExecutor = new ApiResultExecutor(); - /** - * json序列化 - */ - private ResultSerializer jsonResultSerializer = new JsonResultSerializer(); - /** - * xml序列化 - */ - private ResultSerializer xmlResultSerializer = new XmlResultSerializer(); - /** * app秘钥管理 */ @@ -65,9 +52,9 @@ public class ApiConfig { private Signer signer = new ApiSigner(); /** - * 参数解析 + * 参数解析,gateway */ - private ParamParser paramParser = new ApiParamParser(); + private ParamBuilder paramBuilder = new ApiParamBuilder(); /** * 验证 @@ -84,12 +71,6 @@ public class ApiConfig { */ private List i18nModules = new ArrayList(); - /** - * 基础Controller - */ - private BaseZuulController baseZuulController = new BaseZuulController(); - - // -------- fields --------- /** * 忽略验证 diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiContext.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiContext.java index 72ff62d7..56ecd462 100644 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiContext.java +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiContext.java @@ -1,149 +1,29 @@ package com.gitee.sop.gatewaycommon.bean; -import com.gitee.sop.gatewaycommon.param.UploadContext; -import com.netflix.zuul.context.RequestContext; -import com.gitee.sop.gatewaycommon.param.ApiParam; import com.gitee.sop.gatewaycommon.session.SessionManager; -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import java.util.Locale; +//import com.netflix.zuul.context.RequestContext; /** * 应用上下文,方便获取信息 - * - * @author tanghc * + * @author tanghc */ public class ApiContext { - private static final String ATTR_PARAM = "zuul.common.api.param"; - private static final String ATTR_UPLOAD_CONTEXT = "zuul.common.api.upload_context"; - - private ApiContext(){} - - private static void setAttr(String name, Object val) { - HttpServletRequest request = getRequest(); - if (request != null) { - request.setAttribute(name, val); - } - } - - private static Object getAttr(String name) { - HttpServletRequest request = getRequest(); - if (request == null) { - return null; - } - return request.getAttribute(name); - } - /** - * 获取随机码 - * @return 返回随机码 - */ - public static String getRandomKey() { - HttpSession session = getSession(); - if (session == null) { - return null; - } - return (String) session.getAttribute(SopConstants.RANDOM_KEY_NAME); - } - - - - /** - * 获取HttpServletRequest - * - * @return HttpServletRequest - */ - public static HttpServletRequest getRequest() { - return RequestContext.getCurrentContext().getRequest(); + private ApiContext() { } - /** - * 返回默认的HttpServletRequest.getSession(); - * - * @return 没有返回null - */ - public static HttpSession getSession() { - HttpServletRequest req = getRequest(); - if (req == null) { - return null; - } else { - return req.getSession(); - } - } /** * 获取session管理器 + * * @return 返回SessionManager */ public static SessionManager getSessionManager() { return getApiConfig().getSessionManager(); } - /** - * 返回自定义的session,被SessionManager管理 - * - * @return 如果sessionId为null,则返回null - */ - public static HttpSession getManagedSession() { - String sessionId = getSessionId(); - if (sessionId != null) { - return getSessionManager().getSession(sessionId); - } else { - return null; - } - } - - /** - * 同getSessionId() - * @return 返回accessToken,没有返回null - */ - public static String getAccessToken() { - return getSessionId(); - } - - - /** - * 获取登陆的token - * - * @return 没有返回null - */ - public static String getSessionId() { - ApiParam apiParam = getApiParam(); - if (apiParam == null) { - return null; - } - return apiParam.fetchAccessToken(); - } - - /** - * 获取本地化,从HttpServletRequest中获取,没有则返回Locale.SIMPLIFIED_CHINESE - * - * @return Locale - */ - public static Locale getLocale() { - HttpServletRequest req = getRequest(); - if (req == null) { - return Locale.SIMPLIFIED_CHINESE; - } - return req.getLocale(); - } - - public static void setApiParam(ApiParam apiParam) { - setAttr(ATTR_PARAM, apiParam); - } - - /** - * 获取系统参数 - * - * @return 返回ApiParam - */ - public static ApiParam getApiParam() { - return (ApiParam) getAttr(ATTR_PARAM); - } public static ApiConfig getApiConfig() { return ApiConfig.getInstance(); @@ -153,34 +33,4 @@ public class ApiContext { ApiConfig.setInstance(apiConfig); } - - public static ServletContext getServletContext() { - ServletContext ctx = null; - HttpSession session = getSession(); - if (session != null) { - ctx = session.getServletContext(); - } - return ctx; - } - - /** - * 获取上传文件,如果客户端有文件上传,从这里取。 - * @return 如果没有文件上传,返回null - */ - public static UploadContext getUploadContext() { - return (UploadContext) getAttr(ATTR_UPLOAD_CONTEXT); - } - - public static void setUploadContext(UploadContext uploadCtx) { - setAttr(ATTR_UPLOAD_CONTEXT, uploadCtx); - } - - /** - * 获取response - * @return 返回response - */ - public static HttpServletResponse getResponse() { - return RequestContext.getCurrentContext().getResponse(); - } - } diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/RequestMode.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/RequestMode.java deleted file mode 100644 index 8fb274a8..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/RequestMode.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.gitee.sop.gatewaycommon.bean; - -/** - * @author tanghc - */ -public enum RequestMode { - - /** - * 数字签名请求模式 - */ - SIGNATURE, - /** - * 公私钥加密模式,这样请求和返回的数据都经过加密处理 - */ - ENCRYPT - -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/SopConstants.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/SopConstants.java index d6fd6123..a1a2d9c0 100644 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/SopConstants.java +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/SopConstants.java @@ -8,9 +8,9 @@ import java.nio.charset.StandardCharsets; */ public class SopConstants { - public static final String NULL = "null"; public static final String RANDOM_KEY_NAME = "ssl_randomKey"; public static final Charset CHARSET_UTF8 = StandardCharsets.UTF_8; + public static final String UTF8 = "UTF-8"; public static final String FORMAT_JSON = "json"; public static final String FORMAT_XML = "xml"; public static final String AUTHORIZATION = "Authorization"; @@ -30,4 +30,21 @@ public class SopConstants { public static final String REST_PARAM_NAME = "_REST_PARAM_NAME_"; public static final String REST_PARAM_VERSION = "_REST_PARAM_VERSION_"; + + /** + * 在拦截器中调用获取参数: + * String cachedBody = (String)exchange.getAttribute(SopConstants.CACHE_REQUEST_BODY_OBJECT_KEY); + */ + public static final String CACHE_REQUEST_BODY_OBJECT_KEY = "cachedRequestBodyObject"; + + /** + * 在拦截器中调用获取参数: + * Map params = exchange.getAttribute(SopConstants.CACHE_REQUEST_BODY_FOR_MAP); + */ + public static final String CACHE_REQUEST_BODY_FOR_MAP = "cacheRequestBodyForMap"; + + public static final String CACHE_API_PARAM = "cacheApiParam"; + + public static final String X_BIZ_ERROR_CODE = "x-biz-error-code"; + } diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/AlipayZuulConfiguration.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/AlipayGatewayConfiguration.java similarity index 82% rename from sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/AlipayZuulConfiguration.java rename to sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/AlipayGatewayConfiguration.java index 0c341582..4522b5df 100644 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/AlipayZuulConfiguration.java +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/AlipayGatewayConfiguration.java @@ -8,7 +8,7 @@ import com.gitee.sop.gatewaycommon.validate.alipay.AlipaySigner; * * @author tanghc */ -public class AlipayZuulConfiguration extends BaseZuulConfiguration { +public class AlipayGatewayConfiguration extends BaseGatewayConfiguration { static { ApiContext.getApiConfig().setSigner(new AlipaySigner()); diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/BaseGatewayConfiguration.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/BaseGatewayConfiguration.java new file mode 100644 index 00000000..8fa3d041 --- /dev/null +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/BaseGatewayConfiguration.java @@ -0,0 +1,118 @@ +package com.gitee.sop.gatewaycommon.configuration; + +import com.gitee.sop.gatewaycommon.bean.ApiContext; +import com.gitee.sop.gatewaycommon.handler.GatewayExceptionHandler; +import com.gitee.sop.gatewaycommon.filter.GatewayModifyResponseGatewayFilter; +import com.gitee.sop.gatewaycommon.filter.LoadBalancerClientExtFilter; +import com.gitee.sop.gatewaycommon.filter.ValidateFilter; +import com.gitee.sop.gatewaycommon.manager.GatewayZookeeperApiMetaManager; +import com.gitee.sop.gatewaycommon.message.ErrorFactory; +import com.gitee.sop.gatewaycommon.route.DynamicRouteServiceManager; +import com.gitee.sop.gatewaycommon.route.NameVersionRoutePredicateFactory; +import com.gitee.sop.gatewaycommon.route.ReadBodyRoutePredicateFactory; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.core.env.Environment; +import org.springframework.http.codec.ServerCodecConfigurer; +import org.springframework.web.reactive.result.view.ViewResolver; + +import javax.annotation.PostConstruct; +import java.util.Collections; +import java.util.List; + +//import com.gitee.sop.gatewaycommon.filter.ErrorFilter; +//import com.gitee.sop.gatewaycommon.filter.PostResultFilter; +//import com.gitee.sop.gatewaycommon.filter.PreValidateFilter; +//import com.gitee.sop.gatewaycommon.manager.DefaultApiMetaContext; +//import com.gitee.sop.gatewaycommon.manager.SopRouteLocator; +//import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper; +//import org.springframework.cloud.netflix.zuul.filters.ZuulProperties; +//import org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter; + +/** + * @author tanghc + */ +public class BaseGatewayConfiguration { + + @Autowired + protected Environment environment; + + @Autowired + protected GatewayZookeeperApiMetaManager gatewayZookeeperApiMetaManager; + + /** + * 自定义异常处理[@@]注册Bean时依赖的Bean,会从容器中直接获取,所以直接注入即可 + * + * @param viewResolversProvider + * @param serverCodecConfigurer + * @return + */ + @Primary + @Bean + @Order(Ordered.HIGHEST_PRECEDENCE) + public ErrorWebExceptionHandler errorWebExceptionHandler(ObjectProvider> viewResolversProvider, + ServerCodecConfigurer serverCodecConfigurer) { + + GatewayExceptionHandler jsonExceptionHandler = new GatewayExceptionHandler(); + jsonExceptionHandler.setViewResolvers(viewResolversProvider.getIfAvailable(Collections::emptyList)); + jsonExceptionHandler.setMessageWriters(serverCodecConfigurer.getWriters()); + jsonExceptionHandler.setMessageReaders(serverCodecConfigurer.getReaders()); + return jsonExceptionHandler; + } + + @Bean + GatewayModifyResponseGatewayFilter gatewayModifyResponseGatewayFilter() { + return new GatewayModifyResponseGatewayFilter(); + } + + @Bean + ReadBodyRoutePredicateFactory readBodyRoutePredicateFactory() { + return new ReadBodyRoutePredicateFactory(); + } + + @Bean + NameVersionRoutePredicateFactory paramRoutePredicateFactory() { + return new NameVersionRoutePredicateFactory(); + } + + @Bean + ValidateFilter validateFilter() { + return new ValidateFilter(); + } + + @Bean + LoadBalancerClientExtFilter loadBalancerClientExtFilter() { + return new LoadBalancerClientExtFilter(); + } + + @Bean + GatewayZookeeperApiMetaManager zookeeperApiMetaManager(Environment environment, DynamicRouteServiceManager dynamicRouteServiceManager) { + return new GatewayZookeeperApiMetaManager(environment, dynamicRouteServiceManager); + } + + @Bean + DynamicRouteServiceManager dynamicRouteServiceManager() { + return new DynamicRouteServiceManager(); + } + + + @PostConstruct + public void after() { + doAfter(); + } + + protected void doAfter() { + initMessage(); + gatewayZookeeperApiMetaManager.refresh(); + } + + protected void initMessage() { + ErrorFactory.initMessageSource(ApiContext.getApiConfig().getI18nModules()); + } + +} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/BaseZuulConfiguration.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/BaseZuulConfiguration.java deleted file mode 100644 index 704ed496..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/BaseZuulConfiguration.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.gitee.sop.gatewaycommon.configuration; - -import com.gitee.sop.gatewaycommon.bean.ApiContext; -import com.gitee.sop.gatewaycommon.filter.ErrorFilter; -import com.gitee.sop.gatewaycommon.filter.PostResultFilter; -import com.gitee.sop.gatewaycommon.filter.PreValidateFilter; -import com.gitee.sop.gatewaycommon.manager.ApiMetaChangeListener; -import com.gitee.sop.gatewaycommon.manager.ApiMetaContext; -import com.gitee.sop.gatewaycommon.manager.ApiMetaManager; -import com.gitee.sop.gatewaycommon.manager.DefaultApiMetaContext; -import com.gitee.sop.gatewaycommon.manager.DefaultApiMetaManager; -import com.gitee.sop.gatewaycommon.manager.SopRouteLocator; -import com.gitee.sop.gatewaycommon.message.ErrorFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.web.ServerProperties; -import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper; -import org.springframework.cloud.netflix.zuul.filters.ZuulProperties; -import org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter; -import org.springframework.context.annotation.Bean; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.data.redis.listener.PatternTopic; -import org.springframework.data.redis.listener.RedisMessageListenerContainer; - -import javax.annotation.PostConstruct; - -/** - * @author tanghc - */ -public class BaseZuulConfiguration { - - public static final String API_CHANGE_CHANNEL = "channel.sop.api.change"; - - - @Autowired - protected ZuulProperties zuulProperties; - - @Autowired - protected ServerProperties server; - - @Autowired - protected ApiMetaManager apiMetaManager; - - @Bean - public ApiMetaContext apiMetaContext() { - return new DefaultApiMetaContext(); - } - - @Bean - public ApiMetaManager apiMetaManager(StringRedisTemplate stringRedisTemplate, ApiMetaContext apiMetaContext) { - return new DefaultApiMetaManager(stringRedisTemplate, apiMetaContext); - } - - @Bean - PreValidateFilter preValidateFilter() { - return new PreValidateFilter(); - } - - @Bean - public PreDecorationFilter preDecorationFilter(ApiMetaContext apiMetaContext, ProxyRequestHelper proxyRequestHelper) { - SopRouteLocator routeLocator = new SopRouteLocator(apiMetaContext); - return new PreDecorationFilter(routeLocator, - this.server.getServlet().getContextPath(), - this.zuulProperties, - proxyRequestHelper); - } - - @Bean - ErrorFilter errorFilter() { - return new ErrorFilter(); - } - - @Bean - PostResultFilter postResultFilter() { - return new PostResultFilter(); - } - - /** - * 配置redis事件订阅 - * - * @param apiMetaManager - * @param redisTemplate - * @return - */ - @Bean - RedisMessageListenerContainer container(ApiMetaManager apiMetaManager, StringRedisTemplate redisTemplate) { - RedisMessageListenerContainer container = new RedisMessageListenerContainer(); - container.setConnectionFactory(redisTemplate.getConnectionFactory()); - ApiMetaChangeListener apiMetaChangeListener = new ApiMetaChangeListener(apiMetaManager, redisTemplate); - container.addMessageListener(apiMetaChangeListener, new PatternTopic(API_CHANGE_CHANNEL)); - return container; - } - - @Bean - BaseZuulController baseZuulController() { - return ApiContext.getApiConfig().getBaseZuulController(); - } - - @PostConstruct - public void after() { - doAfter(); - } - - protected void doAfter() { - initMessage(); - apiMetaManager.refresh(); - } - - protected void initMessage() { - ErrorFactory.initMessageSource(ApiContext.getApiConfig().getI18nModules()); - } - -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/BaseZuulController.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/BaseZuulController.java deleted file mode 100644 index 37c3c2d7..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/BaseZuulController.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.gitee.sop.gatewaycommon.configuration; - -import com.gitee.sop.gatewaycommon.bean.ApiContext; -import com.gitee.sop.gatewaycommon.result.ResultExecutor; -import com.netflix.zuul.context.RequestContext; -import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.web.servlet.error.ErrorController; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * 处理网关自身异常 - * - * @author tanghc - */ -@Controller -@Slf4j -public class BaseZuulController implements ErrorController { - - public static final String ERROR_PATH = "/error"; - - /** - * 错误最终会到这里来 - */ - @RequestMapping(ERROR_PATH) - @ResponseBody - public Object error(HttpServletRequest request, HttpServletResponse response) { - RequestContext ctx = RequestContext.getCurrentContext(); - Throwable throwable = ctx.getThrowable(); - return this.buildResult(throwable); - } - - protected Object buildResult(Throwable throwable) { - ResultExecutor resultExecutor = ApiContext.getApiConfig().getResultExecutor(); - return resultExecutor.mergeError(throwable); - } - - @Override - public String getErrorPath() { - return ERROR_PATH; - } -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/TaobaoZuulConfiguration.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/TaobaoGatewayConfiguration.java similarity index 89% rename from sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/TaobaoZuulConfiguration.java rename to sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/TaobaoGatewayConfiguration.java index ef3dd3e2..40774b7f 100644 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/TaobaoZuulConfiguration.java +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/configuration/TaobaoGatewayConfiguration.java @@ -9,7 +9,7 @@ import com.gitee.sop.gatewaycommon.validate.taobao.TaobaoSigner; * 淘宝开放平台:http://open.taobao.com/doc.htm * @author tanghc */ -public class TaobaoZuulConfiguration extends BaseZuulConfiguration { +public class TaobaoGatewayConfiguration extends BaseGatewayConfiguration { static { ParamNames.APP_KEY_NAME = "app_key"; diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/easyopen/EasyopenRoute.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/easyopen/EasyopenRoute.java deleted file mode 100644 index 7a827c0f..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/easyopen/EasyopenRoute.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.gitee.sop.gatewaycommon.easyopen; - -import org.springframework.cloud.netflix.zuul.filters.Route; - -import java.util.Collections; -import java.util.Set; - -/** - * @author tanghc - */ -public class EasyopenRoute extends Route { - public EasyopenRoute(String id, String path, String location, String prefix, Boolean retryable, Set ignoredHeaders) { - super(id, path, location, prefix, retryable, ignoredHeaders); - } - - public EasyopenRoute(String id, String location) { - this(id, "/" + location + "/", location, "", false, Collections.emptySet()); - } - -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/easyopen/EasyopenZuulConfig.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/easyopen/EasyopenZuulConfig.java deleted file mode 100644 index 50f42a78..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/easyopen/EasyopenZuulConfig.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.gitee.sop.gatewaycommon.easyopen; - -import com.gitee.sop.gatewaycommon.filter.ErrorFilter; -import com.gitee.sop.gatewaycommon.filter.PostResultFilter; -import com.gitee.sop.gatewaycommon.easyopen.filter.PostEasyopenResultFilter; -import com.gitee.sop.gatewaycommon.filter.PreValidateFilter; -import com.gitee.sop.gatewaycommon.manager.ApiMetaContext; -import com.gitee.sop.gatewaycommon.manager.ApiMetaManager; -import com.gitee.sop.gatewaycommon.manager.DefaultApiMetaContext; -import com.gitee.sop.gatewaycommon.manager.DefaultApiMetaManager; -import com.gitee.sop.gatewaycommon.manager.SopRouteLocator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.web.ServerProperties; -import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper; -import org.springframework.cloud.netflix.zuul.filters.ZuulProperties; -import org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter; -import org.springframework.context.annotation.Bean; -import org.springframework.data.redis.core.StringRedisTemplate; - -import javax.annotation.PostConstruct; - -/** - * @author tanghc - */ -public class EasyopenZuulConfig { - - @Autowired - protected ZuulProperties zuulProperties; - - @Autowired - protected ServerProperties server; - - @Autowired - protected ApiMetaManager apiMetaManager; - - @Bean - public ApiMetaContext apiMetaContext() { - return new DefaultApiMetaContext(); - } - - @Bean - public ApiMetaManager apiMetaManager(StringRedisTemplate stringRedisTemplate, ApiMetaContext apiMetaContext) { - return new DefaultApiMetaManager(stringRedisTemplate, apiMetaContext); - } - - @Bean - public PreDecorationFilter preDecorationFilter(ApiMetaContext apiMetaContext, ProxyRequestHelper proxyRequestHelper) { - SopRouteLocator routeLocator = new SopRouteLocator(apiMetaContext); - return new PreDecorationFilter(routeLocator, - this.server.getServlet().getContextPath(), - this.zuulProperties, - proxyRequestHelper); - } - - @Bean - PreValidateFilter preValidateFilter() { - return new PreValidateFilter(); - } - - @Bean - ErrorFilter errorFilter() { - return new ErrorFilter(); - } - - @Bean - PostResultFilter postResultFilter() { - return new PostEasyopenResultFilter(); - } - - @PostConstruct - public void after() { - apiMetaManager.refresh(); - } -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/easyopen/filter/PostEasyopenResultFilter.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/easyopen/filter/PostEasyopenResultFilter.java deleted file mode 100644 index 38316134..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/easyopen/filter/PostEasyopenResultFilter.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.gitee.sop.gatewaycommon.easyopen.filter; - -import com.gitee.sop.gatewaycommon.filter.PostResultFilter; - -/** - * 合并微服务结果,统一返回格式 - * - * @author tanghc - */ -public class PostEasyopenResultFilter extends PostResultFilter { - private static final String EASYOPEN_SUCCESS_CODE = "0"; -// -// protected Result processServiceResult(InputStream responseDataStream, ResultBuilder resultBuilder) throws IOException { -// String responseBody = IOUtils.toString(responseDataStream, SopConstants.CHARSET_UTF8); -// ApiResult result = this.parseApiResult(responseBody); -// Result finalResult; -// if (EASYOPEN_SUCCESS_CODE.equals(result.getCode())) { -// finalResult = resultBuilder.buildSuccessResult(GATEWAY_SUCCESS_CODE, null, result.getData()); -// } else { -// // 业务出错 -// finalResult = resultBuilder.buildServiceError(result.getCode(), result.getMsg()); -// } -// return finalResult; -// } -// -// protected ApiResult parseApiResult(String responseBody) { -// ApiParam apiParam = ApiContext.getApiParam(); -// String format = apiParam.fetchFormat(); -// return SopConstants.FORMAT_XML.equalsIgnoreCase(format) -// ? XmlUtil.unserialize(responseBody, ApiResult.class) -// : JSON.parseObject(responseBody, ApiResult.class); -// } -// -// protected ResultSerializer buildResultSerializer(HttpServletRequest request, ApiConfig apiConfig) { -// ApiParam apiParam = ApiContext.getApiParam(); -// String format = apiParam.fetchFormat(); -// if (SopConstants.FORMAT_JSON.equalsIgnoreCase(format)) { -// return apiConfig.getJsonResultSerializer(); -// } else if (SopConstants.FORMAT_XML.equalsIgnoreCase(format)) { -// // xml格式输出 -// return apiConfig.getXmlResultSerializer(); -// } else { -// throw ErrorEnum.isv_invalid_format.getErrorMeta().getException(); -// } -// } -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/BaseZuulFilter.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/BaseZuulFilter.java deleted file mode 100644 index e5459948..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/BaseZuulFilter.java +++ /dev/null @@ -1,117 +0,0 @@ -package com.gitee.sop.gatewaycommon.filter; - -import com.alibaba.fastjson.JSON; -import com.gitee.sop.gatewaycommon.result.ApiResult; -import com.netflix.zuul.ZuulFilter; -import com.netflix.zuul.context.RequestContext; -import com.netflix.zuul.exception.ZuulException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author tanghc - */ -public abstract class BaseZuulFilter extends ZuulFilter { - - protected Logger log = LoggerFactory.getLogger(getClass()); - - private Integer filterOrder; - - /** - * 获取过滤器类型 - * @return 返回FilterType - * @see ZuulFilter#filterType() filterType() - */ - protected abstract FilterType getFilterType(); - - /** - * 获取过滤器顺序 - * @return - * @see ZuulFilter#filterOrder() filterOrder() - */ - protected abstract int getFilterOrder(); - - /** - * 执行run - * @param requestContext - * @return - * @throws ZuulException - */ - protected abstract Object doRun(RequestContext requestContext) throws ZuulException; - - /** - * 设置过滤器顺序 - * - * @param filterOrder 顺序,值越小优先执行 - * @return 返回自身对象 - */ - public BaseZuulFilter order(int filterOrder) { - this.filterOrder = filterOrder; - return this; - } - - @Override - public int filterOrder() { - return filterOrder != null ? filterOrder : this.getFilterOrder(); - } - - @Override - public String filterType() { - return this.getFilterType().getType(); - } - - @Override - public boolean shouldFilter() { - return true; - } - - @Override - public Object run() throws ZuulException { - return this.doRun(RequestContext.getCurrentContext()); - } - - /** - * 过滤该请求,不往下级服务去转发请求,到此结束。并填充responseBody - * - * @param requestContext - * @param result - */ - public static void stopRouteAndReturn(RequestContext requestContext, Object result) { - requestContext.setSendZuulResponse(false); - requestContext.setResponseBody(JSON.toJSONString(result)); - } - - public static void main(String[] args) { - System.out.println(JSON.toJSONString(new ApiResult())); - } - - /** - * to classify a filter by type. Standard types in Zuul are "pre" for pre-routing filtering, - * "route" for routing to an origin, "post" for post-routing filters, "error" for error handling. - * We also support a "static" type for static responses see StaticResponseFilter. - * Any filterType made be created or added and doRun by calling FilterProcessor.runFilters(type) - */ - public enum FilterType { - /** zuul过滤器pre类型 */ - PRE("pre"), - /** zuul过滤器route类型 */ - ROUTE("route"), - /** zuul过滤器post类型 */ - POST("post"), - /** zuul过滤器error类型 */ - ERROR("error"), - /** zuul过滤器static类型 */ - STATIC("static"), - ; - - FilterType(String type) { - this.type = type; - } - - private String type; - - public String getType() { - return type; - } - } -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/ErrorFilter.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/ErrorFilter.java deleted file mode 100644 index e476c7d6..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/ErrorFilter.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.gitee.sop.gatewaycommon.filter; - -import com.netflix.zuul.FilterProcessor; -import com.netflix.zuul.ZuulFilter; -import com.netflix.zuul.context.RequestContext; -import com.netflix.zuul.exception.ZuulException; -import org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter; -import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; - -/** - * @author tanghc - */ -public class ErrorFilter extends SendErrorFilter { - - public static final String FAILED_FILTER = "failed.filter"; - - private int filterOrder = 10; - - public ErrorFilter() { - initFilterProcessor(); - } - - public void initFilterProcessor() { - FilterProcessor instance = FilterProcessor.getInstance(); - if (!(instance instanceof MyFilterProcessor)) { - FilterProcessor.setProcessor(new MyFilterProcessor()); - } - } - - @Override - public int filterOrder() { - return filterOrder; - } - - @Override - public boolean shouldFilter() { - // 判断:仅处理来自post过滤器引起的异常 - RequestContext ctx = RequestContext.getCurrentContext(); - ZuulFilter failedFilter = (ZuulFilter) ctx.get(FAILED_FILTER); - return failedFilter != null && failedFilter.filterType().equals(FilterConstants.POST_TYPE); - } - - public static class MyFilterProcessor extends FilterProcessor { - @Override - public Object processZuulFilter(ZuulFilter filter) throws ZuulException { - try { - return super.processZuulFilter(filter); - } catch (ZuulException e) { - RequestContext ctx = RequestContext.getCurrentContext(); - ctx.set(FAILED_FILTER, filter); - throw e; - } - } - } - - public void setFilterOrder(int filterOrder) { - this.filterOrder = filterOrder; - } -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/GatewayModifyResponseGatewayFilter.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/GatewayModifyResponseGatewayFilter.java new file mode 100644 index 00000000..b506c021 --- /dev/null +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/GatewayModifyResponseGatewayFilter.java @@ -0,0 +1,131 @@ +package com.gitee.sop.gatewaycommon.filter; + +import com.gitee.sop.gatewaycommon.bean.ApiContext; +import com.gitee.sop.gatewaycommon.result.ResultExecutor; +import org.reactivestreams.Publisher; +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter; +import org.springframework.cloud.gateway.filter.factory.rewrite.ModifyResponseBodyGatewayFilterFactory; +import org.springframework.cloud.gateway.support.BodyInserterContext; +import org.springframework.cloud.gateway.support.CachedBodyOutputMessage; +import org.springframework.cloud.gateway.support.DefaultClientResponse; +import org.springframework.core.Ordered; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseCookie; +import org.springframework.http.client.reactive.ClientHttpResponse; +import org.springframework.http.server.reactive.ServerHttpResponseDecorator; +import org.springframework.util.MultiValueMap; +import org.springframework.web.reactive.function.BodyInserter; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.client.ExchangeStrategies; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR; + +public class GatewayModifyResponseGatewayFilter implements GlobalFilter, Ordered { + + + @Override + @SuppressWarnings("unchecked") + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + + ServerHttpResponseDecorator responseDecorator = new ServerHttpResponseDecorator(exchange.getResponse()) { + + @Override + public Mono writeWith(Publisher body) { + + Class inClass = String.class; + Class outClass = String.class; + + String originalResponseContentType = exchange.getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR); + HttpHeaders httpHeaders = new HttpHeaders(); + //explicitly add it in this way instead of 'httpHeaders.setContentType(originalResponseContentType)' + //this will prevent exception in case of using non-standard media types like "Content-Type: image" + httpHeaders.add(HttpHeaders.CONTENT_TYPE, originalResponseContentType); + ResponseAdapter responseAdapter = new ResponseAdapter(body, httpHeaders); + DefaultClientResponse clientResponse = new DefaultClientResponse(responseAdapter, ExchangeStrategies.withDefaults()); + + //TODO: flux or mono + Mono modifiedBody = clientResponse.bodyToMono(inClass) + .flatMap(originalBody -> { + // 合并微服务传递过来的结果,变成最终结果 + ResultExecutor resultExecutor = ApiContext.getApiConfig().getResultExecutor(); + String ret = resultExecutor.mergeResult(exchange, String.valueOf(originalBody)); + return Mono.just(ret); + }); + + BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, outClass); + CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, exchange.getResponse().getHeaders()); + return bodyInserter.insert(outputMessage, new BodyInserterContext()) + .then(Mono.defer(() -> { + Flux messageBody = outputMessage.getBody(); + HttpHeaders headers = getDelegate().getHeaders(); + if (!headers.containsKey(HttpHeaders.TRANSFER_ENCODING)) { + messageBody = messageBody.doOnNext(data -> headers.setContentLength(data.readableByteCount())); + } + //TODO: use isStreamingMediaType? + return getDelegate().writeWith(messageBody); + })); + } + + @Override + public Mono writeAndFlushWith(Publisher> body) { + return writeWith(Flux.from(body) + .flatMapSequential(p -> p)); + } + }; + + return chain.filter(exchange.mutate().response(responseDecorator).build()); + } + + @Override + public int getOrder() { + return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1; + } + + public class ResponseAdapter implements ClientHttpResponse { + + private final Flux flux; + private final HttpHeaders headers; + + public ResponseAdapter(Publisher body, HttpHeaders headers) { + this.headers = headers; + if (body instanceof Flux) { + flux = (Flux) body; + } else { + flux = ((Mono) body).flux(); + } + } + + @Override + public Flux getBody() { + return flux; + } + + @Override + public HttpHeaders getHeaders() { + return headers; + } + + @Override + public HttpStatus getStatusCode() { + return null; + } + + @Override + public int getRawStatusCode() { + return 0; + } + + @Override + public MultiValueMap getCookies() { + return null; + } + } +} \ No newline at end of file diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/LoadBalancerClientExtFilter.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/LoadBalancerClientExtFilter.java new file mode 100644 index 00000000..f4b56cbf --- /dev/null +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/LoadBalancerClientExtFilter.java @@ -0,0 +1,56 @@ +package com.gitee.sop.gatewaycommon.filter; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.cloud.gateway.route.Route; +import org.springframework.core.Ordered; +import org.springframework.util.StringUtils; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.util.UriComponentsBuilder; +import reactor.core.publisher.Mono; + +import java.net.URI; + +import static org.springframework.cloud.gateway.filter.LoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.containsEncodedParts; + +/** + * 在LoadBalancerClientFilter后面处理,处理成我们想要的uri + * + * @author tanghc + */ +@Slf4j +public class LoadBalancerClientExtFilter implements GlobalFilter, Ordered { + + @Override + public int getOrder() { + return LOAD_BALANCER_CLIENT_FILTER_ORDER + 1; + } + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR); + Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR); + URI routeUri = route.getUri(); + + URI requestUrl = url; + + String uriStr = routeUri.toString(); + String[] uriArr = uriStr.split("\\#"); + if (uriArr.length == 2) { + String path = uriArr[1]; + UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUri(url); + if (StringUtils.hasLength(path)) { + uriComponentsBuilder.path(path); + } + requestUrl = uriComponentsBuilder.build(true).toUri(); + } + + exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl); + return chain.filter(exchange); + } + +} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/PostResultFilter.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/PostResultFilter.java deleted file mode 100644 index 9bb819c7..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/PostResultFilter.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.gitee.sop.gatewaycommon.filter; - -import com.gitee.sop.gatewaycommon.bean.ApiConfig; -import com.gitee.sop.gatewaycommon.bean.ApiContext; -import com.gitee.sop.gatewaycommon.bean.SopConstants; -import com.gitee.sop.gatewaycommon.result.ResultExecutor; -import com.netflix.zuul.context.RequestContext; -import com.netflix.zuul.exception.ZuulException; -import org.apache.commons.io.IOUtils; -import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; - -import java.io.InputStream; - -/** - * 合并微服务结果,统一返回格式 - * - * @author tanghc - */ -public class PostResultFilter extends BaseZuulFilter { - - @Override - protected FilterType getFilterType() { - return FilterType.POST; - } - - @Override - protected int getFilterOrder() { - return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 1; - } - - @Override - protected Object doRun(RequestContext requestContext) throws ZuulException { - int responseStatusCode = requestContext.getResponseStatusCode(); - InputStream responseDataStream = requestContext.getResponseDataStream(); - ApiConfig apiConfig = ApiContext.getApiConfig(); - ResultExecutor resultExecutor = apiConfig.getResultExecutor(); - String serviceResult; - try { - serviceResult = IOUtils.toString(responseDataStream, SopConstants.CHARSET_UTF8); - } catch (Exception e) { - log.error("业务方无数据返回", e); - serviceResult = SopConstants.EMPTY_JSON; - } - String finalResult = resultExecutor.mergeResult(responseStatusCode, serviceResult); - requestContext.setResponseBody(finalResult); - return null; - } - -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/PreTokenFilter.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/PreTokenFilter.java deleted file mode 100644 index 49fa27a9..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/PreTokenFilter.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.gitee.sop.gatewaycommon.filter; - -import com.gitee.sop.gatewaycommon.message.ErrorEnum; -import com.netflix.zuul.context.RequestContext; -import com.netflix.zuul.exception.ZuulException; -import org.apache.commons.lang.StringUtils; -import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; - -import javax.servlet.http.HttpServletRequest; - -/** - * @author tanghc - */ -public class PreTokenFilter extends BaseZuulFilter { - - @Override - protected FilterType getFilterType() { - return FilterType.PRE; - } - - @Override - protected int getFilterOrder() { - return FilterConstants.PRE_DECORATION_FILTER_ORDER + 1; - } - - @Override - protected Object doRun(RequestContext ctx) throws ZuulException { - Object serviceId = ctx.get(FilterConstants.SERVICE_ID_KEY); - log.info("serviceId:{}", serviceId); - HttpServletRequest request = ctx.getRequest(); - - log.info("send {} request to {}", request.getMethod(), request.getRequestURL().toString()); - - String accessToken = request.getParameter("access_token"); - if (StringUtils.isBlank(accessToken)) { - throw ErrorEnum.AOP_INVALID_APP_AUTH_TOKEN.getErrorMeta().getException(); - } - return null; - } - -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/PreValidateFilter.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/PreValidateFilter.java deleted file mode 100644 index d5680521..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/PreValidateFilter.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.gitee.sop.gatewaycommon.filter; - -import com.gitee.sop.gatewaycommon.bean.ApiContext; -import com.gitee.sop.gatewaycommon.bean.ApiConfig; -import com.gitee.sop.gatewaycommon.exception.ApiException; -import com.gitee.sop.gatewaycommon.param.ApiParam; -import com.gitee.sop.gatewaycommon.validate.Validator; -import com.netflix.zuul.context.RequestContext; -import com.netflix.zuul.exception.ZuulException; -import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; - -import javax.servlet.http.HttpServletRequest; - -/** - * 前置校验 - * @author tanghc - */ -public class PreValidateFilter extends BaseZuulFilter { - @Override - protected FilterType getFilterType() { - return FilterType.PRE; - } - - @Override - protected int getFilterOrder() { - // 在org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter前面 - return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1; - } - - @Override - protected Object doRun(RequestContext requestContext) throws ZuulException { - HttpServletRequest request = requestContext.getRequest(); - ApiConfig apiConfig = ApiContext.getApiConfig(); - // 解析参数 - ApiParam param = apiConfig.getParamParser().parse(request); - ApiContext.setApiParam(param); - // 验证操作,这里有负责验证签名参数 - Validator validator = apiConfig.getValidator(); - try { - validator.validate(param); - } catch (ApiException e) { - log.error("验证失败,params:{}", param.toJSONString(), e); - throw e; - } - return null; - } - -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/ValidateFilter.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/ValidateFilter.java new file mode 100644 index 00000000..66da677d --- /dev/null +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/filter/ValidateFilter.java @@ -0,0 +1,44 @@ +package com.gitee.sop.gatewaycommon.filter; + +import com.gitee.sop.gatewaycommon.bean.ApiConfig; +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.param.ApiParam; +import com.gitee.sop.gatewaycommon.validate.Validator; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.core.Ordered; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +/** + * @author tanghc + */ +@Slf4j +public class ValidateFilter implements GlobalFilter, Ordered { + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + ApiConfig apiConfig = ApiContext.getApiConfig(); + // 解析参数 + ApiParam param = apiConfig.getParamBuilder().build(exchange); + exchange.getAttributes().put(SopConstants.CACHE_API_PARAM, param); + // 验证操作,这里有负责验证签名参数 + Validator validator = apiConfig.getValidator(); + try { + validator.validate(param); + } catch (ApiException e) { + log.error("验证失败,params:{}", param.toJSONString(), e); + throw e; + } + return chain.filter(exchange); + } + + @Override + public int getOrder() { + // 最优先执行 + return Ordered.HIGHEST_PRECEDENCE + 1000; + } +} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/handler/GatewayExceptionHandler.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/handler/GatewayExceptionHandler.java new file mode 100644 index 00000000..e7e4ee89 --- /dev/null +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/handler/GatewayExceptionHandler.java @@ -0,0 +1,155 @@ +package com.gitee.sop.gatewaycommon.handler; + +import com.gitee.sop.gatewaycommon.bean.ApiContext; +import com.gitee.sop.gatewaycommon.result.GatewayResult; +import com.gitee.sop.gatewaycommon.result.ResultExecutor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler; +import org.springframework.http.codec.HttpMessageReader; +import org.springframework.http.codec.HttpMessageWriter; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.util.Assert; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.server.RequestPredicates; +import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import org.springframework.web.reactive.result.view.ViewResolver; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +import java.util.Collections; +import java.util.List; + +/** + * @classDesc: 统一异常处理, 参考{@link org.springframework.web.server.AbstractErrorWebExceptionHandler}修改 + * @author: chenggang + * @createTime: 2018/10/30 + */ +public class GatewayExceptionHandler implements ErrorWebExceptionHandler { + + private static final Logger log = LoggerFactory.getLogger(GatewayExceptionHandler.class); + + @Override + public Mono handle(ServerWebExchange exchange, Throwable ex) { + ResultExecutor resultExecutor = ApiContext.getApiConfig().getResultExecutor(); + GatewayResult errorResult = resultExecutor.buildErrorResult(exchange, ex); + + /** + * 错误记录 + */ + ServerHttpRequest request = exchange.getRequest(); + log.error("[全局异常处理]异常请求路径:{},记录异常信息:{}", request.getPath(), ex.getMessage()); + /** + * 参考AbstractErrorWebExceptionHandler + */ + if (exchange.getResponse().isCommitted()) { + return Mono.error(ex); + } + exceptionHandlerResult.set(errorResult); + ServerRequest newRequest = ServerRequest.create(exchange, this.messageReaders); + return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse).route(newRequest) + .switchIfEmpty(Mono.error(ex)) + .flatMap((handler) -> handler.handle(newRequest)) + .flatMap((response) -> write(exchange, response)); + + } + + /** + * MessageReader + */ + private List> messageReaders = Collections.emptyList(); + + /** + * MessageWriter + */ + private List> messageWriters = Collections.emptyList(); + + /** + * ViewResolvers + */ + private List viewResolvers = Collections.emptyList(); + + /** + * 存储处理异常后的信息 + */ + private ThreadLocal exceptionHandlerResult = new ThreadLocal<>(); + + /** + * 参考AbstractErrorWebExceptionHandler + * + * @param messageReaders + */ + public void setMessageReaders(List> messageReaders) { + Assert.notNull(messageReaders, "'messageReaders' must not be null"); + this.messageReaders = messageReaders; + } + + /** + * 参考AbstractErrorWebExceptionHandler + * + * @param viewResolvers + */ + public void setViewResolvers(List viewResolvers) { + this.viewResolvers = viewResolvers; + } + + /** + * 参考AbstractErrorWebExceptionHandler + * + * @param messageWriters + */ + public void setMessageWriters(List> messageWriters) { + Assert.notNull(messageWriters, "'messageWriters' must not be null"); + this.messageWriters = messageWriters; + } + + + + /** + * 参考DefaultErrorWebExceptionHandler + * + * @param request + * @return + */ + protected Mono renderErrorResponse(ServerRequest request) { + GatewayResult result = exceptionHandlerResult.get(); + return ServerResponse + .status(result.getHttpStatus()) + .contentType(result.getContentType()) + .body(BodyInserters.fromObject(result.getBody())); + } + + /** + * 参考AbstractErrorWebExceptionHandler + * + * @param exchange + * @param response + * @return + */ + private Mono write(ServerWebExchange exchange, + ServerResponse response) { + exchange.getResponse().getHeaders() + .setContentType(response.headers().getContentType()); + return response.writeTo(exchange, new ResponseContext()); + } + + /** + * 参考AbstractErrorWebExceptionHandler + */ + private class ResponseContext implements ServerResponse.Context { + + @Override + public List> messageWriters() { + return GatewayExceptionHandler.this.messageWriters; + } + + @Override + public List viewResolvers() { + return GatewayExceptionHandler.this.viewResolvers; + } + + } + +} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ApiMetaChangeListener.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ApiMetaChangeListener.java deleted file mode 100644 index ea2aded5..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ApiMetaChangeListener.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.gitee.sop.gatewaycommon.manager; - -import org.springframework.data.redis.connection.Message; -import org.springframework.data.redis.connection.MessageListener; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.data.redis.serializer.RedisSerializer; - -/** - * @author tanghc - */ -public class ApiMetaChangeListener implements MessageListener { - - private ApiMetaManager apiMetaManager; - private StringRedisTemplate redisTemplate; - - public ApiMetaChangeListener(ApiMetaManager apiMetaManager, StringRedisTemplate redisTemplate) { - this.apiMetaManager = apiMetaManager; - this.redisTemplate = redisTemplate; - } - - @Override - public void onMessage(Message message, byte[] bytes) { - RedisSerializer stringSerializer = redisTemplate.getStringSerializer(); - String msg = stringSerializer.deserialize(message.getBody()); - this.apiMetaManager.onChange(msg); - } - -} \ No newline at end of file diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ApiMetaContext.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ApiMetaContext.java deleted file mode 100644 index de8a9d26..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ApiMetaContext.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.gitee.sop.gatewaycommon.manager; - -import com.gitee.sop.gatewaycommon.bean.ServiceApiInfo; -import org.springframework.cloud.netflix.zuul.filters.Route; - -/** - * @author tanghc - */ -public interface ApiMetaContext { - /** - * 重新加载接口信息 - * @param serviceId - * @param serviceApiInfo - */ - void reload(String serviceId, ServiceApiInfo serviceApiInfo); - - /** - * 获取接口对应的route信息 - * @param nameVersion - * @return - */ - Route getRoute(String nameVersion); -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultApiMetaContext.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultApiMetaContext.java deleted file mode 100644 index db1cbeed..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultApiMetaContext.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.gitee.sop.gatewaycommon.manager; - -import com.gitee.sop.gatewaycommon.bean.ServiceApiInfo; -import com.gitee.sop.gatewaycommon.message.ErrorEnum; -import lombok.extern.slf4j.Slf4j; -import org.springframework.cloud.netflix.zuul.filters.Route; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -/** - * @author tanghc - */ -@Slf4j -public class DefaultApiMetaContext implements ApiMetaContext { - - /** key:nameVersion */ - private Map nameVersionServiceIdMap = new HashMap<>(128); - - /** key: serviceId , value: md5 */ - private Map serviceIdMd5Map = new HashMap<>(16); - - @Override - public void reload(String serviceId, ServiceApiInfo serviceApiInfo) { - String md5 = serviceIdMd5Map.get(serviceId); - if (md5 != null && md5.equals(serviceApiInfo.getMd5())) { - log.info("MD5相同,无需更改本地接口信息,appName:{}, md5:{}", serviceApiInfo.getAppName(), serviceApiInfo.getMd5()); - return; - } - log.info("更新本地接口信息,appName:{}, md5:{}", serviceApiInfo.getAppName(), serviceApiInfo.getMd5()); - // 移除原来的 - Iterator> iterator = nameVersionServiceIdMap.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - if (entry.getValue().getLocation().equals(serviceId)) { - iterator.remove(); - } - } - List apis = serviceApiInfo.getApis(); - for (ServiceApiInfo.ApiMeta apiMeta : apis) { - Route route = this.buildRoute(serviceId, apiMeta); - nameVersionServiceIdMap.put(apiMeta.fetchNameVersion(), route); - } - serviceIdMd5Map.put(serviceId, serviceApiInfo.getMd5()); - } - - @Override - public Route getRoute(String nameVersion) { - Route route = nameVersionServiceIdMap.get(nameVersion); - if (route == null) { - throw ErrorEnum.ISV_INVALID_METHOD.getErrorMeta().getException(); - } - return route; - } - - protected Route buildRoute(String serviceId, ServiceApiInfo.ApiMeta apiMeta) { - return new Route(apiMeta.getName(), apiMeta.getPath(), serviceId, null, false, null); - } - -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultApiMetaManager.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultApiMetaManager.java deleted file mode 100644 index 44ef79c1..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultApiMetaManager.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.gitee.sop.gatewaycommon.manager; - -import com.alibaba.fastjson.JSON; -import com.gitee.sop.gatewaycommon.bean.ServiceApiInfo; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import org.springframework.data.redis.core.StringRedisTemplate; - -import java.util.Map; - -/** - * 保存在redis中,结构为HSET。格式如下: - *
- * com.gitee.sop.api
- *     <serviceId>:{ md5:"xxx", apis:[{name:"", version:""}] }
- * 
- * @author tanghc - */ -@Getter -@Slf4j -public class DefaultApiMetaManager implements ApiMetaManager { - - private StringRedisTemplate redisTemplate; - private ApiMetaContext apiMetaContext; - - public DefaultApiMetaManager(StringRedisTemplate redisTemplate, ApiMetaContext apiMetaContext) { - this.redisTemplate = redisTemplate; - this.apiMetaContext = apiMetaContext; - } - - @Override - public void refresh() { - log.info("刷新本地接口信息"); - Map entries = redisTemplate.opsForHash().entries(API_STORE_KEY); - for (Map.Entry entry : entries.entrySet()) { - log.info("更新微服务接口,appName:{}", entry.getKey()); - String serviceId = entry.getKey().toString(); - String serviceApiInfoJson = entry.getValue().toString(); - ServiceApiInfo serviceApiInfo = JSON.parseObject(serviceApiInfoJson, ServiceApiInfo.class); - apiMetaContext.reload(serviceId, serviceApiInfo); - } - } - - @Override - public void onChange(String serviceApiInfoJson) { - ServiceApiInfo serviceApiInfo = JSON.parseObject(serviceApiInfoJson, ServiceApiInfo.class); - log.info("Redis订阅推送接口信息,appName:{}, md5:{}", serviceApiInfo.getAppName(), serviceApiInfo.getMd5()); - this.apiMetaContext.reload(serviceApiInfo.getAppName(), serviceApiInfo); - } - -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/GatewayZookeeperApiMetaManager.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/GatewayZookeeperApiMetaManager.java new file mode 100644 index 00000000..1aa67204 --- /dev/null +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/GatewayZookeeperApiMetaManager.java @@ -0,0 +1,168 @@ +package com.gitee.sop.gatewaycommon.manager; + +import com.alibaba.fastjson.JSON; +import com.gitee.sop.gatewaycommon.route.DynamicRouteServiceManager; +import com.gitee.sop.gatewaycommon.route.GatewayFilterDefinition; +import com.gitee.sop.gatewaycommon.route.GatewayPredicateDefinition; +import com.gitee.sop.gatewaycommon.route.GatewayRouteDefinition; +import com.gitee.sop.gatewaycommon.route.ServiceRouteInfo; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.framework.recipes.cache.ChildData; +import org.apache.curator.framework.recipes.cache.PathChildrenCache; +import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent; +import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener; +import org.apache.curator.retry.ExponentialBackoffRetry; +import org.springframework.beans.BeanUtils; +import org.springframework.cloud.gateway.filter.FilterDefinition; +import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition; +import org.springframework.cloud.gateway.route.RouteDefinition; +import org.springframework.core.env.Environment; +import org.springframework.util.StringUtils; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +/** + * 从zookeeper监听route信息 + * + * @author tanghc + */ +@Getter +@Slf4j +public class GatewayZookeeperApiMetaManager implements ApiMetaManager { + + private String sopServiceApiPath = "/sop-service-api"; + + private Environment environment; + + private DynamicRouteServiceManager dynamicRouteServiceManager; + + + public GatewayZookeeperApiMetaManager(Environment environment, DynamicRouteServiceManager dynamicRouteServiceManager) { + this.environment = environment; + this.dynamicRouteServiceManager = dynamicRouteServiceManager; + } + + @Override + public void refresh() { + log.info("刷新本地接口信息"); + try { + String zookeeperServerAddr = environment.getProperty("spring.cloud.zookeeper.connect-string"); + if (StringUtils.isEmpty(zookeeperServerAddr)) { + throw new RuntimeException("未指定spring.cloud.zookeeper.connect-string参数"); + } + CuratorFramework client = CuratorFrameworkFactory.builder() + .connectString(zookeeperServerAddr) + .retryPolicy(new ExponentialBackoffRetry(1000, 3)) + .build(); + + client.start(); + + client.create() + // 如果节点存在则Curator将会使用给出的数据设置这个节点的值 + .orSetData() + // 如果指定节点的父节点不存在,则Curator将会自动级联创建父节点 + .creatingParentContainersIfNeeded() + .forPath(sopServiceApiPath, "".getBytes()); + + this.watchChildren(client, sopServiceApiPath); + } catch (Exception e) { + e.printStackTrace(); + } + } + + protected void watchChildren(CuratorFramework client, String sopServiceApiPath) throws Exception { + // 为子节点添加watcher + // PathChildrenCache: 监听数据节点的增删改,可以设置触发的事件 + final PathChildrenCache childrenCache = new PathChildrenCache(client, sopServiceApiPath, true); + + /** + * StartMode: 初始化方式 + * POST_INITIALIZED_EVENT:异步初始化,初始化之后会触发事件 + * NORMAL:异步初始化 + * BUILD_INITIAL_CACHE:同步初始化 + */ + childrenCache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE); + + // 列出子节点数据列表,需要使用BUILD_INITIAL_CACHE同步初始化模式才能获得,异步是获取不到的 + List childDataList = childrenCache.getCurrentData(); + log.info("微服务API详细数据列表:"); + for (ChildData childData : childDataList) { + String nodeData = new String(childData.getData()); + log.info("\t* 子节点路径:" + childData.getPath() + ",该节点的数据为:" + nodeData); + ServiceRouteInfo serviceRouteInfo = JSON.parseObject(nodeData, ServiceRouteInfo.class); + for (GatewayRouteDefinition gatewayRouteDefinition : serviceRouteInfo.getRouteDefinitionList()) { + RouteDefinition routeDefinition = buildRouteDefinition(gatewayRouteDefinition); + dynamicRouteServiceManager.add(routeDefinition); + } + } + // 添加事件监听器 + childrenCache.getListenable().addListener(new PathChildrenCacheListener() { + @Override + public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent event) throws Exception { + PathChildrenCacheEvent.Type type = event.getType(); + // 通过判断event type的方式来实现不同事件的触发 + if (PathChildrenCacheEvent.Type.CHILD_ADDED.equals(type)) { + String nodeData = new String(event.getData().getData()); + ServiceRouteInfo serviceRouteInfo = JSON.parseObject(nodeData, ServiceRouteInfo.class); + // 添加子节点时触发 + log.info("子节点:{}添加成功,数据为:{}", event.getData().getPath(), nodeData); + for (GatewayRouteDefinition gatewayRouteDefinition : serviceRouteInfo.getRouteDefinitionList()) { + RouteDefinition routeDefinition = buildRouteDefinition(gatewayRouteDefinition); + dynamicRouteServiceManager.add(routeDefinition); + } + } else if (PathChildrenCacheEvent.Type.CHILD_UPDATED.equals(type)) { + String nodeData = new String(event.getData().getData()); + ServiceRouteInfo serviceRouteInfo = JSON.parseObject(nodeData, ServiceRouteInfo.class); + // 修改子节点数据时触发 + log.info("子节点:{}修改成功,数据为:{}", event.getData().getPath(), nodeData); + for (GatewayRouteDefinition gatewayRouteDefinition : serviceRouteInfo.getRouteDefinitionList()) { + RouteDefinition routeDefinition = buildRouteDefinition(gatewayRouteDefinition); + dynamicRouteServiceManager.update(routeDefinition); + } + } else if (PathChildrenCacheEvent.Type.CHILD_REMOVED.equals(type)) { + String nodeData = new String(event.getData().getData()); + ServiceRouteInfo serviceRouteInfo = JSON.parseObject(nodeData, ServiceRouteInfo.class); + // 删除子节点时触发 + log.info("子节点:{}删除成功,数据为:{}", event.getData().getPath(), nodeData); + for (GatewayRouteDefinition gatewayRouteDefinition : serviceRouteInfo.getRouteDefinitionList()) { + dynamicRouteServiceManager.delete(gatewayRouteDefinition.getId()); + } + } + } + }); + } + + protected RouteDefinition buildRouteDefinition(GatewayRouteDefinition gatewayRouteDefinition) { + RouteDefinition routeDefinition = new RouteDefinition(); + routeDefinition.setId(gatewayRouteDefinition.getId()); + routeDefinition.setUri(URI.create(gatewayRouteDefinition.getUri())); + routeDefinition.setOrder(gatewayRouteDefinition.getOrder()); + List filterDefinitionList = new ArrayList<>(gatewayRouteDefinition.getFilters().size()); + List predicateDefinitionList = new ArrayList<>(gatewayRouteDefinition.getPredicates().size()); + for (GatewayFilterDefinition filter : gatewayRouteDefinition.getFilters()) { + FilterDefinition filterDefinition = new FilterDefinition(); + BeanUtils.copyProperties(filter, filterDefinition); + filterDefinitionList.add(filterDefinition); + } + + for (GatewayPredicateDefinition predicate : gatewayRouteDefinition.getPredicates()) { + PredicateDefinition predicateDefinition = new PredicateDefinition(); + BeanUtils.copyProperties(predicate, predicateDefinition); + predicateDefinitionList.add(predicateDefinition); + } + + routeDefinition.setFilters(filterDefinitionList); + routeDefinition.setPredicates(predicateDefinitionList); + return routeDefinition; + } + + @Override + public void onChange(String serviceApiInfoJson) { + } + +} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/SopRouteLocator.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/SopRouteLocator.java deleted file mode 100644 index ffae417f..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/SopRouteLocator.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.gitee.sop.gatewaycommon.manager; - -import com.gitee.sop.gatewaycommon.bean.ApiContext; -import com.gitee.sop.gatewaycommon.param.ApiParam; -import org.springframework.cloud.netflix.zuul.filters.Route; -import org.springframework.cloud.netflix.zuul.filters.RouteLocator; -import org.springframework.core.Ordered; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -/** - * @author tanghc - */ -public class SopRouteLocator implements RouteLocator, Ordered { - - private ApiMetaContext apiMetaContext; - - public SopRouteLocator(ApiMetaContext apiMetaContext) { - this.apiMetaContext = apiMetaContext; - } - - @Override - public Collection getIgnoredPaths() { - return Collections.emptyList(); - } - - @Override - public List getRoutes() { - return null; - } - - @Override - public Route getMatchingRoute(String path) { - ApiParam param = ApiContext.getApiParam(); - String nameVersion = param.fetchNameVersion(); - return apiMetaContext.getRoute(nameVersion); - } - - @Override - public int getOrder() { - return 0; - } -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/message/ErrorMeta.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/message/ErrorMeta.java index 5bb5bc8a..59731c8c 100644 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/message/ErrorMeta.java +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/message/ErrorMeta.java @@ -4,6 +4,8 @@ import com.gitee.sop.gatewaycommon.bean.ApiContext; import com.gitee.sop.gatewaycommon.exception.ApiException; import lombok.Getter; +import java.util.Locale; + /** * 错误对象 * @@ -12,6 +14,8 @@ import lombok.Getter; @Getter public class ErrorMeta { + private static final Locale ZH_CN = Locale.SIMPLIFIED_CHINESE; + private String modulePrefix; private String code; private String subCode; @@ -23,7 +27,7 @@ public class ErrorMeta { } public Error getError() { - return ErrorFactory.getError(this, ApiContext.getLocale()); + return ErrorFactory.getError(this, ZH_CN); } /** @@ -33,14 +37,18 @@ public class ErrorMeta { * @return 返回exception */ public ApiException getException(Object... params) { + Locale locale = ZH_CN; if (params != null && params.length == 1) { Object param = params[0]; if (param instanceof Throwable) { - Error error = ErrorFactory.getError(this, ApiContext.getLocale()); + Error error = ErrorFactory.getError(this, ZH_CN); return new ApiException((Throwable) param, error); } + if (param instanceof Locale) { + locale = (Locale) param; + } } - Error error = ErrorFactory.getError(this, ApiContext.getLocale(), params); + Error error = ErrorFactory.getError(this, locale, params); return new ApiException(error); } diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParam.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParam.java index d2433980..268312e8 100644 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParam.java +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParam.java @@ -2,8 +2,9 @@ package com.gitee.sop.gatewaycommon.param; import com.alibaba.fastjson.JSONObject; import com.gitee.sop.gatewaycommon.bean.SopConstants; -import com.netflix.zuul.context.RequestContext; -import org.apache.commons.lang.StringUtils; +//import com.netflix.zuul.context.RequestContext; +//import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import javax.servlet.http.HttpServletRequest; import java.util.Map; @@ -14,6 +15,10 @@ import java.util.Map; * @author tanghc */ public class ApiParam extends JSONObject implements Param { + + public ApiParam() { + } + public ApiParam(Map map) { super(map); } @@ -36,7 +41,8 @@ public class ApiParam extends JSONObject implements Param { } public HttpServletRequest fetchRequest() { - return RequestContext.getCurrentContext().getRequest(); +// return RequestContext.getCurrentContext().getRequest(); + return null; } /** diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParamBuilder.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParamBuilder.java new file mode 100644 index 00000000..0b7eebe1 --- /dev/null +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParamBuilder.java @@ -0,0 +1,23 @@ +package com.gitee.sop.gatewaycommon.param; + +import com.gitee.sop.gatewaycommon.bean.SopConstants; +import org.springframework.web.server.ServerWebExchange; + +import java.util.Map; + +/** + * @author tanghc + */ +public class ApiParamBuilder implements ParamBuilder { + @Override + public ApiParam build(ServerWebExchange exchange) { + Map params = exchange.getAttribute(SopConstants.CACHE_REQUEST_BODY_FOR_MAP); + ApiParam apiParam = new ApiParam(); + for (Map.Entry entry : params.entrySet()) { + apiParam.put(entry.getKey(), entry.getValue()); + } + return apiParam; + } + + +} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParamParser.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParamParser.java deleted file mode 100644 index d2834b50..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParamParser.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.gitee.sop.gatewaycommon.param; - -import com.alibaba.fastjson.JSON; -import com.gitee.sop.gatewaycommon.bean.ApiContext; -import com.gitee.sop.gatewaycommon.message.ErrorEnum; -import com.gitee.sop.gatewaycommon.util.RequestUtil; -import com.netflix.zuul.http.HttpServletRequestWrapper; -import org.springframework.http.MediaType; -import org.springframework.web.multipart.MultipartFile; -import org.springframework.web.multipart.MultipartHttpServletRequest; -import org.springframework.web.multipart.commons.CommonsMultipartResolver; - -import javax.servlet.http.HttpServletRequest; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -/** - * 参数解析默认实现 - * - * @author tanghc - */ -public class ApiParamParser implements ParamParser { - - private static final String CONTENT_TYPE_MULTIPART = MediaType.MULTIPART_FORM_DATA_VALUE; - private static final String CONTENT_TYPE_JSON = MediaType.APPLICATION_JSON_VALUE; - private static final String CONTENT_TYPE_TEXT = MediaType.TEXT_PLAIN_VALUE; - - @Override - public ApiParam parse(HttpServletRequest request) { - try { - Map params = this.getJson(request); - return new ApiParam(params); - } catch (Exception e) { - throw ErrorEnum.ISV_INVALID_PARAMETER.getErrorMeta().getException(); - } - } - - public Map getJson(HttpServletRequest request) throws Exception { - // zuul会做一层包装 - if (request instanceof HttpServletRequestWrapper) { - HttpServletRequestWrapper req = (HttpServletRequestWrapper) request; - request = req.getRequest(); - } - Map params = null; - - if (RequestUtil.isGetRequest(request)) { - params = RequestUtil.convertRequestParamsToMap(request); - } else { - String contectType = request.getContentType(); - - if (contectType == null) { - contectType = ""; - } - - contectType = contectType.toLowerCase(); - - // json或者纯文本形式 - if (contectType.contains(CONTENT_TYPE_JSON) || contectType.contains(CONTENT_TYPE_TEXT)) { - String txt = RequestUtil.getText(request); - params = JSON.parseObject(txt); - } else if (contectType.contains(CONTENT_TYPE_MULTIPART)) { - // 上传文件形式 - params = this.parseUploadRequest(request); - } else { - params = RequestUtil.convertRequestParamsToMap(request); - } - } - - return params; - } - - /** - * 解析文件上传请求 - * - * @param request - * @return 返回json字符串 - */ - protected Map parseUploadRequest(HttpServletRequest request) { - CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver( - request.getSession().getServletContext()); - // 检查form中是否有enctype="multipart/form-data" - if (multipartResolver.isMultipart(request)) { - MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request; - Map fileMap = multiRequest.getFileMap(); - Map finalMap = new HashMap<>(fileMap.size()); - - Set keys = fileMap.keySet(); - for (String name : keys) { - MultipartFile file = fileMap.get(name); - if (file.getSize() > 0) { - finalMap.put(name, file); - } - } - if (finalMap.size() > 0) { - // 保存上传文件 - ApiContext.setUploadContext(new ApiUploadContext(finalMap)); - } - } - - return RequestUtil.convertRequestParamsToMap(request); - } - -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ParamBuilder.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ParamBuilder.java new file mode 100644 index 00000000..b9637109 --- /dev/null +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ParamBuilder.java @@ -0,0 +1,16 @@ +package com.gitee.sop.gatewaycommon.param; + +import org.springframework.web.server.ServerWebExchange; + +/** + * @author tanghc + */ +public interface ParamBuilder { + /** + * 从request提取参数 + * @param exchange + * @return 返回ApiParam + * @throws Exception + */ + ApiParam build(ServerWebExchange exchange); +} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ParamParser.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ParamParser.java deleted file mode 100644 index 3edceb3d..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ParamParser.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.gitee.sop.gatewaycommon.param; - -import javax.servlet.http.HttpServletRequest; - -/** - * 负责解析参数 - * @author tanghc - * - */ -public interface ParamParser { - - /** - * 从request提取参数 - * @param request - * @return 返回ApiParam - * @throws Exception - */ - ApiParam parse(HttpServletRequest request); -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ApiResultExecutor.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ApiResultExecutor.java index f8bf8c7e..da3ac4e9 100644 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ApiResultExecutor.java +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ApiResultExecutor.java @@ -2,16 +2,23 @@ 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.ApiParam; import com.gitee.sop.gatewaycommon.param.ParamNames; -import com.netflix.zuul.exception.ZuulException; import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.gateway.support.NotFoundException; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.util.CollectionUtils; +import org.springframework.web.server.ResponseStatusException; +import org.springframework.web.server.ServerWebExchange; + +import java.util.List; +import java.util.Map; + /** * @author tanghc @@ -32,32 +39,46 @@ public class ApiResultExecutor implements ResultExecutor { public static final String DATA_SUFFIX = "_response"; @Override - public String mergeResult(int responseStatus, String responseData) { + public String mergeResult(ServerWebExchange exchange, String responseData) { + int responseStatus = HttpStatus.OK.value(); + List errorCodeList = exchange.getResponse().getHeaders().get(SopConstants.X_BIZ_ERROR_CODE); + if (!CollectionUtils.isEmpty(errorCodeList)) { + String errorCode = errorCodeList.get(0); + responseStatus = Integer.valueOf(errorCode); + } if (responseStatus == HttpStatus.OK.value() || responseStatus == BIZ_ERROR_STATUS) { - return mergeSuccess(responseStatus, responseData); + return mergeSuccess(exchange, responseStatus, responseData); } else { // 微服务端有可能返回500错误 // {"path":"/book/getBook3","error":"Internal Server Error","message":"id不能为空","timestamp":"2019-02-13T07:41:00.495+0000","status":500} - return mergeError(responseData); + return mergeError(exchange, responseData); } } @Override - public String mergeError(Throwable throwable) { + public GatewayResult buildErrorResult(ServerWebExchange exchange, Throwable ex) { Error error = null; - if (throwable instanceof ZuulException) { - ZuulException ex = (ZuulException) throwable; - Throwable cause = ex.getCause(); - if (cause instanceof ApiException) { - ApiException apiException = (ApiException) cause; - error = apiException.getError(); + if (ex instanceof ApiException) { + ApiException apiException = (ApiException) ex; + error = apiException.getError(); + } else if (ex instanceof NotFoundException) { + error = ErrorEnum.ISV_INVALID_METHOD.getErrorMeta().getError(); + } else if (ex instanceof ResponseStatusException) { + ResponseStatusException responseStatusException = (ResponseStatusException) ex; + HttpStatus status = responseStatusException.getStatus(); + if (status == HttpStatus.NOT_FOUND) { + error = ErrorEnum.ISV_INVALID_METHOD.getErrorMeta().getError(); } } + if (error == null) { error = ErrorEnum.AOP_UNKNOW_ERROR.getErrorMeta().getError(); } - JSONObject jsonObject = (JSONObject)JSON.toJSON(error); - return this.merge(jsonObject); + + JSONObject jsonObject = (JSONObject) JSON.toJSON(error); + String body = this.merge(exchange, jsonObject); + + return new GatewayResult(HttpStatus.OK, MediaType.APPLICATION_JSON_UTF8, body); } /* @@ -76,7 +97,7 @@ public class ApiResultExecutor implements ResultExecutor { "sign": "ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE" } */ - public String mergeSuccess(int responseStatus, String serviceResult) { + public String mergeSuccess(ServerWebExchange exchange, int responseStatus, String serviceResult) { JSONObject jsonObjectService; // 如果是业务出错 if (responseStatus == BIZ_ERROR_STATUS) { @@ -89,7 +110,7 @@ public class ApiResultExecutor implements ResultExecutor { jsonObjectService.put(GATEWAY_CODE_NAME, SUCCESS_META.getCode()); jsonObjectService.put(GATEWAY_MSG_NAME, SUCCESS_META.getError().getMsg()); } - return this.merge(jsonObjectService); + return this.merge(exchange, jsonObjectService); } /* @@ -104,20 +125,20 @@ public class ApiResultExecutor implements ResultExecutor { "sign": "ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE" } */ - public String mergeError(String serviceResult) { + public String mergeError(ServerWebExchange exchange, String serviceResult) { JSONObject jsonObjectService = new JSONObject(); jsonObjectService.put(GATEWAY_CODE_NAME, ISP_UNKNOW_ERROR_META.getCode()); jsonObjectService.put(GATEWAY_MSG_NAME, ISP_UNKNOW_ERROR_META.getError().getMsg()); - return this.merge(jsonObjectService); + return this.merge(exchange, jsonObjectService); } - private String merge(JSONObject jsonObjectService) { + private String merge(ServerWebExchange exchange, JSONObject jsonObjectService) { JSONObject ret = new JSONObject(); - ApiParam apiParam = ApiContext.getApiParam(); // 点换成下划线 - String apiName = apiParam.fetchName().replace(DOT, UNDERLINE); + Map params = exchange.getAttribute(SopConstants.CACHE_REQUEST_BODY_FOR_MAP); + String apiName = params.getOrDefault(ParamNames.API_NAME, "error").replace(DOT, UNDERLINE); ret.put(apiName + DATA_SUFFIX, jsonObjectService); - ret.put(ParamNames.SIGN_NAME, apiParam.fetchSign()); + ret.put(ParamNames.SIGN_NAME, params.getOrDefault(ParamNames.SIGN_NAME, "")); return ret.toJSONString(); } diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/GatewayResult.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/GatewayResult.java new file mode 100644 index 00000000..ff5556e0 --- /dev/null +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/GatewayResult.java @@ -0,0 +1,21 @@ +package com.gitee.sop.gatewaycommon.result; + +import lombok.Data; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +/** + * @author tanghc + */ +@Data +public class GatewayResult { + private HttpStatus httpStatus; + private MediaType contentType; + private String body; + + public GatewayResult(HttpStatus httpStatus, MediaType contentType, String body) { + this.httpStatus = httpStatus; + this.contentType = contentType; + this.body = body; + } +} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/JsonResultSerializer.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/JsonResultSerializer.java deleted file mode 100644 index e1d14797..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/JsonResultSerializer.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.gitee.sop.gatewaycommon.result; - -import com.alibaba.fastjson.JSON; - -/** - * 序列化json - * @author tanghc - */ -public class JsonResultSerializer implements ResultSerializer { - - @Override - public String serialize(Object obj) { - return JSON.toJSONString(obj); - } - -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ResultBuilder.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ResultBuilder.java deleted file mode 100644 index a2bf66e5..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ResultBuilder.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.gitee.sop.gatewaycommon.result; - -import com.gitee.sop.gatewaycommon.message.Error; - -/** - * @author tanghc - */ -public interface ResultBuilder { - - - /** - * 构建网关错误返回结果 - * - * @param throwable 异常 - * @return 返回最终结果 - */ - Result buildGatewayError(Throwable throwable); - - /** - * 构建网关错误返回结果 - * - * @param error error - * @return 返回最终结果 - */ - Result buildGatewayError(Error error); - -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ResultExecutor.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ResultExecutor.java index fe98f8d5..e1e1b621 100644 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ResultExecutor.java +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ResultExecutor.java @@ -1,21 +1,25 @@ package com.gitee.sop.gatewaycommon.result; +import org.springframework.web.server.ServerWebExchange; + /** + * 对返回结果进行处理 * @author tanghc */ public interface ResultExecutor { /** * 合并结果 - * @param responseStatus + * @param exchange * @param responseData * @return */ - String mergeResult(int responseStatus, String responseData); + String mergeResult(ServerWebExchange exchange, String responseData); /** * 合并错误结果 - * @param throwable + * @param exchange + * @param ex * @return */ - String mergeError(Throwable throwable); + GatewayResult buildErrorResult(ServerWebExchange exchange, Throwable ex); } diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ResultSerializer.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ResultSerializer.java deleted file mode 100644 index a92efffb..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ResultSerializer.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.gitee.sop.gatewaycommon.result; - -/** - * 对象序列化 - * @author tanghc - * - */ -public interface ResultSerializer { - /** - * 序列化 - * - * @param obj - * @return 返回序列化后的结果 - */ - String serialize(Object obj); -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/XmlResultSerializer.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/XmlResultSerializer.java deleted file mode 100644 index fdacbf55..00000000 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/XmlResultSerializer.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.gitee.sop.gatewaycommon.result; - -import com.gitee.sop.gatewaycommon.util.XmlUtil; - -/** - * 序列化成xml - * @author tanghc - */ -public class XmlResultSerializer implements ResultSerializer { - - @Override - public String serialize(Object obj) { - return XmlUtil.serialize(obj); - } - -} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/DynamicRouteServiceManager.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/DynamicRouteServiceManager.java new file mode 100644 index 00000000..74e25005 --- /dev/null +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/DynamicRouteServiceManager.java @@ -0,0 +1,68 @@ +package com.gitee.sop.gatewaycommon.route; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.gateway.event.RefreshRoutesEvent; +import org.springframework.cloud.gateway.route.RouteDefinition; +import org.springframework.cloud.gateway.route.RouteDefinitionRepository; +import org.springframework.cloud.gateway.support.NotFoundException; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.http.ResponseEntity; +import reactor.core.publisher.Mono; + +/** + * 动态更新路由 + * @author thc + */ +@Slf4j +public class DynamicRouteServiceManager implements ApplicationEventPublisherAware { + + @Autowired + private RouteDefinitionRepository routeDefinitionRepository; + + private ApplicationEventPublisher publisher; + + /** 根据ID获取路由 */ + public RouteDefinition get(String id) { + return routeDefinitionRepository.getRouteDefinitions() + .filter(routeDefinition -> { + return routeDefinition.getId().equals(id); + }).blockFirst(); + } + + /** 增加路由 */ + public String add(RouteDefinition definition) { + routeDefinitionRepository.save(Mono.just(definition)).subscribe(); + this.publisher.publishEvent(new RefreshRoutesEvent(this)); + return "success"; + } + + /** 更新路由 */ + public String update(RouteDefinition definition) { + try { + this.routeDefinitionRepository.delete(Mono.just(definition.getId())); + } catch (Exception e) { + return "update fail,not find route routeId: " + definition.getId(); + } + try { + routeDefinitionRepository.save(Mono.just(definition)).subscribe(); + this.publisher.publishEvent(new RefreshRoutesEvent(this)); + return "success"; + } catch (Exception e) { + return "update route fail"; + } + } + + /** 删除路由 */ + public Mono> delete(String id) { + return this.routeDefinitionRepository.delete(Mono.just(id)) + .then(Mono.defer(() -> Mono.just(ResponseEntity.ok().build()))) + .onErrorResume(t -> t instanceof NotFoundException, t -> Mono.just(ResponseEntity.notFound().build())); + } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.publisher = applicationEventPublisher; + } +} \ No newline at end of file diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/GatewayContext.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/GatewayContext.java new file mode 100644 index 00000000..a1139978 --- /dev/null +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/GatewayContext.java @@ -0,0 +1,31 @@ +package com.gitee.sop.gatewaycommon.route; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +/** + * @author tanghc + */ +@Getter +@Setter +@ToString +public class GatewayContext { + + public static final String CACHE_GATEWAY_CONTEXT = "cacheGatewayContext"; + + /** + * cache json body + */ + private String cacheBody; + /** + * cache formdata + */ + private MultiValueMap formData = new LinkedMultiValueMap<>(); + /** + * cache reqeust path + */ + private String path; +} \ No newline at end of file diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/GatewayFilterDefinition.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/GatewayFilterDefinition.java new file mode 100644 index 00000000..7fa2e717 --- /dev/null +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/GatewayFilterDefinition.java @@ -0,0 +1,17 @@ +package com.gitee.sop.gatewaycommon.route; + +import lombok.Data; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author tanghc + */ +@Data +public class GatewayFilterDefinition { + //Filter Name */ + private String name; + //对应的路由规则 */ + private Map args = new LinkedHashMap<>(); +} \ No newline at end of file diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/GatewayPredicateDefinition.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/GatewayPredicateDefinition.java new file mode 100644 index 00000000..eb0d8676 --- /dev/null +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/GatewayPredicateDefinition.java @@ -0,0 +1,17 @@ +package com.gitee.sop.gatewaycommon.route; + +import lombok.Data; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author tanghc + */ +@Data +public class GatewayPredicateDefinition { + /** 断言对应的Name */ + private String name; + /** 配置的断言规则 */ + private Map args = new LinkedHashMap<>(); +} \ No newline at end of file diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/GatewayRouteDefinition.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/GatewayRouteDefinition.java new file mode 100644 index 00000000..f73132f3 --- /dev/null +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/GatewayRouteDefinition.java @@ -0,0 +1,23 @@ +package com.gitee.sop.gatewaycommon.route; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author tanghc + */ +@Data +public class GatewayRouteDefinition { + /** 路由的Id */ + private String id; + /** 路由断言集合配置 */ + private List predicates = new ArrayList<>(); + /** 路由过滤器集合配置 */ + private List filters = new ArrayList<>(); + /** 路由规则转发的目标uri */ + private String uri; + /** 路由执行的顺序 */ + private int order = 0; +} \ No newline at end of file diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/NameVersionRoutePredicateFactory.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/NameVersionRoutePredicateFactory.java new file mode 100644 index 00000000..16d6ec57 --- /dev/null +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/NameVersionRoutePredicateFactory.java @@ -0,0 +1,91 @@ +package com.gitee.sop.gatewaycommon.route; + +import com.gitee.sop.gatewaycommon.bean.SopConstants; +import com.gitee.sop.gatewaycommon.param.ParamNames; +import com.gitee.sop.gatewaycommon.util.RequestUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.server.ServerWebExchange; + +import javax.validation.constraints.NotEmpty; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +/** + * @author tanghc + */ +@Slf4j +public class NameVersionRoutePredicateFactory extends AbstractRoutePredicateFactory { + + public static final String PARAM_KEY = "param"; + public static final String REGEXP_KEY = "regexp"; + + private static final String CACHE_REQUEST_BODY_OBJECT_KEY = SopConstants.CACHE_REQUEST_BODY_OBJECT_KEY; + public static final String CACHE_REQUEST_BODY_FOR_MAP = SopConstants.CACHE_REQUEST_BODY_FOR_MAP; + + + public NameVersionRoutePredicateFactory() { + super(Config.class); + } + + @Override + public List shortcutFieldOrder() { + return Arrays.asList(PARAM_KEY, REGEXP_KEY); + } + + /** + * config.param为nameVersion + * + * @param config + * @return + */ + @Override + public Predicate apply(Config config) { + + return exchange -> { + String cachedBody = exchange.getAttribute(CACHE_REQUEST_BODY_OBJECT_KEY); + if (cachedBody == null) { + return false; + } + Map params = exchange.getAttribute(CACHE_REQUEST_BODY_FOR_MAP); + if (params == null) { + params = RequestUtil.parseQueryToMap(cachedBody); + exchange.getAttributes().put(CACHE_REQUEST_BODY_FOR_MAP, params); + } + + String nameVersion = config.param; + String name = params.getOrDefault(ParamNames.API_NAME, ""); + String version = params.getOrDefault(ParamNames.VERSION_NAME, ""); + return (name + version).equals(nameVersion); + }; + } + + @Validated + public static class Config { + @NotEmpty + private String param; + + private String regexp; + + public String getParam() { + return param; + } + + public Config setParam(String param) { + this.param = param; + return this; + } + + public String getRegexp() { + return regexp; + } + + public Config setRegexp(String regexp) { + this.regexp = regexp; + return this; + } + } +} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/ReadBodyRoutePredicateFactory.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/ReadBodyRoutePredicateFactory.java new file mode 100644 index 00000000..ae4fff34 --- /dev/null +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/ReadBodyRoutePredicateFactory.java @@ -0,0 +1,25 @@ +package com.gitee.sop.gatewaycommon.route; + +import org.springframework.cloud.gateway.handler.predicate.ReadBodyPredicateFactory; + +/** + * 获取form表单插件,使用方式: + * @Bean + * ReadBodyRoutePredicateFactory readBodyRoutePredicateFactory() { + * return new ReadBodyRoutePredicateFactory(); + * } + * + * @author tanghc + */ +public class ReadBodyRoutePredicateFactory extends ReadBodyPredicateFactory { + + @Override + public Config newConfig() { + Config config = super.newConfig(); + config.setInClass(String.class); + config.setPredicate(body -> { + return body != null; + }); + return config; + } +} diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/ServiceRouteInfo.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/ServiceRouteInfo.java new file mode 100644 index 00000000..11c97a95 --- /dev/null +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/ServiceRouteInfo.java @@ -0,0 +1,12 @@ +package com.gitee.sop.gatewaycommon.route; + +import lombok.Data; + +import java.util.List; + +@Data +public class ServiceRouteInfo { + private String appName; + private String md5; + private List routeDefinitionList; +} \ No newline at end of file diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/session/ApiSessionManager.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/session/ApiSessionManager.java index 9246a5d0..465b4bbb 100644 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/session/ApiSessionManager.java +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/session/ApiSessionManager.java @@ -1,6 +1,5 @@ package com.gitee.sop.gatewaycommon.session; -import com.gitee.sop.gatewaycommon.bean.ApiContext; import com.gitee.sop.gatewaycommon.message.ErrorEnum; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; @@ -14,9 +13,8 @@ import java.util.concurrent.TimeUnit; /** * session管理,默认存放的是{@link ApiHttpSession}。采用谷歌guava缓存实现。 - * - * @author tanghc * + * @author tanghc */ public class ApiSessionManager implements SessionManager { private static Logger logger = LoggerFactory.getLogger(ApiSessionManager.class); @@ -31,7 +29,7 @@ public class ApiSessionManager implements SessionManager { @Override public HttpSession getSession(String sessionId) { - if(sessionId == null) { + if (sessionId == null) { return this.createSession(sessionId); } try { @@ -45,12 +43,12 @@ public class ApiSessionManager implements SessionManager { /** * 创建一个session - * + * * @param sessionId 传null将返回一个新session * @return 返回session */ protected HttpSession createSession(String sessionId) { - ServletContext servletContext = getServletContext(); + ServletContext servletContext = null; HttpSession session = this.newSession(sessionId, servletContext); session.setMaxInactiveInterval(getSessionTimeout()); this.cache.put(session.getId(), session); @@ -59,7 +57,7 @@ public class ApiSessionManager implements SessionManager { /** * 返回新的session实例 - * + * * @param sessionId * @param servletContext * @return 返回session @@ -68,10 +66,6 @@ public class ApiSessionManager implements SessionManager { return new ApiHttpSession(servletContext, sessionId); } - protected ServletContext getServletContext() { - return ApiContext.getServletContext(); - } - protected LoadingCache buildCache() { return CacheBuilder.newBuilder().expireAfterAccess(getSessionTimeout(), TimeUnit.MINUTES) .build(new CacheLoader() { @@ -90,7 +84,7 @@ public class ApiSessionManager implements SessionManager { /** * 过期时间,分钟,默认20分钟 - * + * * @return 返回过期时间 */ public int getSessionTimeout() { diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/session/RedisSessionManager.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/session/RedisSessionManager.java index ebf96ceb..f91edf78 100644 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/session/RedisSessionManager.java +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/session/RedisSessionManager.java @@ -1,6 +1,5 @@ package com.gitee.sop.gatewaycommon.session; -import com.gitee.sop.gatewaycommon.bean.ApiContext; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.util.Assert; @@ -10,17 +9,20 @@ import java.util.UUID; /** * SessionManager的redis实现,使用redis管理session - * - * @author tanghc * + * @author tanghc */ public class RedisSessionManager implements SessionManager { private ApiRedisTemplate redisTemplate; - /** 过期时间,30分钟 */ + /** + * 过期时间,30分钟 + */ private int sessionTimeout = 30; - /** 存入redis中key的前缀 */ + /** + * 存入redis中key的前缀 + */ private String keyPrefix = "session:"; public RedisSessionManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) { @@ -32,7 +34,7 @@ public class RedisSessionManager implements SessionManager { public HttpSession getSession(String sessionId) { return this.getSession(sessionId, this.keyPrefix); } - + public HttpSession getSession(String sessionId, String keyPrefix) { if (this.hasKey(sessionId)) { return RedisHttpSession.createExistSession(sessionId, getServletContext(), redisTemplate, keyPrefix); @@ -42,9 +44,10 @@ public class RedisSessionManager implements SessionManager { redisTemplate, keyPrefix); } } - + /** * 构建sessionId + * * @param id * @return 返回sessionid */ @@ -62,7 +65,7 @@ public class RedisSessionManager implements SessionManager { } public ServletContext getServletContext() { - return ApiContext.getServletContext(); + return null; } public int getSessionTimeout() { @@ -71,6 +74,7 @@ public class RedisSessionManager implements SessionManager { /** * 设置session过期时间,单位分钟 + * * @param sessionTimeout */ public void setSessionTimeout(int sessionTimeout) { @@ -91,6 +95,7 @@ public class RedisSessionManager implements SessionManager { /** * 设置存入redis中key的前缀,默认为"session:" + * * @param keyPrefix */ public void setKeyPrefix(String keyPrefix) { diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/util/RequestUtil.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/util/RequestUtil.java index aec2b561..b77c4f4b 100644 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/util/RequestUtil.java +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/util/RequestUtil.java @@ -1,137 +1,46 @@ package com.gitee.sop.gatewaycommon.util; -import com.alibaba.fastjson.JSON; -import com.gitee.sop.gatewaycommon.message.ErrorEnum; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; + /** * @author tanghc */ public class RequestUtil { - private static final String CONTENT_TYPE_URLENCODED = "application/x-www-form-urlencoded"; - private static final String CONTENT_TYPE_JSON = "application/json"; - private static final String CONTENT_TYPE_TEXT = "text/plain"; - private static final String UTF8 = "UTF-8"; - private static final String GET = "get"; - - private static final String UNKOWN = "unknown"; - private static final String LOCAL_IP = "127.0.0.1"; - private static final int IP_LEN = 15; - - public static String getText(HttpServletRequest request) throws Exception { - return IOUtils.toString(request.getInputStream(), UTF8); - } - - /** - * 从request中获取json。如果提交方式是application/x-www-form-urlencoded,则组装成json格式。 - * - * @param request request对象 - * @return 返回json - * @throws IOException - */ - public static String getJson(HttpServletRequest request) throws Exception { - String requestJson = null; - String contectType = request.getContentType(); - if (StringUtils.isBlank(contectType)) { - throw ErrorEnum.ISV_INVALID_CONTENT_TYPE.getErrorMeta().getException(contectType); - } - - contectType = contectType.toLowerCase(); - - if (contectType.contains(CONTENT_TYPE_JSON) || contectType.contains(CONTENT_TYPE_TEXT)) { - requestJson = getText(request); - } else if (contectType.contains(CONTENT_TYPE_URLENCODED)) { - Map params = convertRequestParamsToMap(request); - requestJson = JSON.toJSONString(params); - } else { - throw ErrorEnum.ISV_INVALID_CONTENT_TYPE.getErrorMeta().getException(contectType); - } - return requestJson; - } /** - * request中的参数转换成map - * - * @param request request对象 - * @return 返回参数键值对 + * 将get类型的参数转换成map, + * + * @param query charset=utf-8&biz_content=xxx + * @return */ - public static Map convertRequestParamsToMap(HttpServletRequest request) { - Map paramMap = request.getParameterMap(); - if(paramMap == null || paramMap.isEmpty()) { + public static Map parseQueryToMap(String query) { + if (query == null) { return Collections.emptyMap(); } - Map retMap = new HashMap(paramMap.size()); - - Set> entrySet = paramMap.entrySet(); - - for (Entry entry : entrySet) { - String name = entry.getKey(); - String[] values = entry.getValue(); - if (values.length == 1) { - retMap.put(name, values[0]); - } - } - return retMap; - } - - /** - * 获取客户端真实IP - * - * @param request request对象 - * @return 返回ip - */ - public static String getClientIP(HttpServletRequest request) { - String ipAddress = request.getHeader("x-forwarded-for"); - if (ipAddress == null || ipAddress.length() == 0 || UNKOWN.equalsIgnoreCase(ipAddress)) { - ipAddress = request.getHeader("Proxy-Client-IP"); - } - if (ipAddress == null || ipAddress.length() == 0 || UNKOWN.equalsIgnoreCase(ipAddress)) { - ipAddress = request.getHeader("WL-Proxy-Client-IP"); - } - if (ipAddress == null || ipAddress.length() == 0 || UNKOWN.equalsIgnoreCase(ipAddress)) { - ipAddress = request.getRemoteAddr(); - if (LOCAL_IP.equals(ipAddress)) { - // 根据网卡取本机配置的IP + String[] queryList = StringUtils.split(query, '&'); + Map params = new HashMap<>(16); + for (String param : queryList) { + String[] paramArr = param.split("\\="); + if (paramArr.length == 2) { try { - InetAddress inet = InetAddress.getLocalHost(); - ipAddress = inet.getHostAddress(); - } catch (UnknownHostException e) { - // ignore + params.put(paramArr[0], URLDecoder.decode(paramArr[1], UTF8)); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); } + } else if (paramArr.length == 1) { + params.put(paramArr[0], ""); } - } - - // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 - if (ipAddress != null && ipAddress.length() > IP_LEN) { - if (ipAddress.indexOf(",") > 0) { - ipAddress = ipAddress.substring(0, ipAddress.indexOf(",")); - } - } - return ipAddress; - - } - - /** - * 是否是get请求 - * @param request request对象 - * @return true,是 - */ - public static boolean isGetRequest(HttpServletRequest request) { - return GET.equalsIgnoreCase(request.getMethod()); + return params; } } diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/AbstractSigner.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/AbstractSigner.java index e06236a0..e507db8b 100644 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/AbstractSigner.java +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/AbstractSigner.java @@ -1,12 +1,9 @@ package com.gitee.sop.gatewaycommon.validate; -import com.gitee.sop.gatewaycommon.bean.ApiContext; import com.gitee.sop.gatewaycommon.message.ErrorEnum; import com.gitee.sop.gatewaycommon.param.ApiParam; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang.StringUtils; - -import javax.servlet.http.HttpServletRequest; +import org.apache.commons.lang3.StringUtils; /** * @author tanghc @@ -24,8 +21,7 @@ public abstract class AbstractSigner implements Signer { protected abstract String buildServerSign(ApiParam params, String secret); @Override - public boolean checkSign(HttpServletRequest request, String secret) { - ApiParam apiParam = ApiContext.getApiParam(); + public boolean checkSign(ApiParam apiParam, String secret) { String clientSign = apiParam.fetchSignAndRemove(); if (StringUtils.isBlank(clientSign)) { throw ErrorEnum.ISV_MISSING_SIGNATURE.getErrorMeta().getException(); @@ -33,4 +29,16 @@ public abstract class AbstractSigner implements Signer { String serverSign = buildServerSign(apiParam, secret); return clientSign.equals(serverSign); } + + public static String byte2hex(byte[] bytes) { + StringBuilder sign = new StringBuilder(); + for (int i = 0; i < bytes.length; i++) { + String hex = Integer.toHexString(bytes[i] & 0xFF); + if (hex.length() == 1) { + sign.append("0"); + } + sign.append(hex); + } + return sign.toString(); + } } diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/ApiSigner.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/ApiSigner.java index 133fa1f0..183fc5af 100644 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/ApiSigner.java +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/ApiSigner.java @@ -3,7 +3,6 @@ package com.gitee.sop.gatewaycommon.validate; import com.gitee.sop.gatewaycommon.message.ErrorEnum; import com.gitee.sop.gatewaycommon.param.ApiParam; -import org.apache.tomcat.util.buf.HexUtils; import java.util.ArrayList; import java.util.Collections; @@ -51,6 +50,6 @@ public class ApiSigner extends AbstractSigner { byte[] bytes = signEncipher.encrypt(source, secret); // 第四步:把二进制转化为大写的十六进制 - return HexUtils.toHexString(bytes).toUpperCase(); + return byte2hex(bytes).toUpperCase(); } } diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/ApiValidator.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/ApiValidator.java index eae626d7..37d60c10 100644 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/ApiValidator.java +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/ApiValidator.java @@ -49,7 +49,7 @@ public class ApiValidator implements Validator { checkAppKey(param); checkSign(param); } - checkUploadFile(param); +// checkUploadFile(param); checkTimeout(param); checkFormat(param); } @@ -59,28 +59,28 @@ public class ApiValidator implements Validator { * * @param param */ - protected void checkUploadFile(ApiParam param) { - UploadContext uploadContext = ApiContext.getUploadContext(); - if (uploadContext != null) { - try { - List files = uploadContext.getAllFile(); - for (MultipartFile file : files) { - // 客户端传来的文件md5 - String clientMd5 = param.getString(file.getName()); - if (clientMd5 != null) { - String fileMd5 = DigestUtils.md5Hex(file.getBytes()); - if (!clientMd5.equals(fileMd5)) { - throw ErrorEnum.ISV_UPLOAD_FAIL.getErrorMeta().getException(); - } - } - } - } catch (IOException e) { - logger.error("验证上传文件MD5错误", e); - throw ErrorEnum.ISV_UPLOAD_FAIL.getErrorMeta().getException(); - } - } - - } +// protected void checkUploadFile(ApiParam param) { +// UploadContext uploadContext = ApiContext.getUploadContext(); +// if (uploadContext != null) { +// try { +// List files = uploadContext.getAllFile(); +// for (MultipartFile file : files) { +// // 客户端传来的文件md5 +// String clientMd5 = param.getString(file.getName()); +// if (clientMd5 != null) { +// String fileMd5 = DigestUtils.md5Hex(file.getBytes()); +// if (!clientMd5.equals(fileMd5)) { +// throw ErrorEnum.ISV_UPLOAD_FAIL.getErrorMeta().getException(); +// } +// } +// } +// } catch (IOException e) { +// logger.error("验证上传文件MD5错误", e); +// throw ErrorEnum.ISV_UPLOAD_FAIL.getErrorMeta().getException(); +// } +// } +// +// } protected void checkTimeout(ApiParam param) { int timeoutSeconds = ApiContext.getApiConfig().getTimeoutSeconds(); @@ -129,7 +129,7 @@ public class ApiValidator implements Validator { throw ErrorEnum.ISV_MISSING_SIGNATURE_CONFIG.getErrorMeta().getException(); } Signer signer = apiConfig.getSigner(); - boolean isRightSign = signer.checkSign(ApiContext.getRequest(), secret); + boolean isRightSign = signer.checkSign(param, secret); // 错误的sign if (!isRightSign) { throw ErrorEnum.ISV_INVALID_SIGNATURE.getErrorMeta().getException(param.fetchNameVersion()); diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/Signer.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/Signer.java index 53d27a1c..403ca71e 100644 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/Signer.java +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/Signer.java @@ -1,5 +1,7 @@ package com.gitee.sop.gatewaycommon.validate; +import com.gitee.sop.gatewaycommon.param.ApiParam; + import javax.servlet.http.HttpServletRequest; /** @@ -11,10 +13,10 @@ public interface Signer { /** * 签名校验 - * @param request + * @param apiParam 参数 * @param secret 秘钥 * @return true签名正确 */ - boolean checkSign(HttpServletRequest request, String secret); + boolean checkSign(ApiParam apiParam, String secret); } diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/alipay/AlipaySigner.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/alipay/AlipaySigner.java index 6f690e55..4cdf38f2 100644 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/alipay/AlipaySigner.java +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/alipay/AlipaySigner.java @@ -16,10 +16,9 @@ import javax.servlet.http.HttpServletRequest; public class AlipaySigner implements Signer { @Override - public boolean checkSign(HttpServletRequest request, String secret) { + public boolean checkSign(ApiParam apiParam, String secret) { // 服务端存的是公钥 String publicKey = secret; - ApiParam apiParam = ApiContext.getApiParam(); String charset = apiParam.fetchCharset(); String signType = apiParam.fetchSignMethod(); if (signType == null) { diff --git a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/taobao/TaobaoSigner.java b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/taobao/TaobaoSigner.java index 21a1a620..d22ac812 100644 --- a/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/taobao/TaobaoSigner.java +++ b/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/taobao/TaobaoSigner.java @@ -7,8 +7,7 @@ import com.gitee.sop.gatewaycommon.validate.AbstractSigner; import com.gitee.sop.gatewaycommon.validate.SignEncipher; import com.gitee.sop.gatewaycommon.validate.SignEncipherHMAC_MD5; import com.gitee.sop.gatewaycommon.validate.SignEncipherMD5; -import org.apache.commons.lang.StringUtils; -import org.apache.tomcat.util.buf.HexUtils; +import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.Collections; @@ -59,6 +58,6 @@ public class TaobaoSigner extends AbstractSigner { byte[] bytes = signEncipher.encrypt(source, secret); // 第四步:把二进制转化为大写的十六进制 - return HexUtils.toHexString(bytes).toUpperCase(); + return byte2hex(bytes).toUpperCase(); } } diff --git a/sop-gateway/pom.xml b/sop-gateway/pom.xml index c1a78a50..df9c5649 100644 --- a/sop-gateway/pom.xml +++ b/sop-gateway/pom.xml @@ -26,10 +26,10 @@ 1.0.0-SNAPSHOT - - org.springframework.cloud - spring-cloud-starter-netflix-zuul - + + + + org.springframework.cloud spring-cloud-starter-netflix-eureka-client diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/SopGatewayApplication.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/SopGatewayApplication.java index cc7af2ed..1bdca787 100644 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/SopGatewayApplication.java +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/SopGatewayApplication.java @@ -2,10 +2,10 @@ package com.gitee.sop.gateway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.netflix.zuul.EnableZuulProxy; +//import org.springframework.cloud.netflix.zuul.EnableZuulProxy; // 开启网关功能 -@EnableZuulProxy +//@EnableZuulProxy @SpringBootApplication public class SopGatewayApplication { diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/config/GatewayConfig.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/config/GatewayConfig.java new file mode 100644 index 00000000..4f07eb46 --- /dev/null +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/config/GatewayConfig.java @@ -0,0 +1,36 @@ +package com.gitee.sop.gateway.config; + +import com.gitee.sop.gatewaycommon.bean.ApiContext; +import com.gitee.sop.gatewaycommon.configuration.AlipayGatewayConfiguration; +import com.gitee.sop.gatewaycommon.configuration.TaobaoGatewayConfiguration; +import org.springframework.context.annotation.Configuration; + +import java.util.HashMap; +import java.util.Map; + +/** + * 开通支付宝开放平台能力 + * @author tanghc + */ +//@Configuration +//public class GatewayConfig extends AlipayGatewayConfiguration { +// +// { +// Map appSecretStore = new HashMap(); +// appSecretStore.put("alipay_test", "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlyb9aUBaljQP/vjmBFe1mF8HsWSvyfC2NTlpT/V9E+sBxTr8TSkbzJCeeeOEm4LCaVXL0Qz63MZoT24v7AIXTuMdj4jyiM/WJ4tjrWAgnmohNOegfntTto16C3l234vXz4ryWZMR/7W+MXy5B92wPGQEJ0LKFwNEoLspDEWZ7RdE53VH7w6y6sIZUfK+YkXWSwehfKPKlx+lDw3zRJ3/yvMF+U+BAdW/MfECe1GuBnCFKnlMRh3UKczWyXWkL6ItOpYHHJi/jx85op5BWDje2pY9QowzfN94+0DB3T7UvZeweu3zlP6diwAJDzLaFQX8ULfWhY+wfKxIRgs9NoiSAQIDAQAB"); +// ApiContext.getApiConfig().addAppSecret(appSecretStore); +// } +//} + +/** + * 开通淘宝开放平能力 + */ +@Configuration +public class GatewayConfig extends TaobaoGatewayConfiguration { + + { + Map appSecretStore = new HashMap(); + appSecretStore.put("taobao_test", "G9w0BAQEFAAOCAQ8AMIIBCgKCA"); + ApiContext.getApiConfig().addAppSecret(appSecretStore); + } +} diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/config/ZuulConfig.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/config/ZuulConfig.java deleted file mode 100644 index e9ccd367..00000000 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/config/ZuulConfig.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.gitee.sop.gateway.config; - -import com.gitee.sop.gatewaycommon.bean.ApiContext; -import com.gitee.sop.gatewaycommon.configuration.AlipayZuulConfiguration; -import org.springframework.context.annotation.Configuration; - -import java.util.HashMap; -import java.util.Map; - -/** - * 开通支付宝开放平台能力 - * @author tanghc - */ -@Configuration -public class ZuulConfig extends AlipayZuulConfiguration { - - { - Map appSecretStore = new HashMap(); - appSecretStore.put("alipay_test", "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlyb9aUBaljQP/vjmBFe1mF8HsWSvyfC2NTlpT/V9E+sBxTr8TSkbzJCeeeOEm4LCaVXL0Qz63MZoT24v7AIXTuMdj4jyiM/WJ4tjrWAgnmohNOegfntTto16C3l234vXz4ryWZMR/7W+MXy5B92wPGQEJ0LKFwNEoLspDEWZ7RdE53VH7w6y6sIZUfK+YkXWSwehfKPKlx+lDw3zRJ3/yvMF+U+BAdW/MfECe1GuBnCFKnlMRh3UKczWyXWkL6ItOpYHHJi/jx85op5BWDje2pY9QowzfN94+0DB3T7UvZeweu3zlP6diwAJDzLaFQX8ULfWhY+wfKxIRgs9NoiSAQIDAQAB"); - ApiContext.getApiConfig().addAppSecret(appSecretStore); - } -} - -/** - * 开通淘宝开放平能力 - */ -//@Configuration -//public class ZuulConfig extends TaobaoZuulConfiguration { -// -// { -// Map appSecretStore = new HashMap(); -// appSecretStore.put("taobao_test", "G9w0BAQEFAAOCAQ8AMIIBCgKCA"); -// ApiContext.getApiConfig().addAppSecret(appSecretStore); -// } -//} diff --git a/sop-gateway/src/main/resources/application.properties b/sop-gateway/src/main/resources/application.properties deleted file mode 100644 index 85c1a89c..00000000 --- a/sop-gateway/src/main/resources/application.properties +++ /dev/null @@ -1,28 +0,0 @@ -server.port=8081 -spring.application.name=api-gateway - -# 注册中心 -eureka.host=localhost -eureka.port=1111 -eureka.client.serviceUrl.defaultZone=http://${eureka.host}:${eureka.port}/eureka/ - -# 入口地址,默认是/zuul -zuul.servlet-path=/api - -# 路由配置 -# story服务路由配置 -# 内置有个默认的: -# zuul.routes..path=/<服务名>/** -# zuul.routes..serviceId=<服务名> -# 等同于: -# zuul.routes.<服务名>=/<服务名>/** - - -# Redis数据库索引(默认为0) -spring.redis.database=0 -# Redis服务器地址 -spring.redis.host=127.0.0.1 -# Redis服务器连接端口 -spring.redis.port=6379 -# Redis服务器连接密码(默认为空) -spring.redis.password= diff --git a/sop-gateway/src/main/resources/application.yml b/sop-gateway/src/main/resources/application.yml new file mode 100644 index 00000000..003055cb --- /dev/null +++ b/sop-gateway/src/main/resources/application.yml @@ -0,0 +1,16 @@ +server: + port: 8081 + +eureka: + serverAddr: localhost:1111 + client: + serviceUrl: + defaultZone: http://${eureka.serverAddr}/eureka/ + +spring: + cloud: + gateway: + discovery: + locator: + lower-case-service-id: true + enabled: true diff --git a/sop-gateway/src/main/resources/bootstrap.yml b/sop-gateway/src/main/resources/bootstrap.yml new file mode 100644 index 00000000..9a68f870 --- /dev/null +++ b/sop-gateway/src/main/resources/bootstrap.yml @@ -0,0 +1,8 @@ + +spring: + application: + name: api-gateway + + cloud: + zookeeper: + connect-string: localhost:2181 \ No newline at end of file diff --git a/sop-registry/pom.xml b/sop-registry/pom.xml index 2518b0e9..0c55702e 100644 --- a/sop-registry/pom.xml +++ b/sop-registry/pom.xml @@ -12,7 +12,7 @@ sop-registry 1.0.0-SNAPSHOT sop-registry - 注册中心 + sop-registry 1.8 diff --git a/sop-server-common/.gitignore b/sop-service-common/.gitignore similarity index 100% rename from sop-server-common/.gitignore rename to sop-service-common/.gitignore diff --git a/sop-server-common/pom.xml b/sop-service-common/pom.xml similarity index 72% rename from sop-server-common/pom.xml rename to sop-service-common/pom.xml index 6843c42d..3d6f1341 100644 --- a/sop-server-common/pom.xml +++ b/sop-service-common/pom.xml @@ -10,8 +10,8 @@ com.gitee.sop - sop-server-common - sop-server-common + sop-service-common + sop-service-common 1.0.0-SNAPSHOT @@ -30,6 +30,34 @@ ${fastjson.version} + + + org.springframework.cloud + spring-cloud-starter-zookeeper-all + + + + org.springframework.cloud + spring-cloud-starter-zookeeper-discovery + + + org.apache.zookeeper + zookeeper + + + + + org.apache.zookeeper + zookeeper + 3.4.12 + + + org.slf4j + slf4j-log4j12 + + + + org.springframework.boot spring-boot-starter-web diff --git a/sop-server-common/readme.md b/sop-service-common/readme.md similarity index 84% rename from sop-server-common/readme.md rename to sop-service-common/readme.md index 1335082e..149cc7f7 100644 --- a/sop-server-common/readme.md +++ b/sop-service-common/readme.md @@ -1,3 +1,3 @@ -# sop-server-common +# sop-service-common 微服务端公共组件,每个微服务需要依赖这个jar,先把这个工程mvn deploy到maven私服。 diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/annotation/ApiAbility.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/annotation/ApiAbility.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/annotation/ApiAbility.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/annotation/ApiAbility.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/annotation/ApiMapping.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/annotation/ApiMapping.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/annotation/ApiMapping.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/annotation/ApiMapping.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/bean/ParamNames.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ParamNames.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/bean/ParamNames.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ParamNames.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceApiInfo.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceApiInfo.java similarity index 86% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceApiInfo.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceApiInfo.java index 3b67f8a3..3eb368f1 100644 --- a/sop-server-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceApiInfo.java +++ b/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceApiInfo.java @@ -1,6 +1,7 @@ package com.gitee.sop.servercommon.bean; import com.alibaba.fastjson.annotation.JSONField; +import com.gitee.sop.servercommon.route.GatewayRouteDefinition; import lombok.Data; import java.util.List; @@ -13,6 +14,7 @@ public class ServiceApiInfo { private String md5; private String appName; private List apis; + private List routeDefinitionList; @Data public static class ApiMeta { diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceConfig.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceConfig.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceConfig.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceConfig.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceContext.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceContext.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceContext.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceContext.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/configuration/AlipayServerConfiguration.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/AlipayServiceConfiguration.java similarity index 83% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/configuration/AlipayServerConfiguration.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/AlipayServiceConfiguration.java index e6623169..bc1a7233 100644 --- a/sop-server-common/src/main/java/com/gitee/sop/servercommon/configuration/AlipayServerConfiguration.java +++ b/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/AlipayServiceConfiguration.java @@ -9,9 +9,9 @@ import java.util.List; * 具备支付宝开放平台服务提供能力 * @author tanghc */ -public class AlipayServerConfiguration extends BaseServerConfiguration { +public class AlipayServiceConfiguration extends BaseServiceConfiguration { - public AlipayServerConfiguration() { + public AlipayServiceConfiguration() { // 默认版本号为1.0 ServiceConfig.getInstance().setDefaultVersion("1.0"); } diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/configuration/BaseServerConfiguration.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/BaseServiceConfiguration.java similarity index 67% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/configuration/BaseServerConfiguration.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/BaseServiceConfiguration.java index 23ea2098..f8eba85a 100644 --- a/sop-server-common/src/main/java/com/gitee/sop/servercommon/configuration/BaseServerConfiguration.java +++ b/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/BaseServiceConfiguration.java @@ -1,44 +1,30 @@ package com.gitee.sop.servercommon.configuration; import com.gitee.sop.servercommon.bean.ServiceConfig; -import com.gitee.sop.servercommon.exception.ServiceException; import com.gitee.sop.servercommon.interceptor.ServiceContextInterceptor; import com.gitee.sop.servercommon.manager.ApiMetaManager; import com.gitee.sop.servercommon.manager.DefaultRequestMappingEvent; -import com.gitee.sop.servercommon.manager.RedisApiMetaManager; +import com.gitee.sop.servercommon.manager.ServiceZookeeperApiMetaManager; import com.gitee.sop.servercommon.mapping.ApiMappingHandlerMapping; import com.gitee.sop.servercommon.message.ServiceErrorFactory; -import com.gitee.sop.servercommon.result.ServiceResultBuilder; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.web.servlet.error.ErrorController; import org.springframework.context.annotation.Bean; import org.springframework.core.env.Environment; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import javax.annotation.PostConstruct; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; /** * @author tanghc */ -public class BaseServerConfiguration extends WebMvcConfigurationSupport { +public class BaseServiceConfiguration extends WebMvcConfigurationSupport { - public BaseServerConfiguration() { + public BaseServiceConfiguration() { ServiceConfig.getInstance().getI18nModules().add("i18n/isp/bizerror"); } - @Autowired - private StringRedisTemplate redisTemplate; - @Autowired private Environment environment; @@ -55,7 +41,7 @@ public class BaseServerConfiguration extends WebMvcConfigurationSupport { */ @Override protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() { - ApiMetaManager apiMetaManager = new RedisApiMetaManager(redisTemplate); + ApiMetaManager apiMetaManager = new ServiceZookeeperApiMetaManager(environment); DefaultRequestMappingEvent requestMappingEvent = new DefaultRequestMappingEvent(apiMetaManager, environment); return new ApiMappingHandlerMapping(requestMappingEvent); } diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/configuration/DefaultGlobalExceptionHandler.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/DefaultGlobalExceptionHandler.java similarity index 82% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/configuration/DefaultGlobalExceptionHandler.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/DefaultGlobalExceptionHandler.java index 9395fc41..17e6edf8 100644 --- a/sop-server-common/src/main/java/com/gitee/sop/servercommon/configuration/DefaultGlobalExceptionHandler.java +++ b/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/DefaultGlobalExceptionHandler.java @@ -3,6 +3,7 @@ package com.gitee.sop.servercommon.configuration; import com.gitee.sop.servercommon.bean.ServiceConfig; import com.gitee.sop.servercommon.exception.ServiceException; import com.gitee.sop.servercommon.result.ServiceResultBuilder; +import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestMapping; @@ -16,6 +17,7 @@ import javax.servlet.http.HttpServletResponse; * @author tanghc */ @ControllerAdvice +@Slf4j public class DefaultGlobalExceptionHandler implements GlobalExceptionHandler { @RequestMapping("/error") @@ -27,10 +29,17 @@ public class DefaultGlobalExceptionHandler implements GlobalExceptionHandler { @ExceptionHandler(ServiceException.class) @ResponseBody - public Object exceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception exception) throws Exception { + public Object serviceExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception exception) throws Exception { return this.processError(request, response, exception); } + @ExceptionHandler(Exception.class) + @ResponseBody + public Object exceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception exception) throws Exception { + log.error("系统错误", exception); + return this.processError(request, response, new RuntimeException("系统错误")); + } + /** * 处理异常 * diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/configuration/GlobalExceptionHandler.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/GlobalExceptionHandler.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/configuration/GlobalExceptionHandler.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/GlobalExceptionHandler.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/configuration/TaobaoServerConfiguration.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/TaobaoServiceConfiguration.java similarity index 62% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/configuration/TaobaoServerConfiguration.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/TaobaoServiceConfiguration.java index 50990e0d..eeb7eb0a 100644 --- a/sop-server-common/src/main/java/com/gitee/sop/servercommon/configuration/TaobaoServerConfiguration.java +++ b/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/TaobaoServiceConfiguration.java @@ -4,6 +4,6 @@ package com.gitee.sop.servercommon.configuration; * 具备淘宝开放平台服务提供能力 * @author tanghc */ -public class TaobaoServerConfiguration extends BaseServerConfiguration { +public class TaobaoServiceConfiguration extends BaseServiceConfiguration { } diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/exception/ServiceException.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/exception/ServiceException.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/exception/ServiceException.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/exception/ServiceException.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/interceptor/ServiceContextInterceptor.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/interceptor/ServiceContextInterceptor.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/interceptor/ServiceContextInterceptor.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/interceptor/ServiceContextInterceptor.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/manager/ApiMetaManager.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ApiMetaManager.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/manager/ApiMetaManager.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ApiMetaManager.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/manager/DefaultRequestMappingEvent.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/DefaultRequestMappingEvent.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/manager/DefaultRequestMappingEvent.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/DefaultRequestMappingEvent.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/manager/RedisApiMetaManager.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/RedisApiMetaManager.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/manager/RedisApiMetaManager.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/RedisApiMetaManager.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/manager/RequestMappingEvent.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/RequestMappingEvent.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/manager/RequestMappingEvent.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/RequestMappingEvent.java diff --git a/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ServiceZookeeperApiMetaManager.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ServiceZookeeperApiMetaManager.java new file mode 100644 index 00000000..06379318 --- /dev/null +++ b/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ServiceZookeeperApiMetaManager.java @@ -0,0 +1,153 @@ +package com.gitee.sop.servercommon.manager; + +import com.alibaba.fastjson.JSON; +import com.gitee.sop.servercommon.bean.ServiceApiInfo; +import com.gitee.sop.servercommon.route.GatewayPredicateDefinition; +import com.gitee.sop.servercommon.route.GatewayRouteDefinition; +import com.gitee.sop.servercommon.route.ServiceRouteInfo; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.retry.ExponentialBackoffRetry; +import org.springframework.core.env.Environment; +import org.springframework.util.StringUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * @author tanghc + */ +@Slf4j +@Getter +@Setter +public class ServiceZookeeperApiMetaManager implements ApiMetaManager { + + + /** + * NameVersion=alipay.story.get1.0 + * see com.gitee.sop.gatewaycommon.route.NameVersionRoutePredicateFactory + */ + private static String QUERY_PREDICATE_DEFINITION_TPL = "NameVersion=%s"; + + 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) { + this.environment = environment; + } + + @Override + public void uploadApi(ServiceApiInfo serviceApiInfo) { + ServiceRouteInfo serviceRouteInfo = this.buildServiceGatewayInfo(serviceApiInfo); + this.uploadServiceRouteInfoToZookeeper(serviceRouteInfo); + } + + /** + * 构建接口信息,符合spring cloud gateway的格式 + * + * @param serviceApiInfo + * @return + */ + protected ServiceRouteInfo buildServiceGatewayInfo(ServiceApiInfo serviceApiInfo) { + List apis = serviceApiInfo.getApis(); + List routeDefinitionList = new ArrayList<>(apis.size() + 1); + routeDefinitionList.add(this.buildReadBodyRouteDefinition(serviceApiInfo)); + for (ServiceApiInfo.ApiMeta apiMeta : apis) { + GatewayRouteDefinition gatewayRouteDefinition = this.buildGatewayRouteDefinition(serviceApiInfo, apiMeta); + routeDefinitionList.add(gatewayRouteDefinition); + } + ServiceRouteInfo serviceRouteInfo = new ServiceRouteInfo(); + serviceRouteInfo.setAppName(serviceApiInfo.getAppName()); + serviceRouteInfo.setRouteDefinitionList(routeDefinitionList); + serviceRouteInfo.setMd5(serviceApiInfo.getMd5()); + return serviceRouteInfo; + } + + /** + * 添加com.gitee.sop.gatewaycommon.route.ReadBodyRoutePredicateFactory,解决form表单获取不到问题 + * + * @return + */ + protected GatewayRouteDefinition buildReadBodyRouteDefinition(ServiceApiInfo serviceApiInfo) { + GatewayRouteDefinition gatewayRouteDefinition = this.buildGatewayRouteDefinition(serviceApiInfo, FIRST_API_META); + + GatewayPredicateDefinition gatewayPredicateDefinition = new GatewayPredicateDefinition(); + gatewayPredicateDefinition.setName("ReadBody"); + GatewayPredicateDefinition readerBodyPredicateDefinition = this.buildNameVersionPredicateDefinition(FIRST_API_META); + List predicates = Arrays.asList(gatewayPredicateDefinition, readerBodyPredicateDefinition); + gatewayRouteDefinition.setPredicates(predicates); + + return gatewayRouteDefinition; + } + + protected GatewayRouteDefinition buildGatewayRouteDefinition(ServiceApiInfo serviceApiInfo, ServiceApiInfo.ApiMeta apiMeta) { + GatewayRouteDefinition gatewayRouteDefinition = new GatewayRouteDefinition(); + // 唯一id规则:接口名 + 版本号 + gatewayRouteDefinition.setId(apiMeta.fetchNameVersion()); + gatewayRouteDefinition.setFilters(Collections.emptyList()); + gatewayRouteDefinition.setOrder(0); + List 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); + return gatewayRouteDefinition; + } + + protected GatewayPredicateDefinition buildNameVersionPredicateDefinition(ServiceApiInfo.ApiMeta apiMeta) { + return new GatewayPredicateDefinition(String.format(QUERY_PREDICATE_DEFINITION_TPL, apiMeta.fetchNameVersion())); + } + + /** + * 上传接口信息到zookeeper + * + * @param serviceRouteInfo + */ + protected void uploadServiceRouteInfoToZookeeper(ServiceRouteInfo serviceRouteInfo) { + String zookeeperServerAddr = environment.getProperty("spring.cloud.zookeeper.connect-string"); + if (StringUtils.isEmpty(zookeeperServerAddr)) { + throw new RuntimeException("未指定spring.cloud.zookeeper.connect-string参数"); + } + String serviceRouteInfoJson = JSON.toJSONString(serviceRouteInfo); + CuratorFramework client = null; + try { + // 保存路径 + String savePath = sopServiceApiPath + "/" + serviceRouteInfo.getAppName(); + + client = CuratorFrameworkFactory.builder() + .connectString(zookeeperServerAddr) + .retryPolicy(new ExponentialBackoffRetry(1000, 3)) + .build(); + + client.start(); + + log.info("上传接口信息到zookeeper,path:{}, appName:{}, md5:{}, 接口数量:{}", + savePath, + serviceRouteInfo.getAppName(), + serviceRouteInfo.getMd5(), + serviceRouteInfo.getRouteDefinitionList().size()); + + client.create() + // 如果节点存在则Curator将会使用给出的数据设置这个节点的值 + .orSetData() + // 如果指定节点的父节点不存在,则Curator将会自动级联创建父节点 + .creatingParentContainersIfNeeded() + .forPath(savePath, serviceRouteInfoJson.getBytes()); + } catch (Exception e) { + log.error("更新接口信息到zookeeper失败, appName:{}", serviceRouteInfo.getAppName(), e); + } finally { + if (client != null) { + client.close(); + } + } + } + +} diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingHandlerMapping.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingHandlerMapping.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingHandlerMapping.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingHandlerMapping.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingInfo.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingInfo.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingInfo.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingInfo.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingRequestCondition.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingRequestCondition.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingRequestCondition.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingRequestCondition.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingStringValueResolver.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingStringValueResolver.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingStringValueResolver.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingStringValueResolver.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/message/ServiceError.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/message/ServiceError.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/message/ServiceError.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/message/ServiceError.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/message/ServiceErrorEnum.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/message/ServiceErrorEnum.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/message/ServiceErrorEnum.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/message/ServiceErrorEnum.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/message/ServiceErrorFactory.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/message/ServiceErrorFactory.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/message/ServiceErrorFactory.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/message/ServiceErrorFactory.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/message/ServiceErrorImpl.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/message/ServiceErrorImpl.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/message/ServiceErrorImpl.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/message/ServiceErrorImpl.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/message/ServiceErrorMeta.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/message/ServiceErrorMeta.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/message/ServiceErrorMeta.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/message/ServiceErrorMeta.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/param/ApiArgumentResolver.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/param/ApiArgumentResolver.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/param/ApiArgumentResolver.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/param/ApiArgumentResolver.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/param/ParamValidator.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/param/ParamValidator.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/param/ParamValidator.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/param/ParamValidator.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/param/ServiceParamValidator.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/param/ServiceParamValidator.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/param/ServiceParamValidator.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/param/ServiceParamValidator.java diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/result/DefaultServiceResultBuilder.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/result/DefaultServiceResultBuilder.java similarity index 86% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/result/DefaultServiceResultBuilder.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/result/DefaultServiceResultBuilder.java index c5b909b1..cab2072d 100644 --- a/sop-server-common/src/main/java/com/gitee/sop/servercommon/result/DefaultServiceResultBuilder.java +++ b/sop-service-common/src/main/java/com/gitee/sop/servercommon/result/DefaultServiceResultBuilder.java @@ -9,18 +9,22 @@ import javax.servlet.http.HttpServletResponse; /** * 处理业务返回结果 + * * @author tanghc */ @Slf4j public class DefaultServiceResultBuilder implements ServiceResultBuilder { public static final String ISP_UNKNOWN_ERROR = "isp.unknown-error"; - /** 与网关约定好的状态码,表示业务出错 */ + /** + * 与网关约定好的状态码,表示业务出错 + */ public static final int BIZ_ERROR_CODE = 4000; + public static final String X_BIZ_ERROR_CODE = "x-biz-error-code"; @Override public Object buildError(HttpServletRequest request, HttpServletResponse response, Throwable throwable) { - response.setStatus(BIZ_ERROR_CODE); + response.addHeader(X_BIZ_ERROR_CODE, String.valueOf(BIZ_ERROR_CODE)); String subCode, subMsg; if (throwable instanceof ServiceException) { ServiceException ex = (ServiceException) throwable; diff --git a/sop-server-common/src/main/java/com/gitee/sop/servercommon/result/ServiceResultBuilder.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/result/ServiceResultBuilder.java similarity index 100% rename from sop-server-common/src/main/java/com/gitee/sop/servercommon/result/ServiceResultBuilder.java rename to sop-service-common/src/main/java/com/gitee/sop/servercommon/result/ServiceResultBuilder.java diff --git a/sop-service-common/src/main/java/com/gitee/sop/servercommon/route/GatewayFilterDefinition.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/route/GatewayFilterDefinition.java new file mode 100644 index 00000000..71be9d64 --- /dev/null +++ b/sop-service-common/src/main/java/com/gitee/sop/servercommon/route/GatewayFilterDefinition.java @@ -0,0 +1,17 @@ +package com.gitee.sop.servercommon.route; + +import lombok.Data; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author tanghc + */ +@Data +public class GatewayFilterDefinition { + //Filter Name */ + private String name; + //对应的路由规则 */ + private Map args = new LinkedHashMap<>(); +} \ No newline at end of file diff --git a/sop-service-common/src/main/java/com/gitee/sop/servercommon/route/GatewayPredicateDefinition.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/route/GatewayPredicateDefinition.java new file mode 100644 index 00000000..09c37650 --- /dev/null +++ b/sop-service-common/src/main/java/com/gitee/sop/servercommon/route/GatewayPredicateDefinition.java @@ -0,0 +1,42 @@ +package com.gitee.sop.servercommon.route; + +import lombok.Data; +import org.springframework.util.StringUtils; + +import javax.validation.ValidationException; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author thc + */ +@Data +public class GatewayPredicateDefinition { + public static final String GEN_KEY = "_genkey_"; + /** 断言对应的Name */ + private String name; + /** 配置的断言规则 */ + private Map args = new LinkedHashMap<>(); + + public GatewayPredicateDefinition() { + } + + public GatewayPredicateDefinition(String text) { + int eqIdx = text.indexOf(61); + if (eqIdx <= 0) { + throw new ValidationException("Unable to parse GatewayPredicateDefinition text '" + text + "', must be of the form name=value"); + } else { + this.setName(text.substring(0, eqIdx)); + String[] args = StringUtils.tokenizeToStringArray(text.substring(eqIdx + 1), ","); + + for(int i = 0; i < args.length; ++i) { + this.args.put(generateName(i), args[i]); + } + + } + } + + public static String generateName(int i) { + return GEN_KEY + i; + } +} \ No newline at end of file diff --git a/sop-service-common/src/main/java/com/gitee/sop/servercommon/route/GatewayRouteDefinition.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/route/GatewayRouteDefinition.java new file mode 100644 index 00000000..6227c95f --- /dev/null +++ b/sop-service-common/src/main/java/com/gitee/sop/servercommon/route/GatewayRouteDefinition.java @@ -0,0 +1,23 @@ +package com.gitee.sop.servercommon.route; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author tanghc + */ +@Data +public class GatewayRouteDefinition { + /** 路由的Id */ + private String id; + /** 路由断言集合配置 */ + private List predicates = new ArrayList<>(); + /** 路由过滤器集合配置 */ + private List filters = new ArrayList<>(); + /** 路由规则转发的目标uri */ + private String uri; + /** 路由执行的顺序 */ + private int order = 0; +} \ No newline at end of file diff --git a/sop-service-common/src/main/java/com/gitee/sop/servercommon/route/ServiceRouteInfo.java b/sop-service-common/src/main/java/com/gitee/sop/servercommon/route/ServiceRouteInfo.java new file mode 100644 index 00000000..c59a74eb --- /dev/null +++ b/sop-service-common/src/main/java/com/gitee/sop/servercommon/route/ServiceRouteInfo.java @@ -0,0 +1,15 @@ +package com.gitee.sop.servercommon.route; + +import lombok.Data; + +import java.util.List; + +/** + * @author thc + */ +@Data +public class ServiceRouteInfo { + private String appName; + private String md5; + private List routeDefinitionList; +} \ No newline at end of file diff --git a/sop-server-common/src/main/resources/i18n/isp/error_en.properties b/sop-service-common/src/main/resources/i18n/isp/error_en.properties similarity index 100% rename from sop-server-common/src/main/resources/i18n/isp/error_en.properties rename to sop-service-common/src/main/resources/i18n/isp/error_en.properties diff --git a/sop-server-common/src/main/resources/i18n/isp/error_zh_CN.properties b/sop-service-common/src/main/resources/i18n/isp/error_zh_CN.properties similarity index 100% rename from sop-server-common/src/main/resources/i18n/isp/error_zh_CN.properties rename to sop-service-common/src/main/resources/i18n/isp/error_zh_CN.properties diff --git a/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/config/OpenServerConfig.java b/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/config/OpenServerConfig.java deleted file mode 100644 index 6c1a7f1a..00000000 --- a/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/config/OpenServerConfig.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.gitee.sop.bookweb.config; - -import com.gitee.sop.servercommon.configuration.AlipayServerConfiguration; -import com.gitee.sop.servercommon.configuration.TaobaoServerConfiguration; -import org.springframework.context.annotation.Configuration; - -/** - * 使用支付宝开放平台功能 - * @author tanghc - */ -@Configuration -public class OpenServerConfig extends AlipayServerConfiguration { - -} - -/** - * 使用淘宝开放平台功能 - * @author tanghc - */ -//@Configuration -//public class OpenServerConfig extends TaobaoServerConfiguration { -// -//} diff --git a/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/config/OpenServiceConfig.java b/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/config/OpenServiceConfig.java new file mode 100644 index 00000000..77fb14b3 --- /dev/null +++ b/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/config/OpenServiceConfig.java @@ -0,0 +1,23 @@ +package com.gitee.sop.bookweb.config; + +import com.gitee.sop.servercommon.configuration.AlipayServiceConfiguration; +import com.gitee.sop.servercommon.configuration.TaobaoServiceConfiguration; +import org.springframework.context.annotation.Configuration; + +/** + * 使用支付宝开放平台功能 + * @author tanghc + */ +//@Configuration +//public class OpenServiceConfig extends AlipayServiceConfiguration { +// +//} + +/** + * 使用淘宝开放平台功能 + * @author tanghc + */ +@Configuration +public class OpenServiceConfig extends TaobaoServiceConfiguration { + +} diff --git a/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/AlipayController.java b/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/AlipayController.java index 7f9e86d2..3c36bfce 100644 --- a/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/AlipayController.java +++ b/sop-story/sop-story-web/src/main/java/com/gitee/sop/bookweb/controller/AlipayController.java @@ -3,6 +3,7 @@ package com.gitee.sop.bookweb.controller; import com.gitee.sop.bookweb.message.StoryErrorEnum; import com.gitee.sop.servercommon.annotation.ApiMapping; import com.gitee.sop.story.api.domain.Story; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** @@ -14,10 +15,10 @@ import org.springframework.web.bind.annotation.RestController; public class AlipayController { @ApiMapping(value = "alipay.story.get") - public Story getStory(Story story) { - if (story.getId() == 0) { - throw StoryErrorEnum.param_error.getErrorMeta().getException("id无效"); - } + public Story getStory() { + Story story = new Story(); + story.setId(1); + story.setName("海底小纵队(alipay.story.get)"); return story; } diff --git a/sop-story/sop-story-web/src/main/resources/application.properties b/sop-story/sop-story-web/src/main/resources/application.properties index cb731b6f..e2d6e109 100644 --- a/sop-story/sop-story-web/src/main/resources/application.properties +++ b/sop-story/sop-story-web/src/main/resources/application.properties @@ -5,11 +5,3 @@ eureka.host=localhost eureka.port=1111 eureka.client.serviceUrl.defaultZone=http://${eureka.host}:${eureka.port}/eureka/ -# Redis数据库索引(默认为0) -spring.redis.database=0 -# Redis服务器地址 -spring.redis.host=127.0.0.1 -# Redis服务器连接端口 -spring.redis.port=6379 -# Redis服务器连接密码(默认为空) -spring.redis.password= diff --git a/sop-story/sop-story-web/src/main/resources/bootstrap.yml b/sop-story/sop-story-web/src/main/resources/bootstrap.yml new file mode 100644 index 00000000..37f39ac9 --- /dev/null +++ b/sop-story/sop-story-web/src/main/resources/bootstrap.yml @@ -0,0 +1,7 @@ +spring: + application: + name: story-service + + cloud: + zookeeper: + connect-string: localhost:2181 \ No newline at end of file diff --git a/sop-test/src/test/java/com/gitee/sop/AlipayClientPostTest.java b/sop-test/src/test/java/com/gitee/sop/AlipayClientPostTest.java index 6c830627..c8cf87bb 100644 --- a/sop-test/src/test/java/com/gitee/sop/AlipayClientPostTest.java +++ b/sop-test/src/test/java/com/gitee/sop/AlipayClientPostTest.java @@ -22,7 +22,7 @@ import java.util.Set; public class AlipayClientPostTest extends TestBase { - String url = "http://localhost:8081/api"; + String url = "http://localhost:8081/"; String appId = "alipay_test"; // 支付宝私钥 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="; @@ -51,7 +51,7 @@ biz_content String 是 请求参数的集合,最大长度不限,除公共 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"); + params.put("version", "1.2"); // 业务参数 Map bizContent = new HashMap<>(); diff --git a/sop-test/src/test/java/com/gitee/sop/TaobaoClientPostTest.java b/sop-test/src/test/java/com/gitee/sop/TaobaoClientPostTest.java index e35315ad..978b2399 100644 --- a/sop-test/src/test/java/com/gitee/sop/TaobaoClientPostTest.java +++ b/sop-test/src/test/java/com/gitee/sop/TaobaoClientPostTest.java @@ -15,7 +15,7 @@ import java.util.Map; public class TaobaoClientPostTest extends TestBase { - String url = "http://localhost:8081/api"; + String url = "http://localhost:8081"; String appId = "taobao_test"; // 支付宝私钥 String secret = "G9w0BAQEFAAOCAQ8AMIIBCgKCA"; diff --git a/sop-test/src/test/java/com/gitee/sop/TestBase.java b/sop-test/src/test/java/com/gitee/sop/TestBase.java index f8606e4d..22cc2559 100644 --- a/sop-test/src/test/java/com/gitee/sop/TestBase.java +++ b/sop-test/src/test/java/com/gitee/sop/TestBase.java @@ -27,24 +27,6 @@ import java.util.stream.Collectors; * @author tanghc */ public class TestBase extends TestCase { - public void post(String url, String postJson) throws IOException { - HttpClient httpClient = HttpClientBuilder.create().build(); - HttpPost post = new HttpPost(url); - // 构造消息头 - - post.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"); - // 构建消息实体 - StringEntity entity = new StringEntity(postJson, Charset.forName("UTF-8")); - entity.setContentEncoding("UTF-8"); - // 发送Json格式的数据请求 - entity.setContentType("application/json"); - post.setEntity(entity); - - HttpResponse response = httpClient.execute(post); - HttpEntity responseEntity = response.getEntity(); - String content = IOUtils.toString(responseEntity.getContent(), "UTF-8"); - System.out.println(content); - } /** * 发送POST请求 @@ -52,7 +34,7 @@ public class TestBase extends TestCase { * @return JSON或者字符串 * @throws Exception */ - public static String post(String url, Map params) throws Exception{ + public static String post(String url, Map params) { CloseableHttpClient client = null; CloseableHttpResponse response = null; try{ @@ -78,7 +60,7 @@ public class TestBase extends TestCase { /** * 设置请求的报文头部的编码 */ - post.setHeader(new BasicHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")); + post.setHeader(new BasicHeader("Content-Type", "application/x-www-form-urlencoded")); /** * 执行post请求 */