支持预发布、灰度发布

1.x
tanghc 5 years ago
parent 8718284dc3
commit 5d23eeb1d1
  1. 2
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/ServiceApi.java
  2. 3
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/ConfigGrayUserkey.java
  3. 6
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java
  4. 2
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/AbstractConfiguration.java
  5. 27
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultEnvGrayManager.java
  6. 9
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/EnvGrayManager.java
  7. 53
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreVersionDecisionFilter.java
  8. 96
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/BaseServerChooser.java
  9. 23
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/EnvHttpRequestInterceptor.java
  10. 18
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/HystrixRequestVariableContext.java
  11. 18
      sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/bean/HttpTool.java
  12. 3
      sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/service/impl/RegistryServiceNacos.java
  13. 2
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ParamNames.java
  14. 3
      sop-gateway/src/main/java/com/gitee/sop/gateway/entity/ConfigGrayUserkey.java
  15. 35
      sop-gateway/src/main/java/com/gitee/sop/gateway/loadbalancer/EnvironmentServerChooser.java
  16. 5
      sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbEnvGrayManager.java
  17. 2
      sop-gateway/src/main/java/com/gitee/sop/gateway/manager/ManagerInitializer.java
  18. 16
      sop-test/src/main/java/com/gitee/sop/test/HttpTool.java

@ -211,6 +211,7 @@ public class ServiceApi {
registryService.setMetadata(param.buildServiceInstance(), envPre.getKey(), envPre.getValue());
}
String serviceId = param.getServiceId();
String instanceId = param.getInstanceId();
String userKeyContent = param.getUserKeyContent();
String nameVersionContent = param.getNameVersionContent();
@ -218,6 +219,7 @@ public class ServiceApi {
ConfigGrayUserkey configGrayUserkey = configGrayUserkeyMapper.getByColumn("instance_id", instanceId);
if (configGrayUserkey == null) {
configGrayUserkey = new ConfigGrayUserkey();
configGrayUserkey.setServiceId(serviceId);
configGrayUserkey.setInstanceId(instanceId);
configGrayUserkey.setUserKeyContent(userKeyContent);
configGrayUserkey.setNameVersionContent(nameVersionContent);

@ -25,6 +25,9 @@ public class ConfigGrayUserkey {
/** 数据库字段:id */
private Long id;
/** serviceId, 数据库字段:service_id */
private String serviceId;
/** instanceId, 数据库字段:instance_id */
private String instanceId;

@ -10,13 +10,13 @@ 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.DefaultUserKeyManager;
import com.gitee.sop.gatewaycommon.manager.DefaultEnvGrayManager;
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.RouteConfigManager;
import com.gitee.sop.gatewaycommon.manager.ServiceErrorManager;
import com.gitee.sop.gatewaycommon.manager.UserKeyManager;
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;
@ -127,7 +127,7 @@ public class ApiConfig {
/**
* 用户key管理
*/
private UserKeyManager userKeyManager = new DefaultUserKeyManager();
private EnvGrayManager userKeyManager = new DefaultEnvGrayManager();
/**
* 构建数据节点名称

@ -83,7 +83,7 @@ public class AbstractConfiguration implements ApplicationContextAware {
@Bean
@ConditionalOnMissingBean
UserKeyManager userKeyManager() {
EnvGrayManager userKeyManager() {
return ApiConfig.getInstance().getUserKeyManager();
}

@ -4,18 +4,33 @@ import com.gitee.sop.gatewaycommon.zuul.loadbalancer.ServiceGrayConfig;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author tanghc
*/
public class DefaultUserKeyManager implements UserKeyManager {
public class DefaultEnvGrayManager implements EnvGrayManager {
/**
* KEY:instanceId
*/
private Map<String, ServiceGrayConfig> serviceUserKeyMap = Maps.newConcurrentMap();
private Map<String, List<String>> serviceInstanceIdMap = Maps.newConcurrentMap();
@Override
public void addServiceInstance(String serviceId, String instanceId) {
List<String> instanceIdList = serviceInstanceIdMap.computeIfAbsent(serviceId, key -> new ArrayList<>());
instanceIdList.add(instanceId);
}
@Override
public List<String> listGrayInstanceId(String serviceId) {
return serviceInstanceIdMap.get(serviceId);
}
@Override
public boolean containsKey(String instanceId, Object userKey) {
if (instanceId == null || userKey == null) {
@ -34,14 +49,12 @@ public class DefaultUserKeyManager implements UserKeyManager {
@Override
public ServiceGrayConfig getServiceGrayConfig(String instanceId) {
ServiceGrayConfig serviceGrayConfig = serviceUserKeyMap.get(instanceId);
if (serviceGrayConfig == null) {
serviceGrayConfig = new ServiceGrayConfig();
return serviceUserKeyMap.computeIfAbsent(instanceId, key -> {
ServiceGrayConfig serviceGrayConfig = new ServiceGrayConfig();
serviceGrayConfig.setUserKeys(Sets.newConcurrentHashSet());
serviceGrayConfig.setGrayNameVersion(Maps.newConcurrentMap());
serviceUserKeyMap.put(instanceId, serviceGrayConfig);
}
return serviceGrayConfig;
return serviceGrayConfig;
});
}
@Override

@ -3,10 +3,17 @@ package com.gitee.sop.gatewaycommon.manager;
import com.gitee.sop.gatewaycommon.bean.BeanInitializer;
import com.gitee.sop.gatewaycommon.zuul.loadbalancer.ServiceGrayConfig;
import java.util.List;
/**
* @author tanghc
*/
public interface UserKeyManager extends BeanInitializer {
public interface EnvGrayManager extends BeanInitializer {
void addServiceInstance(String serviceId, String instanceId);
List<String> listGrayInstanceId(String serviceId);
boolean containsKey(String instanceId, Object userKey);
String getVersion(String instanceId, String nameVersion);

@ -0,0 +1,53 @@
package com.gitee.sop.gatewaycommon.zuul.filter;
import com.gitee.sop.gatewaycommon.bean.TargetRoute;
import com.gitee.sop.gatewaycommon.manager.EnvGrayManager;
import com.gitee.sop.gatewaycommon.manager.RouteRepositoryContext;
import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.param.ParamNames;
import com.gitee.sop.gatewaycommon.zuul.ZuulContext;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
/**
* @author tanghc
*/
public class PreVersionDecisionFilter extends BaseZuulFilter {
@Autowired
private EnvGrayManager envGrayManager;
@Override
protected FilterType getFilterType() {
return FilterType.PRE;
}
@Override
protected int getFilterOrder() {
return PRE_LIMIT_FILTER_ORDER + 1;
}
@Override
protected Object doRun(RequestContext requestContext) throws ZuulException {
ApiParam apiParam = ZuulContext.getApiParam();
String nameVersion = apiParam.fetchNameVersion();
TargetRoute targetRoute = RouteRepositoryContext.getRouteRepository().get(nameVersion);
if (targetRoute == null) {
return null;
}
String serviceId = targetRoute.getServiceRouteInfo().getServiceId();
List<String> instanceIdList = envGrayManager.listGrayInstanceId(serviceId);
for (String instanceId : instanceIdList) {
String version = envGrayManager.getVersion(instanceId, nameVersion);
if (version != null) {
requestContext.addZuulRequestHeader(ParamNames.HEADER_VERSION_NAME, version);
break;
}
}
return null;
}
}

@ -6,11 +6,10 @@ import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ZoneAvoidanceRule;
import com.netflix.zuul.context.RequestContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* 服务实例选择器
@ -37,31 +36,88 @@ public abstract class BaseServerChooser extends ZoneAvoidanceRule {
*/
protected abstract boolean canVisit(Server server, HttpServletRequest request);
/**
* 是否是预发布服务器
* @param server 服务器
* @return true
*/
protected abstract boolean isPreServer(Server server);
/**
* 是否是灰度发布服务器
* @param server 服务器
* @return true
*/
protected abstract boolean isGrayServer(Server server);
/**
* 能否访问预发布
* @param server 预发布服务器
* @param request request
* @return true
*/
protected abstract boolean canVisitPre(Server server, HttpServletRequest request);
/**
* 能否访问灰度服务器
* @param server 灰度服务器
* @param request request
* @return true
*/
protected abstract boolean canVisitGray(Server server, HttpServletRequest request);
@Override
public Server choose(Object key) {
ILoadBalancer lb = getLoadBalancer();
// 获取服务实例列表
List<Server> allServers = new ArrayList<>(lb.getAllServers());
int index = -1;
for (int i = 0; i < allServers.size(); i++) {
Server server = allServers.get(i);
if (match(server)) {
index = i;
if (canVisit(server, RequestContext.getCurrentContext().getRequest())) {
return server;
}
}
List<Server> allServers = lb.getAllServers();
HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
List<Server> preServers = allServers.stream()
.filter(this::isPreServer)
.filter(server -> canVisitPre(server, request))
.collect(Collectors.toList());
// int index = -1;
// for (int i = 0; i < allServers.size(); i++) {
// Server server = allServers.get(i);
// if (isPreServer(server)) {
// preServers.add(server);
// }
// if (match(server)) {
// index = i;
// if (canVisit(server, RequestContext.getCurrentContext().getRequest())) {
// return server;
// }
// }
// }
if (!preServers.isEmpty()) {
return this.doChoose(preServers, key);
}
List<Server> grayServers = allServers.stream()
.filter(this::isGrayServer)
.filter(server -> canVisitGray(server, request))
.collect(Collectors.toList());
if (!grayServers.isEmpty()) {
return doChoose(grayServers, key);
}
return super.choose(key);
// 调用默认的算法
// 如果选出了特殊环境服务器,需要移除命中的服务器
if (index > -1) {
allServers.remove(index);
}
if (CollectionUtils.isEmpty(allServers)) {
log.error("无可用服务实例,key:", key);
return null;
}
Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(allServers, key);
// if (index > -1) {
// allServers.remove(index);
// }
// if (CollectionUtils.isEmpty(allServers)) {
// log.error("无可用服务实例,key:", key);
// return null;
// }
}
protected Server doChoose(List<Server> servers, Object key) {
Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(servers, key);
if (server.isPresent()) {
return server.get();
} else {

@ -1,23 +0,0 @@
package com.gitee.sop.gatewaycommon.zuul.loadbalancer;
import com.gitee.sop.gatewaycommon.param.ParamNames;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.support.HttpRequestWrapper;
import java.io.IOException;
/**
* @author tanghc
*/
public class EnvHttpRequestInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
HttpRequestWrapper requestWrapper = new HttpRequestWrapper(request);
String newVersion = HystrixRequestVariableContext.getVersion();
requestWrapper.getHeaders().add(ParamNames.GRAY_HEADER_VERSION_NAME, newVersion);
return execution.execute(requestWrapper, body);
}
}

@ -1,18 +0,0 @@
package com.gitee.sop.gatewaycommon.zuul.loadbalancer;
/**
* @author tanghc
*/
public class HystrixRequestVariableContext {
// private static final HystrixRequestVariableDefault<String> VERSION_HOLDER = new HystrixRequestVariableDefault<>();
private static final ThreadLocal<String> VERSION_HOLDER = new ThreadLocal<>();
public static void setVersion(String version) {
VERSION_HOLDER.set(version);
}
public static String getVersion() {
return VERSION_HOLDER.get();
}
}

@ -1,4 +1,4 @@
package com.gitee.sop.websiteserver.bean;
package com.gitee.sop.registryapi.bean;
import lombok.Data;
import lombok.Getter;
@ -110,7 +110,7 @@ public class HttpTool {
* @return
* @throws IOException
*/
public String request(String url, Map<String, String> form, Map<String, String> header, HTTPMethod method) throws IOException {
public String request(String url, Map<String, ?> form, Map<String, String> header, HTTPMethod method) throws IOException {
Request.Builder requestBuilder = buildRequestBuilder(url, form, method);
// 添加header
addHeader(requestBuilder, header);
@ -153,7 +153,7 @@ public class HttpTool {
}
}
public static Request.Builder buildRequestBuilder(String url, Map<String, String> form, HTTPMethod method) {
public static Request.Builder buildRequestBuilder(String url, Map<String, ?> form, HTTPMethod method) {
switch (method) {
case GET:
return new Request.Builder()
@ -178,18 +178,18 @@ public class HttpTool {
}
}
public static HttpUrl buildHttpUrl(String url, Map<String, String> form) {
public static HttpUrl buildHttpUrl(String url, Map<String, ?> form) {
HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
for (Map.Entry<String, String> entry : form.entrySet()) {
urlBuilder.addQueryParameter(entry.getKey(), entry.getValue());
for (Map.Entry<String, ?> entry : form.entrySet()) {
urlBuilder.addQueryParameter(entry.getKey(), String.valueOf(entry.getValue()));
}
return urlBuilder.build();
}
public static FormBody buildFormBody(Map<String, String> form) {
public static FormBody buildFormBody(Map<String, ?> form) {
FormBody.Builder paramBuilder = new FormBody.Builder(StandardCharsets.UTF_8);
for (Map.Entry<String, String> entry : form.entrySet()) {
paramBuilder.add(entry.getKey(), entry.getValue());
for (Map.Entry<String, ?> entry : form.entrySet()) {
paramBuilder.add(entry.getKey(), String.valueOf(entry.getValue()));
}
return paramBuilder.build();
}

@ -11,7 +11,6 @@ import com.gitee.sop.registryapi.bean.HttpTool;
import com.gitee.sop.registryapi.bean.ServiceInfo;
import com.gitee.sop.registryapi.bean.ServiceInstance;
import com.gitee.sop.registryapi.service.RegistryService;
import okhttp3.OkHttpClient;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
@ -29,8 +28,6 @@ import java.util.Map;
*/
public class RegistryServiceNacos implements RegistryService {
OkHttpClient client = new OkHttpClient();
static HttpTool httpTool = new HttpTool();
@Value("${registry.nacos-server-addr:}")

@ -42,8 +42,6 @@ public class ParamNames {
/** 请求参数的集合,最大长度不限,除公共参数外所有请求参数都必须放在这个参数中传递,具体参照各产品快速接入文档 */
public static String BIZ_CONTENT_NAME = "biz_content";
public static String HEADER_VERSION_NAME = "sop_gray_version";
/** 时间戳格式 */
public static String TIMESTAMP_PATTERN = "yyyy-MM-dd HH:mm:ss";

@ -25,6 +25,9 @@ public class ConfigGrayUserkey {
/** 数据库字段:id */
private Long id;
/** serviceId, 数据库字段:service_id */
private String serviceId;
/** instanceId, 数据库字段:instance_id */
private String instanceId;

@ -1,15 +1,13 @@
package com.gitee.sop.gateway.loadbalancer;
import com.gitee.sop.gateway.manager.DbUserKeyManager;
import com.gitee.sop.gateway.manager.DbEnvGrayManager;
import com.gitee.sop.gatewaycommon.bean.SpringContext;
import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.param.Param;
import com.gitee.sop.gatewaycommon.param.ParamNames;
import com.gitee.sop.gatewaycommon.zuul.ZuulContext;
import com.gitee.sop.gatewaycommon.zuul.loadbalancer.BaseServerChooser;
import com.netflix.loadbalancer.Server;
import com.netflix.niws.loadbalancer.DiscoveryEnabledServer;
import com.netflix.zuul.context.RequestContext;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
@ -30,6 +28,24 @@ public class EnvironmentServerChooser extends BaseServerChooser {
*/
private static final String PRE_DOMAIN = "localhost";
@Override
protected boolean isPreServer(Server server) {
String env = getEnvValue(server);
return ENV_PRE_VALUE.equals(env);
}
@Override
protected boolean isGrayServer(Server server) {
String env = getEnvValue(server);
return ENV_GRAY_VALUE.equals(env);
}
private String getEnvValue(Server server) {
// eureka存储的metadata
Map<String, String> metadata = ((DiscoveryEnabledServer) server).getInstanceInfo().getMetadata();
return metadata.get(MEDATA_KEY_ENV);
}
@Override
protected boolean match(Server server) {
// eureka存储的metadata
@ -70,6 +86,7 @@ public class EnvironmentServerChooser extends BaseServerChooser {
* @param request request
* @return 返回true可以进入到预发环境
*/
@Override
protected boolean canVisitPre(Server server, HttpServletRequest request) {
String serverName = request.getServerName();
return PRE_DOMAIN.equals(serverName);
@ -83,19 +100,19 @@ public class EnvironmentServerChooser extends BaseServerChooser {
*/
protected boolean canVisitGray(Server server, HttpServletRequest request) {
ApiParam apiParam = ZuulContext.getApiParam();
DbUserKeyManager userKeyManager = SpringContext.getBean(DbUserKeyManager.class);
DbEnvGrayManager userKeyManager = SpringContext.getBean(DbEnvGrayManager.class);
boolean canVisit = false;
if (this.isGrayUser(apiParam, userKeyManager, server, request)) {
/*if (this.isGrayUser(apiParam, userKeyManager, server, request)) {
// 指定灰度版本号
String instanceId = server.getMetaInfo().getInstanceId();
String newVersion = userKeyManager.getVersion(instanceId, apiParam.fetchNameVersion());
if (newVersion != null) {
// 在header中设置新的版本号,然后微服务端先获取这个新版本号
RequestContext.getCurrentContext().addZuulRequestHeader(ParamNames.GRAY_HEADER_VERSION_NAME, newVersion);
RequestContext.getCurrentContext().addZuulRequestHeader(ParamNames.HEADER_VERSION_NAME, newVersion);
canVisit = true;
}
}
return canVisit;
}*/
return this.isGrayUser(apiParam, userKeyManager, server, request);
}
@ -108,7 +125,7 @@ public class EnvironmentServerChooser extends BaseServerChooser {
* @param request request
* @return true
*/
protected boolean isGrayUser(Param param, DbUserKeyManager userKeyManager, Server server, HttpServletRequest request) {
protected boolean isGrayUser(Param param, DbEnvGrayManager userKeyManager, Server server, HttpServletRequest request) {
String instanceId = server.getMetaInfo().getInstanceId();
// 这里的灰度用户为appKey,包含此appKey则为灰度用户,允许访问
String appKey = param.fetchAppKey();

@ -6,7 +6,7 @@ import com.gitee.sop.gateway.entity.ConfigGrayUserkey;
import com.gitee.sop.gateway.mapper.ConfigGrayUserkeyMapper;
import com.gitee.sop.gatewaycommon.bean.ChannelMsg;
import com.gitee.sop.gatewaycommon.bean.UserKeyDefinition;
import com.gitee.sop.gatewaycommon.manager.DefaultUserKeyManager;
import com.gitee.sop.gatewaycommon.manager.DefaultEnvGrayManager;
import com.gitee.sop.gatewaycommon.manager.ZookeeperContext;
import com.gitee.sop.gatewaycommon.zuul.loadbalancer.ServiceGrayConfig;
import lombok.extern.slf4j.Slf4j;
@ -29,7 +29,7 @@ import java.util.stream.Stream;
*/
@Slf4j
@Service
public class DbUserKeyManager extends DefaultUserKeyManager {
public class DbEnvGrayManager extends DefaultEnvGrayManager {
private static final int STATUS_ENABLE = 1;
@ -46,6 +46,7 @@ public class DbUserKeyManager extends DefaultUserKeyManager {
List<ConfigGrayUserkey> list = configGrayUserkeyMapper.list(query);
for (ConfigGrayUserkey configGrayUserkey : list) {
this.setServiceGrayConfig(configGrayUserkey);
this.addServiceInstance(configGrayUserkey.getServiceId(), configGrayUserkey.getInstanceId());
}
}

@ -14,6 +14,6 @@ public class ManagerInitializer {
apiConfig.setRouteConfigManager(new DbRouteConfigManager());
apiConfig.setLimitConfigManager(new DbLimitConfigManager());
apiConfig.setIpBlacklistManager(new DbIPBlacklistManager());
apiConfig.setUserKeyManager(new DbUserKeyManager());
apiConfig.setUserKeyManager(new DbEnvGrayManager());
}
}

@ -110,7 +110,7 @@ public class HttpTool {
* @return
* @throws IOException
*/
public String request(String url, Map<String, String> form, Map<String, String> header, HTTPMethod method) throws IOException {
public String request(String url, Map<String, ?> form, Map<String, String> header, HTTPMethod method) throws IOException {
Request.Builder requestBuilder = buildRequestBuilder(url, form, method);
// 添加header
addHeader(requestBuilder, header);
@ -153,7 +153,7 @@ public class HttpTool {
}
}
public static Request.Builder buildRequestBuilder(String url, Map<String, String> form, HTTPMethod method) {
public static Request.Builder buildRequestBuilder(String url, Map<String, ?> form, HTTPMethod method) {
switch (method) {
case GET:
return new Request.Builder()
@ -178,18 +178,18 @@ public class HttpTool {
}
}
public static HttpUrl buildHttpUrl(String url, Map<String, String> form) {
public static HttpUrl buildHttpUrl(String url, Map<String, ?> form) {
HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
for (Map.Entry<String, String> entry : form.entrySet()) {
urlBuilder.addQueryParameter(entry.getKey(), entry.getValue());
for (Map.Entry<String, ?> entry : form.entrySet()) {
urlBuilder.addQueryParameter(entry.getKey(), String.valueOf(entry.getValue()));
}
return urlBuilder.build();
}
public static FormBody buildFormBody(Map<String, String> form) {
public static FormBody buildFormBody(Map<String, ?> form) {
FormBody.Builder paramBuilder = new FormBody.Builder(StandardCharsets.UTF_8);
for (Map.Entry<String, String> entry : form.entrySet()) {
paramBuilder.add(entry.getKey(), entry.getValue());
for (Map.Entry<String, ?> entry : form.entrySet()) {
paramBuilder.add(entry.getKey(), String.valueOf(entry.getValue()));
}
return paramBuilder.build();
}

Loading…
Cancel
Save