设计模式实战 - 工厂模式实现总览页面工作进展指标查询

news/2025/2/19 17:08:00/

设计模式实战 - 工厂模式实现总览页面工作进展指标查询

1. 请求入口 ProgressController

@PostMapping("/progress/indicators")
@ApiOperation(value = "总览工作进展")
@PreAuthorize("hasAnyAuthority('superAdmin','overViewQuery','incidentQuery','alertQuery')")
@OperateLog(handle = { LoggerEnum.operation }, target = "operate.overview.log", action = "operate.overview.query.log")
public ProgressVo queryProgress(@RequestBody @NotNull @Valid ProgressQo progressQo) {return progressService.queryProgress(progressQo);
}

① 请求参数:

@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("总览工作进展查询")
public class ProgressQo {@ApiModelProperty("时间范围")@NotNullprivate TimeRange timeRange;@ApiModelProperty("需要查询的指标")@NotNullprivate List<@Enum(clazz = IndicatorEnum.class, method = "getIndicatorKey", message = "param indicatorKey illegal") String> indicatorKeyList;}

② 指标枚举类:

@AllArgsConstructor
public enum IndicatorEnum {/*** 事件处置率*/DEAL_INCIDENT_RATE("dealIncidentRate", "事件处置率"),DEAL_INCIDENT_CNT("dealIncidentCnt", "事件处置数"),DEAL_IP_CNT("ip", "遏制黑客IP"),DEAL_DNS_CNT("dns", "遏制恶意域名"),DEAL_FILE_CNT("file", "处置文件数"),/** 页面没接入 */DEAL_HOST_CNT("host", "主机处置数"),/** 页面没接入 */DEAL_PROCESS_CNT("process", "进程处置数"),AUTO_DEAL_ENTITY_CNT("autoDeal", "自动处置实体数"),/** 待上线 */DEAL_ORDER_CNT("order", "处置工单数"),EFFECTIVE_DURATION("effectiveDuration", "提效时长"),PROTECTED_RISK_ASSET("protectedRiskAsset", "防护风险资产"),SECURITY_EVALUATE("securityEvaluate", "安全建设评估"),/** 页面没接入 */DEAL_ALERT_CNT("dealAlertCnt", "告警处置数"),/** 页面没接入 */AUTO_DEAL_INCIDENT_CNT("autoDealIncidentCnt", "智能对抗事件自动处置数");/*** 指标的key*/@Getterprivate final String indicatorKey;/*** 指标的名称*/@Getterprivate final String indicatorName;public static IndicatorEnum buildByIndicatorKey(String indicatorKey) {for (IndicatorEnum indicatorEnum : IndicatorEnum.values()) {if (indicatorEnum.getIndicatorKey().equals(indicatorKey)) {return indicatorEnum;}}return null;}
}
{"indicatorKeyList": ["dealIncidentRate","dealIncidentCnt","securityEvaluate","protectedRiskAsset","ip","dns","file","order","effectiveDuration"],"timeRange": {"begin": {"type": "relative","unit": "D","value": 30},"end": null,"timeField": "lastTime"}
}

③ 响应参数:

@ApiModel(description = "总览指标")
@Data
public class ProgressVo implements Serializable {@ApiModelProperty("用户累计处理数")private Long customerSummary;@ApiModelProperty("平台累计处理数")private Long platformSummary;@ApiModelProperty("平台运维时间,单位是天")private Long guardDays;private List<IndicatorRes<?>> indicators;
}
@ApiModel(description = "总览指标")
@Data
public class IndicatorRes<T> {@ApiModelProperty("指标的key")private String indicatorsKey;@ApiModelProperty("指标的名称")private String indicatorsName;@ApiModelProperty("指标的值,可能是浮点型,可能是整型")private T indicatorsValue;@ApiModelProperty("指标的单位,天、个、次等")private String unit;
}
{"strCode": null,"message": "成功","data": {"customerSummary": 12987,"platformSummary": 857,"guardDays": 218,"indicators": [{"indicatorsKey": "dealIncidentCnt","indicatorsName": "事件处置数","indicatorsValue": 11968,"unit": "个"},{"indicatorsKey": "dealIncidentRate","indicatorsName": "事件处置率","indicatorsValue": 19.05,"unit": "%"},{"indicatorsKey": "dns","indicatorsName": "遏制恶意域名","indicatorsValue": 370,"unit": "个"},{"indicatorsKey": "effectiveDuration","indicatorsName": "提效时长","indicatorsValue": 0.0,"unit": "h"},{"indicatorsKey": "file","indicatorsName": "处置文件数","indicatorsValue": 1,"unit": "个"},{"indicatorsKey": "ip","indicatorsName": "遏制黑客IP","indicatorsValue": 57,"unit": "个"},{"indicatorsKey": "order","indicatorsName": "处置工单数","indicatorsValue": null,"unit": "待上线"},{"indicatorsKey": "protectedRiskAsset","indicatorsName": "防护风险资产","indicatorsValue": 925,"unit": "个"},{"indicatorsKey": "securityEvaluate","indicatorsName": "安全建设评估","indicatorsValue": "优","unit": null}]},"code": 0
}

2. 请求业务 ProgressServiceImpl

@Override
public ProgressVo queryProgress(ProgressQo progressQo) {log.info("查询工作进展指标开始, progressQo = {}", progressQo);StopWatch stopWatch = new StopWatch();TimeRange timeRange = progressQo.getTimeRange();List<String> indicatorKeyList = progressQo.getIndicatorKeyList();long startTimestamp = timeRange.getBeginDate().getTime() / 1000L;long endTimestamp = timeRange.getEndDate().getTime() / 1000L;Integer tenantId = Objects.requireNonNull(TenantInfoContext.getTenantInfo()).getProjectId();ProgressVo progressVo = doQueryRedisCache(tenantId, startTimestamp, endTimestamp, indicatorKeyList);if (progressVo != null) {log.info("命中缓存, tenantId = {}, startTimestamp = {}, endTimestamp = {}", tenantId, startTimestamp, endTimestamp);return progressVo;}// 获取处理指标的服务List<IndicatorCount<?>> progressServiceList = new ArrayList<>();if (!CollectionUtils.isEmpty(indicatorKeyList)) {for (String indicatorKey : indicatorKeyList) {progressServiceList.add(indicatorCountServiceFactory.getBeanOfIndicatorKey(indicatorKey));}}List<SaasThreadContextDataHolder> saasThreadContextDataHolders = SaasThreadContextUtil.save();List<Future<IndicatorRes<?>>> indicatorFutureList = new ArrayList<>();for (IndicatorCount<?> indicatorCountService : progressServiceList) {Future<IndicatorRes<?>> future = THREAD_POOL_EXECUTOR.submit(() -> {try {SaasThreadContextUtil.load(saasThreadContextDataHolders);return indicatorCountService.countIndicator(startTimestamp, endTimestamp);} finally {SaasThreadContextUtil.remove();}});indicatorFutureList.add(future);}progressVo = new ProgressVo();// 计算配置的指标List<IndicatorRes<?>> indicatorResList = new ArrayList<>();stopWatch.start("配置化指标统计");for (Future<IndicatorRes<?>> indicatorResFuture : indicatorFutureList) {try {IndicatorRes<?> indicatorRes = indicatorResFuture.get();indicatorResList.add(indicatorRes);} catch (InterruptedException | ExecutionException e) {log.error("查询工作进展指标出错", e);}}progressVo.setIndicators(indicatorResList);stopWatch.stop();log.info("工作进展配置化指标统计结束,耗时:{}", stopWatch.getTotalTimeMillis());stopWatch.start("其他指标统计");// 计算运维天数Future<ApiResponse<Long>> guardDaysFuture = countGuardDays();// 计算您累计处理风险数和平台累计处理风险数Future<Long> customerSummaryFuture = countRiskDeal(startTimestamp, endTimestamp, tenantId);Future<Long> platformSummaryFuture = countPlatformRiskDeal(startTimestamp, endTimestamp, tenantId);try {Long guardDays = guardDaysFuture.get().getData();progressVo.setGuardDays(guardDays);} catch (InterruptedException | ExecutionException e) {log.error("查询平台运维天数失败", e);}try {Long riskDealSum = customerSummaryFuture.get();progressVo.setCustomerSummary(riskDealSum);} catch (InterruptedException | ExecutionException e) {log.error("查询客户累计处理风险数失败", e);}try {Long platformSummary = platformSummaryFuture.get();progressVo.setPlatformSummary(platformSummary);} catch (InterruptedException | ExecutionException e) {log.error("查询平台累计处理风险数失败", e);}stopWatch.stop();if (!CollectionUtils.isEmpty(progressVo.getIndicators())) {String cacheKey = OverviewUtil.buildProgressCacheKey(tenantId, startTimestamp, endTimestamp, indicatorKeyList);redisTemplateConfig.setValueTimeout(cacheKey, progressVo, 300, TimeUnit.SECONDS);}log.info("指标统计全部结束,总耗时:{}", stopWatch.getTotalTimeMillis());return progressVo;
}

1. 查询缓存中数据

@Override
public ProgressVo queryProgress(ProgressQo progressQo) {log.info("查询工作进展指标开始, progressQo = {}", progressQo);StopWatch stopWatch = new StopWatch();// 需要查询的指标参数List<String> indicatorKeyList = progressQo.getIndicatorKeyList();// 查询时间范围参数TimeRange timeRange = progressQo.getTimeRange();long startTimestamp = timeRange.getBeginDate().getTime() / 1000L;long endTimestamp = timeRange.getEndDate().getTime() / 1000L;Integer tenantId = Objects.requireNonNull(TenantInfoContext.getTenantInfo()).getProjectId();// 从缓存中查询,如果缓存命中直接返回,否则查询数据库ProgressVo progressVo = doQueryRedisCache(tenantId, startTimestamp, endTimestamp, indicatorKeyList);if (progressVo != null) {log.info("命中缓存, tenantId = {}, startTimestamp = {}, endTimestamp = {}", tenantId, startTimestamp, endTimestamp);return progressVo;}// ......
}
private ProgressVo doQueryRedisCache(Integer tenantId, long startTimestamp, long endTimestamp, List<String> indicatorKeyList) {// 构建工作进展整体结果指标缓存的keyString cacheKey = OverviewUtil.buildProgressCacheKey(tenantId, startTimestamp, endTimestamp, indicatorKeyList);// 构建缓存处置实体数量的keyString entityCacheKey = OverviewUtil.buildEntityCacheKey(tenantId, startTimestamp, endTimestamp);boolean refreshCache = fetchRefreshCacheByHeader();if (refreshCache) {log.info("请求强制失效缓存, tenantId = {}, startTimestamp = {}, endTimestamp = {}", tenantId, startTimestamp, endTimestamp);redisTemplateConfig.delete(cacheKey);redisTemplateConfig.delete(entityCacheKey);return null;}return (ProgressVo) redisTemplateConfig.getValue(cacheKey);
}

① 构建工作进展整体结果指标缓存的key

/*** 构建工作进展整体结果指标缓存的key** @param tenantId         租户id* @param startTimestamp   开始时间* @param endTimestamp     结束时间* @param indicatorKeyList 待查询得指标* @return redisKey*/
public static String buildProgressCacheKey(Integer tenantId, long startTimestamp, long endTimestamp, List<String> indicatorKeyList) {String indicatorKeys = "";Collections.sort(indicatorKeyList);for (String s : indicatorKeyList) {indicatorKeys = indicatorKeys.concat(":" + s);}return "progress:indicator" + tenantId + ":" + startTimestamp + ":" + endTimestamp + indicatorKeys;
}

② 构建缓存处置实体数量的key

/*** 构建缓存处置实体数量的key** @param tenantId       租户id* @param startTimestamp 开始时间* @param endTimestamp   结束时间* @return redisKey*/
public static String buildEntityCacheKey(Integer tenantId, long startTimestamp, long endTimestamp) {return "progress:entityCnt:" + tenantId + ":" + startTimestamp + ":" + endTimestamp;
}

③ 从HTTP请求头中获取一个名为"refreshCache"的标志位,以指示是否需要刷新缓存。

private boolean fetchRefreshCacheByHeader() {RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();if (requestAttributes == null) {return false;}HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();boolean refreshCache = false;try {String refreshCacheStringValue = request.getHeader("refreshCache");if (refreshCacheStringValue == null) {return false;}return Boolean.parseBoolean(refreshCacheStringValue);} catch (Exception e) {log.info("fetchRefreshCacheByHeader failed", e);}return refreshCache;
}

2. 缓存失效查询数据库

1. 工厂模式计算工作指标

1. 工作进展指标计算服务接口
/*** 总览工作进展指标计算服务*/
public interface IndicatorCount<T> {/*** 是否支持统计指定的indicator指标** @param indicator 指标key* @return bool*/boolean accept(String indicator);/*** 根据时间范围计算指标** @param startTimestamp 开始时间* @param endTimestamp   结束时间* @return 指标*/IndicatorRes<T> countIndicator(Long startTimestamp, Long endTimestamp);
}
@ApiModel(description = "总览指标")
@Data
public class IndicatorRes<T> {@ApiModelProperty("指标的key")private String indicatorsKey;@ApiModelProperty("指标的名称")private String indicatorsName;// 使用了泛型T来表示indicatorsValue属性的类型@ApiModelProperty("指标的值,可能是浮点型,可能是整型")private T indicatorsValue;@ApiModelProperty("指标的单位,天、个、次等")private String unit;
}

① 计算工作进展指标告警处置数

/*** 告警处置数* 计算方法:处置完成+处置中*/
@Service("alertDealCntService")
@CustomLog
public class AlertDealCntService implements IndicatorCount<Long> {@Setter(onMethod_ = { @Autowired })AlertDao alertDao;@Overridepublic boolean accept(String indicator) {if (indicator == null) {return false;}return indicator.equalsIgnoreCase(IndicatorEnum.DEAL_ALERT_CNT.getIndicatorKey());}@Overridepublic IndicatorRes<Long> countIndicator(Long startTimestamp, Long endTimestamp) {log.info("计算告警处置数");Long cnt = null;try {cnt = alertDao.countDealAlert(startTimestamp, endTimestamp);} catch (IOException e) {log.error("统计告警处置数失败", e);}IndicatorRes<Long> indicatorRes = new IndicatorRes<>();indicatorRes.setIndicatorsKey(IndicatorEnum.DEAL_ALERT_CNT.getIndicatorKey());indicatorRes.setIndicatorsName(IndicatorEnum.DEAL_ALERT_CNT.getIndicatorName());indicatorRes.setIndicatorsValue(cnt);indicatorRes.setUnit("个");log.info("告警处置数: {}", cnt);return indicatorRes;}
}
/*** 已处置告警统计** @param startTimestamp 开始时间* @param endTimestamp   结束时间* @throws IOException 查询异常* @return count*/
@Override
public Long countDealAlert(Long startTimestamp, Long endTimestamp) throws IOException {BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();// 处置状态=已处置+处置中boolQueryBuilder.must(QueryBuilders.termsQuery("dealStatus", List.of(DealStatusEnum.DISPOSED.getStatusCode(), DealStatusEnum.DISPOSING.getStatusCode())));// 时间范围RangeQueryBuilder timeRangeQueryBuilder = QueryBuilders.rangeQuery("lastTime");timeRangeQueryBuilder.gte(timeStampToDate(startTimestamp * 1000L));timeRangeQueryBuilder.lte(timeStampToDate(endTimestamp * 1000L));boolQueryBuilder.must(timeRangeQueryBuilder);CountRequest countRequest = new CountRequest(SaasEsFactory.getTenantIndex(DatabaseConstants.ALERT));countRequest.query(boolQueryBuilder);log.info("count alerts, es search dsl: {}", boolQueryBuilder);StopWatch stopWatch = new StopWatch();stopWatch.start();CountResponse countResponse = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);log.info("告警统计结束,花费时间: {}", stopWatch.getTotalTimeMillis());return countResponse.getCount();
}

② 计算工作进展指标事件处置数

/*** 事件处置数* 计算方法:已忽略+已遏制+处置成功+处置中*/
@Service("incidentDealCntService")
@CustomLog
public class IncidentDealCntService implements IndicatorCount<Long> {@Setter(onMethod_ = { @Autowired })IIncidentDao incidentDao;@Overridepublic boolean accept(String indicator) {if (indicator == null) {return false;}return indicator.equalsIgnoreCase(IndicatorEnum.DEAL_INCIDENT_CNT.getIndicatorKey());}@Overridepublic IndicatorRes<Long> countIndicator(Long startTimestamp, Long endTimestamp) {log.info("计算事件处置数");Long cnt = incidentDao.countDealIncident(startTimestamp, endTimestamp);IndicatorRes<Long> indicatorRes = new IndicatorRes<>();indicatorRes.setIndicatorsKey(IndicatorEnum.DEAL_INCIDENT_CNT.getIndicatorKey());indicatorRes.setIndicatorsName(IndicatorEnum.DEAL_INCIDENT_CNT.getIndicatorName());indicatorRes.setIndicatorsValue(cnt);indicatorRes.setUnit("个");return indicatorRes;}
}
@Override
public Long countDealIncident(Long startTime, Long endTime) {Criteria criteria = Criteria.where("endTime").gte(startTime).lte(endTime).and("xthConfirm").is(true).and("dealStatus").in(List.of(IncidentDealStatusEnum.SUPPRESS.getStatusCode(),IncidentDealStatusEnum.DISPOSED.getStatusCode(), IncidentDealStatusEnum.IGNORED.getStatusCode(), IncidentDealStatusEnum.DISPOSING.getStatusCode()));Query query = new Query(criteria);return incidentMongoTemplate.count(query, Incident.class);
}
2. 工作进展指标计算服务工厂类
/*** 指标统计服务工厂类*/
@Component(value = "indicatorCountServiceFactory")
@CustomLog
public class IndicatorCountServiceFactory {@Setter(onMethod_ = @Autowired)private List<IndicatorCount<?>> indicatorCountList;public IndicatorCount<?> getBeanOfIndicatorKey(String indicatorKey) {for (IndicatorCount<?> indicatorCountService : indicatorCountList) {if (indicatorCountService.accept(indicatorKey)) {return indicatorCountService;}}log.warn("没找到统计当前指标的服务,indicatorKey = {}", indicatorKey);return null;}
}
3. 获取所有处理指标的服务
List<IndicatorCount<?>> progressServiceList = new ArrayList<>();
if (!CollectionUtils.isEmpty(indicatorKeyList)) {for (String indicatorKey : indicatorKeyList) {progressServiceList.add(indicatorCountServiceFactory.getBeanOfIndicatorKey(indicatorKey));}
}
4. 多线程执行工作进展指标计算
progressVo = new ProgressVo();// 计算配置的指标
List<IndicatorRes<?>> indicatorResList = new ArrayList<>();
stopWatch.start("配置化指标统计");
for (Future<IndicatorRes<?>> indicatorResFuture : indicatorFutureList) {try {IndicatorRes<?> indicatorRes = indicatorResFuture.get();indicatorResList.add(indicatorRes);} catch (InterruptedException | ExecutionException e) {log.error("查询工作进展指标出错", e);}
}
progressVo.setIndicators(indicatorResList);

2. 计算运维天数

Future<ApiResponse<Long>> guardDaysFuture = countGuardDays();
private Future<ApiResponse<Long>> countGuardDays() {List<SaasThreadContextDataHolder> saasThreadContextDataHolders = SaasThreadContextUtil.save();// 计算运维天数return THREAD_POOL_EXECUTOR.submit(() -> {try {StopWatch stopWatch = new StopWatch();stopWatch.start();SaasThreadContextUtil.load(saasThreadContextDataHolders);ApiResponse<Long> res;try {res = reportFeignClient.getGuardDays();} catch (Exception e) {res = ApiResponse.newInstance(0L);log.info("查询运维天数失败", e);}stopWatch.stop();log.info("运维天数指标查询结束,耗时:{}", stopWatch.getTotalTimeMillis());return res;} finally {SaasThreadContextUtil.remove();}});
}try {Long guardDays = guardDaysFuture.get().getData();progressVo.setGuardDays(guardDays);
} catch (InterruptedException | ExecutionException e) {log.error("查询平台运维天数失败", e);
}

3. 计算您累计处理风险数

Future<Long> customerSummaryFuture = countRiskDeal(startTimestamp, endTimestamp, tenantId);
/*** 客户累计处理风险数** @param startTimestamp 开始时间* @param endTimestamp   结束时间* @param tenantId       租户id* @return res*/
private Future<Long> countRiskDeal(Long startTimestamp, Long endTimestamp, Integer tenantId) {List<SaasThreadContextDataHolder> saasThreadContextDataHolders = SaasThreadContextUtil.save();return THREAD_POOL_EXECUTOR.submit(() -> {try {StopWatch stopWatch = new StopWatch();stopWatch.start();SaasThreadContextUtil.load(saasThreadContextDataHolders);IndicatorRes<Long> incidentDealCnt = incidentDealCntService.countIndicator(startTimestamp, endTimestamp);IndicatorRes<Long> alertDealCnt = alertDealCntService.countIndicator(startTimestamp, endTimestamp);Long incidentDealCntLong = incidentDealCnt.getIndicatorsValue() == null ? 0L : incidentDealCnt.getIndicatorsValue();Long alertDealCntLong = alertDealCnt.getIndicatorsValue() == null ? 0L : alertDealCnt.getIndicatorsValue();long res = incidentDealCntLong + alertDealCntLong;List<EntityCntDto> entityCntDtoList = dealEntityCntService.queryEntityDealCnt(startTimestamp, endTimestamp, tenantId);if (CollectionUtils.isEmpty(entityCntDtoList)) {return res;}for (EntityCntDto entityCnt : entityCntDtoList) {switch (Objects.requireNonNull(IndicatorEnum.buildByIndicatorKey(entityCnt.getEntityType()))) {case DEAL_IP_CNT:case DEAL_DNS_CNT:case DEAL_FILE_CNT:case DEAL_HOST_CNT:case DEAL_PROCESS_CNT:res += entityCnt.getCount();break;default:break;}}stopWatch.stop();log.info("客户累计处理风险数统计结束,总耗时:{}", stopWatch.getTotalTimeMillis());return res;} finally {SaasThreadContextUtil.remove();}});
}try {Long riskDealSum = customerSummaryFuture.get();progressVo.setCustomerSummary(riskDealSum);
} catch (InterruptedException | ExecutionException e) {log.error("查询客户累计处理风险数失败", e);
}

4. 计算平台累计处理风险数

Future<Long> platformSummaryFuture = countPlatformRiskDeal(startTimestamp, endTimestamp, tenantId);
/*** 平台累计处理风险数** @param startTimestamp 开始时间* @param endTimestamp   结束时间* @param tenantId       租户id* @return res*/
private Future<Long> countPlatformRiskDeal(Long startTimestamp, Long endTimestamp, Integer tenantId) {List<SaasThreadContextDataHolder> saasThreadContextDataHolders = SaasThreadContextUtil.save();return THREAD_POOL_EXECUTOR.submit(() -> {try {StopWatch stopWatch = new StopWatch();stopWatch.start();SaasThreadContextUtil.load(saasThreadContextDataHolders);IndicatorRes<Long> incidentAutoDelCnt = incidentAutoDealCntService.countIndicator(startTimestamp, endTimestamp);long res = incidentAutoDelCnt.getIndicatorsValue() == null ? 0 : incidentAutoDelCnt.getIndicatorsValue();List<EntityCntDto> entityCntDtoList = dealEntityCntService.queryEntityDealCnt(startTimestamp, endTimestamp, tenantId);if (CollectionUtils.isEmpty(entityCntDtoList)) {return res;}for (EntityCntDto entityCnt : entityCntDtoList) {if (IndicatorEnum.AUTO_DEAL_ENTITY_CNT.getIndicatorKey().equals(Objects.requireNonNull(entityCnt.getEntityType()))) {res += entityCnt.getCount();}}stopWatch.stop();log.info("平台累计处理风险数统计结束,耗时:{}", stopWatch.getTotalTimeMillis());return res;} finally {SaasThreadContextUtil.remove();}});
}try {Long platformSummary = platformSummaryFuture.get();progressVo.setPlatformSummary(platformSummary);
} catch (InterruptedException | ExecutionException e) {log.error("查询平台累计处理风险数失败", e);
}

3. 设置缓存

if (!CollectionUtils.isEmpty(progressVo.getIndicators())) {String cacheKey = OverviewUtil.buildProgressCacheKey(tenantId, startTimestamp, endTimestamp, indicatorKeyList);redisTemplateConfig.setValueTimeout(cacheKey, progressVo, 300, TimeUnit.SECONDS);
}

http://www.ppmy.cn/news/83729.html

相关文章

ChatGPT提示工程课程,吴恩达OpenAI

Principle 1: Write clear and specific instructions 使用明确的分隔符&#xff0c;是LLM知道这个某个单独的字段。 前提设置&#xff1a; import openai import osfrom dotenv import load_dotenv, find_dotenv _ load_dotenv(find_dotenv()) # read local .env fileopena…

网络是信息传输网络3

网络是信息传输、接收、共享的虚拟平台&#xff0c;通过它把各个点、面、体的信息联系到一起&#xff0c;从而实现这些资源的共享。网络是人类发展史来最重要的发明&#xff0c;提高了科技和人类社会的发展。 网络会借助文字阅读、图片查看、影音播放、下载传输、游戏、聊天等…

5G信道建模研究进展与展望

5G信道建模研究进展与展望 一、信道建模定义二、5G信道建模研究进展1. 5G信道建模的理论框架1.1 大尺度衰落特性1.2 小尺度衰落特性1.3 信道新特性 2. 5G信道测量平台和应用场景2.1 5G信道测量平台2.2 5G信道的应用场景 3. 5G信道特性提取与建模 三、未来6G信道建模的研究方向1…

V-Ray渲染教程:又快又好的V-Ray渲染参数!

Chaos V-Ray 是适用于大部分主流3D设计软件和CAD程序的3D渲染插件&#xff0c;它可以与 3ds Max、Cinema 4D、Houdini、Maya、Nuke、Revit、Rhino、SketchUp、Unreal 无缝协作。借助 V-Ray渲染器强大的功能&#xff0c;艺术家和设计师可以产生出非常逼真的渲染效果。 那么&…

数据分析师职业规划——数据分析师这个岗位,可能近几年会消亡

近期成为月入两万的数据分析师的广告遍地都是&#xff0c;可能会对一些未入行的同学造成错觉。我个人感觉数据分析师这个岗位&#xff0c;可能近几年会消亡。 这不意味着这份工作本身不重要&#xff0c;而是说这份工作本身可能会转化为产品运营的一些必备技能&#xff0c;而不…

jenkins免密登录,拷贝jar包windows到linux并且重启

1、免密登录 生成无密码的密钥对 ssh-keygen -t rsa 一路回车 生成公钥路径&#xff1a;C:\Users\xxx/.ssh/id_rsa.pub 2.将公钥添加到linux本地认证文件中 首先拷贝id_rsa.pub到linux路径下&#xff0c; cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys chm…

【华为OD机试真题2023B卷 JAVA】食堂供餐

华为OD2023(B卷)机试题库全覆盖,刷题指南点这里 食堂供餐 知识点编程基础循环 时间限制:1s 空间限制:32MB 限定语言:不限 题目描述: 某公司员工食堂以盒饭方式供餐。为将员工取餐排队时间降低为0,食堂的供餐速度必须要足够快。现在需要根据以往员工取餐的统计信息,计…

元宇宙应用领域-医疗

元宇宙&#xff08;Metaverse&#xff09;是一个虚拟空间&#xff0c;用户可以通过数字技术和设备在其中生活和工作。元宇宙由一系列相关的技术和应用组成&#xff0c;包括区块链、虚拟现实、增强现实、人工智能、网络安全、大数据和云计算等。 元宇宙是一种新型的虚拟空间&am…