mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 21:57:56 +08:00
5.0
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
package com.gitee.sop.gateway;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@MapperScan(basePackages = {
|
||||
"com.gitee.sop.gateway.mapper"
|
||||
})
|
||||
@SpringBootApplication(scanBasePackages = "com.gitee.sop")
|
||||
public class SopGatewayApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SopGatewayApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,23 @@
|
||||
package com.gitee.sop.gateway.config;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.ApiConfig;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
@Component
|
||||
public class MyConfig {
|
||||
|
||||
@PostConstruct
|
||||
public void after() {
|
||||
ApiConfig.getInstance().setTokenValidator(apiParam -> {
|
||||
// 获取客户端传递过来的token
|
||||
String token = apiParam.fetchAccessToken();
|
||||
return !StringUtils.isBlank(token);
|
||||
// TODO: 校验token有效性,可以从redis中读取
|
||||
|
||||
// 返回true表示这个token真实、有效
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
package com.gitee.sop.gateway.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.gitee.fastmybatis.annotation.Pk;
|
||||
import com.gitee.fastmybatis.annotation.Table;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* 表名:config_gray
|
||||
* 备注:服务灰度配置
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
@Table(name = "config_gray",pk = @Pk(name = "id"))
|
||||
@Data
|
||||
public class ConfigGray {
|
||||
/** 数据库字段:id */
|
||||
private Long id;
|
||||
|
||||
/** 数据库字段:service_id */
|
||||
private String serviceId;
|
||||
|
||||
/** 用户key,多个用引文逗号隔开, 数据库字段:user_key_content */
|
||||
private String userKeyContent;
|
||||
|
||||
/** 需要灰度的接口,goods.get1.0=1.2,多个用英文逗号隔开, 数据库字段:name_version_content */
|
||||
private String nameVersionContent;
|
||||
|
||||
/** 数据库字段:gmt_create */
|
||||
private Date gmtCreate;
|
||||
|
||||
/** 数据库字段:gmt_modified */
|
||||
private Date gmtModified;
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
package com.gitee.sop.gateway.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.gitee.fastmybatis.annotation.Pk;
|
||||
import com.gitee.fastmybatis.annotation.Table;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* 表名:config_gray_instance
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
@Table(name = "config_gray_instance",pk = @Pk(name = "id"))
|
||||
@Data
|
||||
public class ConfigGrayInstance {
|
||||
/** 数据库字段:id */
|
||||
private Long id;
|
||||
|
||||
/** instance_id, 数据库字段:instance_id */
|
||||
private String instanceId;
|
||||
|
||||
/** service_id, 数据库字段:service_id */
|
||||
private String serviceId;
|
||||
|
||||
/** 0:禁用,1:启用, 数据库字段:status */
|
||||
private Byte status;
|
||||
|
||||
/** 数据库字段:gmt_create */
|
||||
private Date gmtCreate;
|
||||
|
||||
/** 数据库字段:gmt_modified */
|
||||
private Date gmtModified;
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
package com.gitee.sop.gateway.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.gitee.fastmybatis.annotation.Pk;
|
||||
import com.gitee.fastmybatis.annotation.Table;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* 表名:config_limit
|
||||
* 备注:限流配置
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
@Table(name = "config_limit",pk = @Pk(name = "id"))
|
||||
@Data
|
||||
public class ConfigLimit {
|
||||
/** 数据库字段:id */
|
||||
private Long id;
|
||||
|
||||
/** 路由id, 数据库字段:route_id */
|
||||
private String routeId;
|
||||
|
||||
/** 数据库字段:app_key */
|
||||
private String appKey;
|
||||
|
||||
/** 限流ip,多个用英文逗号隔开, 数据库字段:limit_ip */
|
||||
private String limitIp;
|
||||
|
||||
|
||||
/** 服务id, 数据库字段:service_id */
|
||||
private String serviceId;
|
||||
|
||||
/** 限流策略,1:窗口策略,2:令牌桶策略, 数据库字段:limit_type */
|
||||
private Byte limitType;
|
||||
|
||||
/** 每秒可处理请求数, 数据库字段: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;
|
||||
|
||||
/** 顺序,值小的优先执行, 数据库字段:order_index */
|
||||
private Integer orderIndex;
|
||||
|
||||
/** 数据库字段:gmt_create */
|
||||
private Date gmtCreate;
|
||||
|
||||
/** 数据库字段:gmt_modified */
|
||||
private Date gmtModified;
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
package com.gitee.sop.gateway.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.gitee.fastmybatis.annotation.Pk;
|
||||
import com.gitee.fastmybatis.annotation.Table;
|
||||
|
||||
|
||||
/**
|
||||
* 表名:config_route_base
|
||||
* 备注:路由配置表
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
@Table(name = "config_route_base",pk = @Pk(name = "id"))
|
||||
@Data
|
||||
public class ConfigRouteBase {
|
||||
/** 数据库字段:id */
|
||||
private Long id;
|
||||
|
||||
/** 路由id, 数据库字段:route_id */
|
||||
private String routeId;
|
||||
|
||||
/** 状态,1:启用,2:禁用, 数据库字段:status */
|
||||
private Byte status;
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
package com.gitee.sop.gateway.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.gitee.fastmybatis.annotation.Pk;
|
||||
import com.gitee.fastmybatis.annotation.Table;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* 表名:config_service_route
|
||||
* 备注:路由配置
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
@Table(name = "config_service_route",pk = @Pk(name = "id"))
|
||||
@Data
|
||||
public class ConfigServiceRoute {
|
||||
/** 数据库字段:id */
|
||||
private String id;
|
||||
|
||||
/** 数据库字段:service_id */
|
||||
private String serviceId;
|
||||
|
||||
/** 接口名, 数据库字段:name */
|
||||
private String name;
|
||||
|
||||
/** 版本号, 数据库字段:version */
|
||||
private String version;
|
||||
|
||||
/** 路由断言(SpringCloudGateway专用), 数据库字段:predicates */
|
||||
private String predicates;
|
||||
|
||||
/** 路由过滤器(SpringCloudGateway专用), 数据库字段:filters */
|
||||
private String filters;
|
||||
|
||||
/** 路由规则转发的目标uri, 数据库字段:uri */
|
||||
private String uri;
|
||||
|
||||
/** uri后面跟的path, 数据库字段:path */
|
||||
private String path;
|
||||
|
||||
/** 路由执行的顺序, 数据库字段:order_index */
|
||||
private Integer orderIndex;
|
||||
|
||||
/** 是否忽略验证,业务参数验证除外, 数据库字段:ignore_validate */
|
||||
private Byte ignoreValidate;
|
||||
|
||||
/** 状态,0:待审核,1:启用,2:禁用, 数据库字段:status */
|
||||
private Byte status;
|
||||
|
||||
/** 是否合并结果, 数据库字段:merge_result */
|
||||
private Byte mergeResult;
|
||||
|
||||
/** 是否需要授权才能访问, 数据库字段:permission */
|
||||
private Byte permission;
|
||||
|
||||
/** 是否需要token, 数据库字段:need_token */
|
||||
private Byte needToken;
|
||||
|
||||
/** 数据库字段:gmt_create */
|
||||
private Date gmtCreate;
|
||||
|
||||
/** 数据库字段:gmt_modified */
|
||||
private Date gmtModified;
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
package com.gitee.sop.gateway.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
@Data
|
||||
public class IsvDetailDTO {
|
||||
|
||||
/** appKey, 数据库字段:app_key */
|
||||
private String appKey;
|
||||
|
||||
/** 0启用,1禁用, 数据库字段:status */
|
||||
private Byte status;
|
||||
|
||||
/** secret, 数据库字段:secret */
|
||||
private String secret;
|
||||
|
||||
/** 开发者生成的公钥, 数据库字段:public_key_isv */
|
||||
private String publicKeyIsv;
|
||||
|
||||
/** 平台生成的私钥, 数据库字段:private_key_platform */
|
||||
private String privateKeyPlatform;
|
||||
|
||||
/** 签名类型:1:RSA2,2:MD5 */
|
||||
private Byte signType;
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
package com.gitee.sop.gateway.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.gitee.fastmybatis.annotation.Pk;
|
||||
import com.gitee.fastmybatis.annotation.Table;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* 表名:isv_info
|
||||
* 备注:isv信息表
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
@Table(name = "isv_info",pk = @Pk(name = "id"))
|
||||
@Data
|
||||
public class IsvInfo {
|
||||
/** 数据库字段:id */
|
||||
private Long id;
|
||||
|
||||
/** appKey, 数据库字段:app_key */
|
||||
private String appKey;
|
||||
|
||||
/** 1启用,2禁用, 数据库字段:status */
|
||||
private Byte status;
|
||||
|
||||
/** 1:RSA2,2:MD5, 数据库字段:sign_type */
|
||||
private Byte signType;
|
||||
|
||||
/** 数据库字段:gmt_create */
|
||||
private Date gmtCreate;
|
||||
|
||||
/** 数据库字段:gmt_modified */
|
||||
private Date gmtModified;
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
package com.gitee.sop.gateway.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.gitee.fastmybatis.annotation.Pk;
|
||||
import com.gitee.fastmybatis.annotation.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* 表名:monitor_info
|
||||
* 备注:接口监控信息
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
@Table(name = "monitor_info",pk = @Pk(name = "id"))
|
||||
@Data
|
||||
public class MonitorInfo {
|
||||
/** 数据库字段:id */
|
||||
private Long id;
|
||||
|
||||
/** 路由id, 数据库字段:route_id */
|
||||
private String routeId;
|
||||
|
||||
/** 接口名, 数据库字段:name */
|
||||
private String name;
|
||||
|
||||
/** 版本号, 数据库字段:version */
|
||||
private String version;
|
||||
|
||||
/** 数据库字段:service_id */
|
||||
private String serviceId;
|
||||
|
||||
/** 数据库字段:instance_id */
|
||||
private String instanceId;
|
||||
|
||||
/** 请求耗时最长时间, 数据库字段:max_time */
|
||||
private Integer maxTime;
|
||||
|
||||
/** 请求耗时最小时间, 数据库字段:min_time */
|
||||
private Integer minTime;
|
||||
|
||||
/** 总时长,毫秒, 数据库字段:total_time */
|
||||
private Long totalTime;
|
||||
|
||||
/** 总调用次数, 数据库字段:total_request_count */
|
||||
private Long totalRequestCount;
|
||||
|
||||
/** 成功次数, 数据库字段:success_count */
|
||||
private Long successCount;
|
||||
|
||||
/** 失败次数(业务主动抛出的异常算作成功,如参数校验,未知的错误算失败), 数据库字段:error_count */
|
||||
private Long errorCount;
|
||||
|
||||
/** 数据库字段:gmt_create */
|
||||
private Date gmtCreate;
|
||||
|
||||
/** 数据库字段:gmt_modified */
|
||||
private Date gmtModified;
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
package com.gitee.sop.gateway.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.gitee.fastmybatis.annotation.Pk;
|
||||
import com.gitee.fastmybatis.annotation.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* 表名:monitor_info_error
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
@Table(name = "monitor_info_error",pk = @Pk(name = "id"))
|
||||
@Data
|
||||
public class MonitorInfoError {
|
||||
/** 数据库字段:id */
|
||||
private Long id;
|
||||
|
||||
/** 错误id,md5Hex(instanceId + routeId + errorMsg), 数据库字段:error_id */
|
||||
private String errorId;
|
||||
|
||||
/** 实例id, 数据库字段:instance_id */
|
||||
private String instanceId;
|
||||
|
||||
/** 数据库字段:route_id */
|
||||
private String routeId;
|
||||
|
||||
/** 数据库字段:error_msg */
|
||||
private String errorMsg;
|
||||
|
||||
/** http status,非200错误, 数据库字段:error_status */
|
||||
private Integer errorStatus;
|
||||
|
||||
/** 错误次数, 数据库字段:count */
|
||||
private Integer count;
|
||||
|
||||
/** 数据库字段:is_deleted */
|
||||
@com.gitee.fastmybatis.core.annotation.LogicDelete
|
||||
private Byte isDeleted;
|
||||
|
||||
/** 数据库字段:gmt_create */
|
||||
private Date gmtCreate;
|
||||
|
||||
/** 数据库字段:gmt_modified */
|
||||
private Date gmtModified;
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
package com.gitee.sop.gateway.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.gitee.fastmybatis.annotation.Pk;
|
||||
import com.gitee.fastmybatis.annotation.Table;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* 表名:perm_isv_role
|
||||
* 备注:isv角色
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
@Table(name = "perm_isv_role",pk = @Pk(name = "id"))
|
||||
@Data
|
||||
public class PermIsvRole {
|
||||
/** 数据库字段:id */
|
||||
private Long id;
|
||||
|
||||
/** isv_info表id, 数据库字段:isv_id */
|
||||
private Long isvId;
|
||||
|
||||
/** 角色code, 数据库字段:role_code */
|
||||
private String roleCode;
|
||||
|
||||
/** 数据库字段:gmt_create */
|
||||
private Date gmtCreate;
|
||||
|
||||
/** 数据库字段:gmt_modified */
|
||||
private Date gmtModified;
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
package com.gitee.sop.gateway.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.gitee.fastmybatis.annotation.Pk;
|
||||
import com.gitee.fastmybatis.annotation.Table;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* 表名:perm_role_permission
|
||||
* 备注:角色权限表
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
@Table(name = "perm_role_permission",pk = @Pk(name = "id"))
|
||||
@Data
|
||||
public class PermRolePermission {
|
||||
/** 数据库字段:id */
|
||||
private Long id;
|
||||
|
||||
/** 角色表code, 数据库字段:role_code */
|
||||
private String roleCode;
|
||||
|
||||
/** api_id, 数据库字段:route_id */
|
||||
private String routeId;
|
||||
|
||||
/** 数据库字段:gmt_create */
|
||||
private Date gmtCreate;
|
||||
|
||||
/** 数据库字段:gmt_modified */
|
||||
private Date gmtModified;
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
package com.gitee.sop.gateway.interceptor;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.interceptor.RouteInterceptor;
|
||||
import com.gitee.sop.gatewaycommon.interceptor.RouteInterceptorContext;
|
||||
import com.gitee.sop.gatewaycommon.param.ApiParam;
|
||||
import com.gitee.sop.gatewaycommon.sync.SopAsyncConfigurer;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 用于收集监控数据
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class MonitorRouteInterceptor implements RouteInterceptor {
|
||||
|
||||
@Autowired
|
||||
SopAsyncConfigurer sopAsyncConfigurer;
|
||||
|
||||
@Autowired
|
||||
MonitorRouteInterceptorService monitorRouteInterceptorService;
|
||||
|
||||
@Override
|
||||
public void preRoute(RouteInterceptorContext context) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterRoute(RouteInterceptorContext context) {
|
||||
sopAsyncConfigurer.getAsyncExecutor().execute(()-> {
|
||||
monitorRouteInterceptorService.storeRequestInfo(context);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return -1000;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,164 @@
|
||||
package com.gitee.sop.gateway.interceptor;
|
||||
|
||||
import com.gitee.sop.gateway.manager.DbMonitorInfoManager;
|
||||
import com.gitee.sop.gatewaycommon.bean.LRUCache;
|
||||
import com.gitee.sop.gatewaycommon.interceptor.RouteInterceptorContext;
|
||||
import com.gitee.sop.gatewaycommon.monitor.MonitorDTO;
|
||||
import com.gitee.sop.gatewaycommon.monitor.MonitorData;
|
||||
import com.gitee.sop.gatewaycommon.monitor.MonitorManager;
|
||||
import com.gitee.sop.gatewaycommon.param.ApiParam;
|
||||
import com.gitee.sop.gatewaycommon.sync.MyNamedThreadFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class MonitorRouteInterceptorService {
|
||||
|
||||
/**
|
||||
* 刷新到数据库时间间隔,秒
|
||||
*/
|
||||
@Value("${sop.monitor.flush-period-seconds:30}")
|
||||
int flushPeriodSeconds;
|
||||
|
||||
/**
|
||||
* 定时任务每n秒,执行一次
|
||||
*/
|
||||
@Value("${sop.monitor.schedule-period-seconds:30}")
|
||||
int schedulePeriodSeconds;
|
||||
|
||||
/**
|
||||
* 错误数量容量
|
||||
*/
|
||||
@Value("${sop.monitor.error-count-capacity:50}")
|
||||
int monitorErrorCapacity;
|
||||
|
||||
@Autowired
|
||||
DbMonitorInfoManager dbMonitorInfoManager;
|
||||
|
||||
@Autowired
|
||||
MonitorManager monitorManager;
|
||||
|
||||
/**
|
||||
* 记录接口调用流量,最大时间,最小时间,总时长,平均时长,调用次数,成功次数,失败次数.
|
||||
* 需要考虑并发情况。
|
||||
*/
|
||||
public synchronized void storeRequestInfo(RouteInterceptorContext context) {
|
||||
ApiParam apiParam = context.getApiParam();
|
||||
ServiceInstance serviceInstance = context.getServiceInstance();
|
||||
String routeId = apiParam.getRouteId();
|
||||
int spendTime = (int)(context.getFinishTimeMillis() - context.getBeginTimeMillis());
|
||||
// 这步操作是线程安全的,底层调用了ConcurrentHashMap.computeIfAbsent
|
||||
String key = getMonitorKey(routeId, serviceInstance.getInstanceId());
|
||||
MonitorData monitorData = monitorManager.getMonitorInfo(key, (k) -> this.createMonitorInfo(apiParam, serviceInstance));
|
||||
monitorData.storeMaxTime(spendTime);
|
||||
monitorData.storeMinTime(spendTime);
|
||||
monitorData.getTotalRequestCount().incrementAndGet();
|
||||
monitorData.getTotalTime().addAndGet(spendTime);
|
||||
if (context.isSuccessRequest()) {
|
||||
monitorData.getSuccessCount().incrementAndGet();
|
||||
} else {
|
||||
monitorData.getErrorCount().incrementAndGet();
|
||||
String errorMsg = context.getServiceErrorMsg();
|
||||
monitorData.addErrorMsg(errorMsg, context.getResponseStatus());
|
||||
}
|
||||
}
|
||||
|
||||
private String getMonitorKey(String routeId, String instanceId) {
|
||||
return routeId + instanceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新到数据库
|
||||
*/
|
||||
private synchronized void flushDb() {
|
||||
Map<String, MonitorData> monitorData = monitorManager.getMonitorData();
|
||||
if (monitorData.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
LocalDateTime checkTime = LocalDateTime.now();
|
||||
List<String> tobeRemoveKeys = new ArrayList<>();
|
||||
List<MonitorDTO> tobeSaveBatch = new ArrayList<>(monitorData.size());
|
||||
monitorData.forEach((key, value) -> {
|
||||
LocalDateTime flushTime = value.getFlushTime();
|
||||
if (flushTime.isEqual(checkTime) || flushTime.isBefore(checkTime)) {
|
||||
log.debug("刷新监控数据到数据库, MonitorData:{}", value);
|
||||
tobeRemoveKeys.add(key);
|
||||
MonitorDTO monitorDTO = getMonitorDTO(value);
|
||||
tobeSaveBatch.add(monitorDTO);
|
||||
}
|
||||
});
|
||||
dbMonitorInfoManager.saveMonitorInfoBatch(tobeSaveBatch);
|
||||
|
||||
for (String key : tobeRemoveKeys) {
|
||||
monitorData.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
private MonitorDTO getMonitorDTO(MonitorData monitorData) {
|
||||
MonitorDTO monitorDTO = new MonitorDTO();
|
||||
monitorDTO.setRouteId(monitorData.getRouteId());
|
||||
monitorDTO.setName(monitorData.getName());
|
||||
monitorDTO.setVersion(monitorData.getVersion());
|
||||
monitorDTO.setServiceId(monitorData.getServiceId());
|
||||
monitorDTO.setInstanceId(monitorData.getInstanceId());
|
||||
monitorDTO.setMaxTime(monitorData.getMaxTime());
|
||||
monitorDTO.setMinTime(monitorData.getMinTime());
|
||||
monitorDTO.setTotalTime(monitorData.getTotalTime().longValue());
|
||||
monitorDTO.setTotalRequestCount(monitorData.getTotalRequestCount().longValue());
|
||||
monitorDTO.setSuccessCount(monitorData.getSuccessCount().longValue());
|
||||
monitorDTO.setErrorCount(monitorData.getErrorCount().longValue());
|
||||
monitorDTO.setErrorMsgList(monitorData.getMonitorErrorMsgMap().values());
|
||||
return monitorDTO;
|
||||
}
|
||||
|
||||
private MonitorData createMonitorInfo(ApiParam apiParam, ServiceInstance serviceInstance) {
|
||||
MonitorData monitorData = new MonitorData();
|
||||
monitorData.setRouteId(apiParam.getRouteId());
|
||||
monitorData.setName(apiParam.fetchName());
|
||||
monitorData.setVersion(apiParam.fetchVersion());
|
||||
monitorData.setServiceId(apiParam.fetchServiceId());
|
||||
monitorData.setInstanceId(serviceInstance.getInstanceId());
|
||||
monitorData.setTotalTime(new AtomicInteger());
|
||||
monitorData.setMaxTime(0);
|
||||
monitorData.setMinTime(0);
|
||||
monitorData.setSuccessCount(new AtomicInteger());
|
||||
monitorData.setTotalRequestCount(new AtomicInteger());
|
||||
monitorData.setErrorCount(new AtomicInteger());
|
||||
monitorData.setFlushTime(getFlushTime());
|
||||
monitorData.setMonitorErrorMsgMap(new LRUCache<>(monitorErrorCapacity));
|
||||
return monitorData;
|
||||
}
|
||||
|
||||
private LocalDateTime getFlushTime() {
|
||||
return LocalDateTime.now()
|
||||
.plusSeconds(flushPeriodSeconds);
|
||||
}
|
||||
|
||||
|
||||
@PostConstruct
|
||||
public void after() {
|
||||
// 每隔schedulePeriodSeconds秒执行一次
|
||||
ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1, new MyNamedThreadFactory("monitorSchedule"));
|
||||
// 延迟执行,随机5~14秒
|
||||
int delay = 5 + new Random().nextInt(10);
|
||||
scheduledThreadPoolExecutor.scheduleWithFixedDelay(this::flushDb, delay, schedulePeriodSeconds, TimeUnit.SECONDS);
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
package com.gitee.sop.gateway.interceptor;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.interceptor.RouteInterceptor;
|
||||
import com.gitee.sop.gatewaycommon.interceptor.RouteInterceptorContext;
|
||||
import com.gitee.sop.gatewaycommon.param.ApiParam;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* 演示拦截器
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MyRouteInterceptor implements RouteInterceptor {
|
||||
|
||||
@Override
|
||||
public void preRoute(RouteInterceptorContext context) {
|
||||
ApiParam apiParam = context.getApiParam();
|
||||
ServerWebExchange exchange = (ServerWebExchange) context.getRequestContext();
|
||||
URI uri = exchange.getRequest().getURI();
|
||||
log.info("请求URL:{}, 请求接口:{}, request_id:{}, app_id:{}, ip:{}",
|
||||
uri,
|
||||
apiParam.fetchNameVersion(),
|
||||
apiParam.fetchRequestId(),
|
||||
apiParam.fetchAppKey(),
|
||||
apiParam.fetchIp()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterRoute(RouteInterceptorContext context) {
|
||||
String serviceErrorMsg = context.getServiceErrorMsg();
|
||||
if (StringUtils.hasText(serviceErrorMsg)) {
|
||||
log.error("错误信息:{}", serviceErrorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,120 @@
|
||||
package com.gitee.sop.gateway.manager;
|
||||
|
||||
import com.gitee.fastmybatis.core.query.Query;
|
||||
import com.gitee.sop.gateway.entity.ConfigGray;
|
||||
import com.gitee.sop.gateway.entity.ConfigGrayInstance;
|
||||
import com.gitee.sop.gateway.mapper.ConfigGrayInstanceMapper;
|
||||
import com.gitee.sop.gateway.mapper.ConfigGrayMapper;
|
||||
import com.gitee.sop.gatewaycommon.bean.ChannelMsg;
|
||||
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
|
||||
import com.gitee.sop.gatewaycommon.bean.ServiceGrayDefinition;
|
||||
import com.gitee.sop.gatewaycommon.manager.DefaultEnvGrayManager;
|
||||
import com.gitee.sop.gatewaycommon.route.RegistryEvent;
|
||||
import com.gitee.sop.gatewaycommon.loadbalancer.ServiceGrayConfig;
|
||||
import com.google.common.collect.Sets;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 存放用户key,这里放在本机内容,如果灰度发布保存的用户id数量偏多,可放在redis中
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DbEnvGrayManager extends DefaultEnvGrayManager implements RegistryEvent {
|
||||
|
||||
private static final int STATUS_ENABLE = 1;
|
||||
|
||||
private static final Function<String[], String> FUNCTION_KEY = arr -> arr[0];
|
||||
private static final Function<String[], String> FUNCTION_VALUE = arr -> arr[1];
|
||||
|
||||
@Autowired
|
||||
private ConfigGrayMapper configGrayMapper;
|
||||
|
||||
@Autowired
|
||||
private ConfigGrayInstanceMapper configGrayInstanceMapper;
|
||||
|
||||
@Override
|
||||
public void onRegistry(InstanceDefinition instanceDefinition) {
|
||||
String instanceId = instanceDefinition.getInstanceId();
|
||||
ConfigGrayInstance grayInstance = configGrayInstanceMapper.getByColumn("instance_id", instanceId);
|
||||
if (grayInstance != null && grayInstance.getStatus() == STATUS_ENABLE) {
|
||||
log.info("实例[{}]开启灰度发布", grayInstance.getInstanceId());
|
||||
this.openGray(grayInstance.getInstanceId(), grayInstance.getServiceId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(String serviceId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
List<ConfigGray> list = configGrayMapper.list(new Query());
|
||||
for (ConfigGray configGray : list) {
|
||||
this.setServiceGrayConfig(configGray);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户key
|
||||
*
|
||||
* @param configGray 灰度配置
|
||||
*/
|
||||
public void setServiceGrayConfig(ConfigGray configGray) {
|
||||
if (configGray == null) {
|
||||
return;
|
||||
}
|
||||
String userKeyData = configGray.getUserKeyContent();
|
||||
String nameVersionContent = configGray.getNameVersionContent();
|
||||
String[] userKeys = StringUtils.split(userKeyData, ',');
|
||||
String[] nameVersionList = StringUtils.split(nameVersionContent, ',');
|
||||
log.info("灰度配置,userKeys.length:{}, nameVersionList:{}", userKeys.length, Arrays.toString(nameVersionList));
|
||||
|
||||
Set<String> userKeySet = Stream.of(userKeys)
|
||||
.collect(Collectors.toCollection(Sets::newConcurrentHashSet));
|
||||
|
||||
Map<String, String> grayNameVersionMap = Stream.of(nameVersionList)
|
||||
.map(nameVersion -> StringUtils.split(nameVersion, '='))
|
||||
.collect(Collectors.toConcurrentMap(FUNCTION_KEY, FUNCTION_VALUE));
|
||||
|
||||
ServiceGrayConfig serviceGrayConfig = new ServiceGrayConfig();
|
||||
serviceGrayConfig.setServiceId(configGray.getServiceId());
|
||||
serviceGrayConfig.setUserKeys(userKeySet);
|
||||
serviceGrayConfig.setGrayNameVersion(grayNameVersionMap);
|
||||
this.saveServiceGrayConfig(serviceGrayConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ChannelMsg channelMsg) {
|
||||
ServiceGrayDefinition userKeyDefinition = channelMsg.toObject(ServiceGrayDefinition.class);
|
||||
String serviceId = userKeyDefinition.getServiceId();
|
||||
switch (channelMsg.getOperation()) {
|
||||
case "set":
|
||||
ConfigGray configGray = configGrayMapper.getByColumn("service_id", serviceId);
|
||||
setServiceGrayConfig(configGray);
|
||||
break;
|
||||
case "open":
|
||||
openGray(userKeyDefinition.getInstanceId(), serviceId);
|
||||
break;
|
||||
case "close":
|
||||
closeGray(userKeyDefinition.getInstanceId());
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
package com.gitee.sop.gateway.manager;
|
||||
|
||||
import com.gitee.sop.gateway.mapper.IPBlacklistMapper;
|
||||
import com.gitee.sop.gatewaycommon.bean.ChannelMsg;
|
||||
import com.gitee.sop.gatewaycommon.manager.DefaultIPBlacklistManager;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 限流配置管理
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DbIPBlacklistManager extends DefaultIPBlacklistManager {
|
||||
|
||||
@Autowired
|
||||
private IPBlacklistMapper ipBlacklistMapper;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
List<String> ipList = ipBlacklistMapper.listAllIP();
|
||||
log.info("加载IP黑名单, size:{}", ipList.size());
|
||||
ipList.forEach(this::add);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ChannelMsg channelMsg) {
|
||||
final IPDto ipDto = channelMsg.toObject(IPDto.class);
|
||||
String ip = ipDto.getIp();
|
||||
switch (channelMsg.getOperation()) {
|
||||
case "add":
|
||||
log.info("添加IP黑名单,ip:{}", ip);
|
||||
add(ip);
|
||||
break;
|
||||
case "delete":
|
||||
log.info("移除IP黑名单,ip:{}", ip);
|
||||
remove(ip);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Data
|
||||
private static class IPDto {
|
||||
private String ip;
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
package com.gitee.sop.gateway.manager;
|
||||
|
||||
import com.gitee.sop.gateway.entity.IsvDetailDTO;
|
||||
import com.gitee.sop.gateway.mapper.IsvInfoMapper;
|
||||
import com.gitee.sop.gatewaycommon.bean.ApiConfig;
|
||||
import com.gitee.sop.gatewaycommon.bean.ChannelMsg;
|
||||
import com.gitee.sop.gatewaycommon.bean.IsvDefinition;
|
||||
import com.gitee.sop.gatewaycommon.secret.CacheIsvManager;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DbIsvManager extends CacheIsvManager {
|
||||
|
||||
public DbIsvManager() {
|
||||
ApiConfig.getInstance().setIsvManager(this);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private IsvInfoMapper isvInfoMapper;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
List<IsvDetailDTO> isvInfoList = isvInfoMapper.listIsvDetail();
|
||||
isvInfoList
|
||||
.forEach(isvInfo -> {
|
||||
IsvDefinition isvDefinition = new IsvDefinition();
|
||||
BeanUtils.copyProperties(isvInfo, isvDefinition);
|
||||
this.getIsvCache().put(isvDefinition.getAppKey(), isvDefinition);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ChannelMsg channelMsg) {
|
||||
final IsvDefinition isvDefinition = channelMsg.toObject(IsvDefinition.class);
|
||||
switch (channelMsg.getOperation()) {
|
||||
case "update":
|
||||
log.info("更新ISV信息,isvDefinition:{}", isvDefinition);
|
||||
update(isvDefinition);
|
||||
break;
|
||||
case "remove":
|
||||
log.info("删除ISV,isvDefinition:{}", isvDefinition);
|
||||
remove(isvDefinition.getAppKey());
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,149 @@
|
||||
package com.gitee.sop.gateway.manager;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.gitee.fastmybatis.core.query.Query;
|
||||
import com.gitee.sop.gateway.entity.IsvInfo;
|
||||
import com.gitee.sop.gateway.entity.PermIsvRole;
|
||||
import com.gitee.sop.gateway.entity.PermRolePermission;
|
||||
import com.gitee.sop.gateway.mapper.IsvInfoMapper;
|
||||
import com.gitee.sop.gateway.mapper.PermIsvRoleMapper;
|
||||
import com.gitee.sop.gateway.mapper.PermRolePermissionMapper;
|
||||
import com.gitee.sop.gatewaycommon.bean.ChannelMsg;
|
||||
import com.gitee.sop.gatewaycommon.bean.IsvRoutePermission;
|
||||
import com.gitee.sop.gatewaycommon.manager.DefaultIsvRoutePermissionManager;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.stream.Collectors.mapping;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
* 从数据库中读取路由权限信息
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DbIsvRoutePermissionManager extends DefaultIsvRoutePermissionManager {
|
||||
|
||||
@Autowired
|
||||
Environment environment;
|
||||
|
||||
@Autowired
|
||||
PermIsvRoleMapper permIsvRoleMapper;
|
||||
|
||||
@Autowired
|
||||
PermRolePermissionMapper permRolePermissionMapper;
|
||||
|
||||
@Autowired
|
||||
IsvInfoMapper isvInfoMapper;
|
||||
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
// key: appKey, value: roleCodeList
|
||||
Map<String, List<String>> appKeyRoleCodeMap = this.getIsvRoleCode();
|
||||
|
||||
for (Map.Entry<String, List<String>> entry : appKeyRoleCodeMap.entrySet()) {
|
||||
this.loadIsvRoutePermission(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public void loadIsvRoutePermission(String appKey, List<String> roleCodeList) {
|
||||
Collections.sort(roleCodeList);
|
||||
List<String> routeIdList = this.getRouteIdList(roleCodeList);
|
||||
String roleCodeListMd5 = DigestUtils.md5Hex(JSON.toJSONString(routeIdList));
|
||||
IsvRoutePermission isvRoutePermission = new IsvRoutePermission();
|
||||
isvRoutePermission.setAppKey(appKey);
|
||||
isvRoutePermission.setRouteIdList(routeIdList);
|
||||
isvRoutePermission.setRouteIdListMd5(roleCodeListMd5);
|
||||
this.update(isvRoutePermission);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取ISV对应的角色
|
||||
* @return 返回ISV角色信息,key:appId,value:角色code列表
|
||||
*/
|
||||
public Map<String, List<String>> getIsvRoleCode() {
|
||||
Query query = new Query();
|
||||
List<PermIsvRole> permIsvRoles = permIsvRoleMapper.list(query);
|
||||
Map<String, List<String>> appKeyRoleCodeMap = permIsvRoles.stream()
|
||||
.map(permIsvRole -> {
|
||||
IsvInfo isvInfo = isvInfoMapper.getById(permIsvRole.getIsvId());
|
||||
if (isvInfo == null) {
|
||||
return null;
|
||||
}
|
||||
IsvRole isvRole = new IsvRole();
|
||||
isvRole.appKey = isvInfo.getAppKey();
|
||||
isvRole.roleCode = permIsvRole.getRoleCode();
|
||||
return isvRole;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.groupingBy(IsvRole::getAppKey,
|
||||
mapping(IsvRole::getRoleCode, toList()))
|
||||
);
|
||||
return appKeyRoleCodeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色对应的路由
|
||||
*
|
||||
* @param roleCodeList
|
||||
* @return
|
||||
*/
|
||||
public List<String> getRouteIdList(List<String> roleCodeList) {
|
||||
if (CollectionUtils.isEmpty(roleCodeList)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Query query = new Query();
|
||||
query.in("role_code", roleCodeList);
|
||||
List<PermRolePermission> rolePermissionList = permRolePermissionMapper.list(query);
|
||||
return rolePermissionList.stream()
|
||||
.map(PermRolePermission::getRouteId)
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ChannelMsg channelMsg) {
|
||||
final IsvRoutePermission isvRoutePermission = channelMsg.toObject(IsvRoutePermission.class);
|
||||
switch (channelMsg.getOperation()) {
|
||||
case "reload":
|
||||
log.info("重新加载路由权限信息,isvRoutePermission:{}", isvRoutePermission);
|
||||
try {
|
||||
load();
|
||||
} catch (Exception e) {
|
||||
log.error("重新加载路由权限失败, channelMsg:{}", channelMsg, e);
|
||||
}
|
||||
break;
|
||||
case "update":
|
||||
log.info("更新ISV路由权限信息,isvRoutePermission:{}", isvRoutePermission);
|
||||
update(isvRoutePermission);
|
||||
break;
|
||||
case "remove":
|
||||
log.info("删除ISV路由权限信息,isvRoutePermission:{}", isvRoutePermission);
|
||||
remove(isvRoutePermission.getAppKey());
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Data
|
||||
static class IsvRole {
|
||||
private String appKey;
|
||||
private String roleCode;
|
||||
}
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
package com.gitee.sop.gateway.manager;
|
||||
|
||||
import com.gitee.fastmybatis.core.query.Query;
|
||||
import com.gitee.sop.gateway.entity.ConfigLimit;
|
||||
import com.gitee.sop.gateway.mapper.ConfigLimitMapper;
|
||||
import com.gitee.sop.gatewaycommon.bean.ChannelMsg;
|
||||
import com.gitee.sop.gatewaycommon.bean.ConfigLimitDto;
|
||||
import com.gitee.sop.gatewaycommon.manager.DefaultLimitConfigManager;
|
||||
import com.gitee.sop.gatewaycommon.util.MyBeanUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 限流配置管理
|
||||
* @author 六如
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DbLimitConfigManager extends DefaultLimitConfigManager {
|
||||
|
||||
@Autowired
|
||||
ConfigLimitMapper configLimitMapper;
|
||||
|
||||
@Override
|
||||
public void load(String serviceId) {
|
||||
Query query = new Query();
|
||||
if (StringUtils.isNotBlank(serviceId)) {
|
||||
query.eq("service_id", serviceId);
|
||||
}
|
||||
configLimitMapper.list(query)
|
||||
.forEach(this::putVal);
|
||||
|
||||
}
|
||||
|
||||
protected void putVal(ConfigLimit object) {
|
||||
ConfigLimitDto configLimitDto = new ConfigLimitDto();
|
||||
MyBeanUtil.copyPropertiesIgnoreNull(object, configLimitDto);
|
||||
this.update(configLimitDto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ChannelMsg channelMsg) {
|
||||
final ConfigLimitDto configLimitDto = channelMsg.toObject(ConfigLimitDto.class);
|
||||
switch (channelMsg.getOperation()) {
|
||||
case "reload":
|
||||
log.info("重新加载限流配置信息,configLimitDto:{}", configLimitDto);
|
||||
load(configLimitDto.getServiceId());
|
||||
break;
|
||||
case "update":
|
||||
log.info("更新限流配置信息,configLimitDto:{}", configLimitDto);
|
||||
update(configLimitDto);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
package com.gitee.sop.gateway.manager;
|
||||
|
||||
import com.gitee.sop.gateway.mapper.MonitorInfoErrorMapper;
|
||||
import com.gitee.sop.gateway.mapper.MonitorInfoMapper;
|
||||
import com.gitee.sop.gatewaycommon.monitor.MonitorDTO;
|
||||
import com.gitee.sop.gatewaycommon.monitor.MonitorErrorMsg;
|
||||
import com.gitee.sop.gatewaycommon.monitor.RouteErrorCount;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
@Service
|
||||
public class DbMonitorInfoManager {
|
||||
|
||||
@Autowired
|
||||
private MonitorInfoMapper monitorInfoMapper;
|
||||
|
||||
@Autowired
|
||||
private MonitorInfoErrorMapper monitorInfoErrorMapper;
|
||||
|
||||
@Value("${sop.monitor.error-count-capacity:50}")
|
||||
int limitCount;
|
||||
|
||||
public void saveMonitorInfoBatch(List<MonitorDTO> list) {
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return;
|
||||
}
|
||||
monitorInfoMapper.saveMonitorInfoBatch(list);
|
||||
this.saveMonitorInfoErrorBatch(list);
|
||||
}
|
||||
|
||||
private void saveMonitorInfoErrorBatch(List<MonitorDTO> list) {
|
||||
List<RouteErrorCount> routeErrorCounts = monitorInfoErrorMapper.listRouteErrorCountAll();
|
||||
// 路由id对应的错误次数,key:routeId,value:错误次数
|
||||
Map<String, Integer> routeErrorCountsMap = routeErrorCounts.stream()
|
||||
.collect(Collectors.toMap(RouteErrorCount::getRouteId, RouteErrorCount::getCount));
|
||||
List<MonitorErrorMsg> monitorErrorMsgList = list.stream()
|
||||
.filter(monitorDTO -> CollectionUtils.isNotEmpty(monitorDTO.getErrorMsgList()))
|
||||
.flatMap(monitorDTO -> {
|
||||
int limit = limitCount - routeErrorCountsMap.getOrDefault(monitorDTO.getRouteId(), 0);
|
||||
// 容量已满
|
||||
if (limit <= 0) {
|
||||
return null;
|
||||
}
|
||||
// 截取剩余
|
||||
return monitorDTO.getErrorMsgList().stream().limit(limit);
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
if (CollectionUtils.isNotEmpty(monitorErrorMsgList)) {
|
||||
monitorInfoErrorMapper.saveMonitorInfoErrorBatch(monitorErrorMsgList);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
package com.gitee.sop.gateway.manager;
|
||||
|
||||
import com.gitee.sop.gateway.mapper.ConfigRouteMapper;
|
||||
import com.gitee.sop.gatewaycommon.bean.ChannelMsg;
|
||||
import com.gitee.sop.gatewaycommon.bean.RouteConfig;
|
||||
import com.gitee.sop.gatewaycommon.manager.DefaultRouteConfigManager;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DbRouteConfigManager extends DefaultRouteConfigManager {
|
||||
|
||||
@Autowired
|
||||
private ConfigRouteMapper configRouteMapper;
|
||||
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
@Override
|
||||
public void load(String serviceId) {
|
||||
List<RouteConfig> routeConfigs = StringUtils.isBlank(serviceId) ? configRouteMapper.listAllRouteConfig()
|
||||
: configRouteMapper.listRouteConfig(serviceId);
|
||||
routeConfigs.forEach(this::save);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ChannelMsg channelMsg) {
|
||||
final RouteConfig routeConfig = channelMsg.toObject(RouteConfig.class);
|
||||
switch (channelMsg.getOperation()) {
|
||||
case "reload":
|
||||
log.info("重新加载路由配置信息,routeConfigDto:{}", routeConfig);
|
||||
load(null);
|
||||
break;
|
||||
case "update":
|
||||
log.info("更新路由配置信息,routeConfigDto:{}", routeConfig);
|
||||
update(routeConfig);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
package com.gitee.sop.gateway.manager;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.gitee.fastmybatis.core.query.Query;
|
||||
import com.gitee.sop.gateway.entity.ConfigServiceRoute;
|
||||
import com.gitee.sop.gateway.mapper.ConfigServiceRouteMapper;
|
||||
import com.gitee.sop.gateway.mapper.SystemLockMapper;
|
||||
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
|
||||
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo;
|
||||
import com.gitee.sop.gatewaycommon.route.RoutesProcessor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class DbRoutesProcessor implements RoutesProcessor {
|
||||
|
||||
@Autowired
|
||||
private ConfigServiceRouteMapper configServiceRouteMapper;
|
||||
|
||||
@Autowired
|
||||
private SystemLockMapper systemLockMapper;
|
||||
|
||||
@Override
|
||||
public void removeAllRoutes(String serviceId) {
|
||||
// 删除serviceId下所有的路由
|
||||
Query delServiceQuery = new Query().eq("service_id", serviceId);
|
||||
configServiceRouteMapper.deleteByQuery(delServiceQuery);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public synchronized void saveRoutes(ServiceRouteInfo serviceRouteInfo, InstanceDefinition instance) {
|
||||
// 抢锁,没抢到阻塞在这里
|
||||
systemLockMapper.lock();
|
||||
String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
|
||||
int result = systemLockMapper.insert(time + serviceRouteInfo.getMd5());
|
||||
// 抢到锁,插入失败,表示其它实例已经处理完毕,这里直接返回
|
||||
if (result == 0) {
|
||||
return;
|
||||
}
|
||||
log.info("保存路由信息到数据库,instance: {}", instance);
|
||||
String serviceId = serviceRouteInfo.getServiceId();
|
||||
List<ConfigServiceRoute> configServiceRoutes = serviceRouteInfo
|
||||
.getRouteDefinitionList()
|
||||
.parallelStream()
|
||||
.map(routeDefinition -> {
|
||||
ConfigServiceRoute configServiceRoute = new ConfigServiceRoute();
|
||||
configServiceRoute.setId(routeDefinition.getId());
|
||||
configServiceRoute.setName(routeDefinition.getName());
|
||||
configServiceRoute.setVersion(routeDefinition.getVersion());
|
||||
configServiceRoute.setUri(routeDefinition.getUri());
|
||||
configServiceRoute.setPath(routeDefinition.getPath());
|
||||
configServiceRoute.setFilters(JSON.toJSONString(routeDefinition.getFilters()));
|
||||
configServiceRoute.setPredicates(JSON.toJSONString(routeDefinition.getPredicates()));
|
||||
configServiceRoute.setIgnoreValidate((byte) routeDefinition.getIgnoreValidate());
|
||||
configServiceRoute.setMergeResult((byte) routeDefinition.getMergeResult());
|
||||
configServiceRoute.setStatus((byte) routeDefinition.getStatus());
|
||||
configServiceRoute.setPermission((byte) routeDefinition.getPermission());
|
||||
configServiceRoute.setOrderIndex(routeDefinition.getOrder());
|
||||
configServiceRoute.setNeedToken((byte)routeDefinition.getNeedToken());
|
||||
configServiceRoute.setServiceId(serviceId);
|
||||
return configServiceRoute;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 删除serviceId下所有的路由
|
||||
this.removeAllRoutes(serviceId);
|
||||
|
||||
if (CollectionUtils.isNotEmpty(configServiceRoutes)) {
|
||||
// 批量保存
|
||||
configServiceRouteMapper.saveBatch(configServiceRoutes);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
package com.gitee.sop.gateway.mapper;
|
||||
|
||||
import com.gitee.fastmybatis.core.mapper.CrudMapper;
|
||||
import com.gitee.sop.gateway.entity.ConfigGrayInstance;
|
||||
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
public interface ConfigGrayInstanceMapper extends CrudMapper<ConfigGrayInstance, Long> {
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
package com.gitee.sop.gateway.mapper;
|
||||
|
||||
import com.gitee.fastmybatis.core.mapper.CrudMapper;
|
||||
import com.gitee.sop.gateway.entity.ConfigGray;
|
||||
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
public interface ConfigGrayMapper extends CrudMapper<ConfigGray, Long> {
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
package com.gitee.sop.gateway.mapper;
|
||||
|
||||
import com.gitee.fastmybatis.core.mapper.CrudMapper;
|
||||
import com.gitee.sop.gateway.entity.ConfigLimit;
|
||||
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
public interface ConfigLimitMapper extends CrudMapper<ConfigLimit, Long> {
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
package com.gitee.sop.gateway.mapper;
|
||||
|
||||
import com.gitee.fastmybatis.core.mapper.CrudMapper;
|
||||
import com.gitee.sop.gateway.entity.ConfigRouteBase;
|
||||
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
public interface ConfigRouteBaseMapper extends CrudMapper<ConfigRouteBase, Long> {
|
||||
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package com.gitee.sop.gateway.mapper;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.RouteConfig;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
@Mapper
|
||||
public interface ConfigRouteMapper {
|
||||
|
||||
@Select("SELECT t.id AS routeId, t2.status " +
|
||||
"FROM config_service_route t " +
|
||||
"LEFT JOIN config_route_base t2 ON t.id=t2.route_id " +
|
||||
"WHERE t.service_id=#{serviceId}")
|
||||
List<RouteConfig> listRouteConfig(@Param("serviceId") String serviceId);
|
||||
|
||||
@Select("SELECT t.id AS routeId, t2.status " +
|
||||
"FROM config_service_route t " +
|
||||
"LEFT JOIN config_route_base t2 ON t.id=t2.route_id ")
|
||||
List<RouteConfig> listAllRouteConfig();
|
||||
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
package com.gitee.sop.gateway.mapper;
|
||||
|
||||
import com.gitee.fastmybatis.core.mapper.CrudMapper;
|
||||
import com.gitee.sop.gateway.entity.ConfigServiceRoute;
|
||||
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
public interface ConfigServiceRouteMapper extends CrudMapper<ConfigServiceRoute, String> {
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package com.gitee.sop.gateway.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* IP黑名单
|
||||
* @author 六如
|
||||
*/
|
||||
@Mapper
|
||||
public interface IPBlacklistMapper {
|
||||
|
||||
/**
|
||||
* 获取所有IP
|
||||
* @return
|
||||
*/
|
||||
@Select("SELECT ip FROM config_ip_blacklist")
|
||||
List<String> listAllIP();
|
||||
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
package com.gitee.sop.gateway.mapper;
|
||||
|
||||
import com.gitee.fastmybatis.core.mapper.CrudMapper;
|
||||
import com.gitee.sop.gateway.entity.IsvDetailDTO;
|
||||
import com.gitee.sop.gateway.entity.IsvInfo;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
public interface IsvInfoMapper extends CrudMapper<IsvInfo, Long> {
|
||||
|
||||
/**
|
||||
* 获取所有的isv信息
|
||||
* @return 所有的isv信息
|
||||
*/
|
||||
@Select("SELECT " +
|
||||
" t.app_key appKey " +
|
||||
" ,t.status " +
|
||||
" ,t2.sign_type signType " +
|
||||
" ,t2.secret " +
|
||||
" ,t2.public_key_isv publicKeyIsv " +
|
||||
" ,t2.private_key_platform privateKeyPlatform " +
|
||||
"FROM isv_info t " +
|
||||
"INNER JOIN isv_keys t2 ON t.app_key = t2.app_key")
|
||||
List<IsvDetailDTO> listIsvDetail();
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
package com.gitee.sop.gateway.mapper;
|
||||
|
||||
import com.gitee.fastmybatis.core.mapper.CrudMapper;
|
||||
import com.gitee.sop.gateway.entity.MonitorInfoError;
|
||||
import com.gitee.sop.gatewaycommon.monitor.MonitorErrorMsg;
|
||||
import com.gitee.sop.gatewaycommon.monitor.RouteErrorCount;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
public interface MonitorInfoErrorMapper extends CrudMapper<MonitorInfoError, Long> {
|
||||
|
||||
@Update("UPDATE monitor_info_error " +
|
||||
"SET is_deleted=0 " +
|
||||
",count=count + 1 " +
|
||||
"WHERE route_id=#{routeId} AND error_id=#{errorId}")
|
||||
int updateError(@Param("routeId") String routeId,@Param("errorId") String errorId);
|
||||
|
||||
int saveMonitorInfoErrorBatch(@Param("list") List<MonitorErrorMsg> list);
|
||||
|
||||
@Select("SELECT route_id routeId, count(*) `count` FROM monitor_info_error \n" +
|
||||
"WHERE is_deleted=0 \n" +
|
||||
"GROUP BY route_id")
|
||||
List<RouteErrorCount> listRouteErrorCount();
|
||||
|
||||
@Select("SELECT route_id routeId, count(*) `count` FROM monitor_info_error \n" +
|
||||
"WHERE is_deleted=0 \n" +
|
||||
"GROUP BY route_id")
|
||||
List<RouteErrorCount> listRouteErrorCountAll();
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
package com.gitee.sop.gateway.mapper;
|
||||
|
||||
import com.gitee.fastmybatis.core.mapper.CrudMapper;
|
||||
import com.gitee.sop.gateway.entity.MonitorInfo;
|
||||
import com.gitee.sop.gatewaycommon.monitor.MonitorDTO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
public interface MonitorInfoMapper extends CrudMapper<MonitorInfo, Long> {
|
||||
|
||||
/**
|
||||
* 更新监控状态
|
||||
*
|
||||
* @return 返回影响行数
|
||||
*/
|
||||
@Update("UPDATE monitor_info " +
|
||||
"set max_time=case when max_time < #{maxTime} then #{maxTime} else max_time end " +
|
||||
",min_time=case when min_time > #{minTime} then #{minTime} else min_time end " +
|
||||
",total_request_count=total_request_count + #{totalRequestCount} " +
|
||||
",total_time=total_time + #{totalTime} " +
|
||||
",success_count=success_count + #{successCount} " +
|
||||
",error_count=error_count + #{errorCount} " +
|
||||
"where route_id=#{routeId}")
|
||||
int updateMonitorInfo(MonitorDTO monitorDTO);
|
||||
|
||||
|
||||
/**
|
||||
* 批量插入监控数据
|
||||
* @param list 监控数据
|
||||
* @return 返回影响行数
|
||||
*/
|
||||
int saveMonitorInfoBatch(@Param("list") List<MonitorDTO> list);
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
package com.gitee.sop.gateway.mapper;
|
||||
|
||||
import com.gitee.fastmybatis.core.mapper.CrudMapper;
|
||||
import com.gitee.sop.gateway.entity.PermIsvRole;
|
||||
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
public interface PermIsvRoleMapper extends CrudMapper<PermIsvRole, Long> {
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
package com.gitee.sop.gateway.mapper;
|
||||
|
||||
import com.gitee.fastmybatis.core.mapper.CrudMapper;
|
||||
import com.gitee.sop.gateway.entity.PermRolePermission;
|
||||
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
public interface PermRolePermissionMapper extends CrudMapper<PermRolePermission, Long> {
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package com.gitee.sop.gateway.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Insert;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.ResultType;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
@Mapper
|
||||
public interface SystemLockMapper {
|
||||
|
||||
/**
|
||||
* 插入唯一值
|
||||
* @param content 唯一值
|
||||
* @return 1:返回成功,0:插入失败
|
||||
*/
|
||||
@Insert("INSERT IGNORE INTO system_lock(content) VALUES (#{content})")
|
||||
@ResultType(int.class)
|
||||
int insert(@Param("content") String content);
|
||||
|
||||
@Select("SELECT id FROM system_lock WHERE id=1 FOR UPDATE")
|
||||
@ResultType(long.class)
|
||||
long lock();
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
# \u56FA\u5B9A\u4E0D\u53D8\uFF0C\u4E0D\u80FD\u6539
|
||||
spring.application.name=sop-gateway
|
||||
# \u4E0D\u7528\u6539\uFF0C\u5982\u679C\u8981\u6539\uFF0C\u8BF7\u5168\u5C40\u66FF\u6362\u4FEE\u6539
|
||||
sop.secret=MZZOUSTua6LzApIWXCwEgbBmxSzpzC
|
||||
|
||||
# \u6587\u4EF6\u4E0A\u4F20\u914D\u7F6E
|
||||
spring.servlet.multipart.enabled=true
|
||||
spring.servlet.multipart.max-file-size=10MB
|
||||
# \u4E0D\u9650\u5236gateway\u8BF7\u6C42\u4F53\u5927\u5C0F
|
||||
spring.codec.max-in-memory-size=-1
|
||||
|
||||
# \u7F51\u5173\u5165\u53E3
|
||||
sop.gateway-index-path=/
|
||||
|
||||
# \u5F00\u542Frestful\u8BF7\u6C42\uFF0C\u9ED8\u8BA4\u5F00\u542F
|
||||
sop.restful.enable=true
|
||||
|
||||
# restful\u8BF7\u6C42\u524D\u7F00
|
||||
sop.restful.path=/rest
|
||||
|
||||
# nacos cloud\u914D\u7F6E
|
||||
spring.cloud.nacos.discovery.server-addr=${register.url}
|
||||
|
||||
# eureka\u5730\u5740
|
||||
eureka.client.serviceUrl.defaultZone=${register.url}
|
||||
|
||||
# \u6570\u636E\u5E93\u914D\u7F6E
|
||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
spring.datasource.url=jdbc:mysql://${mysql.host}/sop?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
|
||||
spring.datasource.username=${mysql.username}
|
||||
spring.datasource.password=${mysql.password}
|
||||
|
||||
#\u8FDE\u63A5\u6C60
|
||||
spring.datasource.hikari.pool-name=HikariCP
|
||||
spring.datasource.hikari.max-lifetime=500000
|
||||
|
||||
spring.cloud.gateway.discovery.locator.lower-case-service-id=true
|
||||
#spring.cloud.gateway.discovery.locator.enabled=true
|
||||
# \u54CD\u5E94\u8D85\u65F6\uFF0C\u9ED8\u8BA410\u79D2\uFF0810000\uFF09
|
||||
spring.cloud.gateway.httpclient.response-timeout=10000
|
||||
spring.cloud.gateway.httpclient.pool.max-idle-time=60000
|
||||
|
||||
# \u4E0D\u7528\u6539
|
||||
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
|
||||
mybatis.fill.com.gitee.fastmybatis.core.support.DateFillInsert=gmt_create
|
||||
mybatis.fill.com.gitee.fastmybatis.core.support.DateFillUpdate=gmt_modified
|
||||
|
@@ -0,0 +1,4 @@
|
||||
# 自定义自动配置类,如果有多个类,使用逗号(,)分隔,\正斜杠标示换行还可以读取到指定的类
|
||||
org.springframework.boot.env.EnvironmentPostProcessor=com.gitee.sop.gatewaycommon.config.SopGatewayEnvironmentPostProcessor
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.gitee.sop.gatewaycommon.config.SopGatewayAutoConfiguration,\
|
||||
com.gitee.sop.bridge.SopRegisterAutoConfiguration
|
@@ -0,0 +1,18 @@
|
||||
# \u66F4\u591A\u914D\u7F6E\uFF0C\u89C1\uFF1AMETA-INF/gateway.properties
|
||||
server.port=8081
|
||||
|
||||
# mysql\u6570\u636E\u5E93\u914D\u7F6E
|
||||
mysql.host=localhost:3306
|
||||
mysql.username=root
|
||||
mysql.password=root
|
||||
|
||||
# nacos\u6CE8\u518C\u4E2D\u5FC3\u5730\u5740
|
||||
register.url=127.0.0.1:8848
|
||||
|
||||
# \u4E0A\u4F20\u6587\u4EF6\u6700\u5927\u5BB9\u91CF\uFF0C\u9ED8\u8BA410MB
|
||||
spring.servlet.multipart.max-file-size=10MB
|
||||
|
||||
# \u54CD\u5E94\u8D85\u65F6\uFF0C\u9ED8\u8BA410\u79D2\uFF0810000\uFF09
|
||||
#spring.cloud.gateway.httpclient.response-timeout=10000
|
||||
|
||||
logging.level.com.gitee=debug
|
@@ -0,0 +1 @@
|
||||
spring.profiles.active=dev
|
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<!-- 注意:文件名必须跟Dao类名字一致,因为是根据文件名做关联。 -->
|
||||
<mapper namespace="com.gitee.sop.gateway.mapper.MonitorInfoErrorMapper">
|
||||
|
||||
<insert id="saveMonitorInfoErrorBatch">
|
||||
INSERT INTO `monitor_info_error` (
|
||||
`error_id`,
|
||||
`instance_id`,
|
||||
`route_id`,
|
||||
`error_msg`,
|
||||
`error_status`,
|
||||
`count`)
|
||||
VALUES
|
||||
<foreach collection="list" item="data" separator="," >
|
||||
(#{data.errorId},
|
||||
#{data.instanceId},
|
||||
#{data.routeId},
|
||||
#{data.errorMsg},
|
||||
#{data.errorStatus},
|
||||
#{data.count})
|
||||
</foreach>
|
||||
ON DUPLICATE KEY UPDATE
|
||||
error_msg = VALUES(error_msg)
|
||||
, error_status = VALUES(error_status)
|
||||
, `count`= `count` + VALUES(count)
|
||||
, is_deleted = 0
|
||||
</insert>
|
||||
|
||||
</mapper>
|
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<!-- 注意:文件名必须跟Dao类名字一致,因为是根据文件名做关联。 -->
|
||||
<mapper namespace="com.gitee.sop.gateway.mapper.MonitorInfoMapper">
|
||||
|
||||
<insert id="saveMonitorInfoBatch">
|
||||
INSERT INTO `monitor_info` (
|
||||
`route_id`,
|
||||
`name`,
|
||||
`version`,
|
||||
`service_id`,
|
||||
`instance_id`,
|
||||
`max_time`,
|
||||
`min_time`,
|
||||
`total_time`,
|
||||
`total_request_count`,
|
||||
`success_count`,
|
||||
`error_count`)
|
||||
VALUES
|
||||
<foreach collection="list" item="data" separator="," >
|
||||
(#{data.routeId},
|
||||
#{data.name},
|
||||
#{data.version},
|
||||
#{data.serviceId},
|
||||
#{data.instanceId},
|
||||
#{data.maxTime},
|
||||
#{data.minTime},
|
||||
#{data.totalTime},
|
||||
#{data.totalRequestCount},
|
||||
#{data.successCount},
|
||||
#{data.errorCount})
|
||||
</foreach>
|
||||
<![CDATA[
|
||||
ON DUPLICATE KEY UPDATE
|
||||
max_time = case when max_time < VALUES(max_time) then VALUES(max_time) else max_time end
|
||||
,min_time = case when min_time > VALUES(min_time) then VALUES(min_time) else min_time end
|
||||
,total_time = total_time + VALUES(total_time)
|
||||
,total_request_count = total_request_count + VALUES(total_request_count)
|
||||
,success_count = success_count + VALUES(success_count)
|
||||
,error_count = error_count + VALUES(error_count)
|
||||
]]></insert>
|
||||
|
||||
</mapper>
|
@@ -0,0 +1,22 @@
|
||||
//package com.gitee.sop.gateway;
|
||||
//
|
||||
//import junit.framework.TestCase;
|
||||
//import org.apache.commons.lang3.StringUtils;
|
||||
//
|
||||
///**
|
||||
// * @author 六如
|
||||
// */
|
||||
//public class ExcludeTest extends TestCase {
|
||||
// public void testRegex() {
|
||||
// String serviceId = "com.aaa.bbb.story-service";
|
||||
// String sopServiceExcludeRegex = "com\\..*;story\\-.*";
|
||||
// if (StringUtils.isNotBlank(sopServiceExcludeRegex)) {
|
||||
// String[] regexArr = sopServiceExcludeRegex.split(";");
|
||||
// for (String regex : regexArr) {
|
||||
// if (serviceId.matches(regex)) {
|
||||
// System.out.println("111");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
@@ -0,0 +1,62 @@
|
||||
package com.gitee.sop.gateway;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.util.LoadBalanceUtil;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 轮询选择一台机器。
|
||||
*
|
||||
* @author 六如
|
||||
*/
|
||||
public class RoundRobinTest extends TestCase {
|
||||
|
||||
public void testDo() {
|
||||
String serviceId = "order-service";
|
||||
List<String> serverList = new ArrayList<>(Arrays.asList("server1", "server2", "server3"));
|
||||
System.out.println(chooseRoundRobinServer(serviceId, serverList));
|
||||
System.out.println(chooseRoundRobinServer(serviceId, serverList));
|
||||
System.out.println(chooseRoundRobinServer(serviceId, serverList));
|
||||
System.out.println(chooseRoundRobinServer(serviceId, serverList));
|
||||
System.out.println(chooseRoundRobinServer(serviceId, serverList));
|
||||
}
|
||||
|
||||
public void testAdd() {
|
||||
String serviceId = "order-service";
|
||||
List<String> serverList = new ArrayList<>(Arrays.asList("server1", "server2", "server3"));
|
||||
System.out.println(chooseRoundRobinServer(serviceId, serverList));
|
||||
System.out.println(chooseRoundRobinServer(serviceId, serverList));
|
||||
// 中途添加一个服务器
|
||||
serverList.add("server4");
|
||||
System.out.println(chooseRoundRobinServer(serviceId, serverList));
|
||||
System.out.println(chooseRoundRobinServer(serviceId, serverList));
|
||||
System.out.println(chooseRoundRobinServer(serviceId, serverList));
|
||||
}
|
||||
|
||||
public void testRemove() {
|
||||
String serviceId = "order-service";
|
||||
List<String> serverList = new ArrayList<>(Arrays.asList("server1", "server2", "server3"));
|
||||
System.out.println(chooseRoundRobinServer(serviceId, serverList));
|
||||
System.out.println(chooseRoundRobinServer(serviceId, serverList));
|
||||
// 中途减少一台服务器
|
||||
serverList.remove(2);
|
||||
System.out.println(chooseRoundRobinServer(serviceId, serverList));
|
||||
System.out.println(chooseRoundRobinServer(serviceId, serverList));
|
||||
System.out.println(chooseRoundRobinServer(serviceId, serverList));
|
||||
}
|
||||
|
||||
/**
|
||||
* 轮询选择一台机器。
|
||||
* 假设有N台服务器:S = {S1, S2, …, Sn},一个指示变量i表示上一次选择的服务器ID。变量i被初始化为N-1。
|
||||
*
|
||||
* @param serviceId serviceId
|
||||
* @param servers 服务器列表
|
||||
* @return 返回一台服务器实例
|
||||
*/
|
||||
private <T> T chooseRoundRobinServer(String serviceId, List<T> servers) {
|
||||
return LoadBalanceUtil.chooseByRoundRobin(serviceId, servers);
|
||||
}
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
package com.gitee.sop.gateway;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class SopGatewayApplicationTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,30 @@
|
||||
package com.gitee.sop.gateway;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.junit.Assert;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
|
||||
/**
|
||||
* @author 六如
|
||||
*/
|
||||
public class UrlPatternTest extends TestCase {
|
||||
|
||||
private PathMatcher pathMatcher = new AntPathMatcher();
|
||||
|
||||
public void testA() {
|
||||
Assert.assertTrue(match("/food/get/{id}", "/food/get/2"));
|
||||
Assert.assertTrue(match("/food/get/{id}1.0", "/food/get/21.0"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pattern food/get/{id}
|
||||
* @param lookupPath /food/get/2
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean match(String pattern, String lookupPath) {
|
||||
return this.pathMatcher.match(pattern, lookupPath);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user