TAOCARTS 知识

国际集运计费引擎实现:策略模式+规则引擎处理复杂运费计算

2026-06-26 系统功能介绍

<<<<<<< HEAD

大模型产品解决方案权益定价云市场伙伴服务了解阿里云查看 "" 全部搜索结果AI 助理文档备案控制台开发者社区首页探索云世界探索云世界热门百炼大模型Modelscope模型即服务弹性计算通义灵码云原生数据库云效DevOps龙蜥操作系统云计算弹性计算无影存储网络倚天大数据大数据计算实时数仓Hologres实时计算FlinkE-MapReduceDataWorksElasticsearch机器学习平台PAI智能搜索推荐数据可视化DataV云原生容器serverless中间件微服务可观测消息队列人工智能机器学习平台PAI视觉智能开放平台智能语音交互自然语言处理多模态模型pythonsdk通用模型数据库关系型数据库NoSQL数据库数据仓库数据管理工具PolarDB开源向量数据库开发与运维云效DevOps钉钉宜搭镜像站问产品动手实践官方博客考认证TIANCHI大赛活动广场活动广场丰富的线上&线下活动,深入探索云世界

做任务,得社区积分和周边

资深技术专家手把手带教

技术交流,直击现场

让创作激发创新

海量开发者使用工具、手册,免费下载

极速、全面、稳定、安全的开源镜像

开发手册、白皮书、案例集等实战精华

热门

摘要:反向海淘运费计算涉及首重续重、体积重、多国家差异化、多渠道路由。本文使用Java策略模式和Drools规则引擎实现灵活可配置的计费系统,支持实时计算和批量试算。

一、需求建模运费规则示例:

美国云途专线:首重0.5kg/85元,续重0.5kg/25元,按实际重量计费

美国EMS:首重0.5kg/110元,续重0.5kg/35元,按体积重(长宽高/5000)取大

加拿大专线:首重1kg/120元,续重0.5kg/30元

二、策略模式实现java// 计费策略接口public interface FreightCalculator {

BigDecimal calculate(ShippingPackage pkg, FreightRule rule);}

// 实际重量策略@Componentpublic class ActualWeightCalculator implements FreightCalculator {

@Override public BigDecimal calculate(ShippingPackage pkg, FreightRule rule) {

double weight = pkg.getActualWeightKg(); if (weight <= rule.getFirstWeight()) {

return rule.getFirstPrice(); } double additional = weight - rule.getFirstWeight(); int units = (int) Math.ceil(additional / rule.getAdditionalUnit()); return rule.getFirstPrice().add(rule.getAdditionalPrice().multiply(BigDecimal.valueOf(units))); }}

// 体积重策略@Componentpublic class VolumetricWeightCalculator implements FreightCalculator {

@Override public BigDecimal calculate(ShippingPackage pkg, FreightRule rule) {

double volumetric = pkg.getLengthCm() pkg.getWidthCm() pkg.getHeightCm() / 5000.0; double weight = Math.max(pkg.getActualWeightKg(), volumetric); // 复用实际重量计算逻辑 return actualWeightCalculator.calculate(new ShippingPackage(weight), rule); }}

// 策略工厂@Componentpublic class FreightCalculatorFactory {

private final Map calculatorMap = new HashMap<>();

public FreightCalculatorFactory() {

calculatorMap.put("actual", new ActualWeightCalculator());

calculatorMap.put("volumetric", new VolumetricWeightCalculator());

// 更多策略...

}

public FreightCalculator getCalculator(String type) {

return calculatorMap.getOrDefault(type, calculatorMap.get("actual"));

}

}三、规则引擎配置运费模板java// Drools规则文件 freight.drlpackage com.taocarts.freight;

import com.taocarts.domain.ShippingRequest;import com.taocarts.domain.FreightResult;

rule "US_YunExpress_Rule" when $req: ShippingRequest(destinationCountry == "US", channel == "YunExpress") then FreightRule rule = new FreightRule(); rule.setFirstWeight(0.5); rule.setFirstPrice(new BigDecimal("85")); rule.setAdditionalUnit(0.5); rule.setAdditionalPrice(new BigDecimal("25")); rule.setCalculatorType("actual"); $req.setMatchedRule(rule);end

rule "US_EMS_Rule" when $req: ShippingRequest(destinationCountry == "US", channel == "EMS") then FreightRule rule = new FreightRule(); rule.setFirstWeight(0.5); rule.setFirstPrice(new BigDecimal("110")); rule.setAdditionalUnit(0.5); rule.setAdditionalPrice(new BigDecimal("35")); rule.setCalculatorType("volumetric"); $req.setMatchedRule(rule);end四、合并发货与拼单分摊java@Servicepublic class CombinedFreightService {

public CombinedFreightResult combineAndCalculate(List orderIds, String channel) {

// 1. 汇总订单商品 List orders = orderService.listByIds(orderIds); double totalActualWeight = orders.stream().mapToDouble(Order::getTotalWeight).sum(); double totalVolumetricWeight = orders.stream() .mapToDouble(o -> o.getLengthCm() o.getWidthCm() o.getHeightCm() / 5000.0) .max().orElse(0); double finalWeight = Math.max(totalActualWeight, totalVolumetricWeight);

// 2. 获取运费规则

FreightRule rule = freightRuleMapper.selectByChannelAndCountry(channel, orders.get(0).getCountry());

FreightCalculator calculator = calculatorFactory.getCalculator(rule.getCalculatorType());

BigDecimal totalFreight = calculator.calculate(new ShippingPackage(finalWeight), rule);

// 3. 按重量分摊

List<FreightShare> shares = new ArrayList<>();

for (Order order : orders) {

double shareRatio = order.getTotalWeight() / totalActualWeight;

BigDecimal shareFreight = totalFreight.multiply(BigDecimal.valueOf(shareRatio));

shares.add(new FreightShare(order.getId(), shareFreight));

}

return new CombinedFreightResult(totalFreight, shares);

}

}五、性能优化运费模板缓存到Redis,每小时刷新一次

体积重计算使用本地缓存减少重复计算

批量计费时使用CompletableFuture并行处理

经压测,单机可支持500次/秒的运费计算请求,P99延迟低于50ms。

关注阿里云公众号或下载阿里云APP,关注云资讯,随时随地运维管控云服务

联系我们:4008013260

© 2009-现在 Aliyun.com 版权所有 增值电信业务经营许可证: 浙B2-20080101 域名注册服务机构许可: 浙D3-20210002

=======

大模型产品解决方案权益定价云市场伙伴服务了解阿里云查看 "" 全部搜索结果AI 助理文档备案控制台开发者社区首页探索云世界探索云世界热门百炼大模型Modelscope模型即服务弹性计算通义灵码云原生数据库云效DevOps龙蜥操作系统云计算弹性计算无影存储网络倚天大数据大数据计算实时数仓Hologres实时计算FlinkE-MapReduceDataWorksElasticsearch机器学习平台PAI智能搜索推荐数据可视化DataV云原生容器serverless中间件微服务可观测消息队列人工智能机器学习平台PAI视觉智能开放平台智能语音交互自然语言处理多模态模型pythonsdk通用模型数据库关系型数据库NoSQL数据库数据仓库数据管理工具PolarDB开源向量数据库开发与运维云效DevOps钉钉宜搭镜像站问产品动手实践官方博客考认证TIANCHI大赛活动广场活动广场丰富的线上&线下活动,深入探索云世界

做任务,得社区积分和周边

资深技术专家手把手带教

技术交流,直击现场

让创作激发创新

海量开发者使用工具、手册,免费下载

极速、全面、稳定、安全的开源镜像

开发手册、白皮书、案例集等实战精华

热门

摘要:反向海淘运费计算涉及首重续重、体积重、多国家差异化、多渠道路由。本文使用Java策略模式和Drools规则引擎实现灵活可配置的计费系统,支持实时计算和批量试算。

一、需求建模运费规则示例:

美国云途专线:首重0.5kg/85元,续重0.5kg/25元,按实际重量计费

美国EMS:首重0.5kg/110元,续重0.5kg/35元,按体积重(长宽高/5000)取大

加拿大专线:首重1kg/120元,续重0.5kg/30元

二、策略模式实现java// 计费策略接口public interface FreightCalculator {

BigDecimal calculate(ShippingPackage pkg, FreightRule rule);}

// 实际重量策略@Componentpublic class ActualWeightCalculator implements FreightCalculator {

@Override public BigDecimal calculate(ShippingPackage pkg, FreightRule rule) {

double weight = pkg.getActualWeightKg(); if (weight <= rule.getFirstWeight()) {

return rule.getFirstPrice(); } double additional = weight - rule.getFirstWeight(); int units = (int) Math.ceil(additional / rule.getAdditionalUnit()); return rule.getFirstPrice().add(rule.getAdditionalPrice().multiply(BigDecimal.valueOf(units))); }}

// 体积重策略@Componentpublic class VolumetricWeightCalculator implements FreightCalculator {

@Override public BigDecimal calculate(ShippingPackage pkg, FreightRule rule) {

double volumetric = pkg.getLengthCm() pkg.getWidthCm() pkg.getHeightCm() / 5000.0; double weight = Math.max(pkg.getActualWeightKg(), volumetric); // 复用实际重量计算逻辑 return actualWeightCalculator.calculate(new ShippingPackage(weight), rule); }}

// 策略工厂@Componentpublic class FreightCalculatorFactory {

private final Map calculatorMap = new HashMap<>();

public FreightCalculatorFactory() {

calculatorMap.put("actual", new ActualWeightCalculator());

calculatorMap.put("volumetric", new VolumetricWeightCalculator());

// 更多策略...

}

public FreightCalculator getCalculator(String type) {

return calculatorMap.getOrDefault(type, calculatorMap.get("actual"));

}

}三、规则引擎配置运费模板java// Drools规则文件 freight.drlpackage com.taocarts.freight;

import com.taocarts.domain.ShippingRequest;import com.taocarts.domain.FreightResult;

rule "US_YunExpress_Rule" when $req: ShippingRequest(destinationCountry == "US", channel == "YunExpress") then FreightRule rule = new FreightRule(); rule.setFirstWeight(0.5); rule.setFirstPrice(new BigDecimal("85")); rule.setAdditionalUnit(0.5); rule.setAdditionalPrice(new BigDecimal("25")); rule.setCalculatorType("actual"); $req.setMatchedRule(rule);end

rule "US_EMS_Rule" when $req: ShippingRequest(destinationCountry == "US", channel == "EMS") then FreightRule rule = new FreightRule(); rule.setFirstWeight(0.5); rule.setFirstPrice(new BigDecimal("110")); rule.setAdditionalUnit(0.5); rule.setAdditionalPrice(new BigDecimal("35")); rule.setCalculatorType("volumetric"); $req.setMatchedRule(rule);end四、合并发货与拼单分摊java@Servicepublic class CombinedFreightService {

public CombinedFreightResult combineAndCalculate(List orderIds, String channel) {

// 1. 汇总订单商品 List orders = orderService.listByIds(orderIds); double totalActualWeight = orders.stream().mapToDouble(Order::getTotalWeight).sum(); double totalVolumetricWeight = orders.stream() .mapToDouble(o -> o.getLengthCm() o.getWidthCm() o.getHeightCm() / 5000.0) .max().orElse(0); double finalWeight = Math.max(totalActualWeight, totalVolumetricWeight);

// 2. 获取运费规则

FreightRule rule = freightRuleMapper.selectByChannelAndCountry(channel, orders.get(0).getCountry());

FreightCalculator calculator = calculatorFactory.getCalculator(rule.getCalculatorType());

BigDecimal totalFreight = calculator.calculate(new ShippingPackage(finalWeight), rule);

// 3. 按重量分摊

List<FreightShare> shares = new ArrayList<>();

for (Order order : orders) {

double shareRatio = order.getTotalWeight() / totalActualWeight;

BigDecimal shareFreight = totalFreight.multiply(BigDecimal.valueOf(shareRatio));

shares.add(new FreightShare(order.getId(), shareFreight));

}

return new CombinedFreightResult(totalFreight, shares);

}

}五、性能优化运费模板缓存到Redis,每小时刷新一次

体积重计算使用本地缓存减少重复计算

批量计费时使用CompletableFuture并行处理

经压测,单机可支持500次/秒的运费计算请求,P99延迟低于50ms。

关注阿里云公众号或下载阿里云APP,关注云资讯,随时随地运维管控云服务

联系我们:4008013260

© 2009-现在 Aliyun.com 版权所有 增值电信业务经营许可证: 浙B2-20080101 域名注册服务机构许可: 浙D3-20210002

>>>>>>> main_dev_20260624

浙公网安备 33010602009975号浙B2-20080101-4