当前位置: 首页 > article >正文

物流项目第五期(运费计算实现、责任链设计模式运用)

前四期:

物流项目第一期(登录业务)-CSDN博客

物流项目第二期(用户端登录与双token三验证)-CSDN博客

物流项目第三期(统一网关、工厂模式运用)-CSDN博客

 物流项目第四期(运费模板列表实现)-CSDN博客

运费计算

运费计算的实现基本是三个步骤:

第一步,根据收件人、发件人的地址,查找对应的模板

第二步,计算实际计费的重量(使用轻抛系数将体积转化为重量,与实际重量相比,取大值)

第三步,按照首重 + 续重的方式计算出总价

基本的流程如下:

功能实现

    /*** 运费计算** @param waybillDTO 运费计算对象* @return 运费模板对象,不仅包含模板数据还包含:computeWeight、expense 字段*/CarriageDTO compute(WaybillDTO waybillDTO);/*** 根据模板类型查询模板,经济区互寄不通过该方法查询模板** @param templateType 模板类型:1-同城寄,2-省内寄,4-跨省* @return 运费模板*/CarriageEntity findByTemplateType(Integer templateType);
/*** 根据运单信息计算运费(主方法)** @param waybillDTO 运单数据对象,包含发件城市、收件城市、重量、体积等信息* @return 返回包含运费结果的 CarriageDTO 对象*/
@Override
public CarriageDTO compute(WaybillDTO waybillDTO) {// 1. 根据传入的运单信息查找匹配的运费模板(根据同城、省内、经济区、跨省等规则判断)CarriageEntity carriage = this.findCarriage(waybillDTO);// 2. 计算实际计费重量:// - 如果有体积,则按体积换算成“体积重量”;// - 否则取实际重量;// - 取两者最大值作为最终计费重量;double computeWeight = this.getComputeWeight(waybillDTO, carriage);// 3. 开始计算运费:// 公式:首重费用 + (计费重量 - 1kg) × 续重单价double expense = carriage.getFirstWeight() + ((computeWeight - 1) * carriage.getContinuousWeight());// 使用 NumberUtil.round 方法保留一位小数(四舍五入)expense = NumberUtil.round(expense, 1).doubleValue();// 4. 构造返回结果对象:// 将数据库实体对象转换为 DTO,并设置计算出的运费和计费重量CarriageDTO carriageDTO = CarriageUtils.toDTO(carriage);carriageDTO.setExpense(expense);         // 设置运费金额carriageDTO.setComputeWeight(computeWeight); // 设置实际计费重量// 5. 返回封装好的 DTO 结果return carriageDTO;
}
/*** 查找适用的运费模板** @param waybillDTO 运单信息,用于判断是否同城、同省、经济区互寄等* @return 匹配的运费模板实体对象*/
private CarriageEntity findCarriage(WaybillDTO waybillDTO) {// 1. 判断是否是“同城”快递:// 比较收件城市 ID 和发件城市 ID 是否相同if (ObjectUtil.equals(waybillDTO.getReceiverCityId(), waybillDTO.getSenderCityId())) {// 同城模板类型常量:CarriageConstant.SAME_CITYCarriageEntity carriageEntity = this.findByTemplateType(CarriageConstant.SAME_CITY);if (ObjectUtil.isNotEmpty(carriageEntity)) {return carriageEntity; // 找到就直接返回}}// 2. 判断是否是“同省”快递:// 获取收件人所在城市的父级行政区划(省份ID)Long receiverProvinceId = this.areaFeign.get(waybillDTO.getReceiverCityId()).getParentId();// 获取寄件人所在城市的父级行政区划(省份ID)Long senderProvinceId = this.areaFeign.get(waybillDTO.getSenderCityId()).getParentId();// 如果收发省份一致,说明是省内快递if (ObjectUtil.equal(receiverProvinceId, senderProvinceId)) {// 查询同省模板CarriageEntity carriageEntity = this.findByTemplateType(CarriageConstant.SAME_PROVINCE);if (ObjectUtil.isNotEmpty(carriageEntity)) {return carriageEntity; // 找到就返回}}// 3. 判断是否属于“经济区互寄”:// 获取所有经济区枚举配置(比如华东、华南、华北等)LinkedHashMap<String, EconomicRegionEnum> EconomicRegionMap = EnumUtil.getEnumMap(EconomicRegionEnum.class);EconomicRegionEnum economicRegionEnum = null;// 遍历每个经济区,检查当前收发省份是否都属于该区域for (EconomicRegionEnum regionEnum : EconomicRegionMap.values()) {boolean result = ArrayUtil.containsAll(regionEnum.getValue(), receiverProvinceId, senderProvinceId);if (result) {economicRegionEnum = regionEnum; // 找到匹配的经济区break;}}if (ObjectUtil.isNotEmpty(economicRegionEnum)) {// 构建查询条件:// 模板类型为经济区(CarriageConstant.ECONOMIC_ZONE)// 快递类型为常规速递(CarriageConstant.REGULAR_FAST)// 关联城市字段中包含经济区编码LambdaQueryWrapper<CarriageEntity> queryWrapper = Wrappers.lambdaQuery(CarriageEntity.class).eq(CarriageEntity::getTemplateType, CarriageConstant.ECONOMIC_ZONE).eq(CarriageEntity::getTransportType, CarriageConstant.REGULAR_FAST).like(CarriageEntity::getAssociatedCity, economicRegionEnum.getCode());// 查询模板CarriageEntity carriageEntity = super.getOne(queryWrapper);if (ObjectUtil.isNotEmpty(carriageEntity)) {return carriageEntity; // 找到就返回}}// 4. 最终兜底策略:跨省快递return this.findByTemplateType(CarriageConstant.TRANS_PROVINCE);
}
/*** 根据体积参数与实际重量计算最终的计费重量** @param waybillDTO 运单信息(含重量、长宽高等)* @param carriage   运费模板(含轻抛系数)* @return 返回最终计费重量(double 类型)*/
private double getComputeWeight(WaybillDTO waybillDTO, CarriageEntity carriage) {// 1. 获取体积参数:Integer volume = waybillDTO.getVolume(); // 用户可能已经传了体积if (ObjectUtil.isEmpty(volume)) {try {// 如果没有传体积,则根据长宽高计算体积(单位:立方厘米)volume = waybillDTO.getMeasureLong() * waybillDTO.getMeasureWidth() * waybillDTO.getMeasureHigh();} catch (Exception e) {// 出错时设为0,防止异常中断volume = 0;}}// 2. 计算体积重量(用于轻泡货):// 体积 ÷ 轻抛系数 → 得到体积重量(保留一位小数)BigDecimal volumeWeight = NumberUtil.div(volume, carriage.getLightThrowingCoefficient(), 1);// 3. 获取实际重量(可能带小数),并保留一位小数double realWeight = NumberUtil.round(waybillDTO.getWeight(), 1).doubleValue();// 4. 取体积重量与实际重量中的较大者作为基础计费重量double computeWeight = NumberUtil.max(volumeWeight.doubleValue(), realWeight);// 5. 根据不同区间,对计费重量进行“续重规则”处理:// 规则一:≤1kg 的,按 1kg 计费if (computeWeight <= 1) {return 1;}// 规则二:1kg ~ 10kg 的,保留原始数值(精确到 0.1kg)if (computeWeight <= 10) {return computeWeight;}// 规则三:≥100kg 的,四舍五入取整数if (computeWeight >= 100) {return NumberUtil.round(computeWeight, 0).doubleValue();}// 规则四:10kg ~ 100kg 的,以 0.5kg 为一个计价单位int integer = NumberUtil.round(computeWeight, 0, RoundingMode.DOWN).intValue(); // 取整数部分double decimalPart = NumberUtil.sub(computeWeight, integer); // 小数部分if (decimalPart == 0) {return integer; // 整数,直接返回}if (decimalPart <= 0.5) {return NumberUtil.add(integer, 0.5); // 0.5以内加0.5}return NumberUtil.add(integer, 1); // 超过0.5,进位
}
/*** 根据模板类型查询运费模板** @param templateType 模板类型(如:同城、省内、跨省)* @return 返回匹配的运费模板实体对象*/
@Override
public CarriageEntity findByTemplateType(Integer templateType) {// 如果调用的是经济区类型的模板,抛出异常(因为 findCarriage 方法已单独处理经济区情况)if (ObjectUtil.equals(templateType, CarriageConstant.ECONOMIC_ZONE)) {throw new SLException(CarriageExceptionEnum.METHOD_CALL_ERROR);}// 构建查询条件:// 模板类型 = templateType// 快递类型 = 常规速递(REGULAR_FAST)LambdaQueryWrapper<CarriageEntity> queryWrapper = Wrappers.lambdaQuery(CarriageEntity.class).eq(CarriageEntity::getTemplateType, templateType).eq(CarriageEntity::getTransportType, CarriageConstant.REGULAR_FAST);// 查询唯一一条记录并返回return super.getOne(queryWrapper);
}
    @PostMapping("compute")@ApiOperation(value = "运费计算")public CarriageDTO compute(@RequestBody WaybillDTO waybillDTO) {return carriageService.compute(waybillDTO);}

代码优化

在上述的运费计算的代码中,通过条件查找运费模板的方法中,判断了很多种情况,如果后续要再增加不同类型的模板或者调整模板之间的优先级,就必须改动代码,所以这样的实现扩展性并不好,也不够灵活。这里可以通过【责任链设计模式】来优化。

解释:

责任链模式是一种行为模式,把多个处理器组成一条链,但具体由哪个处理器来处理,根据条件判断来确定,如果不能处理会传递给该链中的下一个处理器,直到有处理器处理它为止。

之所以采用【责任链】模式,是因为在查找模板时,不同的模板处理逻辑不同,并且这些逻辑组成了一条处理链,有开头有结尾,只要能找到符合条件的模板即结束。

 定义处理链抽象类

package com.sl.ms.carriage.handler;import com.sl.ms.carriage.domain.dto.WaybillDTO;
import com.sl.ms.carriage.entity.CarriageEntity;/*** 运费模板处理链的抽象定义** 该抽象类定义了一个运费模板处理链的基本结构,允许通过链式调用来查找适用的运费模板。* 每个具体的处理器(Handler)需要继承此类并实现 doHandler 方法。*/
public abstract class AbstractCarriageChainHandler {/*** 下一个处理器对象,用于形成处理链。* 如果当前处理器无法找到合适的运费模板,则将请求传递给下一个处理器。*/private AbstractCarriageChainHandler nextHandler;/*** 抽象方法:执行过滤方法,根据输入参数查找运费模板。** @param waybillDTO 输入参数,包含运单的相关信息(如发件城市、收件城市等)* @return 返回匹配的运费模板实体对象,如果没有找到则返回 null*/public abstract CarriageEntity doHandler(WaybillDTO waybillDTO);/*** 执行下一个处理器的方法。** 当前处理器未能找到运费模板时,可以调用此方法将请求传递给下一个处理器。* 如果下游处理器为空或当前处理器已经找到了运费模板,则直接返回当前结果。** @param waybillDTO     输入参数,包含运单的相关信息* @param carriageEntity 上一个处理器处理得到的运费模板对象,如果未找到则为 null* @return 返回下一个处理器处理后的结果,或者直接返回当前的 carriageEntity(如果已找到)*/protected CarriageEntity doNextHandler(WaybillDTO waybillDTO, CarriageEntity carriageEntity) {// 如果没有设置下一个处理器 或者 当前处理器已经找到了运费模板,则直接返回当前结果if (nextHandler == null || carriageEntity != null) {return carriageEntity;}// 否则继续调用下一个处理器进行处理return nextHandler.doHandler(waybillDTO);}/*** 设置下一个处理器。** 通过此方法可以构建处理链,每个处理器可以指定它的下一个处理器,从而形成一条完整的处理链。** @param nextHandler 下游处理器对象*/public void setNextHandler(AbstractCarriageChainHandler nextHandler) {this.nextHandler = nextHandler;}
}

同城寄

/*** 同城寄*/
@Order(100) //定义顺序
@Component
public class SameCityChainHandler extends AbstractCarriageChainHandler {@Resourceprivate CarriageService carriageService;@Overridepublic CarriageEntity doHandler(WaybillDTO waybillDTO) {CarriageEntity carriageEntity = null;if (ObjectUtil.equals(waybillDTO.getReceiverCityId(), waybillDTO.getSenderCityId())) {//同城carriageEntity = this.carriageService.findByTemplateType(CarriageConstant.SAME_CITY);}return doNextHandler(waybillDTO, carriageEntity);}
}

省内寄

/*** 省内寄*/
@Order(200) //定义顺序
@Component
public class SameProvinceChainHandler extends AbstractCarriageChainHandler {@Resourceprivate CarriageService carriageService;@Resourceprivate AreaFeign areaFeign;@Overridepublic CarriageEntity doHandler(WaybillDTO waybillDTO) {CarriageEntity carriageEntity = null;// 获取收寄件地址省份idLong receiverProvinceId = this.areaFeign.get(waybillDTO.getReceiverCityId()).getParentId();Long senderProvinceId = this.areaFeign.get(waybillDTO.getSenderCityId()).getParentId();if (ObjectUtil.equal(receiverProvinceId, senderProvinceId)) {//省内carriageEntity = this.carriageService.findByTemplateType(CarriageConstant.SAME_PROVINCE);}return doNextHandler(waybillDTO, carriageEntity);}
}

经济区互寄

/*** 经济区互寄*/
@Order(300) //定义顺序
@Component
public class EconomicZoneChainHandler extends AbstractCarriageChainHandler {@Resourceprivate CarriageService carriageService;@Resourceprivate AreaFeign areaFeign;@Overridepublic CarriageEntity doHandler(WaybillDTO waybillDTO) {CarriageEntity carriageEntity = null;// 获取收寄件地址省份idLong receiverProvinceId = this.areaFeign.get(waybillDTO.getReceiverCityId()).getParentId();Long senderProvinceId = this.areaFeign.get(waybillDTO.getSenderCityId()).getParentId();//获取经济区城市配置枚举LinkedHashMap<String, EconomicRegionEnum> EconomicRegionMap = EnumUtil.getEnumMap(EconomicRegionEnum.class);EconomicRegionEnum economicRegionEnum = null;for (EconomicRegionEnum regionEnum : EconomicRegionMap.values()) {//该经济区是否全部包含收发件省idboolean result = ArrayUtil.containsAll(regionEnum.getValue(), receiverProvinceId, senderProvinceId);if (result) {economicRegionEnum = regionEnum;break;}}if (ObjectUtil.isNotEmpty(economicRegionEnum)) {//根据类型编码查询LambdaQueryWrapper<CarriageEntity> queryWrapper = Wrappers.lambdaQuery(CarriageEntity.class).eq(CarriageEntity::getTemplateType, CarriageConstant.ECONOMIC_ZONE).eq(CarriageEntity::getTransportType, CarriageConstant.REGULAR_FAST).like(CarriageEntity::getAssociatedCity, economicRegionEnum.getCode());carriageEntity = this.carriageService.getOne(queryWrapper);}return doNextHandler(waybillDTO, carriageEntity);}
}

跨省寄

/*** 跨省*/
@Order(400) //定义顺序
@Component
public class TransProvinceChainHandler extends AbstractCarriageChainHandler {@Resourceprivate CarriageService carriageService;@Overridepublic CarriageEntity doHandler(WaybillDTO waybillDTO) {CarriageEntity carriageEntity = this.carriageService.findByTemplateType(CarriageConstant.TRANS_PROVINCE);return doNextHandler(waybillDTO, carriageEntity);}
}

组装处理链

/*** 查找运费模板处理链 @Order注解指定handler顺序** 该类用于组装和管理一系列的运费模板处理器(AbstractCarriageChainHandler),通过Spring的依赖注入机制,* 按照@Order注解指定的顺序自动注入到List中,并构建处理链。*/
@Component
public class CarriageChainHandler {/*** Spring注入的处理器列表,按照@Order注解从小到大排序。* * 利用Spring的@Resource注解自动注入实现了AbstractCarriageChainHandler接口的所有bean实例,* 并按照@Order注解指定的顺序进行排序。*/@Resourceprivate List<AbstractCarriageChainHandler> chainHandlers;/*** 处理链的第一个处理器。* * 在构造处理链时设置,指向处理链中的第一个处理器对象。*/private AbstractCarriageChainHandler firstHandler;/*** 组装处理链。* * 使用@PostConstruct注解标记的方法,在Spring容器初始化完成后自动调用。* 此方法负责将各个处理器按顺序连接起来,形成一条完整的处理链。*/@PostConstructprivate void constructChain() {// 检查chainHandlers是否为空,如果为空则抛出异常提示未找到处理器if (CollUtil.isEmpty(chainHandlers)) {throw new SLException("not found carriage chain handler!");}// 设置处理链的第一个节点为chainHandlers列表中的第一个元素firstHandler = chainHandlers.get(0);// 遍历chainHandlers列表,依次设置每个处理器的下一个处理器for (int i = 0; i < chainHandlers.size(); i++) {if (i == chainHandlers.size() - 1) {// 对于最后一个处理器,设置其下游处理器为null,表示没有后续处理器chainHandlers.get(i).setNextHandler(null);} else {// 对于非最后一个处理器,设置其下游处理器为下一个处理器chainHandlers.get(i).setNextHandler(chainHandlers.get(i + 1));}}}/*** 根据运单信息查找运费模板。* * 从处理链的第一个处理器开始处理,逐级传递直到找到匹配的运费模板或遍历完所有处理器。** @param waybillDTO 运单数据传输对象,包含发件城市、收件城市等信息* @return 返回匹配的运费模板实体对象*/public CarriageEntity findCarriage(WaybillDTO waybillDTO) {// 从处理链的第一个处理器开始处理return firstHandler.doHandler(waybillDTO);}
}

相关文章:

物流项目第五期(运费计算实现、责任链设计模式运用)

前四期&#xff1a; 物流项目第一期&#xff08;登录业务&#xff09;-CSDN博客 物流项目第二期&#xff08;用户端登录与双token三验证&#xff09;-CSDN博客 物流项目第三期&#xff08;统一网关、工厂模式运用&#xff09;-CSDN博客 物流项目第四期&#xff08;运费模板列…...

前端JavaScript-嵌套事件

点击 如果在多层嵌套中&#xff0c;对每层都设置事件监视器&#xff0c;试试看 <!DOCTYPE html> <html lang"cn"> <body><div id"container"><button>点我&#xff01;</button></div><pre id"output…...

X 下载器 2.1.42 | 国外媒体下载工具 网页视频嗅探下载

X 下载器让你能够轻松地从社交应用如Facebook、Instagram、TikTok等下载视频和图片。通过内置浏览器访问网站&#xff0c;它能自动检测视频和图片&#xff0c;只需点击下载按钮即可完成下载。去除广告&#xff0c;解锁本地会员&#xff0c;享受无广告打扰的下载体验。 大小&am…...

STM32 CAN CANAerospace

STM32的CAN模块对接CANAerospace 刚开始报错如下. 设备开机后整个CAN消息就不发了. USB_CAN调试器报错如下. index time Name ID Type Format Len Data00000001 000.000.000 Event 总线错误 DATA STANDARD 8 接收过程错误-格…...

完整改进RIME算法,基于修正多项式微分学习算子Rime-ice增长优化器,完整MATLAB代码获取

1 简介 为了有效地利用雾状冰生长的物理现象&#xff0c;最近开发了一种优化算法——雾状优化算法&#xff08;RIME&#xff09;。它模拟硬雾状和软雾状过程&#xff0c;构建硬雾状穿刺和软雾状搜索机制。在本研究中&#xff0c;引入了一种增强版本&#xff0c;称为修改的RIME…...

服务器安装xfce桌面环境并通过浏览器操控

最近需要运行某个浏览器的脚本&#xff0c;但是服务器没有桌面环境&#xff0c;无法使用&#xff0c;遂找到了KasmVNC&#xff0c;并配合xfce实现低占用的桌面环境&#xff0c;可以直接使用浏览器进行操作 本文基于雨云——新一代云服务提供商的Debian11服务器操作&#xff0c;…...

Java设计模式之组合模式:从入门到精通(保姆级教程)

文章目录 1. 组合模式概述1.1 专业定义1.2 通俗解释1.3 模式结构2. 组合模式详细解析2.1 模式优缺点2.2 适用场景3. 组合模式实现详解3.1 基础实现3.2 代码解析4. 组合模式进阶应用4.1 透明式 vs 安全式组合模式4.2 组合模式与递归4.3 组合模式与迭代器5. 组合模式在实际开发中…...

Oracle 创建外部表

找别人要一下数据&#xff0c;但是他发来一个 xxx.csv 文件&#xff0c;怎么办&#xff1f; 1、使用视图化工具导入 使用导入工具导入&#xff0c;如 DBeaver&#xff0c;右击要导入的表&#xff0c;选择导入数据。 选择对应的 csv 文件&#xff0c;下一步就行了&#xff08;如…...

大语言模型 17 - MCP Model Context Protocol 介绍对比分析 基本环境配置

MCP 基本介绍 官方地址&#xff1a; https://modelcontextprotocol.io/introduction “MCP 是一种开放协议&#xff0c;旨在标准化应用程序向大型语言模型&#xff08;LLM&#xff09;提供上下文的方式。可以把 MCP 想象成 AI 应用程序的 USB-C 接口。就像 USB-C 提供了一种…...

【软考向】Chapter 9 数据库技术基础

基本概念数据库的三级模式结构 数据模型E-R 模型关系模型各种键完整性约束 关系代数5 种基本的关系代数运算&#xff1a;并、差、笛卡儿积、投影和选择扩展的关系代数运算&#xff1a;交(Intersection)、连接(Join)、除(Division)、广义投影(Generalized Projection)、外连接(O…...

实战:Dify智能体+Java=自动化运营工具!

我们在运营某个圈子的时候&#xff0c;可能每天都要将这个圈子的“热门新闻”发送到朋友圈或聊天群里&#xff0c;但依靠传统的实现手段非常耗时耗力&#xff0c;我们通常要先收集热门新闻&#xff0c;再组装要新闻内容&#xff0c;再根据内容设计海报等。 那怎么才能简化并高…...

STM32单片机GUI系统1 GUI基本内容

目录 一、GUI简介 1、emWin 2、LVGL (Light and Versatile Graphics Library) 3、TouchGFX 4、Qt for Embedded 5、特性对比总结 二、LVGL移植要求 三、优化LVGL运行效果方法 四、LVGL系统文件 一、GUI简介 在嵌入式系统中&#xff0c;emWin、LVGL、TouchGFX 和 Qt 是…...

从零开始学习three.js(21):一文详解three.js中的矩阵Matrix和向量Vector

一、三维世界的数学基石 在Three.js的三维世界里&#xff0c;所有视觉效果的实现都建立在严密的数学基础之上。其中向量&#xff08;Vector&#xff09; 和矩阵&#xff08;Matrix&#xff09; 是最核心的数学工具&#xff0c;它们就像构建数字宇宙的原子与分子&#xff0c;支…...

应届本科生简历制作指南

一、找一个专业的简历模板 首先&#xff0c;你需要访问 Overleaf 的官方网站&#xff0c;也就是Overleaf, Online LaTeX Editor&#xff0c;进入页面后&#xff0c;点击注册按钮&#xff0c;按照提示填写相关信息来创建一个属于自己的账号&#xff0c;通常需要填写用户名、邮箱…...

VUE3+TS实现图片缩放移动弹窗

完整代码 使用VUE3、TS&#xff0c;实现将图片通过鼠标拖拽缩放以及选择缩放比例。 <template><div><el-dialogv-model"dialogVisible"title"查看图片":close-on-click-modal"false":close-on-press-escape"false"fu…...

大语言模型训练数据格式:Alpaca 和 ShareGPT

在大规模语言模型&#xff08;LLM&#xff09;的开发中&#xff0c;训练数据的质量和格式起着至关重要的作用。为了更好地理解和构建高质量的数据集&#xff0c;社区发展出了多种标准化的数据格式。其中&#xff0c;Alpaca 和 ShareGPT 是两种广泛使用的训练数据格式&#xff0…...

实现动态增QuartzJob,通过自定义注解调用相应方法

:::tip 动态增加Quartz定时任务&#xff0c;通过自定义注解来实现具体的定时任务方法调用。 ::: 相关依赖如下 <!-- 用来动态创建 Quartz 定时任务 --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-start…...

PyTorch可视化工具——使用Visdom进行深度学习可视化

文章目录 前置环境Visdom安装并启动VisdomVisdom图形APIVisdom静态更新API详解通用参数说明使用示例Visdom动态更新API详解1. 使用updateappend参数2. ~~使用vis.updateTrace方法~~3. 完整训练监控示例 Visdom可视化操作散点图plot.scatter()散点图案例线性图vis.line()vis.lin…...

Qt无边框界面添加鼠标事件

在Qt中实现无边框窗口的鼠标事件处理&#xff0c;主要涉及窗口拖动和调整大小功能。以下是分步实现的代码示例&#xff1a; 1. 创建无边框窗口 首先&#xff0c;创建一个继承自QWidget的自定义窗口类&#xff0c;并设置无边框标志&#xff1a; #include <QWidget> #in…...

企业级爬虫进阶开发指南

企业级爬虫进阶开发指南 一、分布式任务调度系统的深度设计 1.1 架构设计原理 图表 1.2 核心代码实现与注释 分布式锁服务 # distributed_lock.py import redis import timeclass DistributedLock:def __init__(self, redis_conn):self.redis = redis_connself.lock_key = …...

Ubuntu ping网络没有问题,但是浏览器无法访问到网络

我这边是尝试清楚DNS缓存然后重新访问就可以了。 使用 resolvectl 刷新 DNS 缓存 在 Ubuntu 20.04 及更高版本中&#xff0c;可以使用以下命令来刷新 DNS 缓存&#xff1a; sudo resolvectl flush-caches 使用 systemd-resolve&#xff08;适用于旧版本&#xff09; 如果你…...

网络安全-等级保护(等保) 2-7 GB/T 25058—2019 《信息安全技术 网络安全等级保护实施指南》-2019-08-30发布【现行】

################################################################################ GB/T 22239-2019 《信息安全技术 网络安全等级保护基础要求》包含安全物理环境、安全通信网络、安全区域边界、安全计算环境、安全管理中心、安全管理制度、安全管理机构、安全管理人员、安…...

数据结构实验10.1:内部排序的基本运算

文章目录 一&#xff0c;实验目的二&#xff0c;实验内容1. 数据生成与初始化2. 排序算法实现&#xff08;1&#xff09;直接插入排序&#xff08;2&#xff09;二分插入排序&#xff08;3&#xff09;希尔排序&#xff08;4&#xff09;冒泡排序&#xff08;5&#xff09;快速…...

C#:多线程

一.线程常用概念 线程&#xff08;Thread&#xff09;&#xff1a;操作系统执行程序的最小单位 进程&#xff08;Process&#xff09;&#xff1a;程序在内存中的运行实例 并发&#xff08;Concurrency&#xff09;&#xff1a;多个任务交替执行&#xff08;单核CPU&#xff0…...

基于Zynq SDK的LWIP UDP组播开发实战指南

一、为什么选择LWIP组播? 在工业控制、智能安防、物联网等领域,一对多的高效数据传输需求日益增长。Zynq-7000系列SoC凭借其ARM+FPGA的独特架构,结合LWIP轻量级网络协议栈,成为嵌入式网络开发的理想选择。本文将带您实现: LWIP组播配置全流程动态组播组切换技术零拷贝数据…...

c#将json字符串转换为对象数组

在C#中&#xff0c;将JSON字符串转换为对象数组是一个常见的需求&#xff0c;特别是在处理来自Web API的响应或需要反序列化本地文件内容时。这可以通过使用Newtonsoft.Json&#xff08;也称为Json.NET&#xff09;库或.NET Core内置的System.Text.Json来完成。以下是如何使用这…...

机器学习在智能水泥基复合材料中的应用与实践

“机器学习在智能水泥基复合材料中的应用与实践” 课程 内容 机器学习基础模型与复合材料研究融合 机器学习在复合材料中的应用概述机器学习用于复合材料研究的流程复合材料数据收集与数据预处理 实例&#xff1a;数据的收集和预处理 复合材料机器学习特征工程与选择 实例&a…...

wps编辑技巧

1、编辑模式 2、图片提取方法&#xff1a;右键保存图片 可以直接右键保存下来看看是否是原始图&#xff0c;如果歪着的图&#xff0c;可能保存下来是正的&#xff0c;直接保存试下 3、加批注...

开放世界RPG:无缝地图与动态任务的拓扑学架构

目录 开放世界RPG:无缝地图与动态任务的拓扑学架构引言第一章 地图分块系统1.1 动态加载算法1.2 内存管理模型第二章 任务拓扑网络2.1 任务依赖图2.2 动态可达性分析第三章 NPC行为系统3.1 行为森林架构3.2 日程规划算法第四章 动态事件系统4.1 事件传播模型4.2 玩家影响指标第…...

【图像处理入门】1. 数字图像的本质:从像素到色彩模型

作为图像处理的开篇&#xff0c;本文将带你拆解数字图像的底层逻辑&#xff1a;从模拟图像到数字信号的神奇转换&#xff0c;到像素世界的微观构成&#xff0c;再到彩色图像的编码奥秘。通过 Python 代码实战&#xff0c;你将亲手触摸图像的 “基因”—— 像素值&#xff0c;并…...