diff --git a/sop-admin/sop-admin-front/assets/css/xadmin.css b/sop-admin/sop-admin-front/assets/css/xadmin.css index 13ac6c6a..6d81c56a 100644 --- a/sop-admin/sop-admin-front/assets/css/xadmin.css +++ b/sop-admin/sop-admin-front/assets/css/xadmin.css @@ -675,4 +675,6 @@ table th, table td { color: #393D49; } -.x-win {display: none;padding: 20px;} \ No newline at end of file +.x-win {display: none;padding: 20px;} + +.layui-this{font-weight: bold;} \ No newline at end of file diff --git a/sop-admin/sop-admin-front/pages/dashboard/dashboard.html b/sop-admin/sop-admin-front/pages/dashboard/dashboard.html index b610e3c8..ab949e74 100644 --- a/sop-admin/sop-admin-front/pages/dashboard/dashboard.html +++ b/sop-admin/sop-admin-front/pages/dashboard/dashboard.html @@ -49,7 +49,7 @@ 首页 -
  • +
  • @@ -81,6 +81,12 @@ 路由管理
  • +
  • + + + 限流管理 + +
  • diff --git a/sop-admin/sop-admin-front/pages/service/limitManager.html b/sop-admin/sop-admin-front/pages/service/limitManager.html new file mode 100644 index 00000000..13125cb4 --- /dev/null +++ b/sop-admin/sop-admin-front/pages/service/limitManager.html @@ -0,0 +1,101 @@ + + + + + SOP Admin + + + + + + + + +
    + + 首页 + 服务管理 + 限流管理 + + + +
    +
    +
    +
    +
      +
    +
    +
    +
    + 路由名称: + + +
    +
    + +
    +
    +
    + +
    +
    + +
    + +
    + +
    +
    +
    + +
    + + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    + +
    +
    + + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/sop-admin/sop-admin-front/pages/service/limitManager.js b/sop-admin/sop-admin-front/pages/service/limitManager.js new file mode 100644 index 00000000..078bf456 --- /dev/null +++ b/sop-admin/sop-admin-front/pages/service/limitManager.js @@ -0,0 +1,165 @@ +lib.importJs('../../assets/js/routerole.js') + .use(['element', 'table', 'tree', 'form'], function () { + var LIMIT_STATUS = { + '1': '已开启' + ,'0': '已关闭' + } + // 限流策略,1:漏桶策略,2:令牌桶策略 + var LIMIT_TYPE = { + '1': '漏桶策略' + ,'2': '令牌桶策略' + } + var element = layui.element; + var form = layui.form; + var updateForm = layui.Form('updateForm'); + var addForm = layui.Form('addForm'); + var authForm = layui.Form('authForm'); + var table = layui.table; + + var currentServiceId; + var limitTable; + var smTitle; + + + form.on('submit(searchFilter)', function (data) { + var param = data.field; + param.serviceId = currentServiceId; + searchTable(param) + return false; + }); + + // 监听修改提交 + form.on('submit(updateWinSubmitFilter)', function(data) { + ApiUtil.post('route.update', data.field, function (resp) { + layer.closeAll(); + limitTable.reload(); + }) + return false; + }); + + form.on('radio(limitTypeFilter)', function(data){ + $('.limit-type').hide(); + $('.type' + data.value).show(); + }); + + element.on('tab(serviceTabFilter)', function(data){ + loadLimitTable(this.innerHTML); + }); + + + function initServiceTab() { + ApiUtil.post('service.list', {}, function (resp) { + var serviceList = resp.data; + var html = []; + for (var i = 0; i < serviceList.length; i++) { + var serviceInfo = serviceList[i]; + var clazz = i === 0 ? 'class="layui-this"' : ''; + html.push('
  • ' + serviceInfo.serviceId + '
  • '); + } + $('#serviceTab').html(html.join('')); + + if (serviceList.length > 0) { + loadLimitTable(serviceList[0].serviceId); + } + }); + } + + + function loadLimitTable(serviceId) { + currentServiceId = serviceId; + searchTable({ + serviceId: serviceId + }); + smTitle = '[ serviceId:' + currentServiceId + ' ]'; + } + + /** + * 查询表格 + * @param params + */ + function searchTable(params) { + var postData = { + data: JSON.stringify(params) + }; + if (!limitTable) { + limitTable = renderTable(postData); + } else { + limitTable.reload({ + where: postData + }) + } + } + + function renderTable(postData) { + var limitTable = table.render({ + elem: '#limitTable' + , url: ApiUtil.createUrl('route.limit.list') + , where: postData + , headers: {access_token: ApiUtil.getAccessToken()} + , cellMinWidth: 80 //全局定义常规单元格的最小宽度,layui 2.2.1 新增 + , cols: [[ + {field: 'id', title: 'id(接口名+版本号)', width: 200} + , { + field: 'type', title: '限流策略', width: 80, templet: function (row) { + return LIMIT_TYPE[row.type + '']; + } + } + , { + field: 'info', title: '限流信息', width: 500, templet: function (row) { + if (row.limitStatus == 0) { + return '--' + } + var html = []; + if (row.type == 1) { + html.push('每秒可处理请求数:' + row.execCountPerSecond); + html.push('错误码:' + row.limitCode); + html.push('错误信息:' + row.limitMsg); + } else if(row.type == 2) { + html.push('令牌桶容量:' + row.tokenBucketCount); + } + return html.join(','); + } + } + , { + field: 'limitStatus', title: '状态', width: 80, templet: function (row) { + return LIMIT_STATUS[row.limitStatus + '']; + } + } + , { + fixed: 'right', title: '操作', width: 100, templet: function (row) { + var html = ['修改']; + return html.join(''); + } + } + ]] + }); + + //监听单元格事件 + table.on('tool(limitTableFilter)', function(obj) { + var data = obj.data; + var event = obj.event; + if(event === 'edit'){ + //表单初始赋值 + data.serviceId = currentServiceId; + + updateForm.setData(data); + $('.limit-type').hide(); + $('.type' + data.type).show(); + + layer.open({ + type: 1 + ,title: '修改限流' + smTitle + ,area: ['600px', '380px'] + ,content: $('#updateWin') //这里content是一个DOM,注意:最好该元素要存放在body最外层,否则可能被其它的相对元素所影响 + }); + } + }); + + return limitTable; + } + + initServiceTab(); + + RouteRole.loadAllRole(form, 'roleArea'); + +}); \ No newline at end of file diff --git a/sop-admin/sop-admin-front/pages/service/routeManager.html b/sop-admin/sop-admin-front/pages/service/routeManager.html index eac883c0..cf87b4e8 100644 --- a/sop-admin/sop-admin-front/pages/service/routeManager.html +++ b/sop-admin/sop-admin-front/pages/service/routeManager.html @@ -21,37 +21,31 @@ href="javascript:location.replace(location.href);" title="刷新"> -
    +
    -
    -
      +
      +
        +
      -
      - 点击树节点查看 +
      +
      + 路由名称: + + +
      - - -
      @@ -75,20 +69,6 @@
      -
      - -
      - - -
      -
      -
      - -
      - - -
      -
      @@ -126,20 +106,6 @@
      -
      - -
      - - -
      -
      -
      - -
      - - -
      -
      diff --git a/sop-admin/sop-admin-front/pages/service/routeManager.js b/sop-admin/sop-admin-front/pages/service/routeManager.js index 62022553..d3fcf5bd 100644 --- a/sop-admin/sop-admin-front/pages/service/routeManager.js +++ b/sop-admin/sop-admin-front/pages/service/routeManager.js @@ -5,6 +5,7 @@ lib.importJs('../../assets/js/routerole.js') ,'1': '已启用' ,'2': '已禁用' } + var element = layui.element; var form = layui.form; var updateForm = layui.Form('updateForm'); var addForm = layui.Form('addForm'); @@ -50,43 +51,30 @@ lib.importJs('../../assets/js/routerole.js') return false; }); + element.on('tab(serviceTabFilter)', function(data){ + loadRouteTable(this.innerHTML); + }); - function initTree() { + + function initServiceTab() { ApiUtil.post('service.list', {}, function (resp) { var serviceList = resp.data; - var children = []; + var html = []; for (var i = 0; i < serviceList.length; i++) { var serviceInfo = serviceList[i]; - children.push({ - id: i + 1, - name: serviceInfo.serviceId - }) + var clazz = i === 0 ? 'class="layui-this"' : ''; + html.push('
    • ' + serviceInfo.serviceId + '
    • '); } + $('#serviceTab').html(html.join('')); - layui.tree({ - elem: '#leftTree' //传入元素选择器 - , nodes: [{ //节点 - name: '服务列表' - , spread: true // 展开 - , children: children - }] - , click: function (node) { - if (node.id) { - reloadRightPart(node) - } - } - }); + if (serviceList.length > 0) { + loadRouteTable(serviceList[0].serviceId); + } }); } - /** - * 更新右边部分 - * @param node 树节点 - */ - function reloadRightPart(node) { - $('#optTip').hide(); - $('#rightPart').show(); - var serviceId = node.name; + + function loadRouteTable(serviceId) { currentServiceId = serviceId; searchTable({ serviceId: serviceId @@ -174,7 +162,7 @@ lib.importJs('../../assets/js/routerole.js') layer.open({ type: 1 ,title: '修改路由' + smTitle - ,area: ['500px', '460px'] + ,area: ['500px', '350px'] ,content: $('#updateWin') //这里content是一个DOM,注意:最好该元素要存放在body最外层,否则可能被其它的相对元素所影响 }); } else if (event === 'auth') { @@ -210,7 +198,7 @@ lib.importJs('../../assets/js/routerole.js') layer.open({ type: 1 ,title: '添加路由' + smTitle - ,area: ['500px', '460px'] + ,area: ['500px', '350px'] ,content: $('#addWin') }); } @@ -218,7 +206,7 @@ lib.importJs('../../assets/js/routerole.js') return routeTable; } - initTree(); + initServiceTab(); RouteRole.loadAllRole(form, 'roleArea'); diff --git a/sop-admin/sop-admin-server/pom.xml b/sop-admin/sop-admin-server/pom.xml index 0182ade8..71c4a94d 100644 --- a/sop-admin/sop-admin-server/pom.xml +++ b/sop-admin/sop-admin-server/pom.xml @@ -37,7 +37,7 @@ net.oschina.durcframework easyopen-spring-boot-starter - 1.16.0 + 1.16.2 diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/result/IsvFormVO.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/result/IsvFormVO.java index 744ec68b..262fc25b 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/result/IsvFormVO.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/result/IsvFormVO.java @@ -8,10 +8,10 @@ import lombok.Data; */ @Data public class IsvFormVO { - @ApiDocField(description = "appKey") + @ApiDocField(description = "appKey", example = "aaaa") private String appKey; - @ApiDocField(description = "secret") + @ApiDocField(description = "secret", example = "bbbb") private String secret; @ApiDocField(description = "pubKey") diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/result/IsvVO.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/result/IsvVO.java index 1206677b..ed2057fd 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/result/IsvVO.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/isv/result/IsvVO.java @@ -12,15 +12,15 @@ import java.util.List; @Data public class IsvVO { /** 数据库字段:id */ - @ApiDocField(description = "id") + @ApiDocField(description = "id", example = "1") private Long id; /** appKey, 数据库字段:app_key */ - @ApiDocField(description = "appKey") + @ApiDocField(description = "appKey", example = "aaaa") private String appKey; /** secret, 数据库字段:secret */ - @ApiDocField(description = "appKey") + @ApiDocField(description = "secret", example = "bbbb") private String secret; /** 公钥, 数据库字段:pub_key */ diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/LimitApi.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/LimitApi.java new file mode 100644 index 00000000..0abe386c --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/LimitApi.java @@ -0,0 +1,115 @@ +package com.gitee.sop.adminserver.api.service; + +import com.gitee.easyopen.annotation.Api; +import com.gitee.easyopen.annotation.ApiService; +import com.gitee.easyopen.doc.annotation.ApiDoc; +import com.gitee.easyopen.doc.annotation.ApiDocMethod; +import com.gitee.easyopen.exception.ApiException; +import com.gitee.easyopen.util.CopyUtil; +import com.gitee.fastmybatis.core.query.Query; +import com.gitee.sop.adminserver.api.service.param.LimitParam; +import com.gitee.sop.adminserver.api.service.param.RouteSearchParam; +import com.gitee.sop.adminserver.api.service.result.LimitVO; +import com.gitee.sop.adminserver.bean.GatewayRouteDefinition; +import com.gitee.sop.adminserver.bean.RouteConfigDto; +import com.gitee.sop.adminserver.common.LimitEnum; +import com.gitee.sop.adminserver.entity.ConfigRouteLimit; +import com.gitee.sop.adminserver.mapper.ConfigRouteLimitMapper; +import com.gitee.sop.adminserver.service.RouteConfigService; +import com.gitee.sop.adminserver.service.RouteService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 限流 + * + * @author tanghc + */ +@ApiService +@ApiDoc("服务管理") +@Slf4j +public class LimitApi { + + @Autowired + RouteService routeService; + + @Autowired + RouteConfigService routeConfigService; + + @Autowired + ConfigRouteLimitMapper configRouteLimitMapper; + + @Api(name = "route.limit.list") + @ApiDocMethod(description = "限流列表", elementClass = LimitVO.class) + List listLimit(RouteSearchParam param) throws Exception { + List routeDefinitionList = routeService.getRouteDefinitionList(param); + List routeIdList = getRouteIdList(routeDefinitionList); + // key:routeId + Map routeLimitMap = getStoreConfigRouteLimit(routeIdList); + List gatewayRouteDefinitions = routeDefinitionList + .stream() + .map(gatewayRouteDefinition -> { + LimitVO vo = new LimitVO(); + CopyUtil.copyProperties(gatewayRouteDefinition, vo); + ConfigRouteLimit configRouteLimit = routeLimitMap.getOrDefault(gatewayRouteDefinition.getId(), getDefaultLimit()); + CopyUtil.copyPropertiesIgnoreNull(configRouteLimit, vo); + return vo; + }) + .collect(Collectors.toList()); + return gatewayRouteDefinitions; + } + + private List getRouteIdList(List routeDefinitionList) { + return routeDefinitionList + .stream() + .map(GatewayRouteDefinition::getId) + .collect(Collectors.toList()); + } + + private Map getStoreConfigRouteLimit(List routeIdList) { + Query query = new Query(); + query.in("route_id", routeIdList); + // key:routeId + Map routeLimitMap = configRouteLimitMapper.list(query) + .stream() + .collect(Collectors.toMap(ConfigRouteLimit::getRouteId, Function.identity())); + return routeLimitMap; + } + + private ConfigRouteLimit getDefaultLimit() { + ConfigRouteLimit configRouteLimit = new ConfigRouteLimit(); + configRouteLimit.setType(LimitEnum.TYPE_LEAKY_BUCKET.getVal()); + configRouteLimit.setLimitStatus(LimitEnum.STATUS_CLOSE.getVal()); + return configRouteLimit; + } + + @Api(name = "route.limit.update") + @ApiDocMethod(description = "修改限流") + @Transactional(rollbackFor = Exception.class) + public void updateLimtit(LimitParam param) { + String routeId = param.getRouteId(); + ConfigRouteLimit configRouteLimit = configRouteLimitMapper.getByColumn("route_id", routeId); + if (configRouteLimit == null) { + configRouteLimit = new ConfigRouteLimit(); + CopyUtil.copyPropertiesIgnoreNull(param, configRouteLimit); + configRouteLimitMapper.save(configRouteLimit); + } else { + CopyUtil.copyPropertiesIgnoreNull(param, configRouteLimit); + configRouteLimitMapper.updateIgnoreNull(configRouteLimit); + } + RouteConfigDto routeConfigDto = new RouteConfigDto(); + CopyUtil.copyPropertiesIgnoreNull(param, routeConfigDto); + try { + routeConfigService.sendRouteConfigMsg(routeConfigDto); + } catch (Exception e) { + log.error("推送限流消息错误, param:{}", param, e); + throw new ApiException("修改失败,请查看日志"); + } + } +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/RouteApi.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/RouteApi.java index 252eeb23..bd0b4ef4 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/RouteApi.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/RouteApi.java @@ -6,6 +6,7 @@ import com.gitee.easyopen.annotation.ApiService; import com.gitee.easyopen.doc.annotation.ApiDoc; import com.gitee.easyopen.doc.annotation.ApiDocMethod; import com.gitee.easyopen.exception.ApiException; +import com.gitee.easyopen.util.CopyUtil; import com.gitee.fastmybatis.core.query.Query; import com.gitee.sop.adminserver.api.isv.result.RoleVO; import com.gitee.sop.adminserver.api.service.param.RouteParam; @@ -14,23 +15,26 @@ import com.gitee.sop.adminserver.api.service.param.RouteSearchParam; import com.gitee.sop.adminserver.api.service.result.RouteVO; import com.gitee.sop.adminserver.api.service.result.ServiceInfo; import com.gitee.sop.adminserver.bean.GatewayRouteDefinition; +import com.gitee.sop.adminserver.bean.RouteConfigDto; import com.gitee.sop.adminserver.bean.ZookeeperContext; +import com.gitee.sop.adminserver.entity.ConfigRouteBase; import com.gitee.sop.adminserver.entity.PermRole; import com.gitee.sop.adminserver.entity.PermRolePermission; +import com.gitee.sop.adminserver.mapper.ConfigRouteBaseMapper; import com.gitee.sop.adminserver.mapper.PermRoleMapper; import com.gitee.sop.adminserver.mapper.PermRolePermissionMapper; +import com.gitee.sop.adminserver.service.RouteConfigService; import com.gitee.sop.adminserver.service.RoutePermissionService; +import com.gitee.sop.adminserver.service.RouteService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; -import org.apache.curator.framework.recipes.cache.ChildData; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Collections; import java.util.Date; import java.util.List; import java.util.stream.Collectors; @@ -49,36 +53,24 @@ public class RouteApi { @Autowired PermRoleMapper permRoleMapper; + @Autowired + ConfigRouteBaseMapper configRouteBaseMapper; + @Autowired RoutePermissionService routePermissionService; + @Autowired + RouteConfigService routeConfigService; + + @Autowired + RouteService routeService; + @Api(name = "route.list") @ApiDocMethod(description = "路由列表") List listRoute(RouteSearchParam param) throws Exception { - if (StringUtils.isBlank(param.getServiceId())) { - return Collections.emptyList(); - } - - String searchPath = ZookeeperContext.getSopRouteRootPath() + "/" + param.getServiceId(); - - List childDataList = ZookeeperContext.getChildrenData(searchPath); - - List routeDefinitionList = childDataList.stream() - .map(childData -> { - String serviceNodeData = new String(childData.getData()); - GatewayRouteDefinition routeDefinition = JSON.parseObject(serviceNodeData, GatewayRouteDefinition.class); - return routeDefinition; - }) - .filter(gatewayRouteDefinition -> { - boolean isRoute = gatewayRouteDefinition.getOrder() != Integer.MIN_VALUE; - String id = param.getId(); - if (StringUtils.isBlank(id)) { - return isRoute; - } else { - return isRoute && gatewayRouteDefinition.getId().contains(id); - } - }) - .map(gatewayRouteDefinition->{ + List routeDefinitionList = routeService.getRouteDefinitionList(param) + .stream() + .map(gatewayRouteDefinition -> { RouteVO vo = new RouteVO(); BeanUtils.copyProperties(gatewayRouteDefinition, vo); vo.setRoles(this.getRouteRole(gatewayRouteDefinition.getId())); @@ -96,8 +88,10 @@ public class RouteApi { String zookeeperRoutePath = serviceIdPath + "/" + param.getId(); String data = ZookeeperContext.getData(zookeeperRoutePath); GatewayRouteDefinition routeDefinition = JSON.parseObject(data, GatewayRouteDefinition.class); - BeanUtils.copyProperties(param, routeDefinition); + CopyUtil.copyPropertiesIgnoreNull(param, routeDefinition); ZookeeperContext.updatePathData(zookeeperRoutePath, JSON.toJSONString(routeDefinition)); + + this.updateRouteConfig(param); } @Api(name = "route.add") @@ -109,7 +103,7 @@ public class RouteApi { throw new ApiException("id已存在"); } GatewayRouteDefinition routeDefinition = new GatewayRouteDefinition(); - BeanUtils.copyProperties(param, routeDefinition); + CopyUtil.copyPropertiesIgnoreNull(param, routeDefinition); ZookeeperContext.createNewData(zookeeperRoutePath, JSON.toJSONString(routeDefinition)); ServiceInfo serviceInfo = new ServiceInfo(); serviceInfo.setServiceId(param.getServiceId()); @@ -118,6 +112,37 @@ public class RouteApi { serviceInfo.setCreateTime(now); serviceInfo.setUpdateTime(now); ZookeeperContext.updatePathData(serviceIdPath, JSON.toJSONString(serviceInfo)); + + this.updateRouteConfig(param); + } + + private void updateRouteConfig(RouteParam param) { + try { + String routeId = param.getId(); + ConfigRouteBase configRouteBase = configRouteBaseMapper.getByColumn("route_id", routeId); + boolean doSave = configRouteBase == null; + if (doSave) { + configRouteBase = new ConfigRouteBase(); + configRouteBase.setRouteId(param.getId()); + } + configRouteBase.setStatus(param.getStatus().byteValue()); + + int i = doSave ? configRouteBaseMapper.save(configRouteBase) + : configRouteBaseMapper.update(configRouteBase); + + if (i > 0) { + this.sendMsg(param); + } + } catch (Exception e) { + log.error("发送msg失败", e); + } + } + + private void sendMsg(RouteParam param) throws Exception { + RouteConfigDto routeConfigDto = new RouteConfigDto(); + routeConfigDto.setRouteId(param.getId()); + routeConfigDto.setStatus(param.getStatus()); + routeConfigService.sendRouteConfigMsg(routeConfigDto); } @Api(name = "route.role.get") @@ -166,9 +191,10 @@ public class RouteApi { } try { - routePermissionService.sendRoutePermissionReloadToZookeeper(); + routePermissionService.sendRoutePermissionReloadMsg(); } catch (Exception e) { - log.info("消息推送--路由权限(reload)失败",e); + log.info("消息推送--路由权限(reload)失败", e); + throw new ApiException("修改失败,请查看日志"); } } diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/LimitParam.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/LimitParam.java new file mode 100644 index 00000000..f9e5ea62 --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/LimitParam.java @@ -0,0 +1,45 @@ +package com.gitee.sop.adminserver.api.service.param; + +import com.gitee.easyopen.doc.annotation.ApiDocField; +import com.gitee.sop.adminserver.bean.GatewayRouteDefinition; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 限流 + * @author tanghc + */ +@Data +public class LimitParam { + @ApiDocField(description = "routeId") + @NotBlank + private String routeId; + + /** 限流策略,1:漏桶策略,2:令牌桶策略, 数据库字段:type */ + @ApiDocField(description = "限流策略,1:漏桶策略,2:令牌桶策略") + @NotNull + private Byte type; + + /** 每秒可处理请求数, 数据库字段:exec_count_per_second */ + @ApiDocField(description = "每秒可处理请求数") + private Integer execCountPerSecond; + + /** 返回的错误码, 数据库字段:limit_code */ + @ApiDocField(description = "返回的错误码") + private String limitCode; + + /** 返回的错误信息, 数据库字段:limit_msg */ + @ApiDocField(description = "返回的错误信息") + private String limitMsg; + + /** 令牌桶容量, 数据库字段:token_bucket_count */ + @ApiDocField(description = "令牌桶容量") + private Integer tokenBucketCount; + + /** 1:开启,0关闭, 数据库字段:limit_status */ + @ApiDocField(description = "1:开启,0关闭") + @NotNull + private Byte limitStatus; +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/RouteParam.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/RouteParam.java index f7f786cf..3ea6bbd4 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/RouteParam.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/RouteParam.java @@ -38,14 +38,6 @@ public class RouteParam { @ApiDocField(description = "路由path") private String path; - - /** - * 是否忽略验证,业务参数验证除外 - */ - @NotNull - @ApiDocField(description = "是否忽略验证,1:是,0:否") - private Integer ignoreValidate; - /** * 状态 */ @@ -53,10 +45,4 @@ public class RouteParam { @ApiDocField(description = "状态,0:审核,1:启用,2:禁用") private Integer status; - /** - * 状态 - */ - @NotNull - @ApiDocField(description = "是否合并结果,1:是,0:否") - private Integer mergeResult; } diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/RouteSearchParam.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/RouteSearchParam.java index 39904ef6..61b9d7c2 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/RouteSearchParam.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/RouteSearchParam.java @@ -4,12 +4,18 @@ import com.gitee.easyopen.doc.annotation.ApiDocField; import lombok.Getter; import lombok.Setter; +import javax.validation.constraints.NotBlank; + /** * @author tanghc */ @Getter @Setter -public class RouteSearchParam extends ServiceSearchParam { - @ApiDocField(description = "id") +public class RouteSearchParam { + @ApiDocField(description = "服务名serviceId") + @NotBlank(message = "serviceId不能为空") + private String serviceId; + + @ApiDocField(description = "路由id") private String id; } diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/ServiceSearchParam.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/ServiceSearchParam.java index f8db7cff..34535ad6 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/ServiceSearchParam.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/ServiceSearchParam.java @@ -4,6 +4,8 @@ import com.gitee.easyopen.doc.annotation.ApiDocField; import lombok.Getter; import lombok.Setter; +import javax.validation.constraints.NotBlank; + /** * @author tanghc */ @@ -11,6 +13,6 @@ import lombok.Setter; @Setter public class ServiceSearchParam { - @ApiDocField(description = "serviceId") + @ApiDocField(description = "服务名serviceId") private String serviceId; } diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/result/LimitVO.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/result/LimitVO.java new file mode 100644 index 00000000..08ca8611 --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/result/LimitVO.java @@ -0,0 +1,54 @@ +package com.gitee.sop.adminserver.api.service.result; + +import com.gitee.easyopen.doc.annotation.ApiDocField; +import lombok.Data; + +/** + * 限流 + * + * @author tanghc + */ +@Data +public class LimitVO { + @ApiDocField(description = "路由id") + private String id; + + @ApiDocField(description = "serviceId") + private String serviceId; + + /** + * 限流策略,1:漏桶策略,2:令牌桶策略, 数据库字段:type + */ + @ApiDocField(description = "限流策略,1:漏桶策略,2:令牌桶策略") + private Byte type; + + /** + * 每秒可处理请求数, 数据库字段:exec_count_per_second + */ + @ApiDocField(description = "每秒可处理请求数") + private Integer execCountPerSecond; + + /** + * 返回的错误码, 数据库字段:limit_code + */ + @ApiDocField(description = "返回的错误码") + private String limitCode; + + /** + * 返回的错误信息, 数据库字段:limit_msg + */ + @ApiDocField(description = "返回的错误信息") + private String limitMsg; + + /** + * 令牌桶容量, 数据库字段:token_bucket_count + */ + @ApiDocField(description = "令牌桶容量") + private Integer tokenBucketCount; + + /** + * 1:开启,0关闭, 数据库字段:limit_status + */ + @ApiDocField(description = "1:开启,0关闭") + private Byte limitStatus; +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/system/param/LoginForm.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/system/param/LoginForm.java index cfb7856b..08da9e47 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/system/param/LoginForm.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/system/param/LoginForm.java @@ -1,9 +1,17 @@ package com.gitee.sop.adminserver.api.system.param; +import com.gitee.easyopen.doc.annotation.ApiDocField; import lombok.Data; +import javax.validation.constraints.NotBlank; + @Data public class LoginForm { + @NotBlank(message = "用户名不能为空") + @ApiDocField(description = "用户名", required = true) private String username; + + @NotBlank(message = "密码不能为空") + @ApiDocField(description = "密码", required = true) private String password; } \ No newline at end of file diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/GatewayRouteDefinition.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/GatewayRouteDefinition.java index e40d5831..6b130a49 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/GatewayRouteDefinition.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/GatewayRouteDefinition.java @@ -1,5 +1,6 @@ package com.gitee.sop.adminserver.bean; +import com.gitee.easyopen.doc.annotation.ApiDocField; import lombok.Data; import java.util.ArrayList; @@ -13,6 +14,7 @@ public class GatewayRouteDefinition { /** * 路由的Id */ + @ApiDocField(description = "路由id") private String id = ""; /** @@ -28,11 +30,13 @@ public class GatewayRouteDefinition { /** * 路由规则转发的目标uri */ + @ApiDocField(description = "uri") private String uri; /** * uri后面跟的path */ + @ApiDocField(description = "path") private String path; /** @@ -43,20 +47,24 @@ public class GatewayRouteDefinition { /** * 是否忽略验证,业务参数验证除外 */ + @ApiDocField(description = "是否忽略验证,业务参数验证除外,1:忽略,0:不忽略") private int ignoreValidate; /** * 状态,0:待审核,1:启用,2:禁用 */ + @ApiDocField(description = "状态,0:待审核,1:启用,2:禁用") private int status = 1; /** * 合并结果 */ + @ApiDocField(description = "合并结果,1:合并,2:不合并") private int mergeResult = 1; /** * 是否需要授权才能访问 */ + @ApiDocField(description = "是否需要授权才能访问,1:是,2:否") private int permission; } \ No newline at end of file diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/RouteConfigDto.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/RouteConfigDto.java new file mode 100644 index 00000000..5455f487 --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/RouteConfigDto.java @@ -0,0 +1,37 @@ +package com.gitee.sop.adminserver.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 Integer status; + + +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/ZookeeperContext.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/ZookeeperContext.java index 410c6801..a2122c75 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/ZookeeperContext.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/ZookeeperContext.java @@ -67,6 +67,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; } diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/common/LimitEnum.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/common/LimitEnum.java new file mode 100644 index 00000000..e516dbf9 --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/common/LimitEnum.java @@ -0,0 +1,36 @@ +package com.gitee.sop.adminserver.common; + +/** + * 限流 + * @author tanghc + */ +public enum LimitEnum { + /** + * 限流策略,1:漏桶策略 + */ + TYPE_LEAKY_BUCKET((byte) 1), + /** + * 限流策略,2:令牌桶策略 + */ + TYPE_TOKEN_BUCKET((byte) 2), + /** + * 1:开启 + */ + STATUS_OPEN((byte) 1), + /** + * 0关闭 + */ + STATUS_CLOSE((byte) 0), + + ; + + LimitEnum(byte val) { + this.val = val; + } + + private byte val; + + public byte getVal() { + return val; + } +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/ConfigRouteBase.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/ConfigRouteBase.java new file mode 100644 index 00000000..9c1d1254 --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/ConfigRouteBase.java @@ -0,0 +1,40 @@ +package com.gitee.sop.adminserver.entity; + +import lombok.Data; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + + +/** + * 表名:config_route_base + * 备注:路由配置表 + * + * @author tanghc + */ +@Table(name = "config_route_base") +@Data +public class ConfigRouteBase { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + /** 数据库字段:id */ + private Long id; + + /** 路由id, 数据库字段:route_id */ + private String routeId; + + /** 状态,1:启用,2:禁用, 数据库字段:status */ + private Byte status; + + /** 数据库字段:gmt_create */ + private Date gmtCreate; + + /** 数据库字段:gmt_modified */ + private Date gmtModified; +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/ConfigRouteLimit.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/ConfigRouteLimit.java new file mode 100644 index 00000000..66d25175 --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/ConfigRouteLimit.java @@ -0,0 +1,55 @@ +package com.gitee.sop.adminserver.entity; + +import lombok.Data; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + + +/** + * 表名:config_route_limit + * 备注:路由限流配置 + * + * @author tanghc + */ +@Table(name = "config_route_limit") +@Data +public class ConfigRouteLimit { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + /** 数据库字段:id */ + private Integer id; + + /** 路由id, 数据库字段:route_id */ + 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; + + /** 数据库字段:gmt_create */ + private Date gmtCreate; + + /** 数据库字段:gmt_modified */ + private Date gmtModified; +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/ConfigRouteBaseMapper.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/ConfigRouteBaseMapper.java new file mode 100644 index 00000000..8d2d6d34 --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/ConfigRouteBaseMapper.java @@ -0,0 +1,12 @@ +package com.gitee.sop.adminserver.mapper; + +import com.gitee.fastmybatis.core.mapper.CrudMapper; + +import com.gitee.sop.adminserver.entity.ConfigRouteBase; + + +/** + * @author tanghc + */ +public interface ConfigRouteBaseMapper extends CrudMapper { +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/ConfigRouteLimitMapper.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/ConfigRouteLimitMapper.java new file mode 100644 index 00000000..38438296 --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/ConfigRouteLimitMapper.java @@ -0,0 +1,12 @@ +package com.gitee.sop.adminserver.mapper; + +import com.gitee.fastmybatis.core.mapper.CrudMapper; + +import com.gitee.sop.adminserver.entity.ConfigRouteLimit; + + +/** + * @author tanghc + */ +public interface ConfigRouteLimitMapper extends CrudMapper { +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/ConfigRouteBaseService.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/ConfigRouteBaseService.java new file mode 100644 index 00000000..f69256fc --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/ConfigRouteBaseService.java @@ -0,0 +1,15 @@ +package com.gitee.sop.adminserver.service; + +import org.springframework.stereotype.Service; + +/** + * @author tanghc + */ +@Service +public class ConfigRouteBaseService { + + public void updateConfigRouteBase() { + + } + +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RouteConfigService.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RouteConfigService.java new file mode 100644 index 00000000..8719938d --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RouteConfigService.java @@ -0,0 +1,30 @@ +package com.gitee.sop.adminserver.service; + +import com.alibaba.fastjson.JSON; +import com.gitee.sop.adminserver.bean.ChannelMsg; +import com.gitee.sop.adminserver.bean.RouteConfigDto; +import com.gitee.sop.adminserver.bean.ZookeeperContext; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * @author tanghc + */ +@Service +@Slf4j +public class RouteConfigService { + + /** + * 发送路由配置消息 + * @param routeConfigDto + * @throws Exception + */ + public void sendRouteConfigMsg(RouteConfigDto routeConfigDto) throws Exception { + String configData = JSON.toJSONString(routeConfigDto); + ChannelMsg channelMsg = new ChannelMsg("update", configData); + String jsonData = JSON.toJSONString(channelMsg); + String path = ZookeeperContext.getRouteConfigChannelPath(); + log.info("消息推送--路由配置(update), path:{}, data:{}", path, jsonData); + ZookeeperContext.createOrUpdateData(path, jsonData); + } +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RoutePermissionService.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RoutePermissionService.java index 2e2e5373..3600a31f 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RoutePermissionService.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RoutePermissionService.java @@ -93,7 +93,7 @@ public class RoutePermissionService { /** * 推送所有路由权限到zookeeper */ - public void sendRoutePermissionReloadToZookeeper() throws Exception { + public void sendRoutePermissionReloadMsg() throws Exception { ChannelMsg channelMsg = new ChannelMsg("reload", null); String jsonData = JSON.toJSONString(channelMsg); String path = ZookeeperContext.getIsvRoutePermissionChannelPath(); diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RouteService.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RouteService.java new file mode 100644 index 00000000..4b48c084 --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RouteService.java @@ -0,0 +1,53 @@ +package com.gitee.sop.adminserver.service; + +import com.alibaba.fastjson.JSON; +import com.gitee.sop.adminserver.api.service.param.RouteSearchParam; +import com.gitee.sop.adminserver.bean.GatewayRouteDefinition; +import com.gitee.sop.adminserver.bean.ZookeeperContext; +import org.apache.commons.lang.StringUtils; +import org.apache.curator.framework.recipes.cache.ChildData; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.toList; + +/** + * @author tanghc + */ +@Service +public class RouteService { + + public List getRouteDefinitionList(RouteSearchParam param) throws Exception { + if (StringUtils.isBlank(param.getServiceId())) { + return Collections.emptyList(); + } + + String searchPath = ZookeeperContext.getSopRouteRootPath() + "/" + param.getServiceId(); + + List childDataList = ZookeeperContext.getChildrenData(searchPath); + + List routeDefinitionStream = childDataList.stream() + .map(childData -> { + String serviceNodeData = new String(childData.getData()); + GatewayRouteDefinition routeDefinition = JSON.parseObject(serviceNodeData, GatewayRouteDefinition.class); + return routeDefinition; + }) + .filter(gatewayRouteDefinition -> { + boolean isRoute = gatewayRouteDefinition.getOrder() != Integer.MIN_VALUE; + String id = param.getId(); + if (StringUtils.isBlank(id)) { + return isRoute; + } else { + return isRoute && gatewayRouteDefinition.getId().contains(id); + } + }) + .collect(toList()) + ; + + return routeDefinitionStream; + } + +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java index 5fce9ba4..f9326a63 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java @@ -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 --------- /** diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/BaseRouteDefinition.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/BaseRouteDefinition.java index 389101c8..e46e6671 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/BaseRouteDefinition.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/BaseRouteDefinition.java @@ -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(); - } } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/RouteConfig.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/RouteConfig.java new file mode 100644 index 00000000..0093daa9 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/RouteConfig.java @@ -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; + } +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/RouteConfigDto.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/RouteConfigDto.java new file mode 100644 index 00000000..664bb478 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/RouteConfigDto.java @@ -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; + + +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/NameVersionRoutePredicateFactory.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/NameVersionRoutePredicateFactory.java index cc6686cc..1ee16ce3 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/NameVersionRoutePredicateFactory.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/NameVersionRoutePredicateFactory.java @@ -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; } } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultRouteConfigManager.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultRouteConfigManager.java new file mode 100644 index 00000000..701c772e --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultRouteConfigManager.java @@ -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 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); + } +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/RouteConfigManager.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/RouteConfigManager.java new file mode 100644 index 00000000..67ace4df --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/RouteConfigManager.java @@ -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); +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ZookeeperContext.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ZookeeperContext.java index a39e23ba..33a717f2 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ZookeeperContext.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ZookeeperContext.java @@ -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; } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/message/ErrorEnum.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/message/ErrorEnum.java index c9557854..6a20cfed 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/message/ErrorEnum.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/message/ErrorEnum.java @@ -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"), diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/util/MyBeanUtil.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/util/MyBeanUtil.java new file mode 100644 index 00000000..14fd3963 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/util/MyBeanUtil.java @@ -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 { + + /** + * 属性拷贝,第一个参数中的属性值拷贝到第二个参数中
      + * 注意:当第一个参数中的属性有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 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 pojoToMap(Object pojo) { + if (pojo == null) { + return Collections.emptyMap(); + } + String json = JSON.toJSONString(pojo); + return JSON.parseObject(json); + } + + + /** + * 将map对象转换成普通类 + * + * @param 普通类类型 + * @param map map对象 + * @param pojoClass 普通类 + * @return 返回普通类 + */ + public static T mapToPojo(Map map, Class pojoClass) { + return new JSONObject(map).toJavaObject(pojoClass); + } + + /** + * map集合转换成对象集合 + * + * @param 普通类类型 + * @param list map集合 + * @param pojoClass 待转换的对象类型 + * @return 返回对象集合 + */ + public static List mapListToObjList(List> list, Class pojoClass) { + if (list == null) { + return Collections.emptyList(); + } + List retList = new ArrayList<>(list.size()); + for (Map map : list) { + retList.add(mapToPojo(map, pojoClass)); + } + return retList; + } + +} \ No newline at end of file diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/SopRouteLocator.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/SopRouteLocator.java index 0972e51a..e22c57de 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/SopRouteLocator.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/SopRouteLocator.java @@ -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(); } diff --git a/sop-common/sop-gateway-common/src/main/resources/i18n/open/error_en.properties b/sop-common/sop-gateway-common/src/main/resources/i18n/open/error_en.properties index 2fca82c6..dbdcf00c 100644 --- a/sop-common/sop-gateway-common/src/main/resources/i18n/open/error_en.properties +++ b/sop-common/sop-gateway-common/src/main/resources/i18n/open/error_en.properties @@ -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 diff --git a/sop-common/sop-gateway-common/src/main/resources/i18n/open/error_zh_CN.properties b/sop-common/sop-gateway-common/src/main/resources/i18n/open/error_zh_CN.properties index 3a700088..29b9fd7f 100644 --- a/sop-common/sop-gateway-common/src/main/resources/i18n/open/error_zh_CN.properties +++ b/sop-common/sop-gateway-common/src/main/resources/i18n/open/error_zh_CN.properties @@ -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 diff --git a/sop-example/sop-book/sop-book-web/pom.xml b/sop-example/sop-book/sop-book-web/pom.xml index 232bf99f..52e2f2e3 100644 --- a/sop-example/sop-book/sop-book-web/pom.xml +++ b/sop-example/sop-book/sop-book-web/pom.xml @@ -23,7 +23,7 @@ com.gitee.sop sop-service-common - 1.0.0-SNAPSHOT + 1.2.0-SNAPSHOT com.gitee.sop diff --git a/sop-example/sop-easyopen/pom.xml b/sop-example/sop-easyopen/pom.xml index cc9116c8..2b8312ce 100644 --- a/sop-example/sop-easyopen/pom.xml +++ b/sop-example/sop-easyopen/pom.xml @@ -29,7 +29,7 @@ com.gitee.sop sop-service-common - 1.0.0-SNAPSHOT + 1.2.0-SNAPSHOT org.springframework.cloud diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/entity/ConfigRouteBase.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/entity/ConfigRouteBase.java new file mode 100644 index 00000000..80d69165 --- /dev/null +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/entity/ConfigRouteBase.java @@ -0,0 +1,39 @@ +package com.gitee.sop.gateway.entity; + +import lombok.Data; + +import javax.persistence.Column; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Date; + + +/** + * 表名:config_route_base + * 备注:路由配置表 + * + * @author tanghc + */ +@Table(name = "config_route_base") +@Data +public class ConfigRouteBase { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + /** 数据库字段:id */ + private Long id; + + /** 路由id, 数据库字段:route_id */ + private String routeId; + + /** 状态,1:启用,2:禁用, 数据库字段:status */ + private Byte status; + + /** 数据库字段:gmt_create */ + private Date gmtCreate; + + /** 数据库字段:gmt_modified */ + private Date gmtModified; +} diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/entity/ConfigRouteLimit.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/entity/ConfigRouteLimit.java new file mode 100644 index 00000000..8926bc43 --- /dev/null +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/entity/ConfigRouteLimit.java @@ -0,0 +1,54 @@ +package com.gitee.sop.gateway.entity; + +import lombok.Data; + +import javax.persistence.Column; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Date; + + +/** + * 表名:config_route_limit + * 备注:路由限流配置 + * + * @author tanghc + */ +@Table(name = "config_route_limit") +@Data +public class ConfigRouteLimit { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + /** 数据库字段:id */ + private Integer id; + + /** 路由id, 数据库字段:route_id */ + 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; + + /** 数据库字段:gmt_create */ + private Date gmtCreate; + + /** 数据库字段:gmt_modified */ + private Date gmtModified; +} diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvManager.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvManager.java index dc6f861d..e6ae46d8 100644 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvManager.java +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvManager.java @@ -33,7 +33,6 @@ public class DbIsvManager extends CacheIsvManager { @Override public void load(Function secretGetter) { - log.info("从数据库读取ISV信息,保存到本地"); List isvInfoList = isvInfoMapper.list(new Query()); isvInfoList.stream() .forEach(isvInfo -> { diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbRouteConfigManager.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbRouteConfigManager.java new file mode 100644 index 00000000..a76e78cd --- /dev/null +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbRouteConfigManager.java @@ -0,0 +1,83 @@ +package com.gitee.sop.gateway.manager; + +import com.alibaba.fastjson.JSON; +import com.gitee.fastmybatis.core.query.Query; +import com.gitee.sop.gateway.mapper.ConfigRouteBaseMapper; +import com.gitee.sop.gateway.mapper.ConfigRouteLimitMapper; +import com.gitee.sop.gatewaycommon.bean.ChannelMsg; +import com.gitee.sop.gatewaycommon.bean.RouteConfig; +import com.gitee.sop.gatewaycommon.bean.RouteConfigDto; +import com.gitee.sop.gatewaycommon.manager.DefaultRouteConfigManager; +import com.gitee.sop.gatewaycommon.manager.ZookeeperContext; +import com.gitee.sop.gatewaycommon.util.MyBeanUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +/** + * @author tanghc + */ +@Component +@Slf4j +public class DbRouteConfigManager extends DefaultRouteConfigManager { + + @Autowired + ConfigRouteBaseMapper configRouteBaseMapper; + + @Autowired + ConfigRouteLimitMapper configRouteLimitMapper; + + @Autowired + Environment environment; + + @Override + public void load() { + Query query = new Query(); + + configRouteBaseMapper.list(query) + .stream() + .forEach(configRouteBase -> { + String key = configRouteBase.getRouteId(); + putVal(key, configRouteBase); + }); + + configRouteLimitMapper.list(query) + .stream() + .forEach(configRouteLimit -> { + String key = configRouteLimit.getRouteId(); + putVal(key, configRouteLimit); + }); + + } + + protected void putVal(String key, Object object) { + RouteConfig routeConfig = routeConfigMap.getOrDefault(key, newRouteConfig()); + MyBeanUtil.copyPropertiesIgnoreNull(object, routeConfig); + routeConfigMap.put(key, routeConfig); + } + + + @PostConstruct + protected void after() throws Exception { + ZookeeperContext.setEnvironment(environment); + String path = ZookeeperContext.getRouteConfigChannelPath(); + ZookeeperContext.listenPath(path, nodeCache -> { + String nodeData = new String(nodeCache.getCurrentData().getData()); + ChannelMsg channelMsg = JSON.parseObject(nodeData, ChannelMsg.class); + final RouteConfigDto routeConfigDto = JSON.parseObject(channelMsg.getData(), RouteConfigDto.class); + switch (channelMsg.getOperation()) { + case "reload": + log.info("重新加载路由配置信息,routeConfigDto:{}", routeConfigDto); + load(); + break; + case "update": + log.info("更新路由配置信息,routeConfigDto:{}", routeConfigDto); + update(routeConfigDto); + break; + } + }); + } +} diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/ManagerInitializer.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/ManagerInitializer.java index 1dc1d202..c503a0fb 100644 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/ManagerInitializer.java +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/ManagerInitializer.java @@ -13,15 +13,19 @@ import org.springframework.stereotype.Component; @Slf4j public class ManagerInitializer { @Autowired - private DbIsvManager dbIsvManager; + DbIsvManager dbIsvManager; @Autowired - private DbIsvRoutePermissionManager dbIsvRoutePermissionManager; + DbIsvRoutePermissionManager dbIsvRoutePermissionManager; + + @Autowired + DbRouteConfigManager dbRouteConfigManager; public void init() { ApiConfig apiConfig = ApiConfig.getInstance(); apiConfig.setIsvManager(dbIsvManager); apiConfig.setIsvRoutePermissionManager(dbIsvRoutePermissionManager); + apiConfig.setRouteConfigManager(dbRouteConfigManager); // 从数据库加载isv信息 log.debug("从数据库加载isv信息"); @@ -32,5 +36,8 @@ public class ManagerInitializer { log.debug("从数据库加载路由权限信息"); dbIsvRoutePermissionManager.load(); + + log.debug("从数据库加载路由配置信息"); + dbRouteConfigManager.load(); } } diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/mapper/ConfigRouteBaseMapper.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/mapper/ConfigRouteBaseMapper.java new file mode 100644 index 00000000..dda4c5b3 --- /dev/null +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/mapper/ConfigRouteBaseMapper.java @@ -0,0 +1,11 @@ +package com.gitee.sop.gateway.mapper; + +import com.gitee.fastmybatis.core.mapper.CrudMapper; +import com.gitee.sop.gateway.entity.ConfigRouteBase; + + +/** + * @author tanghc + */ +public interface ConfigRouteBaseMapper extends CrudMapper { +} diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/mapper/ConfigRouteLimitMapper.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/mapper/ConfigRouteLimitMapper.java new file mode 100644 index 00000000..4dfb7f86 --- /dev/null +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/mapper/ConfigRouteLimitMapper.java @@ -0,0 +1,11 @@ +package com.gitee.sop.gateway.mapper; + +import com.gitee.fastmybatis.core.mapper.CrudMapper; +import com.gitee.sop.gateway.entity.ConfigRouteLimit; + + +/** + * @author tanghc + */ +public interface ConfigRouteLimitMapper extends CrudMapper { +}