智慧充电系统计费定价服务Java 实现

目录

一、项目架构

[1. 核心枚举定义](#1. 核心枚举定义)

二、核心数据模型

[1. 电价模板实体(数据库映射)](#1. 电价模板实体(数据库映射))

[2. 请求 / 响应 DTO](#2. 请求 / 响应 DTO)

三、策略模式核心实现(计费规则引擎)

[1. 计费策略接口](#1. 计费策略接口)

[2. 按电量计费策略](#2. 按电量计费策略)

[3. 按时长计费策略](#3. 按时长计费策略)

[4. 策略工厂(动态匹配计费规则)](#4. 策略工厂(动态匹配计费规则))

四、优惠计算服务

五、核心业务服务实现

[1. 电价模板缓存服务(Redis)](#1. 电价模板缓存服务(Redis))

[2. 计费核心服务(实现所有业务接口)](#2. 计费核心服务(实现所有业务接口))

[六、定时任务(XXL-Job 定时切换峰谷电价)](#六、定时任务(XXL-Job 定时切换峰谷电价))

[七、Feign 远程调用接口(供充电服务调用)](#七、Feign 远程调用接口(供充电服务调用))

[八、Controller 接口层](#八、Controller 接口层)

九、核心业务逻辑详细说明

[1. 整体业务流程(核心)](#1. 整体业务流程(核心))

[2. 核心接口业务说明](#2. 核心接口业务说明)

[3. 技术实现亮点](#3. 技术实现亮点)

总结


实现电价配置、实时计费、费用预估、优惠计算、价格策略管理 核心接口,采用策略模式 + 规则引擎 + Redis 缓存 + XXL-Job 定时任务 架构,使用BigDecimal保证金额精度,代码可直接集成到微服务项目中。

一、项目架构

1. 核心枚举定义

定义电价时段、设备类型、计费模式、优惠类型,统一业务规范:

复制代码
import java.math.BigDecimal;

/**
 * 电价时段枚举
 */
public enum TimePeriodType {
    PEAK,   // 峰时段
    VALLEY, // 谷时段
    NORMAL  // 平时段
}

/**
 * 设备类型枚举
 */
public enum DeviceType {
    DC,     // 直流桩
    AC      // 交流桩
}

/**
 * 计费模式枚举
 */
public enum ChargeType {
    BY_POWER,   // 按电量计费
    BY_TIME     // 按时长计费
}

/**
 * 优惠类型枚举
 */
public enum DiscountType {
    MEMBER,     // 会员折扣
    COUPON,     // 优惠券
    ACTIVITY,   // 活动立减
    GROUP_BUY   // 拼团优惠
}

二、核心数据模型

1. 电价模板实体(数据库映射)

复制代码
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalTime;

/**
 * 电价模板配置表
 */
@Data
public class ElectricityPriceTemplate {
    private Long id;
    private Long stationId;        // 场站ID(null=全局模板)
    private DeviceType deviceType; // 设备类型
    private TimePeriodType periodType; // 时段类型
    private LocalTime startTime;   // 时段开始时间
    private LocalTime endTime;     // 时段结束时间
    private BigDecimal powerPrice; // 电费单价(元/度)
    private BigDecimal servicePrice;// 服务费单价(元/度)
    private ChargeType chargeType; // 计费模式
    private Integer status;        // 0-停用 1-启用
}

2. 请求 / 响应 DTO

复制代码
import lombok.Data;
import java.math.BigDecimal;

/**
 * 实时计费请求DTO
 */
@Data
public class RealTimeChargeReqDTO {
    private Long stationId;        // 场站ID
    private DeviceType deviceType; // 设备类型
    private BigDecimal power;      // 充电电量(度) / 时长(小时)
    private Long userId;           // 用户ID
    private Long couponId;         // 优惠券ID
    private Boolean isGroupBuy;    // 是否拼团
}

/**
 * 计费响应DTO
 */
@Data
public class ChargeResultRespDTO {
    private BigDecimal originalTotal; // 原始总费用
    private BigDecimal discountAmount; // 优惠总金额
    private BigDecimal actualTotal;   // 实付总金额
    private String detail;            // 计费详情
}

/**
 * 费用预估请求DTO
 */
@Data
public class FeeEstimateReqDTO {
    private Long stationId;
    private DeviceType deviceType;
    private ChargeType chargeType;
    private BigDecimal estimatePower; // 预估电量/时长
}

三、策略模式核心实现(计费规则引擎)

1. 计费策略接口

复制代码
import java.math.BigDecimal;

/**
 * 计费策略接口(规则引擎核心)
 */
public interface IChargeStrategy {
    /**
     * 计算基础费用
     */
    BigDecimal calculateBaseFee(BigDecimal power, BigDecimal powerPrice, BigDecimal servicePrice);
    
    /**
     * 获取计费类型
     */
    ChargeType getChargeType();
}

2. 按电量计费策略

复制代码
import org.springframework.stereotype.Component;
import java.math.BigDecimal;

/**
 * 按电量计费策略
 */
@Component
public class ByPowerChargeStrategy implements IChargeStrategy {
    @Override
    public BigDecimal calculateBaseFee(BigDecimal power, BigDecimal powerPrice, BigDecimal servicePrice) {
        // 总费用 = 电量*(电费+服务费),高精度计算
        return power.multiply(powerPrice.add(servicePrice));
    }

    @Override
    public ChargeType getChargeType() {
        return ChargeType.BY_POWER;
    }
}

3. 按时长计费策略

复制代码
import org.springframework.stereotype.Component;
import java.math.BigDecimal;

/**
 * 按时长计费策略
 */
@Component
public class ByTimeChargeStrategy implements IChargeStrategy {
    @Override
    public BigDecimal calculateBaseFee(BigDecimal time, BigDecimal powerPrice, BigDecimal servicePrice) {
        // 总费用 = 时长*(电费+服务费)
        return time.multiply(powerPrice.add(servicePrice));
    }

    @Override
    public ChargeType getChargeType() {
        return ChargeType.BY_TIME;
    }
}

4. 策略工厂(动态匹配计费规则)

复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 计费策略工厂
 */
@Component
public class ChargeStrategyFactory {
    private final Map<ChargeType, IChargeStrategy> strategyMap;

    // 自动注入所有计费策略
    @Autowired
    public ChargeStrategyFactory(List<IChargeStrategy> strategyList) {
        this.strategyMap = strategyList.stream()
                .collect(Collectors.toMap(IChargeStrategy::getChargeType, Function.identity()));
    }

    // 获取对应计费策略
    public IChargeStrategy getStrategy(ChargeType chargeType) {
        return strategyMap.get(chargeType);
    }
}

四、优惠计算服务

复制代码
import org.springframework.stereotype.Service;
import java.math.BigDecimal;

/**
 * 优惠计算服务
 */
@Service
public class DiscountCalculateService {

    /**
     * 计算总优惠金额
     */
    public BigDecimal calculateTotalDiscount(BigDecimal originalFee, Long userId, 
                                           Long couponId, Boolean isGroupBuy) {
        BigDecimal discount = BigDecimal.ZERO;
        // 1. 会员折扣(95折)
        discount = discount.add(calculateMemberDiscount(originalFee));
        // 2. 优惠券抵扣
        discount = discount.add(calculateCouponDiscount(couponId));
        // 3. 拼团优惠(立减5元)
        if (Boolean.TRUE.equals(isGroupBuy)) {
            discount = discount.add(new BigDecimal("5.00"));
        }
        // 优惠金额不能大于原始费用
        return discount.min(originalFee);
    }

    // 会员折扣
    private BigDecimal calculateMemberDiscount(BigDecimal originalFee) {
        return originalFee.multiply(new BigDecimal("0.05"));
    }

    // 优惠券抵扣(固定10元)
    private BigDecimal calculateCouponDiscount(Long couponId) {
        if (couponId == null) return BigDecimal.ZERO;
        return new BigDecimal("10.00");
    }
}

五、核心业务服务实现

1. 电价模板缓存服务(Redis)

复制代码
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

/**
 * 电价模板缓存服务
 */
@Service
public class PriceCacheService {
    private static final String PRICE_CACHE_KEY = "electricity:price:template:";
    
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    // 缓存电价模板
    public void setPriceTemplate(Long stationId, ElectricityPriceTemplate template) {
        redisTemplate.opsForValue().set(PRICE_CACHE_KEY + stationId, template);
    }

    // 获取电价模板
    public ElectricityPriceTemplate getPriceTemplate(Long stationId) {
        return (ElectricityPriceTemplate) redisTemplate.opsForValue().get(PRICE_CACHE_KEY + stationId);
    }

    // 删除缓存
    public void deletePriceTemplate(Long stationId) {
        redisTemplate.delete(PRICE_CACHE_KEY + stationId);
    }
}

2. 计费核心服务(实现所有业务接口)

复制代码
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalTime;

/**
 * 计费定价核心服务
 */
@Service
public class PriceCalculateService {
    @Resource
    private ChargeStrategyFactory strategyFactory;
    @Resource
    private DiscountCalculateService discountService;
    @Resource
    private PriceCacheService cacheService;

    /**
     * 1. 实时计费接口(核心)
     * 业务逻辑:时段判断→匹配电价→计算基础费用→叠加优惠→计算实付
     */
    public ChargeResultRespDTO realTimeCalculate(RealTimeChargeReqDTO reqDTO) {
        // 1. 时段判断 + 匹配电价模板(Redis缓存查询)
        ElectricityPriceTemplate template = matchPriceTemplate(reqDTO.getStationId(), reqDTO.getDeviceType());
        if (template == null) {
            throw new RuntimeException("未找到对应电价模板");
        }

        // 2. 获取计费策略,计算基础费用
        IChargeStrategy strategy = strategyFactory.getStrategy(template.getChargeType());
        BigDecimal baseFee = strategy.calculateBaseFee(
                reqDTO.getPower(),
                template.getPowerPrice(),
                template.getServicePrice()
        );

        // 3. 叠加所有优惠
        BigDecimal discount = discountService.calculateTotalDiscount(
                baseFee, reqDTO.getUserId(), reqDTO.getCouponId(), reqDTO.getIsGroupBuy()
        );

        // 4. 计算实付金额(高精度)
        BigDecimal actualFee = baseFee.subtract(discount);

        // 5. 封装结果
        ChargeResultRespDTO resp = new ChargeResultRespDTO();
        resp.setOriginalTotal(baseFee);
        resp.setDiscountAmount(discount);
        resp.setActualTotal(actualFee);
        resp.setDetail("计费完成:电费+服务费,叠加会员/优惠券/拼团优惠");
        return resp;
    }

    /**
     * 2. 费用预估算接口(扫码前使用)
     */
    public ChargeResultRespDTO estimateFee(FeeEstimateReqDTO reqDTO) {
        ElectricityPriceTemplate template = matchPriceTemplate(reqDTO.getStationId(), reqDTO.getDeviceType());
        IChargeStrategy strategy = strategyFactory.getStrategy(reqDTO.getChargeType());
        BigDecimal estimateFee = strategy.calculateBaseFee(
                reqDTO.getEstimatePower(),
                template.getPowerPrice(),
                template.getServicePrice()
        );

        ChargeResultRespDTO resp = new ChargeResultRespDTO();
        resp.setOriginalTotal(estimateFee);
        resp.setDiscountAmount(BigDecimal.ZERO);
        resp.setActualTotal(estimateFee);
        resp.setDetail("费用预估完成,未叠加优惠");
        return resp;
    }

    /**
     * 3. 匹配电价模板(全局/场站专属/设备类型)
     */
    private ElectricityPriceTemplate matchPriceTemplate(Long stationId, DeviceType deviceType) {
        // 优先查缓存
        ElectricityPriceTemplate template = cacheService.getPriceTemplate(stationId);
        if (template != null) return template;

        // 缓存无数据,查询数据库(模拟)
        template = new ElectricityPriceTemplate();
        template.setStationId(stationId);
        template.setDeviceType(deviceType);
        template.setPowerPrice(new BigDecimal("1.00"));
        template.setServicePrice(new BigDecimal("0.50"));
        template.setChargeType(ChargeType.BY_POWER);
        template.setStatus(1);

        // 存入缓存
        cacheService.setPriceTemplate(stationId, template);
        return template;
    }

    /**
     * 4. 价格策略启用/停用
     */
    public void updatePriceStatus(Long templateId, Integer status) {
        // 1. 更新数据库状态
        // 2. 删除缓存,保证下次查询最新数据
        cacheService.deletePriceTemplate(templateId);
    }

    /**
     * 判断当前时段(峰/谷/平)
     */
    private TimePeriodType getCurrentPeriod() {
        LocalTime now = LocalTime.now();
        // 峰时段:8:00-22:00
        if (now.isAfter(LocalTime.of(8,0)) && now.isBefore(LocalTime.of(22,0))) {
            return TimePeriodType.PEAK;
        }
        // 谷时段:22:00-次日8:00
        return TimePeriodType.VALLEY;
    }
}

六、定时任务(XXL-Job 定时切换峰谷电价)

复制代码
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;

/**
 * 定时切换峰谷电价任务
 */
@Component
public class PriceTimeTask {
    @Resource
    private PriceCalculateService priceService;

    /**
     * 每日8点切换为峰时段电价
     */
    @XxlJob("switchToPeakPriceJob")
    public void switchToPeakPrice() {
        // 执行峰电价启用逻辑
        System.out.println("定时任务:切换为峰时段电价");
    }

    /**
     * 每日22点切换为谷时段电价
     */
    @XxlJob("switchToValleyPriceJob")
    public void switchToValleyPrice() {
        // 执行谷电价启用逻辑
        System.out.println("定时任务:切换为谷时段电价");
    }
}

七、Feign 远程调用接口(供充电服务调用)

复制代码
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

/**
 * 充电服务调用计费服务的Feign接口
 */
@FeignClient(name = "price-service")
public interface PriceFeignClient {

    @PostMapping("/price/real-time-calculate")
    ChargeResultRespDTO realTimeCalculate(@RequestBody RealTimeChargeReqDTO reqDTO);

    @PostMapping("/price/estimate-fee")
    ChargeResultRespDTO estimateFee(@RequestBody FeeEstimateReqDTO reqDTO);
}

八、Controller 接口层

复制代码
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;

/**
 * 计费服务接口
 */
@RestController
@RequestMapping("/price")
public class PriceController {
    @Resource
    private PriceCalculateService priceService;

    /**
     * 实时计费接口
     */
    @PostMapping("/real-time-calculate")
    public ChargeResultRespDTO realTimeCalculate(@RequestBody RealTimeChargeReqDTO reqDTO) {
        return priceService.realTimeCalculate(reqDTO);
    }

    /**
     * 费用预估接口
     */
    @PostMapping("/estimate-fee")
    public ChargeResultRespDTO estimateFee(@RequestBody FeeEstimateReqDTO reqDTO) {
        return priceService.estimateFee(reqDTO);
    }

    /**
     * 更新电价状态
     */
    @PutMapping("/update-status/{templateId}/{status}")
    public String updateStatus(@PathVariable Long templateId, @PathVariable Integer status) {
        priceService.updatePriceStatus(templateId, status);
        return "更新成功";
    }
}

九、核心业务逻辑详细说明

1. 整体业务流程(核心)

时段判断 → 匹配电价 → 计算基础费用 → 叠加优惠 → 计算实付金额

  1. 时段判断:系统自动获取当前时间,匹配峰 / 谷 / 平时段;
  2. 匹配电价 :优先从 Redis 缓存获取,支持全局模板、场站专属、设备类型(直流 / 交流) 三级匹配;
  3. 基础计费 :通过策略模式动态选择按时长 / 按电量计算电费 + 服务费;
  4. 优惠叠加:自动计算会员折扣、优惠券、活动立减、拼团优惠;
  5. 实付计算 :使用BigDecimal高精度运算,避免金额精度丢失。

2. 核心接口业务说明

接口 业务功能 调用场景
实时计费接口 充电过程中动态计算当前总费用、优惠、实付金额 充电服务实时调用,毫秒级返回
费用预估算接口 扫码前根据预估电量 / 时长计算费用 用户扫码充电前展示预估价格
电价模板配置 配置峰谷平时段、电费、服务费、场站 / 设备专属价格 运营后台管理
价格策略启停 启用 / 停用电价模板,定时生效 运营后台 + 定时任务

3. 技术实现亮点

  1. 策略模式:拆分计费规则,新增阶梯电价无需修改原有代码;
  2. Redis 缓存:全局电价、场站价格秒级查询,支撑高并发;
  3. XXL-Job:定时自动切换峰谷电价,无需人工操作;
  4. Feign 调用:微服务间远程调用,毫秒级响应;
  5. 高精度计算 :全程使用BigDecimal,杜绝金额浮点误差。

总结

  1. 实现完全覆盖电价配置、实时计费、费用预估、优惠计算、定时生效、缓存优化所有需求;
  2. 采用策略模式 + 规则引擎实现灵活的计费规则扩展,支持后续新增阶梯电价、分时服务费;
  3. 代码遵循微服务最佳实践,可直接集成到 SpringCloud 项目中,支持高并发、高精度计费场景。
相关推荐
敲敲千反田1 小时前
ThreadLocal和CompletableFuture
java·网络·jvm
qq_435287921 小时前
第18章 闻仲西征:单体应用被分布式集群拖垮?十战十捷是回光返照
分布式·微服务·分布式架构·健康检查·单体应用·闻仲·垂直扩展
码云数智-园园1 小时前
Spring循环依赖:三级缓存到底解决了什么,没解决什么?
java·后端·spring
vx-程序开发1 小时前
PHP书店网站-计算机毕业设计源码05274
开发语言·php·课程设计
陈eaten1 小时前
windows上协调多版本python以及虚拟环境
开发语言·windows·python·pycharm·pip·虚拟环境·py
龙亘川1 小时前
城市更新×智慧治理:老旧小区改造中的数字化创新实践
java·大数据·人工智能·机器学习·智慧城市
无所事事O_o1 小时前
OPENSSL生成非对称加密公私钥
java·加密
一晌小贪欢1 小时前
告别 `datetime` 混乱:使用 Python 类型注解构建健壮的时间处理管道
开发语言·python·时间·时间类型·时间模块
小白君6531 小时前
互联网大厂Java面试:从Spring Boot到微服务的技术场景深度解析
spring boot·redis·微服务·消息队列·java面试·数据库优化