From c274b6508fdc8ebf872b6c02febfefe14c0ee4fa Mon Sep 17 00:00:00 2001 From: tanghc Date: Thu, 8 Aug 2019 10:57:59 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/sop/gatewaycommon/manager/DefaultEnvGrayManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultEnvGrayManager.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultEnvGrayManager.java index 3fa8561f..bdfc8760 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultEnvGrayManager.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultEnvGrayManager.java @@ -40,7 +40,7 @@ public class DefaultEnvGrayManager implements EnvGrayManager { if (serviceId == null || nameVersion == null) { return null; } - boolean opened = instanceIdServiceIdMap.values().contains(serviceId); + boolean opened = instanceIdServiceIdMap.containsValue(serviceId); // 没有开启灰度 if (!opened) { return null; From da172a9b39d0ca5777c91dde740eff0710429cd6 Mon Sep 17 00:00:00 2001 From: tanghc Date: Thu, 8 Aug 2019 15:18:17 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/sop/servercommon/util/OpenUtil.java | 6 +- .../storyweb/controller/AlipayController.java | 30 ++--- .../sop/gateway/config/PreParamFilter.java | 116 ++++++++++++++++++ 3 files changed, 132 insertions(+), 20 deletions(-) create mode 100644 sop-gateway/src/main/java/com/gitee/sop/gateway/config/PreParamFilter.java diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/util/OpenUtil.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/util/OpenUtil.java index 61c1d527..a99813cd 100644 --- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/util/OpenUtil.java +++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/util/OpenUtil.java @@ -67,12 +67,8 @@ public class OpenUtil { for (Map.Entry entry : entrySet) { String name = entry.getKey(); String[] values = entry.getValue(); - if (values.length == 1) { + if (values.length >= 1) { retMap.put(name, values[0]); - } else if (values.length > 1) { - retMap.put(name, values); - } else { - retMap.put(name, ""); } } diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/AlipayController.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/AlipayController.java index 563c1721..05233fed 100644 --- a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/AlipayController.java +++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/AlipayController.java @@ -127,13 +127,26 @@ public class AlipayController { // http://localhost:2222/alipay.story.get/ @ApiMapping(value = "alipay.story.get") - public Story getStory() { + public Story getStory(Story param) { Story story = new Story(); story.setId(1); - story.setName("海底小纵队(alipay.story.get1.0)"); + story.setName("海底小纵队(alipay.story.get1.0), param:" + param); return story; } + /** + * + * @param param 对应biz_content中的内容,并自动JSR-303校验 + * @return + */ + @ApiMapping(value = "alipay.story.get", version = "1.2") + public Story getStory11(Story param) { + Story story2 = new Story(); + story2.setId(1); + story2.setName("海底小纵队(alipay.story.get1.2), param:" + param); + return story2; + } + /** * 参数绑定 * @param story 对应biz_content中的内容,并自动JSR-303校验 @@ -153,19 +166,6 @@ public class AlipayController { return storyVO; } - /** - * - * @param story 对应biz_content中的内容,并自动JSR-303校验 - * @return - */ - @ApiMapping(value = "alipay.story.get", version = "1.2") - public Story getStory11(Story story) { - Story story2 = new Story(); - story2.setId(1); - story2.setName("海底小纵队(alipay.story.get1.2)"); - return story2; - } - /** * 演示文档表格树 * @param story diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/config/PreParamFilter.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/config/PreParamFilter.java new file mode 100644 index 00000000..74b78789 --- /dev/null +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/config/PreParamFilter.java @@ -0,0 +1,116 @@ +package com.gitee.sop.gateway.config; + +import com.alibaba.fastjson.JSONObject; +import com.gitee.sop.gatewaycommon.param.ApiParam; +import com.gitee.sop.gatewaycommon.param.ParamNames; +import com.gitee.sop.gatewaycommon.zuul.ZuulContext; +import com.gitee.sop.gatewaycommon.zuul.filter.BaseZuulFilter; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.netflix.zuul.context.RequestContext; +import com.netflix.zuul.exception.ZuulException; +import com.netflix.zuul.http.HttpServletRequestWrapper; +import com.netflix.zuul.http.ServletInputStreamWrapper; +import org.apache.commons.lang.StringUtils; +import org.springframework.http.HttpMethod; + +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * @author tanghc + */ +public class PreParamFilter extends BaseZuulFilter { + @Override + protected FilterType getFilterType() { + return FilterType.PRE; + } + + @Override + protected int getFilterOrder() { + return 0; + } + + @Override + protected Object doRun(RequestContext requestContext) throws ZuulException { + ApiParam apiParam = ZuulContext.getApiParam(); + JSONObject bizContent = apiParam.getJSONObject(ParamNames.BIZ_CONTENT_NAME); + // 修改biz_content中的参数 + bizContent.put("name", "修改了111"); + apiParam.put(ParamNames.BIZ_CONTENT_NAME, bizContent.toJSONString()); + + HttpServletRequest request = requestContext.getRequest(); + String contentType = request.getContentType(); + if (StringUtils.containsIgnoreCase(contentType, "json")) { + byte[] bytes = apiParam.toJSONString().getBytes(StandardCharsets.UTF_8); + requestContext.setRequest(new HttpServletRequestWrapper(requestContext.getRequest()) { + @Override + public ServletInputStream getInputStream() throws IOException { + return new ServletInputStreamWrapper(bytes); + } + + @Override + public byte[] getContentData() { + return bytes; + } + + @Override + public int getContentLength() { + return bytes.length; + } + + @Override + public long getContentLengthLong() { + return bytes.length; + } + }); + } else if(StringUtils.containsIgnoreCase(contentType, "form")) { + List list = Lists.newArrayList(); + try { + for (Map.Entry entry : apiParam.entrySet()) { + list.add(entry.getKey() + "=" + URLEncoder.encode(String.valueOf(entry.getValue()), "UTF-8")); + } + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + String paramsStr = StringUtils.join(list, "&"); + byte[] bytes = paramsStr.getBytes(StandardCharsets.UTF_8); + requestContext.setRequest(new HttpServletRequestWrapper(requestContext.getRequest()) { + @Override + public ServletInputStream getInputStream() throws IOException { + return new ServletInputStreamWrapper(bytes); + } + + @Override + public byte[] getContentData() { + return bytes; + } + + @Override + public int getContentLength() { + return bytes.length; + } + + @Override + public long getContentLengthLong() { + return bytes.length; + } + }); + } else if(HttpMethod.GET.name().equalsIgnoreCase(request.getMethod())) { + Map> newParams = Maps.newHashMap(); + for (Map.Entry entry : apiParam.entrySet()) { + newParams.put(entry.getKey(), Collections.singletonList(String.valueOf(entry.getValue()))); + } + requestContext.setRequestQueryParams(newParams); + } + + return null; + } +} From 8a27cccdc5592e11f656c43d6450f462cb983ab3 Mon Sep 17 00:00:00 2001 From: tanghc Date: Thu, 8 Aug 2019 15:56:29 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=B7=AF=E7=94=B1404?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BaseGatewayConfiguration.java | 9 +++++ .../ServiceZookeeperApiMetaManager.java | 37 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/configuration/BaseGatewayConfiguration.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/configuration/BaseGatewayConfiguration.java index 1224ae05..5a3c2b6e 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/configuration/BaseGatewayConfiguration.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/configuration/BaseGatewayConfiguration.java @@ -12,7 +12,9 @@ import com.gitee.sop.gatewaycommon.gateway.route.ReadBodyRoutePredicateFactory; import com.gitee.sop.gatewaycommon.manager.AbstractConfiguration; import com.gitee.sop.gatewaycommon.manager.RouteManager; import com.gitee.sop.gatewaycommon.manager.RouteRepositoryContext; +import com.gitee.sop.gatewaycommon.param.ParamBuilder; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; @@ -21,6 +23,7 @@ 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 org.springframework.web.server.ServerWebExchange; import java.util.Collections; import java.util.List; @@ -54,6 +57,12 @@ public class BaseGatewayConfiguration extends AbstractConfiguration { return jsonExceptionHandler; } + @Bean + @ConditionalOnMissingBean + ParamBuilder paramBuilder() { + return ApiConfig.getInstance().getGatewayParamBuilder(); + } + /** * 处理返回结果 */ diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ServiceZookeeperApiMetaManager.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ServiceZookeeperApiMetaManager.java index 191b8e54..ac11af39 100644 --- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ServiceZookeeperApiMetaManager.java +++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ServiceZookeeperApiMetaManager.java @@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON; import com.gitee.sop.servercommon.bean.ServiceApiInfo; import com.gitee.sop.servercommon.bean.ZookeeperTool; import com.gitee.sop.servercommon.exception.ZookeeperPathNotExistException; +import com.gitee.sop.servercommon.route.GatewayPredicateDefinition; import com.gitee.sop.servercommon.route.GatewayRouteDefinition; import com.gitee.sop.servercommon.route.ServiceRouteInfo; import lombok.Getter; @@ -17,6 +18,7 @@ import org.springframework.util.StringUtils; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -39,6 +41,15 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager { private static final String DEFAULT_CONTEXT_PATH = "/"; + /** + * NameVersion=alipay.story.get1.0 + * see com.gitee.sop.gatewaycommon.routeDefinition.NameVersionRoutePredicateFactory + */ + private static String QUERY_PREDICATE_DEFINITION_TPL = "NameVersion=%s"; + + private static ServiceApiInfo.ApiMeta FIRST_API_META = new ServiceApiInfo.ApiMeta("_first.route_", "/", "v_000"); + + private Environment environment; private ZookeeperTool zookeeperTool; @@ -94,6 +105,7 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager { protected ServiceRouteInfo buildServiceGatewayInfo(ServiceApiInfo serviceApiInfo) { List apis = serviceApiInfo.getApis(); List routeDefinitionList = new ArrayList<>(apis.size()); + routeDefinitionList.add(this.buildReadBodyRouteDefinition(serviceApiInfo)); for (ServiceApiInfo.ApiMeta apiMeta : apis) { GatewayRouteDefinition gatewayRouteDefinition = this.buildGatewayRouteDefinition(serviceApiInfo, apiMeta); routeDefinitionList.add(gatewayRouteDefinition); @@ -136,6 +148,7 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager { BeanUtils.copyProperties(apiMeta, gatewayRouteDefinition); gatewayRouteDefinition.setId(routeId); gatewayRouteDefinition.setFilters(Collections.emptyList()); + gatewayRouteDefinition.setPredicates(this.buildPredicates(apiMeta)); String uri = this.buildUri(serviceApiInfo, apiMeta); String path = this.buildServletPath(serviceApiInfo, apiMeta); gatewayRouteDefinition.setUri(uri); @@ -143,6 +156,30 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager { return gatewayRouteDefinition; } + protected List buildPredicates(ServiceApiInfo.ApiMeta apiMeta) { + GatewayPredicateDefinition gatewayPredicateDefinition = new GatewayPredicateDefinition(); + gatewayPredicateDefinition.setName("ReadBody"); + return Arrays.asList(gatewayPredicateDefinition, this.buildNameVersionPredicateDefinition(apiMeta)); + } + + protected GatewayPredicateDefinition buildNameVersionPredicateDefinition(ServiceApiInfo.ApiMeta apiMeta) { + return new GatewayPredicateDefinition(String.format(QUERY_PREDICATE_DEFINITION_TPL, apiMeta.fetchNameVersion())); + } + + /** + * 添加com.gitee.sop.gatewaycommon.routeDefinition.ReadBodyRoutePredicateFactory,解决form表单获取不到问题 + * + * @return 返回路由定义 + */ + protected GatewayRouteDefinition buildReadBodyRouteDefinition(ServiceApiInfo serviceApiInfo) { + GatewayRouteDefinition readBodyRouteDefinition = this.buildGatewayRouteDefinition(serviceApiInfo, FIRST_API_META); + readBodyRouteDefinition.setOrder(Integer.MIN_VALUE); + + readBodyRouteDefinition.setPredicates(this.buildPredicates(FIRST_API_META)); + + return readBodyRouteDefinition; + } + protected String buildUri(ServiceApiInfo serviceApiInfo, ServiceApiInfo.ApiMeta apiMeta) { return PROTOCOL_LOAD_BALANCE + serviceApiInfo.getServiceId(); } From 36b5123ad7e910ebe9152c1fed82273e5ca2b043 Mon Sep 17 00:00:00 2001 From: tanghc Date: Thu, 8 Aug 2019 20:52:13 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E5=8A=A8=E6=80=81=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sop/gatewaycommon/bean/ApiConfig.java | 7 +- .../manager/ParameterFormatter.java | 19 +++ .../configuration/BaseZuulConfiguration.java | 9 ++ .../zuul/filter/PreValidateFilter.java | 8 + .../zuul/param/BaseParameterFormatter.java | 146 ++++++++++++++++++ .../sop/gateway/config/PreParamFilter.java | 116 -------------- .../com/gitee/sop/sdk/client/OpenHttp.java | 23 +-- .../test/java/com/gitee/sop/sdk/SdkTest.java | 6 +- 8 files changed, 192 insertions(+), 142 deletions(-) create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ParameterFormatter.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/BaseParameterFormatter.java delete mode 100644 sop-gateway/src/main/java/com/gitee/sop/gateway/config/PreParamFilter.java diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java index f76cd5ea..e0bbabbd 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java @@ -5,18 +5,19 @@ import com.gitee.sop.gatewaycommon.gateway.result.GatewayResult; import com.gitee.sop.gatewaycommon.gateway.result.GatewayResultExecutor; import com.gitee.sop.gatewaycommon.limit.DefaultLimitManager; import com.gitee.sop.gatewaycommon.limit.LimitManager; +import com.gitee.sop.gatewaycommon.manager.DefaultEnvGrayManager; import com.gitee.sop.gatewaycommon.manager.DefaultIPBlacklistManager; import com.gitee.sop.gatewaycommon.manager.DefaultIsvRoutePermissionManager; import com.gitee.sop.gatewaycommon.manager.DefaultLimitConfigManager; import com.gitee.sop.gatewaycommon.manager.DefaultRouteConfigManager; import com.gitee.sop.gatewaycommon.manager.DefaultServiceErrorManager; -import com.gitee.sop.gatewaycommon.manager.DefaultEnvGrayManager; +import com.gitee.sop.gatewaycommon.manager.EnvGrayManager; import com.gitee.sop.gatewaycommon.manager.IPBlacklistManager; import com.gitee.sop.gatewaycommon.manager.IsvRoutePermissionManager; import com.gitee.sop.gatewaycommon.manager.LimitConfigManager; +import com.gitee.sop.gatewaycommon.manager.ParameterFormatter; import com.gitee.sop.gatewaycommon.manager.RouteConfigManager; import com.gitee.sop.gatewaycommon.manager.ServiceErrorManager; -import com.gitee.sop.gatewaycommon.manager.EnvGrayManager; import com.gitee.sop.gatewaycommon.param.ParamBuilder; import com.gitee.sop.gatewaycommon.result.DataNameBuilder; import com.gitee.sop.gatewaycommon.result.DefaultDataNameBuilder; @@ -149,6 +150,8 @@ public class ApiConfig { */ private ZuulErrorController zuulErrorController = new ZuulErrorController(); + private ParameterFormatter zuulParametersFormatter; + // -------- fields --------- /** diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ParameterFormatter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ParameterFormatter.java new file mode 100644 index 00000000..4e51cf11 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ParameterFormatter.java @@ -0,0 +1,19 @@ +package com.gitee.sop.gatewaycommon.manager; + +import com.alibaba.fastjson.JSONObject; + +/** + * 参数格式化 + * + * @author tanghc + */ +public interface ParameterFormatter { + + /** + * 参数格式化,即动态修改请求参数 + * + * @param requestParams 原始请求参数,在此基础上追加或修改参数 + * @param requestContext requestContext + */ + void format(JSONObject requestParams, T requestContext); +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java index 8f0287f6..62063af4 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java @@ -3,6 +3,7 @@ package com.gitee.sop.gatewaycommon.zuul.configuration; import com.gitee.sop.gatewaycommon.bean.ApiConfig; import com.gitee.sop.gatewaycommon.bean.ApiContext; import com.gitee.sop.gatewaycommon.manager.AbstractConfiguration; +import com.gitee.sop.gatewaycommon.manager.ParameterFormatter; import com.gitee.sop.gatewaycommon.manager.RouteRepositoryContext; import com.gitee.sop.gatewaycommon.param.ParamBuilder; import com.gitee.sop.gatewaycommon.zuul.filter.ErrorFilter; @@ -44,6 +45,12 @@ public class BaseZuulConfiguration extends AbstractConfiguration { return ApiConfig.getInstance().getZuulParamBuilder(); } + @Bean + @ConditionalOnMissingBean + ParameterFormatter preParamFilter(){ + return ApiConfig.getInstance().getZuulParametersFormatter(); + } + /** * 路由存储 * @return @@ -120,6 +127,8 @@ public class BaseZuulConfiguration extends AbstractConfiguration { return new PreVersionDecisionFilter(); } + + /** * 错误处理扩展 */ diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreValidateFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreValidateFilter.java index 41999b66..f41f8522 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreValidateFilter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreValidateFilter.java @@ -1,6 +1,7 @@ package com.gitee.sop.gatewaycommon.zuul.filter; import com.gitee.sop.gatewaycommon.exception.ApiException; +import com.gitee.sop.gatewaycommon.manager.ParameterFormatter; import com.gitee.sop.gatewaycommon.param.ApiParam; import com.gitee.sop.gatewaycommon.param.ParamBuilder; import com.gitee.sop.gatewaycommon.validate.Validator; @@ -19,6 +20,9 @@ public class PreValidateFilter extends BaseZuulFilter { @Autowired private ParamBuilder paramBuilder; + @Autowired(required = false) + private ParameterFormatter parameterFormatter; + @Autowired private Validator validator; @@ -40,6 +44,10 @@ public class PreValidateFilter extends BaseZuulFilter { // 验证操作,这里有负责验证签名参数 try { validator.validate(param); + // 校验成功后进行参数转换 + if (parameterFormatter != null) { + parameterFormatter.format(param, requestContext); + } } catch (ApiException e) { log.error("验证失败,ip:{}, params:{}", param.fetchIp(), param.toJSONString(), e); throw e; diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/BaseParameterFormatter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/BaseParameterFormatter.java new file mode 100644 index 00000000..24941c84 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/BaseParameterFormatter.java @@ -0,0 +1,146 @@ +package com.gitee.sop.gatewaycommon.zuul.param; + +import com.gitee.sop.gatewaycommon.bean.SopConstants; +import com.gitee.sop.gatewaycommon.manager.ParameterFormatter; +import com.gitee.sop.gatewaycommon.param.ApiParam; +import com.gitee.sop.gatewaycommon.util.RequestUtil; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.netflix.zuul.context.RequestContext; +import com.netflix.zuul.exception.ZuulException; +import com.netflix.zuul.http.HttpServletRequestWrapper; +import com.netflix.zuul.http.ServletInputStreamWrapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.cloud.netflix.zuul.util.RequestContentDataExtractor; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpOutputMessage; +import org.springframework.http.MediaType; +import org.springframework.http.converter.FormHttpMessageConverter; +import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.commons.CommonsMultipartResolver; + +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * @author tanghc + */ +@Slf4j +public abstract class BaseParameterFormatter implements ParameterFormatter { + + private FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter(); + + public void formatParams(ApiParam apiParam, RequestContext requestContext) throws ZuulException { + this.format(apiParam, requestContext); + HttpServletRequest request = requestContext.getRequest(); + String contentType = request.getContentType(); + if (StringUtils.containsIgnoreCase(contentType, MediaType.APPLICATION_JSON_VALUE)) { + byte[] bytes = apiParam.toJSONString().getBytes(StandardCharsets.UTF_8); + requestContext.setRequest(new ChangeParamsHttpServletRequestWrapper(request, bytes)); + } else if(StringUtils.containsIgnoreCase(contentType, MediaType.APPLICATION_FORM_URLENCODED_VALUE)) { + List list = Lists.newArrayList(); + try { + for (Map.Entry entry : apiParam.entrySet()) { + list.add(entry.getKey() + "=" + URLEncoder.encode(String.valueOf(entry.getValue()), SopConstants.UTF8)); + } + } catch (UnsupportedEncodingException e) { + log.error("字符集不支持", e); + } + String paramsStr = StringUtils.join(list, "&"); + byte[] data = paramsStr.getBytes(StandardCharsets.UTF_8); + requestContext.setRequest(new ChangeParamsHttpServletRequestWrapper(request, data)); + } else if(RequestUtil.isMultipart(request)) { + FormHttpOutputMessage outputMessage = new FormHttpOutputMessage(); + try { + // 转成MultipartRequest + CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(request.getServletContext()); + request = commonsMultipartResolver.resolveMultipart(request); + // 重写新的值 + MultiValueMap builder = RequestContentDataExtractor.extract(request); + for (Map.Entry entry : apiParam.entrySet()) { + builder.put(entry.getKey(), Collections.singletonList(String.valueOf(entry.getValue()))); + } + MediaType mediaType = MediaType.valueOf(request.getContentType()); + // 将字段以及上传文件重写写入到流中 + formHttpMessageConverter.write(builder, mediaType, outputMessage); + // 获取新的上传文件流 + byte[] data = outputMessage.getInput(); + + requestContext.setRequest(new ChangeParamsHttpServletRequestWrapper(request, data)); + // 必须要重新指定content-type,因为此时的boundary已经发生改变 + requestContext.getZuulRequestHeaders().put("content-type", outputMessage.getHeaders().getContentType().toString()); + } catch (Exception e) { + log.error("修改上传文件请求参数失败, apiParam:{}", apiParam, e); + } + } else if(HttpMethod.GET.name().equalsIgnoreCase(request.getMethod())) { + Map> newParams = Maps.newHashMap(); + for (Map.Entry entry : apiParam.entrySet()) { + newParams.put(entry.getKey(), Collections.singletonList(String.valueOf(entry.getValue()))); + } + requestContext.setRequestQueryParams(newParams); + } + } + + + private static class FormHttpOutputMessage implements HttpOutputMessage { + + private HttpHeaders headers = new HttpHeaders(); + private ByteArrayOutputStream output = new ByteArrayOutputStream(); + + @Override + public HttpHeaders getHeaders() { + return this.headers; + } + + @Override + public OutputStream getBody() throws IOException { + return this.output; + } + + public byte[] getInput() throws IOException { + this.output.flush(); + return this.output.toByteArray(); + } + + } + + private static class ChangeParamsHttpServletRequestWrapper extends HttpServletRequestWrapper { + private byte[] data; + + public ChangeParamsHttpServletRequestWrapper(HttpServletRequest request, byte[] data) { + super(request); + this.data = data; + } + + @Override + public ServletInputStream getInputStream() throws IOException { + return new ServletInputStreamWrapper(data); + } + + @Override + public byte[] getContentData() { + return data; + } + + @Override + public int getContentLength() { + return data.length; + } + + @Override + public long getContentLengthLong() { + return data.length; + } + } +} diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/config/PreParamFilter.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/config/PreParamFilter.java deleted file mode 100644 index 74b78789..00000000 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/config/PreParamFilter.java +++ /dev/null @@ -1,116 +0,0 @@ -package com.gitee.sop.gateway.config; - -import com.alibaba.fastjson.JSONObject; -import com.gitee.sop.gatewaycommon.param.ApiParam; -import com.gitee.sop.gatewaycommon.param.ParamNames; -import com.gitee.sop.gatewaycommon.zuul.ZuulContext; -import com.gitee.sop.gatewaycommon.zuul.filter.BaseZuulFilter; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.netflix.zuul.context.RequestContext; -import com.netflix.zuul.exception.ZuulException; -import com.netflix.zuul.http.HttpServletRequestWrapper; -import com.netflix.zuul.http.ServletInputStreamWrapper; -import org.apache.commons.lang.StringUtils; -import org.springframework.http.HttpMethod; - -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * @author tanghc - */ -public class PreParamFilter extends BaseZuulFilter { - @Override - protected FilterType getFilterType() { - return FilterType.PRE; - } - - @Override - protected int getFilterOrder() { - return 0; - } - - @Override - protected Object doRun(RequestContext requestContext) throws ZuulException { - ApiParam apiParam = ZuulContext.getApiParam(); - JSONObject bizContent = apiParam.getJSONObject(ParamNames.BIZ_CONTENT_NAME); - // 修改biz_content中的参数 - bizContent.put("name", "修改了111"); - apiParam.put(ParamNames.BIZ_CONTENT_NAME, bizContent.toJSONString()); - - HttpServletRequest request = requestContext.getRequest(); - String contentType = request.getContentType(); - if (StringUtils.containsIgnoreCase(contentType, "json")) { - byte[] bytes = apiParam.toJSONString().getBytes(StandardCharsets.UTF_8); - requestContext.setRequest(new HttpServletRequestWrapper(requestContext.getRequest()) { - @Override - public ServletInputStream getInputStream() throws IOException { - return new ServletInputStreamWrapper(bytes); - } - - @Override - public byte[] getContentData() { - return bytes; - } - - @Override - public int getContentLength() { - return bytes.length; - } - - @Override - public long getContentLengthLong() { - return bytes.length; - } - }); - } else if(StringUtils.containsIgnoreCase(contentType, "form")) { - List list = Lists.newArrayList(); - try { - for (Map.Entry entry : apiParam.entrySet()) { - list.add(entry.getKey() + "=" + URLEncoder.encode(String.valueOf(entry.getValue()), "UTF-8")); - } - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - String paramsStr = StringUtils.join(list, "&"); - byte[] bytes = paramsStr.getBytes(StandardCharsets.UTF_8); - requestContext.setRequest(new HttpServletRequestWrapper(requestContext.getRequest()) { - @Override - public ServletInputStream getInputStream() throws IOException { - return new ServletInputStreamWrapper(bytes); - } - - @Override - public byte[] getContentData() { - return bytes; - } - - @Override - public int getContentLength() { - return bytes.length; - } - - @Override - public long getContentLengthLong() { - return bytes.length; - } - }); - } else if(HttpMethod.GET.name().equalsIgnoreCase(request.getMethod())) { - Map> newParams = Maps.newHashMap(); - for (Map.Entry entry : apiParam.entrySet()) { - newParams.put(entry.getKey(), Collections.singletonList(String.valueOf(entry.getValue()))); - } - requestContext.setRequestQueryParams(newParams); - } - - return null; - } -} diff --git a/sop-sdk/sdk-java/src/main/java/com/gitee/sop/sdk/client/OpenHttp.java b/sop-sdk/sdk-java/src/main/java/com/gitee/sop/sdk/client/OpenHttp.java index 68aaf5d9..d202aef6 100644 --- a/sop-sdk/sdk-java/src/main/java/com/gitee/sop/sdk/client/OpenHttp.java +++ b/sop-sdk/sdk-java/src/main/java/com/gitee/sop/sdk/client/OpenHttp.java @@ -1,6 +1,7 @@ package com.gitee.sop.sdk.client; import com.gitee.sop.sdk.common.OpenConfig; +import com.gitee.sop.sdk.common.RequestMethod; import com.gitee.sop.sdk.common.UploadFile; import okhttp3.Cookie; import okhttp3.CookieJar; @@ -118,7 +119,7 @@ public class OpenHttp { * @return * @throws IOException */ - public String request(String url, Map form, Map header, HTTPMethod method) throws IOException { + public String request(String url, Map form, Map header, RequestMethod method) throws IOException { Request.Builder requestBuilder = buildRequestBuilder(url, form, method); // 添加header addHeader(requestBuilder, header); @@ -134,7 +135,7 @@ public class OpenHttp { } } - public static Request.Builder buildRequestBuilder(String url, Map form, HTTPMethod method) { + public static Request.Builder buildRequestBuilder(String url, Map form, RequestMethod method) { switch (method) { case GET: return new Request.Builder() @@ -241,22 +242,4 @@ public class OpenHttp { this.httpClient = httpClient; } - public enum HTTPMethod { - GET, - POST, - PUT, - HEAD, - DELETE; - - private HTTPMethod() { - } - - public String value() { - return this.name(); - } - - public static HTTPMethod fromValue(String v) { - return valueOf(v.toUpperCase()); - } - } } diff --git a/sop-sdk/sdk-java/src/test/java/com/gitee/sop/sdk/SdkTest.java b/sop-sdk/sdk-java/src/test/java/com/gitee/sop/sdk/SdkTest.java index 16a2b18c..3ae9c3b3 100644 --- a/sop-sdk/sdk-java/src/test/java/com/gitee/sop/sdk/SdkTest.java +++ b/sop-sdk/sdk-java/src/test/java/com/gitee/sop/sdk/SdkTest.java @@ -100,11 +100,9 @@ public class SdkTest extends TestCase { if (response.isSuccess()) { List responseFiles = response.getFiles(); System.out.println("您上传的文件信息:"); - responseFiles.stream().forEach(file->{ - System.out.println(file); - }); + responseFiles.forEach(System.out::println); } else { - System.out.println("errorCode:" + response.getCode() + ",errorMsg:" + response.getMsg()); + System.out.println(JSON.toJSONString(response)); } System.out.println("--------------------"); } From 96e47407f077bf386f3258ae9bac876b01a9dc1e Mon Sep 17 00:00:00 2001 From: tanghc Date: Fri, 9 Aug 2019 12:46:46 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E5=8A=A8=E6=80=81=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/docs/files/10111_动态修改请求参数.md | 33 +++++++++ .../sop/gatewaycommon/bean/ApiConfig.java | 4 +- .../manager/ParameterFormatter.java | 7 +- .../configuration/BaseZuulConfiguration.java | 11 ++- .../zuul/filter/BaseZuulFilter.java | 7 +- .../filter/PreParameterFormatterFilter.java | 42 +++++++++++ .../zuul/filter/PreValidateFilter.java | 8 --- .../zuul/param/ZuulParameterFormatter.java | 10 +++ ...rFormatter.java => ZuulParameterUtil.java} | 71 ++++++++++++++----- 9 files changed, 158 insertions(+), 35 deletions(-) create mode 100644 doc/docs/files/10111_动态修改请求参数.md create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreParameterFormatterFilter.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterFormatter.java rename sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/{BaseParameterFormatter.java => ZuulParameterUtil.java} (63%) diff --git a/doc/docs/files/10111_动态修改请求参数.md b/doc/docs/files/10111_动态修改请求参数.md new file mode 100644 index 00000000..90f2f7f4 --- /dev/null +++ b/doc/docs/files/10111_动态修改请求参数.md @@ -0,0 +1,33 @@ +# 动态修改请求参数 + +自1.14.0开始,zuul网关支持动态修改请求参数。即在网关修改客户端传递过来的参数,然后发送到微服务端。 + +``` +客户端参数{"name": "jim"} --> zuul中修改为{"name": "Lucy"} --> 微服务端将收到{"name": "Lucy"} +``` + +使用场景:客户端请求参数经过加密,在网关解密后,再次发送明文参数给微服务端 + +- 如何使用 + +在网关springboot启动函数中添加如下代码 + +```java +public static void main(String[] args) { + ApiConfig.getInstance().setZuulParameterFormatter(requestParams -> { + // 获取biz_content + JSONObject jsonObject = requestParams.getJSONObject(ParamNames.BIZ_CONTENT_NAME); + // 修改biz_content中的值 + jsonObject.put("name", "name修改了111"); + jsonObject.put("remark", "remark修改了222"); + // 重新设置biz_content + requestParams.put(ParamNames.BIZ_CONTENT_NAME, jsonObject); + }); + SpringApplication.run(SopGatewayApplication.class, args); +} + +``` + +其中requestParams是客户端传递过来的参数,直接修改其中的值即可。 + +更多参考:com.gitee.sop.gatewaycommon.zuul.filter.PreParameterFormatterFilter.java diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java index e0bbabbd..ab6fb813 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java @@ -15,7 +15,6 @@ import com.gitee.sop.gatewaycommon.manager.EnvGrayManager; import com.gitee.sop.gatewaycommon.manager.IPBlacklistManager; import com.gitee.sop.gatewaycommon.manager.IsvRoutePermissionManager; import com.gitee.sop.gatewaycommon.manager.LimitConfigManager; -import com.gitee.sop.gatewaycommon.manager.ParameterFormatter; import com.gitee.sop.gatewaycommon.manager.RouteConfigManager; import com.gitee.sop.gatewaycommon.manager.ServiceErrorManager; import com.gitee.sop.gatewaycommon.param.ParamBuilder; @@ -35,6 +34,7 @@ import com.gitee.sop.gatewaycommon.validate.Signer; import com.gitee.sop.gatewaycommon.validate.Validator; import com.gitee.sop.gatewaycommon.zuul.configuration.ZuulErrorController; import com.gitee.sop.gatewaycommon.zuul.param.ZuulParamBuilder; +import com.gitee.sop.gatewaycommon.zuul.param.ZuulParameterFormatter; import com.gitee.sop.gatewaycommon.zuul.result.ZuulResultExecutor; import com.netflix.zuul.context.RequestContext; import lombok.Data; @@ -150,7 +150,7 @@ public class ApiConfig { */ private ZuulErrorController zuulErrorController = new ZuulErrorController(); - private ParameterFormatter zuulParametersFormatter; + private ZuulParameterFormatter zuulParameterFormatter; // -------- fields --------- diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ParameterFormatter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ParameterFormatter.java index 4e51cf11..8fd2caf7 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ParameterFormatter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ParameterFormatter.java @@ -1,19 +1,18 @@ package com.gitee.sop.gatewaycommon.manager; -import com.alibaba.fastjson.JSONObject; +import java.util.Map; /** * 参数格式化 * * @author tanghc */ -public interface ParameterFormatter { +public interface ParameterFormatter> { /** * 参数格式化,即动态修改请求参数 * * @param requestParams 原始请求参数,在此基础上追加或修改参数 - * @param requestContext requestContext */ - void format(JSONObject requestParams, T requestContext); + void format(T requestParams); } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java index 62063af4..e93c5a33 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java @@ -1,5 +1,6 @@ package com.gitee.sop.gatewaycommon.zuul.configuration; +import com.alibaba.fastjson.JSONObject; import com.gitee.sop.gatewaycommon.bean.ApiConfig; import com.gitee.sop.gatewaycommon.bean.ApiContext; import com.gitee.sop.gatewaycommon.manager.AbstractConfiguration; @@ -11,6 +12,7 @@ import com.gitee.sop.gatewaycommon.zuul.filter.FormBodyWrapperFilterExt; import com.gitee.sop.gatewaycommon.zuul.filter.PostResultFilter; import com.gitee.sop.gatewaycommon.zuul.filter.PreHttpServletRequestWrapperFilter; import com.gitee.sop.gatewaycommon.zuul.filter.PreLimitFilter; +import com.gitee.sop.gatewaycommon.zuul.filter.PreParameterFormatterFilter; import com.gitee.sop.gatewaycommon.zuul.filter.PreValidateFilter; import com.gitee.sop.gatewaycommon.zuul.filter.PreVersionDecisionFilter; import com.gitee.sop.gatewaycommon.zuul.filter.Servlet30WrapperFilterExt; @@ -47,8 +49,8 @@ public class BaseZuulConfiguration extends AbstractConfiguration { @Bean @ConditionalOnMissingBean - ParameterFormatter preParamFilter(){ - return ApiConfig.getInstance().getZuulParametersFormatter(); + ParameterFormatter preParamFilter(){ + return ApiConfig.getInstance().getZuulParameterFormatter(); } /** @@ -111,6 +113,11 @@ public class BaseZuulConfiguration extends AbstractConfiguration { return new PreValidateFilter(); } + @Bean + PreParameterFormatterFilter preParameterFormatterFilter() { + return new PreParameterFormatterFilter(); + } + /** * 开启限流 */ diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/BaseZuulFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/BaseZuulFilter.java index 29b97e4f..2147c1f3 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/BaseZuulFilter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/BaseZuulFilter.java @@ -23,11 +23,14 @@ public abstract class BaseZuulFilter extends ZuulFilter { /** 签名验证过滤 */ public static final int PRE_VALIDATE_FILTER_ORDER = -1000; + /** 参数格式化过滤器 */ + public static final int PRE_PARAMETER_FORMATTER_FILTER_ORDER = PRE_VALIDATE_FILTER_ORDER + 1; + /** 权限验证过滤 */ - public static final int PRE_ROUTE_PERMISSION_FILTER_ORDER = PRE_VALIDATE_FILTER_ORDER + 1; + public static final int PRE_ROUTE_PERMISSION_FILTER_ORDER = PRE_VALIDATE_FILTER_ORDER + 100; /** 限流过滤 */ - public static final int PRE_LIMIT_FILTER_ORDER = PRE_ROUTE_PERMISSION_FILTER_ORDER + 1; + public static final int PRE_LIMIT_FILTER_ORDER = PRE_ROUTE_PERMISSION_FILTER_ORDER + 100; private Integer filterOrder; diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreParameterFormatterFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreParameterFormatterFilter.java new file mode 100644 index 00000000..9f88470c --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreParameterFormatterFilter.java @@ -0,0 +1,42 @@ +package com.gitee.sop.gatewaycommon.zuul.filter; + +import com.gitee.sop.gatewaycommon.param.ApiParam; +import com.gitee.sop.gatewaycommon.param.ParamNames; +import com.gitee.sop.gatewaycommon.zuul.ZuulContext; +import com.gitee.sop.gatewaycommon.zuul.param.ZuulParameterFormatter; +import com.gitee.sop.gatewaycommon.zuul.param.ZuulParameterUtil; +import com.netflix.zuul.context.RequestContext; +import com.netflix.zuul.exception.ZuulException; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * 参数格式化过滤器,动态修改参数,此过滤器放在前面校验后面 + * + * @author tanghc + */ +public class PreParameterFormatterFilter extends BaseZuulFilter { + + @Autowired(required = false) + private ZuulParameterFormatter zuulParameterFormatter; + + @Override + protected FilterType getFilterType() { + return FilterType.PRE; + } + + @Override + protected int getFilterOrder() { + return PRE_PARAMETER_FORMATTER_FILTER_ORDER; + } + + @Override + protected Object doRun(RequestContext requestContext) throws ZuulException { + ApiParam apiParam = ZuulContext.getApiParam(); + // 校验成功后进行参数转换 + if (zuulParameterFormatter != null) { + ZuulParameterUtil.format(apiParam, zuulParameterFormatter::format); + requestContext.addZuulRequestHeader(ParamNames.HEADER_VERSION_NAME, apiParam.fetchVersion()); + } + return null; + } +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreValidateFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreValidateFilter.java index f41f8522..41999b66 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreValidateFilter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreValidateFilter.java @@ -1,7 +1,6 @@ package com.gitee.sop.gatewaycommon.zuul.filter; import com.gitee.sop.gatewaycommon.exception.ApiException; -import com.gitee.sop.gatewaycommon.manager.ParameterFormatter; import com.gitee.sop.gatewaycommon.param.ApiParam; import com.gitee.sop.gatewaycommon.param.ParamBuilder; import com.gitee.sop.gatewaycommon.validate.Validator; @@ -20,9 +19,6 @@ public class PreValidateFilter extends BaseZuulFilter { @Autowired private ParamBuilder paramBuilder; - @Autowired(required = false) - private ParameterFormatter parameterFormatter; - @Autowired private Validator validator; @@ -44,10 +40,6 @@ public class PreValidateFilter extends BaseZuulFilter { // 验证操作,这里有负责验证签名参数 try { validator.validate(param); - // 校验成功后进行参数转换 - if (parameterFormatter != null) { - parameterFormatter.format(param, requestContext); - } } catch (ApiException e) { log.error("验证失败,ip:{}, params:{}", param.fetchIp(), param.toJSONString(), e); throw e; diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterFormatter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterFormatter.java new file mode 100644 index 00000000..23885acd --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterFormatter.java @@ -0,0 +1,10 @@ +package com.gitee.sop.gatewaycommon.zuul.param; + +import com.alibaba.fastjson.JSONObject; +import com.gitee.sop.gatewaycommon.manager.ParameterFormatter; + +/** + * @author tanghc + */ +public interface ZuulParameterFormatter extends ParameterFormatter { +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/BaseParameterFormatter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterUtil.java similarity index 63% rename from sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/BaseParameterFormatter.java rename to sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterUtil.java index 24941c84..d8e29c8d 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/BaseParameterFormatter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterUtil.java @@ -1,13 +1,10 @@ package com.gitee.sop.gatewaycommon.zuul.param; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import com.gitee.sop.gatewaycommon.bean.SopConstants; -import com.gitee.sop.gatewaycommon.manager.ParameterFormatter; -import com.gitee.sop.gatewaycommon.param.ApiParam; import com.gitee.sop.gatewaycommon.util.RequestUtil; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import com.netflix.zuul.context.RequestContext; -import com.netflix.zuul.exception.ZuulException; import com.netflix.zuul.http.HttpServletRequestWrapper; import com.netflix.zuul.http.ServletInputStreamWrapper; import lombok.extern.slf4j.Slf4j; @@ -19,6 +16,7 @@ import org.springframework.http.HttpOutputMessage; import org.springframework.http.MediaType; import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.commons.CommonsMultipartResolver; import javax.servlet.ServletInputStream; @@ -29,30 +27,55 @@ import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.Collectors; /** + * zuul参数工具 * @author tanghc */ @Slf4j -public abstract class BaseParameterFormatter implements ParameterFormatter { +public class ZuulParameterUtil { - private FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter(); + private static FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter(); - public void formatParams(ApiParam apiParam, RequestContext requestContext) throws ZuulException { - this.format(apiParam, requestContext); + /** + * 格式化参数 + * @param apiParam 请求的参数 + * @param consumer 修改参数 + * @param 参数类型 + */ + public static > void format(T apiParam, Consumer consumer) { + RequestContext requestContext = RequestContext.getCurrentContext(); + consumer.accept(apiParam); HttpServletRequest request = requestContext.getRequest(); String contentType = request.getContentType(); if (StringUtils.containsIgnoreCase(contentType, MediaType.APPLICATION_JSON_VALUE)) { - byte[] bytes = apiParam.toJSONString().getBytes(StandardCharsets.UTF_8); + String json = (apiParam instanceof JSONObject) ? + ((JSONObject) apiParam).toJSONString() + : JSON.toJSONString(apiParam); + byte[] bytes = json.getBytes(StandardCharsets.UTF_8); requestContext.setRequest(new ChangeParamsHttpServletRequestWrapper(request, bytes)); } else if(StringUtils.containsIgnoreCase(contentType, MediaType.APPLICATION_FORM_URLENCODED_VALUE)) { - List list = Lists.newArrayList(); + List list = new ArrayList<>(apiParam.size()); try { for (Map.Entry entry : apiParam.entrySet()) { - list.add(entry.getKey() + "=" + URLEncoder.encode(String.valueOf(entry.getValue()), SopConstants.UTF8)); + String key = entry.getKey(); + Object value = entry.getValue(); + if (value instanceof Collection) { + Collection collection = (Collection) value; + for (Object el : collection) { + list.add(key + "=" + URLEncoder.encode(String.valueOf(el), SopConstants.UTF8)); + } + } else { + list.add(key + "=" + URLEncoder.encode(String.valueOf(value), SopConstants.UTF8)); + } } } catch (UnsupportedEncodingException e) { log.error("字符集不支持", e); @@ -64,12 +87,19 @@ public abstract class BaseParameterFormatter implements ParameterFormatter builder = RequestContentDataExtractor.extract(request); for (Map.Entry entry : apiParam.entrySet()) { - builder.put(entry.getKey(), Collections.singletonList(String.valueOf(entry.getValue()))); + Object value = entry.getValue(); + if (value instanceof List) { + builder.put(entry.getKey(), (List)value); + } else { + builder.put(entry.getKey(), Collections.singletonList(String.valueOf(value))); + } } MediaType mediaType = MediaType.valueOf(request.getContentType()); // 将字段以及上传文件重写写入到流中 @@ -84,9 +114,15 @@ public abstract class BaseParameterFormatter implements ParameterFormatter> newParams = Maps.newHashMap(); + Map> newParams = new HashMap<>(); for (Map.Entry entry : apiParam.entrySet()) { - newParams.put(entry.getKey(), Collections.singletonList(String.valueOf(entry.getValue()))); + Object value = entry.getValue(); + if (value instanceof List) { + List valueList = ((List) value).stream().map(String::valueOf).collect(Collectors.toList()); + newParams.put(entry.getKey(), valueList); + } else { + newParams.put(entry.getKey(), Collections.singletonList(String.valueOf(value))); + } } requestContext.setRequestQueryParams(newParams); } @@ -143,4 +179,5 @@ public abstract class BaseParameterFormatter implements ParameterFormatter Date: Fri, 9 Aug 2019 16:22:22 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E6=94=AF=E6=8C=81swagger-bootstrap?= =?UTF-8?q?=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../servercommon/swagger/SwaggerSupport.java | 4 ++++ sop-example/sop-story/sop-story-web/pom.xml | 17 +++-------------- .../sop/storyweb/config/OpenServiceConfig.java | 12 +++++++----- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/swagger/SwaggerSupport.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/swagger/SwaggerSupport.java index a5e2bd80..023c9c2a 100644 --- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/swagger/SwaggerSupport.java +++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/swagger/SwaggerSupport.java @@ -29,6 +29,10 @@ public abstract class SwaggerSupport { @Bean public Docket createRestApi() { + return getDocket(); + } + + protected Docket getDocket() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() diff --git a/sop-example/sop-story/sop-story-web/pom.xml b/sop-example/sop-story/sop-story-web/pom.xml index 3fb4c313..05831f74 100644 --- a/sop-example/sop-story/sop-story-web/pom.xml +++ b/sop-example/sop-story/sop-story-web/pom.xml @@ -79,22 +79,11 @@ io.springfox springfox-swagger2 2.9.2 - - - io.swagger - swagger-models - - - io.swagger - swagger-models - 1.5.21 - - - io.springfox - springfox-swagger-ui - 2.9.2 + com.github.xiaoymin + swagger-bootstrap-ui + 1.9.5 diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/config/OpenServiceConfig.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/config/OpenServiceConfig.java index dd9a5f12..cbea3472 100644 --- a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/config/OpenServiceConfig.java +++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/config/OpenServiceConfig.java @@ -22,10 +22,11 @@ public class OpenServiceConfig extends AlipayServiceConfiguration { @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { super.addResourceHandlers(registry); - registry.addResourceHandler("swagger-ui.html") - .addResourceLocations("classpath:/META-INF/resources/"); - registry.addResourceHandler("/webjars/**") - .addResourceLocations("classpath:/META-INF/resources/webjars/"); + // 支持swagger-bootstrap-ui首页 + registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/"); + // 支持默认swagger + registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); + registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); } @@ -43,9 +44,10 @@ public class OpenServiceConfig extends AlipayServiceConfiguration { @Override protected boolean swaggerAccessProtected() { - return true; + return false; } } + } /** From 50b5e8f85401bf6c736856ef6248079a9cf91657 Mon Sep 17 00:00:00 2001 From: tanghc Date: Fri, 9 Aug 2019 16:29:43 +0800 Subject: [PATCH 7/7] =?UTF-8?q?admin=E6=9C=8D=E5=8A=A1=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E5=9C=A8=E7=BA=BF/=E7=A6=BB=E7=BA=BF=E7=AD=9B=E9=80=89(?= =?UTF-8?q?=E5=9C=A8=E7=BA=BF=E9=9D=A0=E5=89=8D)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gitee/sop/registryapi/bean/ServiceInfo.java | 14 +++----------- .../service/impl/RegistryServiceNacos.java | 7 ++++++- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/bean/ServiceInfo.java b/sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/bean/ServiceInfo.java index 2d19dd58..45417810 100644 --- a/sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/bean/ServiceInfo.java +++ b/sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/bean/ServiceInfo.java @@ -1,24 +1,16 @@ package com.gitee.sop.registryapi.bean; -import lombok.Getter; -import lombok.Setter; +import lombok.Data; -import java.util.Collections; import java.util.List; /** * @author tanghc */ -@Getter -@Setter +@Data public class ServiceInfo { /** 服务名称 */ private String serviceId; /** 实例列表 */ - private List instances = Collections.emptyList(); - - @Override - public String toString() { - return "服务名称: " + serviceId + ", 实例数:" + instances.size(); - } + private List instances; } diff --git a/sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/service/impl/RegistryServiceNacos.java b/sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/service/impl/RegistryServiceNacos.java index 6f7746d2..00b31d85 100644 --- a/sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/service/impl/RegistryServiceNacos.java +++ b/sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/service/impl/RegistryServiceNacos.java @@ -18,6 +18,8 @@ import org.springframework.util.CollectionUtils; import javax.annotation.PostConstruct; import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -51,7 +53,9 @@ public class RegistryServiceNacos implements RegistryService { ServiceInfo serviceInfo = new ServiceInfo(); serviceInfo.setServiceId(serviceName); List instanceList = namingService.getAllInstances(serviceName); - if (!CollectionUtils.isEmpty(instanceList)) { + if (CollectionUtils.isEmpty(instanceList)) { + serviceInfo.setInstances(Collections.emptyList()); + } else { serviceInfo.setInstances(new ArrayList<>(instanceList.size())); for (Instance instance : instanceList) { ServiceInstance serviceInstance = new ServiceInstance(); @@ -68,6 +72,7 @@ public class RegistryServiceNacos implements RegistryService { } serviceInfoList.add(serviceInfo); } + serviceInfoList.sort(Comparator.comparingInt(o -> o.getInstances().size())); return serviceInfoList; }