本次修改的源码在:https://gitee.com/stonic-open-source/sentinel-parent
一
下载源码 地址:https://github.com/alibaba/Sentinel/releases/tag/1.8.6
编辑
二
导入idea,等待maven下载好各种依赖
三
打开sentile-dashboard这个模块,打开resources下的application.properties配置
把下列配置加进去
#你的nacos地址 nacos.server-addr=localhost:8148 #准备把sentinel配置同步到的nacos命名空间 nacos.namespace=zixun_dev #你的nacos用户名 nacos.username=nacos #你的nacos密码 nacos.password=nacos
四
打开sentile-dashboard下的pom,把sentinel-datasource-nacos的<scope>test</scope>删掉(记得刷新一下maven)
编辑
编辑
五
rule文件夹下新建一个nacos目录
把图中test的NacosConfig和Util复制到nacos目录下
编辑
编辑
六
然后在nacos下新建一个NacosInfoConfig类,用于读取配置文件
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /** * @author 刘辉 * @description * @since 2024/5/17 上午10:26 */ @Component @ConfigurationProperties(prefix = "nacos") public class NacosInfoConfig { private String serverAddr; private String username; private String password; private String namespace; public String getServerAddr() { return serverAddr; } public void setServerAddr(String serverAddr) { this.serverAddr = serverAddr; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getNamespace() { return namespace; } public void setNamespace(String namespace) { this.namespace = namespace; } }
七
然后修改一下NacosConfigUtil的内容 其中group_id需要和你springcloud项目配置的nacos中sentinel的groupId一致
public final class NacosConfigUtil { /** * 同步到nacos生成的groupId 没有可不填 */ public static final String GROUP_ID = "zixun_sentinel"; /** * 同步到nacos生成的sentinel api规则的后缀 */ public static final String API_DATA_ID_POSTFIX = "-api-rules"; /** * 同步到nacos生成的sentinel 流控规则的后缀 */ public static final String FLOW_DATA_ID_POSTFIX = "-flow-rules"; /** * 同步到nacos生成的sentinel 参数规则的后缀 */ public static final String PARAM_FLOW_DATA_ID_POSTFIX = "-param-rules"; public static final String CLUSTER_MAP_DATA_ID_POSTFIX = "-cluster-map"; /** * cc for `cluster-client` */ public static final String CLIENT_CONFIG_DATA_ID_POSTFIX = "-cc-config"; /** * cs for `cluster-server` */ public static final String SERVER_TRANSPORT_CONFIG_DATA_ID_POSTFIX = "-cs-transport-config"; public static final String SERVER_FLOW_CONFIG_DATA_ID_POSTFIX = "-cs-flow-config"; public static final String SERVER_NAMESPACE_SET_DATA_ID_POSTFIX = "-cs-namespace-set"; private NacosConfigUtil() {} }
编辑
八
修改NacosConfig文件
将配置的nacos信息注入进去,且新增gateway流控配置和sentinel全局规则的配置
import java.util.List; import java.util.Properties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiDefinitionEntity; import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity; import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity; import com.alibaba.csp.sentinel.datasource.Converter; import com.alibaba.fastjson.JSON; import com.alibaba.nacos.api.config.ConfigFactory; import com.alibaba.nacos.api.config.ConfigService; /** * @author Eric Zhao * @since 1.4.0 */ @Configuration public class NacosConfig { @Autowired private NacosInfoConfig nacosInfoConfig; /** * sentinel本地流控 编码器 * @return */ @Bean public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() { return JSON::toJSONString; } /** * sentinel 针对gateway流控配置 编码器 * @return */ @Bean public Converter<List<GatewayFlowRuleEntity>, String> flowRuleGatewayEntityEncoder() { return JSON::toJSONString; } /** * sentinel 针对全局流控配置 编码器 * @return */ @Bean public Converter<List<ApiDefinitionEntity>, String> flowRuleNacosEntityEncoder() { return JSON::toJSONString; } /** * sentinel本地流控 解码器 * @return */ @Bean public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() { return s -> JSON.parseArray(s, FlowRuleEntity.class); } /** * sentinel 针对gateway流控配置 解码器 * @return */ @Bean public Converter<String, List<GatewayFlowRuleEntity>> flowRuleGatewayEntityDecoder() { return s -> JSON.parseArray(s, GatewayFlowRuleEntity.class); } /** * sentinel 针对全局流控配置 解码器 * @return */ @Bean public Converter<String, List<ApiDefinitionEntity>> flowRuleNacosEntityDecoder() { return s -> JSON.parseArray(s, ApiDefinitionEntity.class); } @Bean public ConfigService nacosConfigService() throws Exception { Properties properties = new Properties(); //Nacos地址 properties.put("serverAddr", nacosInfoConfig.getServerAddr()); //Nacos用户名 properties.put("username", nacosInfoConfig.getUsername()); //Nacos密码 properties.put("password", nacosInfoConfig.getPassword()); properties.put("namespace", nacosInfoConfig.getNamespace()); return ConfigFactory.createConfigService(properties); } }
九
新建FlowRuleGatewayProvider和FlowRuleGatewayPublisher 分别提供gateway添加和查询的操作
import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity; import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil; import com.alibaba.csp.sentinel.datasource.Converter; import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.nacos.api.config.ConfigService; /** * @author Eric Zhao * @since 1.4.0 */ @Component("flowRuleGatewayProvider") public class FlowRuleGatewayProvider implements DynamicRuleProvider<List<GatewayFlowRuleEntity>> { @Autowired private ConfigService configService; @Autowired @Qualifier("flowRuleGatewayEntityDecoder") private Converter<String, List<GatewayFlowRuleEntity>> converter; @Override public List<GatewayFlowRuleEntity> getRules(String appName) throws Exception { String rules = configService.getConfig(appName + NacosConfigUtil.FLOW_DATA_ID_POSTFIX, NacosConfigUtil.GROUP_ID, 3000); if (StringUtil.isEmpty(rules)) { return new ArrayList<>(); } return converter.convert(rules); } }
import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity; import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher; import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil; import com.alibaba.csp.sentinel.datasource.Converter; import com.alibaba.csp.sentinel.util.AssertUtil; import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.ConfigType; /** * @author Eric Zhao * @since 1.4.0 */ @Component("flowRuleGatewayPublisher") public class FlowRuleGatewayPublisher implements DynamicRulePublisher<List<GatewayFlowRuleEntity>> { @Autowired private ConfigService configService; @Autowired @Qualifier("flowRuleGatewayEntityEncoder") private Converter<List<GatewayFlowRuleEntity>, String> converter; @Override public void publish(String app, List<GatewayFlowRuleEntity> rules) throws Exception { AssertUtil.notEmpty(app, "app name cannot be empty"); if (rules == null) { return; } configService.publishConfig(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX, NacosConfigUtil.GROUP_ID, converter.convert(rules), ConfigType.JSON.getType()); } }
新建FlowRuleApiProvider和FlowRuleApiPublisher 分别提供sentinel全局规则 查询和编辑
import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiDefinitionEntity; import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil; import com.alibaba.csp.sentinel.datasource.Converter; import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.nacos.api.config.ConfigService; /** * @author Eric Zhao * @since 1.4.0 */ @Component("flowRuleNacosProvider") public class FlowRuleApiProvider implements DynamicRuleProvider<List<ApiDefinitionEntity>> { @Autowired private ConfigService configService; @Autowired @Qualifier("flowRuleNacosEntityDecoder") private Converter<String, List<ApiDefinitionEntity>> converter; @Override public List<ApiDefinitionEntity> getRules(String appName) throws Exception { String rules = configService.getConfig(appName + NacosConfigUtil.API_DATA_ID_POSTFIX, NacosConfigUtil.GROUP_ID, 3000); if (StringUtil.isEmpty(rules)) { return new ArrayList<>(); } return converter.convert(rules); } }
import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiDefinitionEntity; import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher; import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil; import com.alibaba.csp.sentinel.datasource.Converter; import com.alibaba.csp.sentinel.util.AssertUtil; import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.ConfigType; /** * @author Eric Zhao * @since 1.4.0 */ @Component("flowRuleNacosPublisher") public class FlowRuleApiPublisher implements DynamicRulePublisher<List<ApiDefinitionEntity>> { @Autowired private ConfigService configService; @Autowired @Qualifier("flowRuleNacosEntityEncoder") private Converter<List<ApiDefinitionEntity>, String> converter; @Override public void publish(String app, List<ApiDefinitionEntity> rules) throws Exception { AssertUtil.notEmpty(app, "app name cannot be empty"); if (rules == null) { return; } configService.publishConfig(app + NacosConfigUtil.API_DATA_ID_POSTFIX, NacosConfigUtil.GROUP_ID, converter.convert(rules), ConfigType.JSON.getType()); } }
自此配置方面就结束了,接下来上controller代码
十
找到controller下的gateway目录两个controller
编辑
下边的增删改查方法都有修改,修改的地方比较多,这里我直接贴主要替换的代码和controller全部代码大家直接粘贴
GatewayApiController修改处:
@Autowired @Qualifier("flowRuleNacosProvider") private DynamicRuleProvider<List<ApiDefinitionEntity>> ruleProvider; @Autowired @Qualifier("flowRuleNacosPublisher") private DynamicRulePublisher<List<ApiDefinitionEntity>> rulePublisher;
package com.alibaba.csp.sentinel.dashboard.controller.gateway; import com.alibaba.csp.sentinel.dashboard.auth.AuthAction; import com.alibaba.csp.sentinel.dashboard.auth.AuthService; import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient; import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiDefinitionEntity; import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiPredicateItemEntity; import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo; import com.alibaba.csp.sentinel.dashboard.domain.Result; import com.alibaba.csp.sentinel.dashboard.domain.vo.gateway.api.AddApiReqVo; import com.alibaba.csp.sentinel.dashboard.domain.vo.gateway.api.ApiPredicateItemVo; import com.alibaba.csp.sentinel.dashboard.domain.vo.gateway.api.UpdateApiReqVo; import com.alibaba.csp.sentinel.dashboard.repository.gateway.InMemApiDefinitionStore; import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher; import com.alibaba.csp.sentinel.util.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.util.*; import static com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants.*; /** * Gateway api Controller for manage gateway api definitions. * * @author cdfive * @since 1.7.0 */ @RestController @RequestMapping(value = "/gateway/api") public class GatewayApiController { private final Logger logger = LoggerFactory.getLogger(GatewayApiController.class); @Autowired private InMemApiDefinitionStore repository; @Autowired private SentinelApiClient sentinelApiClient; @Autowired @Qualifier("flowRuleNacosProvider") private DynamicRuleProvider<List<ApiDefinitionEntity>> ruleProvider; @Autowired @Qualifier("flowRuleNacosPublisher") private DynamicRulePublisher<List<ApiDefinitionEntity>> rulePublisher; @GetMapping("/list.json") @AuthAction(AuthService.PrivilegeType.READ_RULE) public Result<List<ApiDefinitionEntity>> queryApis(String app, String ip, Integer port) { if (StringUtil.isEmpty(app)) { return Result.ofFail(-1, "app can't be null or empty"); } if (StringUtil.isEmpty(ip)) { return Result.ofFail(-1, "ip can't be null or empty"); } if (port == null) { return Result.ofFail(-1, "port can't be null"); } try { List<ApiDefinitionEntity> apis = ruleProvider.getRules(app); // List<ApiDefinitionEntity> apis = sentinelApiClient.fetchApis(app, ip, port).get(); repository.saveAll(apis); return Result.ofSuccess(apis); } catch (Throwable throwable) { logger.error("queryApis error:", throwable); return Result.ofThrowable(-1, throwable); } } @PostMapping("/new.json") @AuthAction(AuthService.PrivilegeType.WRITE_RULE) public Result<ApiDefinitionEntity> addApi(HttpServletRequest request, @RequestBody AddApiReqVo reqVo) { String app = reqVo.getApp(); if (StringUtil.isBlank(app)) { return Result.ofFail(-1, "app can't be null or empty"); } ApiDefinitionEntity entity = new ApiDefinitionEntity(); entity.setApp(app.trim()); String ip = reqVo.getIp(); if (StringUtil.isBlank(ip)) { return Result.ofFail(-1, "ip can't be null or empty"); } entity.setIp(ip.trim()); Integer port = reqVo.getPort(); if (port == null) { return Result.ofFail(-1, "port can't be null"); } entity.setPort(port); // API名称 String apiName = reqVo.getApiName(); if (StringUtil.isBlank(apiName)) { return Result.ofFail(-1, "apiName can't be null or empty"); } entity.setApiName(apiName.trim()); // 匹配规则列表 List<ApiPredicateItemVo> predicateItems = reqVo.getPredicateItems(); if (CollectionUtils.isEmpty(predicateItems)) { return Result.ofFail(-1, "predicateItems can't empty"); } List<ApiPredicateItemEntity> predicateItemEntities = new ArrayList<>(); for (ApiPredicateItemVo predicateItem : predicateItems) { ApiPredicateItemEntity predicateItemEntity = new ApiPredicateItemEntity(); // 匹配模式 Integer matchStrategy = predicateItem.getMatchStrategy(); if (!Arrays.asList(URL_MATCH_STRATEGY_EXACT, URL_MATCH_STRATEGY_PREFIX, URL_MATCH_STRATEGY_REGEX).contains(matchStrategy)) { return Result.ofFail(-1, "invalid matchStrategy: " + matchStrategy); } predicateItemEntity.setMatchStrategy(matchStrategy); // 匹配串 String pattern = predicateItem.getPattern(); if (StringUtil.isBlank(pattern)) { return Result.ofFail(-1, "pattern can't be null or empty"); } predicateItemEntity.setPattern(pattern); predicateItemEntities.add(predicateItemEntity); } entity.setPredicateItems(new LinkedHashSet<>(predicateItemEntities)); // 检查API名称不能重复 List<ApiDefinitionEntity> allApis = repository.findAllByMachine(MachineInfo.of(app.trim(), ip.trim(), port)); if (allApis.stream().map(o -> o.getApiName()).anyMatch(o -> o.equals(apiName.trim()))) { return Result.ofFail(-1, "apiName exists: " + apiName); } Date date = new Date(); entity.setGmtCreate(date); entity.setGmtModified(date); try { entity = repository.save(entity); publishApis(entity.getApp()); } catch (Throwable throwable) { logger.error("add gateway api error:", throwable); return Result.ofThrowable(-1, throwable); } // if (!publishApis(app, ip, port)) { // logger.warn("publish gateway apis fail after add"); // } return Result.ofSuccess(entity); } @PostMapping("/save.json") @AuthAction(AuthService.PrivilegeType.WRITE_RULE) public Result<ApiDefinitionEntity> updateApi(@RequestBody UpdateApiReqVo reqVo) { String app = reqVo.getApp(); if (StringUtil.isBlank(app)) { return Result.ofFail(-1, "app can't be null or empty"); } Long id = reqVo.getId(); if (id == null) { return Result.ofFail(-1, "id can't be null"); } ApiDefinitionEntity entity = repository.findById(id); if (entity == null) { return Result.ofFail(-1, "api does not exist, id=" + id); } // 匹配规则列表 List<ApiPredicateItemVo> predicateItems = reqVo.getPredicateItems(); if (CollectionUtils.isEmpty(predicateItems)) { return Result.ofFail(-1, "predicateItems can't empty"); } List<ApiPredicateItemEntity> predicateItemEntities = new ArrayList<>(); for (ApiPredicateItemVo predicateItem : predicateItems) { ApiPredicateItemEntity predicateItemEntity = new ApiPredicateItemEntity(); // 匹配模式 int matchStrategy = predicateItem.getMatchStrategy(); if (!Arrays.asList(URL_MATCH_STRATEGY_EXACT, URL_MATCH_STRATEGY_PREFIX, URL_MATCH_STRATEGY_REGEX).contains(matchStrategy)) { return Result.ofFail(-1, "Invalid matchStrategy: " + matchStrategy); } predicateItemEntity.setMatchStrategy(matchStrategy); // 匹配串 String pattern = predicateItem.getPattern(); if (StringUtil.isBlank(pattern)) { return Result.ofFail(-1, "pattern can't be null or empty"); } predicateItemEntity.setPattern(pattern); predicateItemEntities.add(predicateItemEntity); } entity.setPredicateItems(new LinkedHashSet<>(predicateItemEntities)); Date date = new Date(); entity.setGmtModified(date); try { entity = repository.save(entity); publishApis(entity.getApp()); } catch (Throwable throwable) { logger.error("update gateway api error:", throwable); return Result.ofThrowable(-1, throwable); } // if (!publishApis(app, entity.getIp(), entity.getPort())) { // logger.warn("publish gateway apis fail after update"); // } return Result.ofSuccess(entity); } @PostMapping("/delete.json") @AuthAction(AuthService.PrivilegeType.DELETE_RULE) public Result<Long> deleteApi(Long id) { if (id == null) { return Result.ofFail(-1, "id can't be null"); } ApiDefinitionEntity oldEntity = repository.findById(id); if (oldEntity == null) { return Result.ofSuccess(null); } try { repository.delete(id); publishApis(oldEntity.getApp()); } catch (Throwable throwable) { logger.error("delete gateway api error:", throwable); return Result.ofThrowable(-1, throwable); } // if (!publishApis(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) { // logger.warn("publish gateway apis fail after delete"); // } return Result.ofSuccess(id); } // private boolean publishApis(String app, String ip, Integer port) { // List<ApiDefinitionEntity> apis = repository.findAllByMachine(MachineInfo.of(app, ip, port)); // return sentinelApiClient.modifyApis(app, ip, port, apis); // } private void publishApis(/*@NonNull*/ String app) throws Exception { List<ApiDefinitionEntity> rules = repository.findAllByApp(app); rulePublisher.publish(app, rules); } }
GatewayFlowRuleController修改为:
@Autowired @Qualifier("flowRuleGatewayProvider") private DynamicRuleProvider<List<GatewayFlowRuleEntity>> ruleProvider; @Autowired @Qualifier("flowRuleGatewayPublisher") private DynamicRulePublisher<List<GatewayFlowRuleEntity>> rulePublisher;
package com.alibaba.csp.sentinel.dashboard.controller.gateway; import com.alibaba.csp.sentinel.dashboard.auth.AuthAction; import com.alibaba.csp.sentinel.dashboard.auth.AuthService; import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient; import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity; import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayParamFlowItemEntity; import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity; import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo; import com.alibaba.csp.sentinel.dashboard.domain.Result; import com.alibaba.csp.sentinel.dashboard.domain.vo.gateway.rule.AddFlowRuleReqVo; import com.alibaba.csp.sentinel.dashboard.domain.vo.gateway.rule.GatewayParamFlowItemVo; import com.alibaba.csp.sentinel.dashboard.domain.vo.gateway.rule.UpdateFlowRuleReqVo; import com.alibaba.csp.sentinel.dashboard.repository.gateway.InMemGatewayFlowRuleStore; import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher; import com.alibaba.csp.sentinel.util.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.web.bind.annotation.*; import java.util.Arrays; import java.util.Date; import java.util.List; import static com.alibaba.csp.sentinel.slots.block.RuleConstant.*; import static com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants.*; import static com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity.*; /** * Gateway flow rule Controller for manage gateway flow rules. * * @author cdfive * @since 1.7.0 */ @RestController @RequestMapping(value = "/gateway/flow") public class GatewayFlowRuleController { private final Logger logger = LoggerFactory.getLogger(GatewayFlowRuleController.class); @Autowired private InMemGatewayFlowRuleStore repository; @Autowired private SentinelApiClient sentinelApiClient; @Autowired @Qualifier("flowRuleGatewayProvider") private DynamicRuleProvider<List<GatewayFlowRuleEntity>> ruleProvider; @Autowired @Qualifier("flowRuleGatewayPublisher") private DynamicRulePublisher<List<GatewayFlowRuleEntity>> rulePublisher; @GetMapping("/list.json") @AuthAction(AuthService.PrivilegeType.READ_RULE) public Result<List<GatewayFlowRuleEntity>> queryFlowRules(String app, String ip, Integer port) { if (StringUtil.isEmpty(app)) { return Result.ofFail(-1, "app can't be null or empty"); } if (StringUtil.isEmpty(ip)) { return Result.ofFail(-1, "ip can't be null or empty"); } if (port == null) { return Result.ofFail(-1, "port can't be null"); } // try { // List<GatewayFlowRuleEntity> rules = sentinelApiClient.fetchGatewayFlowRules(app, ip, port).get(); // repository.saveAll(rules); // return Result.ofSuccess(rules); // } catch (Throwable throwable) { // logger.error("query gateway flow rules error:", throwable); // return Result.ofThrowable(-1, throwable); // } try { List<GatewayFlowRuleEntity> rules = ruleProvider.getRules(app); rules = repository.saveAll(rules); return Result.ofSuccess(rules); } catch (Throwable throwable) { logger.error("Error when querying flow rules", throwable); return Result.ofThrowable(-1, throwable); } } @PostMapping("/new.json") @AuthAction(AuthService.PrivilegeType.WRITE_RULE) public Result<GatewayFlowRuleEntity> addFlowRule(@RequestBody AddFlowRuleReqVo reqVo) { String app = reqVo.getApp(); if (StringUtil.isBlank(app)) { return Result.ofFail(-1, "app can't be null or empty"); } GatewayFlowRuleEntity entity = new GatewayFlowRuleEntity(); entity.setApp(app.trim()); String ip = reqVo.getIp(); if (StringUtil.isBlank(ip)) { return Result.ofFail(-1, "ip can't be null or empty"); } entity.setIp(ip.trim()); Integer port = reqVo.getPort(); if (port == null) { return Result.ofFail(-1, "port can't be null"); } entity.setPort(port); // API类型, Route ID或API分组 Integer resourceMode = reqVo.getResourceMode(); if (resourceMode == null) { return Result.ofFail(-1, "resourceMode can't be null"); } if (!Arrays.asList(RESOURCE_MODE_ROUTE_ID, RESOURCE_MODE_CUSTOM_API_NAME).contains(resourceMode)) { return Result.ofFail(-1, "invalid resourceMode: " + resourceMode); } entity.setResourceMode(resourceMode); // API名称 String resource = reqVo.getResource(); if (StringUtil.isBlank(resource)) { return Result.ofFail(-1, "resource can't be null or empty"); } entity.setResource(resource.trim()); // 针对请求属性 GatewayParamFlowItemVo paramItem = reqVo.getParamItem(); if (paramItem != null) { GatewayParamFlowItemEntity itemEntity = new GatewayParamFlowItemEntity(); entity.setParamItem(itemEntity); // 参数属性 0-ClientIP 1-Remote Host 2-Header 3-URL参数 4-Cookie Integer parseStrategy = paramItem.getParseStrategy(); if (!Arrays.asList(PARAM_PARSE_STRATEGY_CLIENT_IP, PARAM_PARSE_STRATEGY_HOST, PARAM_PARSE_STRATEGY_HEADER , PARAM_PARSE_STRATEGY_URL_PARAM, PARAM_PARSE_STRATEGY_COOKIE).contains(parseStrategy)) { return Result.ofFail(-1, "invalid parseStrategy: " + parseStrategy); } itemEntity.setParseStrategy(paramItem.getParseStrategy()); // 当参数属性为2-Header 3-URL参数 4-Cookie时,参数名称必填 if (Arrays.asList(PARAM_PARSE_STRATEGY_HEADER, PARAM_PARSE_STRATEGY_URL_PARAM, PARAM_PARSE_STRATEGY_COOKIE).contains(parseStrategy)) { // 参数名称 String fieldName = paramItem.getFieldName(); if (StringUtil.isBlank(fieldName)) { return Result.ofFail(-1, "fieldName can't be null or empty"); } itemEntity.setFieldName(paramItem.getFieldName()); } String pattern = paramItem.getPattern(); // 如果匹配串不为空,验证匹配模式 if (StringUtil.isNotEmpty(pattern)) { itemEntity.setPattern(pattern); Integer matchStrategy = paramItem.getMatchStrategy(); if (!Arrays.asList(PARAM_MATCH_STRATEGY_EXACT, PARAM_MATCH_STRATEGY_CONTAINS, PARAM_MATCH_STRATEGY_REGEX).contains(matchStrategy)) { return Result.ofFail(-1, "invalid matchStrategy: " + matchStrategy); } itemEntity.setMatchStrategy(matchStrategy); } } // 阈值类型 0-线程数 1-QPS Integer grade = reqVo.getGrade(); if (grade == null) { return Result.ofFail(-1, "grade can't be null"); } if (!Arrays.asList(FLOW_GRADE_THREAD, FLOW_GRADE_QPS).contains(grade)) { return Result.ofFail(-1, "invalid grade: " + grade); } entity.setGrade(grade); // QPS阈值 Double count = reqVo.getCount(); if (count == null) { return Result.ofFail(-1, "count can't be null"); } if (count < 0) { return Result.ofFail(-1, "count should be at lease zero"); } entity.setCount(count); // 间隔 Long interval = reqVo.getInterval(); if (interval == null) { return Result.ofFail(-1, "interval can't be null"); } if (interval <= 0) { return Result.ofFail(-1, "interval should be greater than zero"); } entity.setInterval(interval); // 间隔单位 Integer intervalUnit = reqVo.getIntervalUnit(); if (intervalUnit == null) { return Result.ofFail(-1, "intervalUnit can't be null"); } if (!Arrays.asList(INTERVAL_UNIT_SECOND, INTERVAL_UNIT_MINUTE, INTERVAL_UNIT_HOUR, INTERVAL_UNIT_DAY).contains(intervalUnit)) { return Result.ofFail(-1, "Invalid intervalUnit: " + intervalUnit); } entity.setIntervalUnit(intervalUnit); // 流控方式 0-快速失败 2-匀速排队 Integer controlBehavior = reqVo.getControlBehavior(); if (controlBehavior == null) { return Result.ofFail(-1, "controlBehavior can't be null"); } if (!Arrays.asList(CONTROL_BEHAVIOR_DEFAULT, CONTROL_BEHAVIOR_RATE_LIMITER).contains(controlBehavior)) { return Result.ofFail(-1, "invalid controlBehavior: " + controlBehavior); } entity.setControlBehavior(controlBehavior); if (CONTROL_BEHAVIOR_DEFAULT == controlBehavior) { // 0-快速失败, 则Burst size必填 Integer burst = reqVo.getBurst(); if (burst == null) { return Result.ofFail(-1, "burst can't be null"); } if (burst < 0) { return Result.ofFail(-1, "invalid burst: " + burst); } entity.setBurst(burst); } else if (CONTROL_BEHAVIOR_RATE_LIMITER == controlBehavior) { // 1-匀速排队, 则超时时间必填 Integer maxQueueingTimeoutMs = reqVo.getMaxQueueingTimeoutMs(); if (maxQueueingTimeoutMs == null) { return Result.ofFail(-1, "maxQueueingTimeoutMs can't be null"); } if (maxQueueingTimeoutMs < 0) { return Result.ofFail(-1, "invalid maxQueueingTimeoutMs: " + maxQueueingTimeoutMs); } entity.setMaxQueueingTimeoutMs(maxQueueingTimeoutMs); } Date date = new Date(); entity.setGmtCreate(date); entity.setGmtModified(date); try { entity = repository.save(entity); publishRules(entity.getApp()); } catch (Throwable throwable) { logger.error("add gateway flow rule error:", throwable); return Result.ofThrowable(-1, throwable); } // if (!publishRules(app, ip, port)) { // logger.warn("publish gateway flow rules fail after add"); // } return Result.ofSuccess(entity); } @PostMapping("/save.json") @AuthAction(AuthService.PrivilegeType.WRITE_RULE) public Result<GatewayFlowRuleEntity> updateFlowRule(@RequestBody UpdateFlowRuleReqVo reqVo) { String app = reqVo.getApp(); if (StringUtil.isBlank(app)) { return Result.ofFail(-1, "app can't be null or empty"); } Long id = reqVo.getId(); if (id == null) { return Result.ofFail(-1, "id can't be null"); } GatewayFlowRuleEntity entity = repository.findById(id); if (entity == null) { return Result.ofFail(-1, "gateway flow rule does not exist, id=" + id); } // 针对请求属性 GatewayParamFlowItemVo paramItem = reqVo.getParamItem(); if (paramItem != null) { GatewayParamFlowItemEntity itemEntity = new GatewayParamFlowItemEntity(); entity.setParamItem(itemEntity); // 参数属性 0-ClientIP 1-Remote Host 2-Header 3-URL参数 4-Cookie Integer parseStrategy = paramItem.getParseStrategy(); if (!Arrays.asList(PARAM_PARSE_STRATEGY_CLIENT_IP, PARAM_PARSE_STRATEGY_HOST, PARAM_PARSE_STRATEGY_HEADER , PARAM_PARSE_STRATEGY_URL_PARAM, PARAM_PARSE_STRATEGY_COOKIE).contains(parseStrategy)) { return Result.ofFail(-1, "invalid parseStrategy: " + parseStrategy); } itemEntity.setParseStrategy(paramItem.getParseStrategy()); // 当参数属性为2-Header 3-URL参数 4-Cookie时,参数名称必填 if (Arrays.asList(PARAM_PARSE_STRATEGY_HEADER, PARAM_PARSE_STRATEGY_URL_PARAM, PARAM_PARSE_STRATEGY_COOKIE).contains(parseStrategy)) { // 参数名称 String fieldName = paramItem.getFieldName(); if (StringUtil.isBlank(fieldName)) { return Result.ofFail(-1, "fieldName can't be null or empty"); } itemEntity.setFieldName(paramItem.getFieldName()); } String pattern = paramItem.getPattern(); // 如果匹配串不为空,验证匹配模式 if (StringUtil.isNotEmpty(pattern)) { itemEntity.setPattern(pattern); Integer matchStrategy = paramItem.getMatchStrategy(); if (!Arrays.asList(PARAM_MATCH_STRATEGY_EXACT, PARAM_MATCH_STRATEGY_CONTAINS, PARAM_MATCH_STRATEGY_REGEX).contains(matchStrategy)) { return Result.ofFail(-1, "invalid matchStrategy: " + matchStrategy); } itemEntity.setMatchStrategy(matchStrategy); } } else { entity.setParamItem(null); } // 阈值类型 0-线程数 1-QPS Integer grade = reqVo.getGrade(); if (grade == null) { return Result.ofFail(-1, "grade can't be null"); } if (!Arrays.asList(FLOW_GRADE_THREAD, FLOW_GRADE_QPS).contains(grade)) { return Result.ofFail(-1, "invalid grade: " + grade); } entity.setGrade(grade); // QPS阈值 Double count = reqVo.getCount(); if (count == null) { return Result.ofFail(-1, "count can't be null"); } if (count < 0) { return Result.ofFail(-1, "count should be at lease zero"); } entity.setCount(count); // 间隔 Long interval = reqVo.getInterval(); if (interval == null) { return Result.ofFail(-1, "interval can't be null"); } if (interval <= 0) { return Result.ofFail(-1, "interval should be greater than zero"); } entity.setInterval(interval); // 间隔单位 Integer intervalUnit = reqVo.getIntervalUnit(); if (intervalUnit == null) { return Result.ofFail(-1, "intervalUnit can't be null"); } if (!Arrays.asList(INTERVAL_UNIT_SECOND, INTERVAL_UNIT_MINUTE, INTERVAL_UNIT_HOUR, INTERVAL_UNIT_DAY).contains(intervalUnit)) { return Result.ofFail(-1, "Invalid intervalUnit: " + intervalUnit); } entity.setIntervalUnit(intervalUnit); // 流控方式 0-快速失败 2-匀速排队 Integer controlBehavior = reqVo.getControlBehavior(); if (controlBehavior == null) { return Result.ofFail(-1, "controlBehavior can't be null"); } if (!Arrays.asList(CONTROL_BEHAVIOR_DEFAULT, CONTROL_BEHAVIOR_RATE_LIMITER).contains(controlBehavior)) { return Result.ofFail(-1, "invalid controlBehavior: " + controlBehavior); } entity.setControlBehavior(controlBehavior); if (CONTROL_BEHAVIOR_DEFAULT == controlBehavior) { // 0-快速失败, 则Burst size必填 Integer burst = reqVo.getBurst(); if (burst == null) { return Result.ofFail(-1, "burst can't be null"); } if (burst < 0) { return Result.ofFail(-1, "invalid burst: " + burst); } entity.setBurst(burst); } else if (CONTROL_BEHAVIOR_RATE_LIMITER == controlBehavior) { // 2-匀速排队, 则超时时间必填 Integer maxQueueingTimeoutMs = reqVo.getMaxQueueingTimeoutMs(); if (maxQueueingTimeoutMs == null) { return Result.ofFail(-1, "maxQueueingTimeoutMs can't be null"); } if (maxQueueingTimeoutMs < 0) { return Result.ofFail(-1, "invalid maxQueueingTimeoutMs: " + maxQueueingTimeoutMs); } entity.setMaxQueueingTimeoutMs(maxQueueingTimeoutMs); } Date date = new Date(); entity.setGmtModified(date); try { entity = repository.save(entity); publishRules(entity.getApp()); } catch (Throwable throwable) { logger.error("update gateway flow rule error:", throwable); return Result.ofThrowable(-1, throwable); } // if (!publishRules(app, entity.getIp(), entity.getPort())) { // logger.warn("publish gateway flow rules fail after update"); // } return Result.ofSuccess(entity); } @PostMapping("/delete.json") @AuthAction(AuthService.PrivilegeType.DELETE_RULE) public Result<Long> deleteFlowRule(Long id) { if (id == null) { return Result.ofFail(-1, "id can't be null"); } GatewayFlowRuleEntity oldEntity = repository.findById(id); if (oldEntity == null) { return Result.ofSuccess(null); } try { repository.delete(id); publishRules(oldEntity.getApp()); } catch (Throwable throwable) { logger.error("delete gateway flow rule error:", throwable); return Result.ofThrowable(-1, throwable); } // if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) { // logger.warn("publish gateway flow rules fail after delete"); // } return Result.ofSuccess(id); } // private boolean publishRules(String app, String ip, Integer port) { // List<GatewayFlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port)); // return sentinelApiClient.modifyGatewayFlowRules(app, ip, port, rules); // } private void publishRules(/*@NonNull*/ String app) throws Exception { List<GatewayFlowRuleEntity> rules = repository.findAllByApp(app); rulePublisher.publish(app, rules); } }
十一
启动程序 编辑
然后添加流控规则,查询规则都从nacos获取
编辑
至此就没问题了