This commit is contained in:
tanghc
2019-04-10 17:48:51 +08:00
parent 45ab847197
commit a3b87a5f5f
51 changed files with 1440 additions and 159 deletions

View File

@@ -4,7 +4,9 @@ import com.gitee.sop.gatewaycommon.gateway.param.GatewayParamBuilder;
import com.gitee.sop.gatewaycommon.gateway.result.GatewayResult;
import com.gitee.sop.gatewaycommon.gateway.result.GatewayResultExecutor;
import com.gitee.sop.gatewaycommon.manager.DefaultIsvRoutePermissionManager;
import com.gitee.sop.gatewaycommon.manager.DefaultRouteConfigManager;
import com.gitee.sop.gatewaycommon.manager.IsvRoutePermissionManager;
import com.gitee.sop.gatewaycommon.manager.RouteConfigManager;
import com.gitee.sop.gatewaycommon.param.ParamBuilder;
import com.gitee.sop.gatewaycommon.result.ResultExecutor;
import com.gitee.sop.gatewaycommon.secret.CacheIsvManager;
@@ -94,6 +96,11 @@ public class ApiConfig {
*/
private IsvRoutePermissionManager isvRoutePermissionManager = new DefaultIsvRoutePermissionManager();
/**
* 路由配置管理
*/
private RouteConfigManager routeConfigManager = new DefaultRouteConfigManager();
// -------- fields ---------
/**

View File

@@ -34,11 +34,6 @@ public class BaseRouteDefinition {
*/
private int ignoreValidate;
/**
* 状态0待审核1启用2禁用
*/
private int status = 1;
/**
* 是否合并结果
*/
@@ -48,8 +43,4 @@ public class BaseRouteDefinition {
* 接口是否需要授权才能访问
*/
private int permission;
public boolean enable() {
return status == RouteStatus.ENABLE.getStatus();
}
}

View File

@@ -0,0 +1,46 @@
package com.gitee.sop.gatewaycommon.bean;
import lombok.Data;
/**
* @author tanghc
*/
@Data
public class RouteConfig {
public static final byte STATUS_ENABLE = 1;
public static final byte LIMIT_STATUS_CLOSE = 0;
private String routeId;
/** 限流策略1漏桶策略2令牌桶策略, 数据库字段type */
private Byte type;
/** 每秒可处理请求数, 数据库字段exec_count_per_second */
private Integer execCountPerSecond;
/** 返回的错误码, 数据库字段limit_code */
private String limitCode;
/** 返回的错误信息, 数据库字段limit_msg */
private String limitMsg;
/** 令牌桶容量, 数据库字段token_bucket_count */
private Integer tokenBucketCount;
/** 限流开启状态1:开启0关闭, 数据库字段limit_status */
private Byte limitStatus = LIMIT_STATUS_CLOSE;
/**
* 状态0待审核1启用2禁用
*/
private Byte status = STATUS_ENABLE;
/**
* 是否启用
* @return
*/
public boolean enable() {
return status == STATUS_ENABLE;
}
}

View File

@@ -0,0 +1,37 @@
package com.gitee.sop.gatewaycommon.bean;
import lombok.Data;
/**
* @author tanghc
*/
@Data
public class RouteConfigDto {
private String routeId;
/** 限流策略1漏桶策略2令牌桶策略, 数据库字段type */
private Byte type;
/** 每秒可处理请求数, 数据库字段exec_count_per_second */
private Integer execCountPerSecond;
/** 返回的错误码, 数据库字段limit_code */
private String limitCode;
/** 返回的错误信息, 数据库字段limit_msg */
private String limitMsg;
/** 令牌桶容量, 数据库字段token_bucket_count */
private Integer tokenBucketCount;
/** 限流开启状态1:开启0关闭, 数据库字段limit_status */
private Byte limitStatus;
/**
* 状态0待审核1启用2禁用
*/
private Byte status;
}

View File

@@ -1,7 +1,10 @@
package com.gitee.sop.gatewaycommon.gateway.route;
import com.gitee.sop.gatewaycommon.bean.ApiConfig;
import com.gitee.sop.gatewaycommon.bean.RouteConfig;
import com.gitee.sop.gatewaycommon.bean.SopConstants;
import com.gitee.sop.gatewaycommon.bean.TargetRoute;
import com.gitee.sop.gatewaycommon.manager.RouteConfigManager;
import com.gitee.sop.gatewaycommon.manager.RouteRepositoryContext;
import com.gitee.sop.gatewaycommon.param.ParamNames;
import com.gitee.sop.gatewaycommon.util.RequestUtil;
@@ -64,7 +67,9 @@ public class NameVersionRoutePredicateFactory extends AbstractRoutePredicateFact
boolean match = (name + version).equals(nameVersion);
if (match) {
TargetRoute targetRoute = RouteRepositoryContext.getRouteRepository().get(nameVersion);
if (targetRoute != null && !targetRoute.getRouteDefinition().enable()) {
RouteConfigManager routeConfigManager = ApiConfig.getInstance().getRouteConfigManager();
RouteConfig routeConfig = routeConfigManager.get(nameVersion);
if (targetRoute != null && !routeConfig.enable()) {
return false;
}
}

View File

@@ -0,0 +1,49 @@
package com.gitee.sop.gatewaycommon.manager;
import com.gitee.sop.gatewaycommon.bean.RouteConfig;
import com.gitee.sop.gatewaycommon.bean.RouteConfigDto;
import com.gitee.sop.gatewaycommon.util.MyBeanUtil;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author tanghc
*/
public class DefaultRouteConfigManager implements RouteConfigManager {
/**
* key: routeId
*/
protected static Map<String, RouteConfig> routeConfigMap = new ConcurrentHashMap<>(64);
private static RouteConfig DEFAULT_CONFIG;
public DefaultRouteConfigManager() {
DEFAULT_CONFIG = this.newRouteConfig();
}
@Override
public void load() {
}
@Override
public void update(RouteConfigDto routeConfigDto) {
String key = routeConfigDto.getRouteId();
RouteConfig routeConfig = routeConfigMap.get(key);
if (routeConfig == null) {
routeConfig = newRouteConfig();
routeConfigMap.put(key, routeConfig);
}
MyBeanUtil.copyPropertiesIgnoreNull(routeConfigDto, routeConfig);
}
protected RouteConfig newRouteConfig() {
return new RouteConfig();
}
@Override
public RouteConfig get(String routeId) {
return routeConfigMap.getOrDefault(routeId, DEFAULT_CONFIG);
}
}

View File

@@ -0,0 +1,25 @@
package com.gitee.sop.gatewaycommon.manager;
import com.gitee.sop.gatewaycommon.bean.RouteConfig;
import com.gitee.sop.gatewaycommon.bean.RouteConfigDto;
/**
* 路由配置管理
* @author tanghc
*/
public interface RouteConfigManager {
void load();
/**
* 更新路由配置
* @param routeConfigDto
*/
void update(RouteConfigDto routeConfigDto);
/**
* 获取路由配置
* @param routeId
* @return
*/
RouteConfig get(String routeId);
}

View File

@@ -74,6 +74,10 @@ public class ZookeeperContext {
return SOP_MSG_CHANNEL_PATH + "/isv-route-permission";
}
public static String getRouteConfigChannelPath() {
return SOP_MSG_CHANNEL_PATH + "/route-conf";
}
public static CuratorFramework getClient() {
return client;
}

View File

@@ -10,8 +10,11 @@ public enum ErrorEnum {
/** 服务暂不可用 */
ISP_UNKNOW_ERROR(Codes.CODE_UNKNOW, "isp.unknow-error"),
/** */
/** 服务暂不可用 */
AOP_UNKNOW_ERROR(Codes.CODE_UNKNOW, "aop.unknow-error"),
/** 服务不可用,路由被禁用 */
ISP_API_DISABLED(Codes.CODE_UNKNOW, "isp.service-not-available"),
/** 无效的访问令牌 */
AOP_INVALID_AUTH_TOKEN(Codes.CODE_AUTH, "aop.invalid-auth-token"),

View File

@@ -0,0 +1,130 @@
package com.gitee.sop.gatewaycommon.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.util.Assert;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* 对象拷贝
*
* @author tanghc
*/
public class MyBeanUtil extends org.springframework.beans.BeanUtils {
/**
* 属性拷贝,第一个参数中的属性值拷贝到第二个参数中<br>
* 注意:当第一个参数中的属性有null值时,不会拷贝进去
*
* @param source 源对象
* @param target 目标对象
* @throws BeansException
*/
public static void copyPropertiesIgnoreNull(Object source, Object target)
throws BeansException {
Assert.notNull(source, "Source must not be null");
Assert.notNull(target, "Target must not be null");
Class<?> actualEditable = target.getClass();
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
for (PropertyDescriptor targetPd : targetPds) {
Method writeMethod = targetPd.getWriteMethod();
if (writeMethod != null) {
PropertyDescriptor sourcePd = getPropertyDescriptor(
source.getClass(), targetPd.getName());
if (sourcePd != null && sourcePd.getReadMethod() != null) {
try {
Method readMethod = sourcePd.getReadMethod();
if (!Modifier.isPublic(readMethod.getDeclaringClass()
.getModifiers())) {
readMethod.setAccessible(true);
}
Object value = readMethod.invoke(source);
// 这里判断value是否为空 当然这里也能进行一些特殊要求的处理
// 例如绑定时格式转换等等
if (value != null) {
if (!Modifier.isPublic(writeMethod
.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(target, value);
}
} catch (Throwable ex) {
throw new FatalBeanException(
"Could not copy properties from source to target field name mismatch:" + targetPd.getName(),
ex);
}
}
}
}
}
/**
* 属性拷贝把map中的值拷贝到target中去
*
* @param map map对象
* @param target 目标对象
*/
public static void copyPropertiesForMap(Map<String, Object> map, Object target) {
Assert.notNull(map, "map must not be null");
Assert.notNull(target, "Target must not be null");
Object pojo = mapToPojo(map, target.getClass());
copyProperties(pojo, target);
}
/**
* 将实体对象转换成Map
*
* @param pojo 实体类
* @return 返回map
*/
public static Map<String, Object> pojoToMap(Object pojo) {
if (pojo == null) {
return Collections.emptyMap();
}
String json = JSON.toJSONString(pojo);
return JSON.parseObject(json);
}
/**
* 将map对象转换成普通类
*
* @param <T> 普通类类型
* @param map map对象
* @param pojoClass 普通类
* @return 返回普通类
*/
public static <T> T mapToPojo(Map<String, Object> map, Class<T> pojoClass) {
return new JSONObject(map).toJavaObject(pojoClass);
}
/**
* map集合转换成对象集合
*
* @param <T> 普通类类型
* @param list map集合
* @param pojoClass 待转换的对象类型
* @return 返回对象集合
*/
public static <T> List<T> mapListToObjList(List<Map<String, Object>> list, Class<T> pojoClass) {
if (list == null) {
return Collections.emptyList();
}
List<T> retList = new ArrayList<>(list.size());
for (Map<String, Object> map : list) {
retList.add(mapToPojo(map, pojoClass));
}
return retList;
}
}

View File

@@ -1,5 +1,8 @@
package com.gitee.sop.gatewaycommon.zuul.route;
import com.gitee.sop.gatewaycommon.bean.ApiConfig;
import com.gitee.sop.gatewaycommon.bean.RouteConfig;
import com.gitee.sop.gatewaycommon.manager.RouteConfigManager;
import com.gitee.sop.gatewaycommon.message.ErrorEnum;
import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.zuul.ZuulContext;
@@ -51,8 +54,10 @@ public class SopRouteLocator implements RouteLocator, Ordered {
return null;
}
// 路由是否启用
if (!zuulTargetRoute.getRouteDefinition().enable()) {
throw ErrorEnum.ISV_INVALID_METHOD.getErrorMeta().getException();
RouteConfigManager routeConfigManager = ApiConfig.getInstance().getRouteConfigManager();
RouteConfig routeConfig = routeConfigManager.get(zuulTargetRoute.getRouteDefinition().getId());
if (!routeConfig.enable()) {
throw ErrorEnum.ISP_API_DISABLED.getErrorMeta().getException();
}
return zuulTargetRoute.getTargetRouteDefinition();
}

View File

@@ -5,6 +5,7 @@ open.error_10000=Success
open.error_20000=Service is temporarily unavailable
open.error_20000_isp.unknow-error=Service is temporarily unavailable
open.error_20000_aop.unknow-error=Service is temporarily unavailable
open.error_20000_isp.service-not-available=Service is temporarily unavailable
open.error_20001=Insufficient authorization authority
open.error_20001_aop.invalid-auth-token=Invalid access token

View File

@@ -3,6 +3,7 @@
#open.error_20000=服务不可用
#open.error_20000_isp.unknow-error=服务暂不可用
#open.error_20000_aop.unknow-error=服务暂不可用
#open.error_20000_isp.service-not-available=服务暂不可用
#
#open.error_20001=授权权限不足
#open.error_20001_aop.invalid-auth-token=无效的访问令牌
@@ -59,6 +60,7 @@ open.error_10000=Success
open.error_20000=\u670d\u52a1\u4e0d\u53ef\u7528
open.error_20000_isp.unknow-error=\u670d\u52a1\u6682\u4e0d\u53ef\u7528
open.error_20000_aop.unknow-error=\u670d\u52a1\u6682\u4e0d\u53ef\u7528
open.error_20000_isp.service-not-available=\u670d\u52a1\u6682\u4e0d\u53ef\u7528
open.error_20001=\u6388\u6743\u6743\u9650\u4e0d\u8db3
open.error_20001_aop.invalid-auth-token=\u65e0\u6548\u7684\u8bbf\u95ee\u4ee4\u724c