一、整体架构设计
技术栈
- 框架:SpringBoot 3.x + Spring MVC + Spring Task(定时任务)
- 存储:MySQL(订单主表 + 详情表)
- 交互:RESTful API 接口,Feign/HTTP 调用依赖服务(充电 / 计费 / 支付)
- 规范:面向接口编程,统一返回结果
核心模块划分
- 实体层:订单枚举、订单主表、订单详情表
- DAO 层:Mapper 数据访问
- Service 层:核心业务逻辑(接口 + 实现)
- Controller 层:对外 API 接口
- 定时任务:异常订单自动修复
- 远程调用:依赖服务接口
二、核心实体定义(Java Bean)
1. 订单状态枚举(核心业务状态)
/**
* 订单状态枚举
* 待支付、充电中、已完成、已取消、异常
*/
public enum OrderStatus {
PENDING_PAYMENT, // 待支付
CHARGING, // 充电中
COMPLETED, // 已完成
CANCELED, // 已取消
ABNORMAL // 异常订单
}
2. 订单主表实体
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
public class Order {
private Long id; // 主键ID
private String orderNo; // 订单号(唯一)
private Long userId; // 用户ID
private Long deviceId; // 设备ID(充电桩)
private Long stationId; // 场站ID
private OrderStatus orderStatus;// 订单状态
private BigDecimal totalPower; // 总电量(度)
private Integer chargeDuration; // 充电时长(秒)
private BigDecimal originalPrice;// 原价
private BigDecimal discountPrice;// 优惠价
private BigDecimal actualPrice; // 实付价
private LocalDateTime createTime;// 创建时间
private LocalDateTime updateTime;// 更新时间
private String remark; // 备注(异常原因)
}
3. 订单详情 DTO(接口传输对象)
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class OrderDetailDTO {
private String orderNo;
private Long userId;
private Long deviceId;
private Long stationId;
private OrderStatus orderStatus;
private BigDecimal totalPower;
private Integer chargeDuration;
private BigDecimal originalPrice;
private BigDecimal discountPrice;
private BigDecimal actualPrice;
private LocalDateTime createTime;
}
三、服务接口定义(核心业务接口)
这是订单服务对外暴露的核心接口,完全匹配你要求的:创建订单、订单状态查询、订单详情查询。
/**
* 订单服务核心接口
*/
public interface OrderService {
/**
* 1. 创建订单(充电启动时调用)
* 业务:生成待支付订单,关联用户/设备/场站
*/
Order createOrder(Long userId, Long deviceId, Long stationId);
/**
* 2. 查询订单状态
*/
OrderStatus getOrderStatus(String orderNo);
/**
* 3. 查询订单详情
*/
OrderDetailDTO getOrderDetail(String orderNo);
/**
* 4. 充电中更新订单数据(电量/时长)
*/
void updateChargingData(String orderNo, BigDecimal totalPower, Integer chargeDuration);
/**
* 5. 充电结束,计算费用并更新订单
*/
void finishCharge(String orderNo);
/**
* 6. 支付成功,完结订单
*/
void paySuccess(String orderNo);
/**
* 7. 取消订单
*/
void cancelOrder(String orderNo);
/**
* 8. 异常订单自动修复(定时任务调用)
*/
void autoRepairAbnormalOrders();
}
四、接口实现类(核心业务逻辑详解)
这是最关键的业务实现,我会逐方法讲解业务含义 + 代码逻辑。
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.UUID;
@Service
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {
private final OrderMapper orderMapper;
// 远程调用:计费服务
private final BillingService billingService;
// 远程调用:支付服务
private final PaymentService paymentService;
// ====================== 核心业务实现 ======================
/**
* 1. 创建订单
* 业务场景:用户启动充电 → 充电服务调用此接口 → 生成【待支付】空订单
* 业务规则:
* 1. 生成唯一订单号
* 2. 初始状态:待支付
* 3. 初始电量/时长/金额为0
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Order createOrder(Long userId, Long deviceId, Long stationId) {
Order order = new Order();
// 生成唯一订单号(时间戳+UUID)
String orderNo = "ORDER_" + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().replace("-", "").substring(0, 8);
order.setOrderNo(orderNo);
order.setUserId(userId);
order.setDeviceId(deviceId);
order.setStationId(stationId);
// 初始状态:待支付
order.setOrderStatus(OrderStatus.PENDING_PAYMENT);
// 初始数据
order.setTotalPower(BigDecimal.ZERO);
order.setChargeDuration(0);
order.setOriginalPrice(BigDecimal.ZERO);
order.setDiscountPrice(BigDecimal.ZERO);
order.setActualPrice(BigDecimal.ZERO);
order.setCreateTime(LocalDateTime.now());
order.setUpdateTime(LocalDateTime.now());
// 入库
orderMapper.insert(order);
return order;
}
/**
* 2. 查询订单状态
* 业务:用户/设备/运营端查询当前订单处于什么阶段
*/
@Override
public OrderStatus getOrderStatus(String orderNo) {
Order order = orderMapper.selectByOrderNo(orderNo);
if (order == null) {
throw new RuntimeException("订单不存在");
}
return order.getOrderStatus();
}
/**
* 3. 查询订单详情
* 业务:用户查看历史订单、运营端对账
*/
@Override
public OrderDetailDTO getOrderDetail(String orderNo) {
Order order = orderMapper.selectByOrderNo(orderNo);
if (order == null) {
throw new RuntimeException("订单不存在");
}
// 转换为DTO返回
OrderDetailDTO dto = new OrderDetailDTO();
// 属性拷贝(可使用BeanUtils)
dto.setOrderNo(order.getOrderNo());
dto.setUserId(order.getUserId());
dto.setDeviceId(order.getDeviceId());
dto.setStationId(order.getStationId());
dto.setOrderStatus(order.getOrderStatus());
dto.setTotalPower(order.getTotalPower());
dto.setChargeDuration(order.getChargeDuration());
dto.setOriginalPrice(order.getOriginalPrice());
dto.setDiscountPrice(order.getDiscountPrice());
dto.setActualPrice(order.getActualPrice());
dto.setCreateTime(order.getCreateTime());
return dto;
}
/**
* 4. 充电中更新数据(实时上报)
* 业务:充电桩实时上传电量、时长 → 订单服务更新数据
* 状态约束:必须是【充电中/待支付】才能更新
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void updateChargingData(String orderNo, BigDecimal totalPower, Integer chargeDuration) {
Order order = orderMapper.selectByOrderNo(orderNo);
if (order == null) throw new RuntimeException("订单不存在");
// 状态校验:只有待支付/充电中可以更新
if (order.getOrderStatus() != OrderStatus.PENDING_PAYMENT
&& order.getOrderStatus() != OrderStatus.CHARGING) {
throw new RuntimeException("订单状态不允许更新充电数据");
}
// 更新为充电中状态
order.setOrderStatus(OrderStatus.CHARGING);
order.setTotalPower(totalPower);
order.setChargeDuration(chargeDuration);
order.setUpdateTime(LocalDateTime.now());
orderMapper.updateById(order);
}
/**
* 5. 充电结束 → 计算费用
* 业务流程:
* 1. 调用计费服务,根据电量/时长计算 原价、优惠价、实付价
* 2. 更新订单金额
* 3. 状态改为【待支付】
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void finishCharge(String orderNo) {
Order order = orderMapper.selectByOrderNo(orderNo);
if (order == null) throw new RuntimeException("订单不存在");
if (order.getOrderStatus() != OrderStatus.CHARGING) {
throw new RuntimeException("只有充电中订单可以结束充电");
}
// 远程调用【计费服务】计算费用
BillingDTO billing = billingService.calculateFee(
order.getTotalPower(),
order.getStationId()
);
// 更新订单价格
order.setOriginalPrice(billing.getOriginalPrice());
order.setDiscountPrice(billing.getDiscountPrice());
order.setActualPrice(billing.getActualPrice());
// 充电结束 → 状态改为待支付
order.setOrderStatus(OrderStatus.PENDING_PAYMENT);
order.setUpdateTime(LocalDateTime.now());
orderMapper.updateById(order);
}
/**
* 6. 支付成功 → 订单完结
* 业务:支付服务回调 → 订单改为【已完成】
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void paySuccess(String orderNo) {
Order order = orderMapper.selectByOrderNo(orderNo);
if (order == null) throw new RuntimeException("订单不存在");
if (order.getOrderStatus() != OrderStatus.PENDING_PAYMENT) {
throw new RuntimeException("只有待支付订单可以支付");
}
order.setOrderStatus(OrderStatus.COMPLETED);
order.setUpdateTime(LocalDateTime.now());
orderMapper.updateById(order);
}
/**
* 7. 取消订单
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void cancelOrder(String orderNo) {
Order order = orderMapper.selectByOrderNo(orderNo);
if (order == null) throw new RuntimeException("订单不存在");
order.setOrderStatus(OrderStatus.CANCELED);
order.setRemark("用户主动取消/系统取消");
order.setUpdateTime(LocalDateTime.now());
orderMapper.updateById(order);
}
/**
* 8. 异常订单自动修复(定时任务)
* 业务规则:
* 1. 充电中超过24小时未结束 → 标记异常
* 2. 待支付超过1小时 → 自动取消
* 3. 无状态订单 → 修复为待支付
*/
@Override
@Transactional
public void autoRepairAbnormalOrders() {
// 1. 查询超过24小时充电中订单 → 标记异常
orderMapper.updateChargingTimeoutToAbnormal();
// 2. 查询超过1小时待支付未支付 → 自动取消
orderMapper.updatePendingPaymentToCancel();
// 3. 无电量/无状态异常订单 → 修复
orderMapper.repairNullDataOrders();
}
}
五、Controller 层(对外 API 接口)
提供给前端 / 其他微服务调用的 HTTP 接口。
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/order")
@RequiredArgsConstructor
public class OrderController {
private final OrderService orderService;
/**
* 创建订单
*/
@PostMapping("/create")
public Result<Order> createOrder(
@RequestParam Long userId,
@RequestParam Long deviceId,
@RequestParam Long stationId) {
return Result.success(orderService.createOrder(userId, deviceId, stationId));
}
/**
* 查询订单状态
*/
@GetMapping("/status/{orderNo}")
public Result<OrderStatus> getOrderStatus(@PathVariable String orderNo) {
return Result.success(orderService.getOrderStatus(orderNo));
}
/**
* 查询订单详情
*/
@GetMapping("/detail/{orderNo}")
public Result<OrderDetailDTO> getOrderDetail(@PathVariable String orderNo) {
return Result.success(orderService.getOrderDetail(orderNo));
}
/**
* 取消订单
*/
@PostMapping("/cancel/{orderNo}")
public Result<Void> cancelOrder(@PathVariable String orderNo) {
orderService.cancelOrder(orderNo);
return Result.success();
}
}
六、定时任务(异常订单自动修复)
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* 订单定时任务:异常修复
*/
@Component
@RequiredArgsConstructor
public class OrderScheduleTask {
private final OrderService orderService;
/**
* 每10分钟执行一次:异常订单自动修复
* 解决:充电中断、超时未支付、状态异常
*/
@Scheduled(fixedRate = 600000)
public void autoRepairOrder() {
orderService.autoRepairAbnormalOrders();
}
}
七、完整业务流程讲解(最核心!)
这是订单服务串联充电、计费、支付三大服务的标准生命周期:
1. 启动充电
- 充电服务调用
createOrder() - 生成订单,状态 = 待支付
- 订单电量 / 金额 = 0
2. 充电过程
- 充电桩实时上报数据
- 调用
updateChargingData() - 订单状态改为 充电中
- 实时更新电量、时长
3. 停止充电
- 调用
finishCharge() - 远程调用计费服务计算费用
- 订单写入:原价、优惠价、实付价
- 状态改为 待支付
4. 用户支付
- 支付服务完成支付后回调
- 调用
paySuccess() - 状态改为 已完成
- 订单生命周期结束
5. 异常处理
- 充电中断超过 24 小时 → 标记异常
- 待支付 1 小时未支付 → 自动取消
- 定时任务自动修复,保证数据一致性
八、依赖服务交互说明
- 充电服务
- 调用:创建订单、更新充电数据、结束充电
- 计费服务
- 订单结束时调用,计算费用
- 支付服务
- 支付成功回调,完结订单
九、关键业务规则总结
- 状态不可逆已完成 / 已取消 → 不能再修改充电数据
- 数据强校验只有充电中订单可以结束充电
- 事务保证所有订单写操作加事务,异常回滚
- 自动修复定时任务解决充电中断、系统异常导致的脏订单
- 财务依据订单数据不可删除,只更新状态,用于对账
总结
- 这套代码可直接用于 SpringBoot 项目开发
- 接口包含:创建订单、状态查询、详情查询三大核心对外接口
- 完整实现了订单生命周期:待支付 → 充电中 → 待支付 → 已完成 / 已取消 / 异常
- 包含异常自动修复 、事务控制 、微服务远程调用等生产级特性
- 是充电平台财务和对账的核心数据服务