物流项目第五期(运费计算实现、责任链设计模式运用)
前四期:
物流项目第一期(登录业务)-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);}
}
相关文章:
物流项目第五期(运费计算实现、责任链设计模式运用)
前四期: 物流项目第一期(登录业务)-CSDN博客 物流项目第二期(用户端登录与双token三验证)-CSDN博客 物流项目第三期(统一网关、工厂模式运用)-CSDN博客 物流项目第四期(运费模板列…...
PrintStream PrintWriter Java 打印流
使用场景: 代替 System.out 输出日志(比如 System.setOut(printStream))需要输出各种类型(如 println(123)、println("hello")) 常用方法: print(), println() → 支持所有基本类型和对象pr…...
前端excel表格解析为json,并模仿excel显示
前端环境:elementUI vue2 <style lang"scss" scoped> 页面效果 jsondata为mock数据,为方便调试其内容可清空,首行(字母坐标)随数据内容自动变化,首列也是一样,模拟excel …...
NumPy 2.x 完全指南【十六】分割数组
文章目录 1. 数组分割1.1 split1.2 array_split1.3 vsplit1.4 hsplit1.5 dsplit1.6 unstack 1. 数组分割 数组分割是指将一个数组拆分为多个子数组的操作,常用于数据处理、并行计算、分块处理等场景。NumPy 提供了多种分割函数,允许用户沿不同方向&…...
vue3 + vite 使用tailwindcss
第一步:安装依赖 vite版本较低(“vite”: “^4.0.0”)所以就使用低版本的tailwindcss npm install -D tailwindcss3.4.1 postcss autoprefixer第二步:配置文件生成 npx tailwindcss init -p会自动生成两个文件postcss.config.js和…...
K个一组链表翻转
目录 1. 题意 2. 解题思路 3. 代码 1. 题意 给一个链表,按 k 进行翻转,也就是 k 2 ,两两进行翻转,如果不够2则不动。 2. 解题思路 首先思考怎么翻转一个链表,反转链表:https://leetcode.cn/problems…...
逆向音乐APP:Python爬虫获取音乐榜单 (1)
1. 引言 在数字音乐时代,许多平台如音乐有榜单,限制非付费用户访问高音质或独家内容。然而,从技术研究的角度来看,我们可以通过逆向工程和Python爬虫技术解音乐的API接口,获取付费音乐的播放链接。 2. 技术准备 在当…...
STM32之串口通信WIFI上云
一、W模块的原理与应用 基本概念 如果打算让硬件设备可以通过云服务器进行通信(数据上报/指令下发),像主流的云服务器有阿里云、腾讯云、华为云,以及其他物联网云平台:巴法云.......,硬件设备需要通过TCP…...
Python爬虫实战:获取天气网最近一周北京的天气数据,为日常出行做参考
1. 引言 随着互联网技术的发展,气象数据的获取与分析已成为智慧城市建设的重要组成部分。天气网作为权威的气象信息发布平台,其数据具有较高的准确性和实时性。然而,人工获取和分析天气数据效率低下,无法满足用户对精细化、个性化气象服务的需求。本文设计并实现了一套完整…...
【Java学习笔记】main方法
main 方法 一、深入理解 main 方法 特变注意!! 1. 在main()方法中,我们可以直接调用 mian 方法所在类的静态方法或静态属性 2. 不能访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中…...
振动分析 - 献个宝
1.一个自制的振动能量分析工具 这个分析工具似乎真的定位到了故障的具体位置。 1.1对一组实验室虚拟信号的分析结果: 1.2 对现场真实数据的分析结果 依照边频带的调制,和边频的缝隙宽度,基本定位到问题。 追加几份待看的文档: 齿轮结构的频谱特征 - 知乎使用 FFT 获得…...
数学实验(Matlab绘图基础)
一、二维曲线的绘制 Matlab绘图原理 MATLAB绘图的核心原理基于数据点或函数离散化,通过描点连线生成图形。以下是具体解析: 1.数据离散化 二维数据通过(x, y)坐标点表示,连续函数需离散化处理(如t0:0.01…...
【android bluetooth 协议分析 02】【bluetooth hal 层详解 3】【高通蓝牙hal主要流程介绍-上】
1. 背景 本节主要讨论 高通 蓝牙 hal 中,的一些流程。 看看你是否都清楚如下问题: 高通芯片电如何控制?串口是在哪里控制的?固件如何下载?初始化流程是怎么样的? 如果你已经对上述讨论的问题,…...
Linux | tmux | 无法复制粘贴
问题:在Linux中使用tmux时,总是没法使用复制粘贴功能; 解决: 如果希望直接用鼠标选择并复制(类似普通终端),可以: 在 ~/.tmux.conf 中添加:sh set -g mouse on;重新加载 tmux 配置…...
如何通过小贝加速实现精准网络故障排查
在日常使用电脑的过程中,我们常常需要监控系统运行状态、优化性能或排查网络问题。最近发现一款名为小贝加速的桌面工具,在此分享关于小贝加速如何实现网络监控。 系统优化 该工具提供了简洁明了的系统优化功能。通过扫描可以清理系统冗余文件、释放内存…...
Nginx 网站服务
目录 一:基于授权的访问控制 1:基于授权的访问控制简介 2:基于授权的访问控制步骤 二:基于客户端的访问控制 1:基于客户端的访问控制简介 2:基于客户端的访问控制步骤 三:Nginx 虚拟主机…...
Python 字典的用法和技巧
字典的创建与初始化 Python 字典是一种可变容器模型,可存储任意类型对象。字典的每个键值对用冒号分隔,键值对之间用逗号分隔,整个字典包括在花括号中。 # 创建一个空字典 empty_dict {}# 创建一个包含键值对的字典 my_dict {name: Alice…...
电力设备制造企业数字化转型路径研究:从生产优化到生态重构
电力设备制造业作为支撑能源革命的核心领域,其数字化转型不仅关乎企业降本增效,更是实现“双碳”目标与新型电力系统建设的关键抓手。本文基于行业标杆案例与实践经验,系统梳理电力设备企业数字化转型的五大核心路径。 一、生产流程智能化&a…...
初识GPU加速:如何利用GPU提升AI训练效率
随着人工智能(AI)和深度学习技术的快速发展,训练深度神经网络(DNN)已经变得越来越复杂和计算密集。传统的CPU已经无法满足大量计算任务的需求,因此,GPU(图形处理单元)成为了训练深度学习模型时的必备工具。本篇文章将介绍如何利用GPU加速AI训练效率,以及在使用GPU时应…...
深入解析异步编程:Java NIO、Python `async/await` 与 C# `async/await` 的对比
在现代编程中,异步编程已成为处理 I/O 密集型任务(如网络请求、文件操作等)的高效方式。不同的编程语言提供了各自的异步编程模型,以提高程序的性能和资源利用率。本文将深入解析 Java 的 NIO、Python 的 async/await 和 C# 的 as…...
阿里云数据盘级别
数据盘PL0、PL1、PL2和PL3的区别体现在性能、容量范围以及应用场景等方面。具体分析如下: 性能 PL0:单盘最大IOPS为10,000,最大吞吐量为180MB/s。适用于中小型MySQL和SQLServer等数据库场景,中小规模ELK日志集群,SAP和…...
使用 Spring AI Alibaba 集成阿里云百炼大模型应用
随着人工智能技术的飞速发展,大模型在各个领域的应用越来越广泛。阿里云百炼大模型提供了强大的语言理解和生成能力,但如何将其高效地集成到实际应用中,一直是开发者关注的焦点。本文将详细介绍如何使用 Spring AI Alibaba 集成阿里云百炼大模…...
阿里云合集(不定期更新)
一、阿里云申请免费域名证书流程:https://blog.csdn.net/humors221/article/details/143266059 二、阿里云发送国内短信怎样编程:https://blog.csdn.net/humors221/article/details/139544193 三、阿里云ECS服务器磁盘空间不足的几个文件:h…...
零基础设计模式——创建型模式 - 抽象工厂模式
第二部分:创建型模式 - 抽象工厂模式 (Abstract Factory Pattern) 我们已经学习了单例模式(保证唯一实例)和工厂方法模式(延迟创建到子类)。现在,我们来探讨创建型模式中更为复杂和强大的一个——抽象工厂…...
ConcurrentHashMap导致的死锁事故
事故现象 某线上服务共100台容器,第二天上午流量高峰期部分容器(约10%)cpu飙升,升至100%。 部分堆栈信息 堆栈信息如下如所示: 当前线程堆栈显示在JsonContext.get方法中调用computeIfAbsent,其Lambda表…...
Python高效网络爬虫开发指南
Python 网络爬虫入门与实战 一、引言 随着互联网数据的爆炸性增长,获取和分析这些数据变得越来越重要。网络爬虫作为数据采集的重要工具,在这其中扮演了不可或缺的角色。 二、环境搭建 首先我们需要安装Python环境以及一些必要的库: req…...
关于C++使用位运算交换变量值的分析
1、使用临时变量交换 交换变量的值,最常见的方法就是用临时变量。 void swap1(int& a, int& b){int c a;a b;b c; }清晰明了。 2、位运算版 对于整数类型,相信很多人都见过下面方法,可以使用位运算,从而不借用临时…...
06 接口自动化-框架封装思想建立之httprunner框架(下)
文章目录 一、httprunner如何实现数据驱动第一种:直接在脚本里面指定参数列表,最简单。适合于参数比较少的情况。第二种:使用CSV文件,适合于参数比较大的情况。第三种方式:使用函数生成数据,适用于数据变化…...
Dirsearch 深度使用教程:从基础扫描到携带 Cookie 探索网站
在网络安全测试和网站信息收集过程中,Dirsearch 是一款强大的开源工具,能够快速扫描网站,找出潜在的目录和文件。而当面对需要登录才能访问的网站资源时,通过携带 Cookie 扫描,Dirsearch 可以模拟已登录状态࿰…...
垃圾回收(GC)基础原理全面解析
掌握 GC 原理,是高效 Java 开发的第一步! 前言 垃圾回收(Garbage Collection,简称 GC)是 Java 的核心优势之一,它让开发者无需手动管理内存,极大降低了内存泄露和悬挂指针的风险。但当应用进入高并发、大数据量的场景时,GC 机制本身反而会成为性能瓶颈。 理解 GC 的原…...
海康NVR录像回放SDK原始流转FLV视频流:基于Java的流媒体转码(无需安装第三方插件ffmpeg)
wlinker-video-monitor 代码地址:https://gitee.com/wlinker/wlinker-video-monitor 背景与需求 在安防监控、智能楼宇等场景中,海康威视设备作为行业主流硬件,常需要将录像回放功能集成到Web系统中。然而,海康设备的原始视频流…...
【项目】SpringBoot +MybatisPlus集成多数据源
引言 应项目需求,需要引入另外的Mysql数据库,但是项目已经引入一个Mysql,这时有几种方案 通过Dynamic-DataSource 框架,无缝集成 但是是动态切换数据源的,跟项目需求不符合,于是采取第二种通过自定义数据…...
Suricata 3规则介绍、以及使用
列出更新源列表(有好多个规则源,后面有介绍的) suricata-update list-sourcesName: sslbl/ja3-fingerprintsVendor: Abuse.chSummary: Abuse.ch Suricata JA3 Fingerprint RulesetLicense: CC0-1.0 Name: malsilo/win-malwareVendor: malsil…...
基于OpenCV的物体跟踪:CSRT算法
文章目录 引言一、系统概述二、CSRT算法简介三、核心代码解析1. 初始化跟踪器和摄像头2. 主循环结构3. 目标选择与跟踪初始化4. 目标跟踪与结果显示5. 资源释放 四、系统使用说明五、完整代码六、总结 引言 目标跟踪是计算机视觉领域的重要应用之一,广泛应用于视频…...
面向未来,遨游推出5G-A智能防爆对讲机等系列终端
从5G扬帆到5G-A启航,遨游通讯始终立于技术潮头。在通信技术加速向5G-A演进的关键节点,遨游通讯旗舰产品AORO M6 Pro智能防爆对讲机,不仅实现了芯片到系统架构的全面自主可控,更通过5G-A技术的高速率、低时延、广连接与通感一体能力…...
qt浏览文件支持惯性
#include <QApplication> #include <QListWidget> #include <QScroller> #include <QScrollerProperties>int main(int argc, char *argv[]) {QApplication app(argc, argv);// 创建列表控件并添加示例项QListWidget listWidget;for (int i 0; i <…...
算子窗口操作
抠图 (提取图像感兴趣的区域) * 使用halcon 抠图* 窗体属性设设置: 设置窗体绘制图案的模式 magrin边框模式(只有一个边框) * fill填充模式(边框内部会有一个遮罩层) dev_set_draw (fill)* 设置颜色 dev_set_color (green) * 设置线宽dev_set_line_width (5)read_image (Im…...
如何提灯验车
✅ 重点 车标倾斜特别严重 导航定位不准 发动机顿挫异响 自动门把手关闭时异响 底盘有划痕和主驾位与扶手箱位置间隙过小磨损 蓝牙钥匙解锁异常,开关解锁不灵敏 空调无法制冷 灯罩有划痕 开启大灯就有嗡嗡嗡的异响 ✅ 一、文件与证件检…...
人工智能在生物医学研究中的创新应用
随着人工智能(AI)技术的飞速发展,其在生物医学领域的应用逐渐成为研究热点。AI不仅为生物医学研究提供了强大的工具,还在疾病诊断、药物研发、基因编辑等方面展现出巨大的潜力。本文将探讨人工智能在生物医学研究中的创新应用&…...
迁移学习实战:用预训练模型解决小样本图像分类
🚀 迁移学习实战:用预训练模型解决小样本图像分类(PyTorch实现) 当我们没有成千上万的训练样本时,如何训练一个表现良好的图像分类模型?答案是——迁移学习。本篇将带你用 PyTorch 快速上手迁移学习,用预训练模型(如 ResNet18)解决小样本分类问题。 🧠 一、什么是迁…...
html,js获取扫码设备的输入内容
<script type"text/javascript"><!-- window.onload function () {// 获取扫描的二维码内容 var code ""; var lastTime, nextTime; var lastCode, nextCode; document.onkeypress function (e) { nextCode e.which; ne…...
项目执行中缺乏风险管理,如何预防潜在问题?
要预防潜在问题,必须在项目执行中融入建立全面的风险识别机制、制定应对策略、实施动态监控、强化团队风险意识、定期评估与复盘。其中,建立全面的风险识别机制至关重要。项目初期若未进行系统性的风险识别,就很难在项目过程中及时应对变化&a…...
树形展示三级分类数据
vue3 实现多级分类_产品设计 平台端添加多个二级三级分类的页面-CSDN博客...
大模型如何助力数学可视化?
大家好,我是 i 学习的老章 在数学学习和教学中,将抽象概念可视化对于理解至关重要。Manim 是一个强大的数学动画引擎,由著名数学科普视频作者 3Blue1Brown 开发并广为人知。 老章较早之前就介绍过 manim:B 站上爆红的数学视频&a…...
什么是endpoints?
在 Kubernetes 中,Endpoints 是一个资源对象,它表示服务(Service)到 Pod 的网络连接。 Endpoints 的主要作用是将服务的虚拟 IP 地址映射到实际的 Pod IP 地址,从而实现服务发现和负载均衡。 1.Endpoints 的作用 服务…...
基于 Redis 实现短信验证码登录功能的完整方案
🧱 一、技术栈与依赖配置 使用 Spring Boot Redis 实现短信验证码登录,以下是推荐的 Maven 依赖: <dependencies><!-- Spring Boot Web --><dependency><groupId>org.springframework.boot</groupId><ar…...
监控易一体化运维:拥有全部核心技术,助力国产化信创运维
在数字化转型浪潮与信创产业蓬勃发展的当下,企业对运维系统的要求愈发严苛。随着数字化领域的巨大变迁,一款强大且适配信创环境的运维系统对企业的重要性不言而喻。今天,让我们一同深度剖析监控易系统在信创领域展现出的卓越优势。 信创产业&…...
微 PE , USM 魔术师两款 PE 对比
微 PE 和 USM 魔术师两款 PE 各有特点: 纯净度 微 PE:没有植入强制性、商业性软件和链接,也没有病毒和木马,非常纯净。USM 魔术师:同样无广告、无流氓、无捆绑、无后门,从官方途径下载能保证纯净度。 功能…...
测试模版1
本篇技术博文摘要 🌟 引言 📘 在这个变幻莫测、快速发展的技术时代,与时俱进是每个IT工程师的必修课。我是盛透侧视攻城狮,一名什么都会一丢丢的网络安全工程师,也是众多技术社区的活跃成员以及多家大厂官方认可人员&a…...
elementUI 中el-date-picker和el-select的样式调整
1. el-date-picker <el-date-picker class"select1" size"small" v-model"timeRangeArr" type"daterange" align"right" unlink-panels range-separator"至" start-placeholder"开始日期" end-pla…...