sentinel-1.8.7与nacos-2.3.0实现动态规则配置、双向同步

😊 @ 作者: 一恍过去
💖 @ 主页: https://blog.csdn.net/zhuocailing3390
🎊 @ 社区: Java技术栈交流
🎉 @ 主题: sentinel-1.8.7与nacos-2.3.0实现动态规则配置、双向同步
⏱️ @ 创作时间: 2024年04月2日

目录

  • 1、为什么整合Nacos
  • 2、源码拉取
  • 3、创建公共配置
  • 4、控制台规则配置
    • 4.1、流控规则
    • 4.2、熔断降级规则
    • 4.3、热点规则
    • 4.4、系统规则
    • 4.5、授权规则
  • 5、网关控制台规则配置
    • 5.1、API管理
    • 5.2、流程规则
    • 5.3、降级规则
    • 5.4、系统规则
  • 6、效果测试
  • 7、整合Cloud使用
  • 8、打包部署
  • 9、源码包下载

1、为什么整合Nacos

默认情况下Sentinel配置的规则是储存的内存中,在重新Sentinel服务后,配置会显示,我们通过整合第三方中间件实现,配置的持久化,比如使用Nacos

我们要实现SentinelNacos的双向同步持久化,就需要对sentinel-dashboard的源码包进行修改。

2、源码拉取

1、下载源码压缩包
在Sentinel-github下载需要版本的压缩包,比如Sentinel-1.8.7.zip,或者直接从Git上将代码Clone

2、加载源码
将下载好的Sentinel-1.8.7.zip解压,使用IDE工具,打开sentinel-dashboard工程,或者直接从Git上将代码Clone
在这里插入图片描述

3、创建公共配置

在进行规则代码修改之前需要创建Nacos配置文件,在com.alibaba.csp.sentinel.dashboard.rule包下创建nacos包,并且在包下创建四个类:RuleNacosConfigRuleNacosProviderRuleNacosPublisherNacosConfigUtil
在这里插入图片描述

RuleNacosConfig:

package com.alibaba.csp.sentinel.dashboard.rule.nacos;

import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigFactory;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Properties;


@Configuration
public class NacosConfig {

    @Bean
    public ConfigService nacosConfigService() throws Exception {
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.SERVER_ADDR, "localhost:8848");
        // properties.put(PropertyKeyConst.NAMESPACE, "xxx");
        properties.put(PropertyKeyConst.USERNAME, "nacos");
        properties.put(PropertyKeyConst.PASSWORD, "nacos");
        return ConfigFactory.createConfigService(properties);
    }
}

RuleNacosProvider:

package com.alibaba.csp.sentinel.dashboard.rule.nacos;

import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class RuleNacosProvider {

    @Autowired
    private ConfigService configService;

    public String getRules(String dataId) throws Exception {

        // 将服务名称设置为GroupId
        return configService.getConfig(dataId, NacosConfigUtil.GROUP_ID, 3000);
    }
}

RuleNacosPublisher:

package com.alibaba.csp.sentinel.dashboard.rule.nacos;

import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class RuleNacosPublisher {

    @Autowired
    private ConfigService configService;

    public void publish(String dataId, String rules) {
        try {
            if (rules == null) {
                return;
            }
            configService.publishConfig(dataId, NacosConfigUtil.GROUP_ID, rules);
        } catch (NacosException e) {
            throw new RuntimeException(e);
        }
    }
}

NacosConfigUtil:

package com.alibaba.csp.sentinel.dashboard.rule.nacos;

/**
 * @author Eric Zhao
 * @since 1.4.0
 */
public final class NacosConfigUtil {

    public static final String GROUP_ID = "SENTINEL_GROUP";

    public static final String FLOW_DATA_ID_POSTFIX = "-flow-rules";

    public static final String GATEWAY_FLOW_DATA_ID_POSTFIX = "-gateway-rules";

    public static final String AUTHORITY_FLOW_DATA_ID_POSTFIX = "-authority-rules";

    public static final String SYSTEM_FLOW_DATA_ID_POSTFIX = "-system-rules";

    public static final String DEGRADE_FLOW_DATA_ID_POSTFIX = "-degrade-rules";

    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() {
    }
}

4、控制台规则配置

通过修改源码,实现流控规则、降级规则、热点规则、系统规则、授权规则的持久化操作;

4.1、流控规则

修改FlowControllerV1:
RuleNacosPublisherRuleNacosProvider注入到FlowControllerV1

// 加入以下代码:
@Autowired
private RuleNacosProvider ruleProvider;
@Autowired
private RuleNacosPublisher rulePublisher;

修改读取逻辑:

// 修改位置如下:
List<FlowRuleEntity> rules = sentinelApiClient.fetchFlowRuleOfMachine(app, ip, port);

// 将上面代码修改为以下代码:
String ruleStr = ruleProvider.getRules(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX);
List<FlowRuleEntity> rules = new ArrayList<>();
if (ruleStr != null) {
     rules = JSON.parseArray(ruleStr, FlowRuleEntity.class);
     if (rules != null && !rules.isEmpty()) {
         for (FlowRuleEntity entity : rules) {
              entity.setApp(app);
         }
    }
}

修改推送逻辑:

// 1、修改位置如下:
private CompletableFuture<Void> publishRules(String app, String ip, Integer port) {
     List<FlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
     return sentinelApiClient.setFlowRuleOfMachineAsync(app, ip, port, rules);
}

// 将上面代码修改为以下代码:
private void publishRules(String app) {
   List<FlowRuleEntity> rules = repository.findAllByApp(app);
   String ruleStr = JSON.toJSONString(rules);
   rulePublisher.publish(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX, ruleStr);
}
=======================================================================================

// 2、修改位置如下:有两处
publishRules(entity.getApp(), entity.getIp(), entity.getPort()).get(5000, TimeUnit.MILLISECONDS);

// 将上面代码修改为以下代码:
publishRules(entity.getApp());
=======================================================================================

// 3、修改位置如下:
publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort()).get(5000, TimeUnit.MILLISECONDS);

// 将上面代码修改为以下代码:
publishRules(oldEntity.getApp());

4.2、熔断降级规则

修改DegradeController:
RuleNacosProviderRuleNacosPublisher注入到DegradeController

// 加入以下代码:
@Autowired
private RuleNacosProvider ruleProvider;
@Autowired
private RuleNacosPublisher rulePublisher;

修改读取逻辑:

// 修改位置如下:
List<DegradeRuleEntity> rules = sentinelApiClient.fetchDegradeRuleOfMachine(app, ip, port);

// 将上面代码修改为以下代码:
String ruleStr = ruleProvider.getRules(app + NacosConfigUtil.DEGRADE_FLOW_DATA_ID_POSTFIX);
List<DegradeRuleEntity> rules = new ArrayList<>();
if (ruleStr != null) {
    rules = JSON.parseArray(ruleStr, DegradeRuleEntity.class);
    if (rules != null && !rules.isEmpty()) {
        for (DegradeRuleEntity entity : rules) {
            entity.setApp(app);
       }
    }
}
rules = repository.saveAll(rules);
return Result.ofSuccess(rules);

修改推送逻辑:

// 1、修改位置如下:
private boolean publishRules(String app, String ip, Integer port) {
   List<DegradeRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
   return sentinelApiClient.setDegradeRuleOfMachine(app, ip, port, rules);
}

// 将上面代码修改为以下代码:
private boolean publishRules(String app) {
   List<DegradeRuleEntity> rules = repository.findAllByApp(app);
   String ruleStr = JSON.toJSONString(rules);
   rulePublisher.publish(app + NacosConfigUtil.DEGRADE_FLOW_DATA_ID_POSTFIX, ruleStr);
   return true;
}
=======================================================================================

// 2、修改位置如下:有两处
if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
     logger.warn("Publish degrade rules failed, app={}", entity.getApp());
}

// 将上面代码修改为以下代码:
if (!publishRules(entity.getApp())){
     logger.warn("Publish degrade rules failed, app={}", entity.getApp());
}
=======================================================================================

// 3、修改位置如下:
if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) {
   logger.warn("Publish degrade rules failed, app={}", oldEntity.getApp());
}

// 将上面代码修改为以下代码:
if (!publishRules(oldEntity.getApp())){
     logger.warn("Publish degrade rules failed, app={}", entity.getApp());
}

4.3、热点规则

修改ParamFlowRuleController:
RuleNacosProviderRuleNacosPublisher注入到ParamFlowRuleController

// 加入以下代码:
@Autowired
private RuleNacosProvider ruleProvider;
@Autowired
private RuleNacosPublisher rulePublisher;

修改读取逻辑:

// 修改位置如下:
return sentinelApiClient.fetchParamFlowRulesOfMachine(app, ip, port)
                .thenApply(repository::saveAll)
                .thenApply(Result::ofSuccess)
                .get();

// 将上面代码修改为以下代码:
String ruleStr = ruleProvider.getRules(app + NacosConfigUtil.PARAM_FLOW_DATA_ID_POSTFIX);
List<ParamFlowRuleEntity> rules = new ArrayList<>();
if (ruleStr != null) {
    rules = JSON.parseArray(ruleStr, ParamFlowRuleEntity.class);
    if (rules != null && !rules.isEmpty()) {
        for (ParamFlowRuleEntity entity : rules) {
           entity.setApp(app);
   		}
    }
}
rules = repository.saveAll(rules);
return Result.ofSuccess(rules);

修改推送逻辑:

// 1、修改位置如下:
private CompletableFuture<Void> publishRules(String app, String ip, Integer port) {
    List<ParamFlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
    return sentinelApiClient.setParamFlowRuleOfMachine(app, ip, port, rules);
}

// 将上面代码修改为以下代码:
private void publishRules(String app) {
   try {
       List<ParamFlowRuleEntity> rules = repository.findAllByApp(app);
       String ruleStr = JSON.toJSONString(rules);
       rulePublisher.publish(app + NacosConfigUtil.PARAM_FLOW_DATA_ID_POSTFIX, ruleStr);
   } catch (Exception e) {
     e.printStackTrace();
   }
}
=======================================================================================

// 2、修改位置如下:有两处
try {
   entity = repository.save(entity);
   publishRules(entity.getApp(), entity.getIp(), entity.getPort()).get();
   return Result.ofSuccess(entity);
} catch (ExecutionException ex) {
	....
}
// 将上面代码修改为以下代码:
try {
   entity = repository.save(entity);
   publishRules(entity.getApp());
   return Result.ofSuccess(entity);
} catch (Exception ex) {
	....
}
=======================================================================================

// 3、修改位置如下:
try {
 	repository.delete(id);
    publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort()).get();
    return Result.ofSuccess(id);
} catch (ExecutionException ex) {
	....
}

// 将上面代码修改为以下代码:
try {
 	repository.delete(id);
    publishRules(oldEntity.getApp());
    return Result.ofSuccess(id);
} catch (Exception ex) {
	....
}

4.4、系统规则

修改SystemController:
RuleNacosProviderRuleNacosPublisher注入到SystemController

// 加入以下代码:
@Autowired
private RuleNacosProvider ruleProvider;
@Autowired
private RuleNacosPublisher rulePublisher;

修改读取逻辑:

// 修改位置如下:
List<SystemRuleEntity> rules = sentinelApiClient.fetchSystemRuleOfMachine(app, ip, port);

// 将上面代码修改为以下代码:
String ruleStr = ruleProvider.getRules(app + NacosConfigUtil.SYSTEM_FLOW_DATA_ID_POSTFIX);
List<SystemRuleEntity> rules = new ArrayList<>();
if (ruleStr != null) {
    rules = JSON.parseArray(ruleStr, SystemRuleEntity.class);
    if (rules != null && !rules.isEmpty()) {
        for (SystemRuleEntity entity : rules) {
             entity.setApp(app);
        }
    }
}

修改推送逻辑:

// 1、修改位置如下:
private boolean publishRules(String app, String ip, Integer port) {
   List<SystemRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
   return sentinelApiClient.setSystemRuleOfMachine(app, ip, port, rules);
}

// 将上面代码修改为以下代码:
private boolean publishRules(String app) {
    List<SystemRuleEntity> rules = repository.findAllByApp(app);
    String ruleStr = JSON.toJSONString(rules);
    rulePublisher.publish(app + NacosConfigUtil.SYSTEM_FLOW_DATA_ID_POSTFIX, ruleStr);
    return true;
}
=======================================================================================

// 2、修改位置如下
if (!publishRules(app, ip, port)) {
    logger.warn("Publish system rules fail after rule add");
}

// 将上面代码修改为以下代码:
if (!publishRules(entity.getApp())) {
    logger.warn("Publish system rules fail after rule add");
}
=======================================================================================

// 3、修改位置如下
if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
    logger.info("publish system rules fail after rule update");
}

// 将上面代码修改为以下代码:
if (!publishRules(entity.getApp())) {
    logger.warn("Publish system rules fail after rule add");
}
=======================================================================================

// 4、修改位置如下:
if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) {
    logger.info("publish system rules fail after rule delete");
}

// 将上面代码修改为以下代码:
if (!publishRules(oldEntity.getApp())) {
    logger.info("publish system rules fail after rule delete");
}

4.5、授权规则

修改AuthorityRuleController:
RuleNacosPublisherRuleNacosProvider注入到AuthorityRuleController

// 加入以下代码:
@Autowired
private RuleNacosProvider ruleProvider;
@Autowired
private RuleNacosPublisher rulePublisher;

修改读取逻辑:

// 修改位置如下:
List<AuthorityRuleEntity> rules = sentinelApiClient.fetchAuthorityRulesOfMachine(app, ip, port);

// 将上面代码修改为以下代码:
String ruleStr = ruleProvider.getRules(app + NacosConfigUtil.SYSTEM_FLOW_DATA_ID_POSTFIX);
List<AuthorityRuleEntity> rules = new ArrayList<>();
if (ruleStr != null) {
     rules = JSON.parseArray(ruleStr, AuthorityRuleEntity.class);
     if (rules != null && !rules.isEmpty()) {
         for (AuthorityRuleEntity entity : rules) {
              entity.setApp(app);
         }
    }
}

修改推送逻辑:

// 1、修改位置如下:
private boolean publishRules(String app, String ip, Integer port) {
    List<AuthorityRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
    return sentinelApiClient.setAuthorityRuleOfMachine(app, ip, port, rules);
}

// 将上面代码修改为以下代码:
private boolean publishRules(String app) {
   List<AuthorityRuleEntity> rules = repository.findAllByApp(app);
   String ruleStr = JSON.toJSONString(rules);
   rulePublisher.publish(app + NacosConfigUtil.AUTHORITY_FLOW_DATA_ID_POSTFIX, ruleStr);
   return true;
}
=======================================================================================

// 2、修改位置如下:有两处
if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
    logger.info("Publish authority rules failed after rule update");
}

// 将上面代码修改为以下代码:
if (!publishRules(entity.getApp())) {
    logger.info("Publish authority rules failed after rule update");
}
=======================================================================================

// 3、修改位置如下:
if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) {
   logger.error("Publish authority rules failed after rule delete");
}

// 将上面代码修改为以下代码:
if (!publishRules(oldEntity.getApp())) {
   logger.error("Publish authority rules failed after rule delete");
}

5、网关控制台规则配置

配置网关控制台规则,在启动网关时需要加上参数:-Dcsp.sentinel.app.type=1

本次源码修改中暂时没有做处理,如果需要可以参照下面的代码示例。

5.1、API管理

修改GatewayApiController:
RuleNacosPublisherRuleNacosProvider注入到GatewayApiController

// 加入以下代码:
@Autowired
private RuleNacosProvider ruleProvider;
@Autowired
private RuleNacosPublisher rulePublisher;

修改读取逻辑:

// 修改位置如下:
List<ApiDefinitionEntity> apis = sentinelApiClient.fetchApis(app, ip, port).get();

// 将上面代码修改为以下代码:
String ruleStr = ruleProvider.getRules(app + NacosConfigUtil.GATEWAY_FLOW_DATA_ID_POSTFIX);
List<ApiDefinitionEntity> apis = new ArrayList<>();
if (ruleStr != null) {
    apis = JSON.parseArray(ruleStr, ApiDefinitionEntity.class);
    if (apis != null && !apis.isEmpty()) {
        for (ApiDefinitionEntity entity : apis) {
             entity.setApp(app);
        }
    }
}
  

修改推送逻辑:

// 1、修改位置如下:
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 boolean publishApi(String app) {

List<ApiDefinitionEntity> apis= repository.findAllByApp(app);
String ruleStr = JSON.toJSONString(apis);
rulePublisher.publish(app + NacosConfigUtil.GATEWAY_FLOW_DATA_ID_POSTFIX, ruleStr);
return true;
}
=======================================================================================

// 2、修改位置如下
if (!publishApis(app, ip, port)) {
     logger.warn("publish gateway apis fail after add");
}

// 将上面代码修改为以下代码:
if (!publishApis(entity.getApp())) {
     logger.warn("publish gateway apis fail after add");
}
=======================================================================================

// 3、修改位置如下
if (!publishApis(app, entity.getIp(), entity.getPort())) {
    logger.warn("publish gateway apis fail after update");
}

// 将上面代码修改为以下代码:
if (!publishApis(entity.getApp())
=======================================================================================

// 4、修改位置如下:
if (!publishApis(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) {
    logger.warn("publish gateway apis fail after delete");
}

// 将上面代码修改为以下代码:
if (!publishApis(oldEntity.getApp())) {
    logger.warn("publish gateway apis fail after delete");
}

5.2、流程规则

使用的是控制台规则配置中的流控规则接口,无需在做操作,参考《4.1、流控规则》。

5.3、降级规则

使用的是控制台规则配置中的降级规则接口,无需在做操作,参考《4.2、降级规则》。

5.4、系统规则

使用的是控制台规则配置中的系统规则接口,无需在做操作,参考《4.4、系统规则》。

6、效果测试

我们以流控规则为例,演示一个数据同步持久化的操作;

1、nacos同步到sentinel:

需要注意的是,nacos中的分组必须为SENTINEL_GROUP

在nacos中,新增配置文件,文件的DataId为user-service-flow-rules,内容为:

[
    {
    	"app":"user-service",// 服务名称
        "resource": "/list", //资源名称
        "count": 1, //阀值
        "grade": 1, //阀值类型,0表示线程数,1表示QPS;
        "limitApp": "default", //来源应用	
        "strategy": 0,// 流控模式,0表示直接,1表示关联,2表示链路;
        "controlBehavior": 0 //流控效果,0表示快速失败,1表示Warm Up,2表示排队等待
    }
]

在这里插入图片描述

查看Sentinel控制台:数据已经实现了同步
在这里插入图片描述

2、sentinel同步到nacos:

我们在sentinel控制台,建立任意流控规则,如下:
在这里插入图片描述

查看Nacos控制台:配置数据已经实现了同步
在这里插入图片描述

7、整合Cloud使用

整合cloud使用时,需要调整配置文件,以流控规则热点规则为例,其他的规则可以参考着进行配置,配置中的rule-typegroupIddataId需要写对(与nacos匹配)

spring:
  cloud:
    sentinel:
      transport:
        port: 9999 #跟控制台交流的端口,随意指定一个未使用的端口即可
        dashboard: 127.0.0.1:8080 # 指定控制台服务的地址
      #添加Nacos数据源配置
      datasource:
        #名字自定义即可,配置流控规则
        sentinel-flow:
          nacos:
            server-addr: 127.0.0.1:8848
            username: nacos
            password: nacos
            rule-type: flow
            groupId: SENTINEL_GROUP
            #namespace: public
            dataId: user-service-flow-rules
        #名字自定义即可,配置热点规则
        sentinel-param:
          nacos:
            server-addr: 127.0.0.1:8848
            username: nacos
            password: nacos
            rule-type: param-flow
            groupId: SENTINEL_GROUP
            #namespace: public
            dataId: user-service-param-rules

8、打包部署

进入到sentinel-dashboard所在目的,通过mvn clean install package -DskipTests=true进行打包。

部署jar参考:
《Linux搭建Sentinel 控制台环境》
《Docker搭建Sentinel 控制台环境》

9、源码包下载

对于上述修改的代码,源码下载地址:
https://gitee.com/lhzlx/sentinel-nacos.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/571922.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FL Studio21.2中文破解版下载2024最新五月破解步骤教程

FL Studio 21.2.3.4004中文版 中文别名水果编曲软件&#xff0c;是一款全能的音乐制作软件&#xff0c;包括编曲、录音、剪辑和混音等诸多功能&#xff0c;让你的电脑编程一个全能的录音室&#xff0c;它为您提供了一个集成的开发环境&#xff0c;使用起来非常简单有效&#xf…

MATLAB命令

MATLAB是一个用于数值计算和数据可视化的交互式程序。您可以通过在命令窗口的MATLAB提示符 ‘>>’ 处键入命令来输入命令。 在本节中&#xff0c;我们将提供常用的通用MATLAB命令列表。 用于管理会话的命令 MATLAB提供了用于管理会话的各种命令。下表提供了所有此类命令…

基于springboot+vue+Mysql的CSGO赛事管理系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

京东商品差评获取

1.背景 场景一&#xff1a;一个市场研究员或者是一个企业的产品经理&#xff0c;需要下载差评来了解消费者对于某一产品或者服务的不满&#xff0c;以便改进他们的产品或服务。 场景二&#xff1a;一个人是某个企业的竞争对手&#xff0c;需要下载差评来了解他们的竞争对手的…

java自动生成pojo,springboot自动生成pojo

第一步 pom引入依赖 <dependencies><!-- mybatis-generator --><dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId><version>1.3.7</version></dependency>&…

乒乓球廉价底板及套胶评测5

今天给同事贴一个银河t2底板&#xff0c;正手狂39度&#xff0c;反手拍里奥&#xff0c;银河t2是碳板&#xff0c;考虑到使用的长期性&#xff0c;没有灌油&#xff0c;用的无机胶水。 这套装备本身没有什么瑕疵&#xff0c;主要还是考虑正手狂三的通透性&#xff0c;我认为有…

QML 中的状态

Qt hello – 专注于Qt的技术分享平台 状态描述了当前用户界面样子&#xff0c;QML中一个状态定义了一组属性的改变&#xff0c;并且会在一定条件下被触发。 假设有这么一个场景&#xff0c;红黄绿三个灯&#xff0c;用一个按钮&#xff0c;点击后依次切换三个灯亮起。使用QWi…

【C++干货基地】深度理解C++中的高效内存管理方式 new delete

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引入 哈喽各位铁汁们好啊&#xff0c;我是博主鸽芷咕《C干货基地》是由我的襄阳家乡零食基地有感而发&#xff0c;不知道各位的…

星松云新品边缘计算路由器,上网收益两不误

随着互联网的普及和发展&#xff0c;人们对于网络带宽和稳定性的需求日益增加&#xff0c;而同时&#xff0c;对于网络使用的成本也变得越来越重要。在这样的背景下&#xff0c;星松云推出了全新的边缘计算路由器&#xff0c;为用户带来了一个既能享受高速网络&#xff0c;又能…

设计模式(六):原型模式

设计模式&#xff08;六&#xff09;&#xff1a;原型模式 1. 原型模式的介绍2. 原型模式的类图3. 原型模式的实现3.1 创建一个原型接口3.2 创建具体原型3.3 创建一个数据缓存类3.4 测试 1. 原型模式的介绍 原型模式&#xff08;Prototype Pattern&#xff09;属于创建型模式&…

2024 年 Rust 开发者路线图

Rust 近年来因其对性能、安全性和并发性的关注而广受欢迎。作为一名开发人员&#xff0c;掌握 Rust 可以为各种机会打开大门&#xff0c;包括 Web 开发。 在 github 上发现了这个优秀的路线图&#xff0c;由 Anshul Goyal 创建&#xff0c;它提供了一条全面的路径&#xff0c;概…

在RISC-V64架构的CV1811C开发板上应用perf工具进行多线程程序性能分析及火焰图调试

CV1811C环境编译 SDK目录结构 . ├── build // 编译目录,存放编译脚本以及各board差异化配置 ├── buildroot-2021.05 // buildroot开源工具 ├── freertos // freertos系统 ├── fsbl // fsbl启动固件,prebuilt形式存在…

【漏洞复现】通天星CMSV6车载监控平台Druid弱口令漏洞

漏洞描述: 通天星CMSV6车载定位监控平台拥有以位置服务、无线3G/4G视频传输、云存储服务为核心的研发团队,专注于为定位、无线视频终端产品提供平台服务,通天星CMSV6产品覆盖车载录像机、单兵录像机、网络监控摄像机、行驶记录仪等产品的视频综合平台。 通天星CMSV6车载视…

网络爬虫之HTTP原理

** URI和URL URI的全称Uniform Resource Identifier &#xff0c;即统一资源标志符。URL的全称Uniform Resource Locator 即统一资源定位符。 URL是URI的子集&#xff0c;也就是每一个URL就是URI&#xff0c;但是每一个URI不一定是URL&#xff0c;URI还有一个子类叫URN&#x…

AutoGPT-Forge使用教程,自行构建agent智能体

本博客给出AutoGPT-forge四个教程的翻译与理解&#xff0c;使用GPT4翻译&#xff0c; 参考官方教程https://aiedge.medium.com/autogpt-forge-a-comprehensive-guide-to-your-first-steps-a1dfdf46e3b4 使用AutoGPT Github代码日期2024/4/22&#xff1b; 博客开始编辑日期20…

计算机毕业设计springboot市场摊位管理系统【附源码】

基于JavaWeb开发的springboot市场摊位管理系统 &#x1f345; 作者主页 央顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承接各种定制系统 &#…

JS 添加数组元素( 4种方法 )

No.内容链接1Openlayers 【入门教程】 - 【源代码示例300】 2Leaflet 【入门教程】 - 【源代码图文示例 150】 3Cesium 【入门教程】 - 【源代码图文示例200】 4MapboxGL【入门教程】 - 【源代码图文示例150】 5前端就业宝典 【面试题详细答案 1000】 文章目录 一、四种…

HTTP/1.1,HTTP/2.0和HTTP/3.0 各版本协议的详解(2024-04-24)

1、HTTP介绍 HTTP 协议有多个版本&#xff0c;目前广泛使用的是 HTTP/1.1 和 HTTP/2&#xff0c;以及正在逐步推广的 HTTP/3。 HTTP/1.1&#xff1a;支持持久连接&#xff0c;允许多个请求/响应通过同一个 TCP 连接传输&#xff0c;减少了建立和关闭连接的消耗。 HTTP/2&#…

【leetcode面试经典150题】73. 从中序与后序遍历序列构造二叉树(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主&#xff0c;题解使用C语言。&#xff08;若有使用其他语言的同学也可了解题解思路&#xff0c;本质上语法内容一致&…

BUUCTF-MISC-09文件中的秘密1

9.文件中的秘密1 题目&#xff1a;flag包含在图片的属性中