1. 项目背景与核心价值
超市在线配送管理系统是当前零售行业数字化转型中的关键基础设施。我在2018年参与过某连锁超市的配送系统升级项目,当时他们还在使用Excel表格手动分配配送任务,每天凌晨3点工作人员就要开始手工计算最优路线,经常出现漏单、错单的情况。而基于Java SSM框架实现的在线配送系统,能够将订单处理效率提升300%以上。
这个开源项目采用经典的SSM(Spring+SpringMVC+MyBatis)技术栈构建,特别适合Java开发者学习企业级应用开发的全流程。与市面上其他教学项目不同,它完整实现了从商品管理、订单处理到配送调度的全链条功能,包含了实际业务中常见的复杂查询、事务处理和高并发场景解决方案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构解析
2.1 SSM框架选型考量
选择SSM而非Spring Boot是考虑到教学项目的渐进式学习需求。在IntelliJ IDEA中手动配置SSM环境能让开发者更清晰地理解各组件间的依赖关系。项目中特别值得注意的配置包括:
- Spring事务管理的声明式配置
xml复制<!-- 在applicationContext.xml中 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
- MyBatis的动态SQL实践
java复制<!-- 在Mapper.xml中 -->
<select id="findAvailableDrivers" resultType="Driver">
SELECT * FROM driver
WHERE status = '空闲'
<if test="currentLocation != null">
AND current_location = #{currentLocation}
</if>
ORDER BY rating DESC
</select>
2.2 数据库设计要点
系统采用MySQL 5.7,包含12张核心表。配送调度相关的表设计体现了几个关键技巧:
- 配送区域表使用空间索引优化地理查询
sql复制CREATE TABLE delivery_zone (
zone_id INT PRIMARY KEY,
zone_name VARCHAR(50),
polygon GEOMETRY NOT NULL SRID 4326,
SPATIAL INDEX(polygon)
);
- 订单表采用垂直分表设计,将频繁更新的配送状态单独存放
sql复制CREATE TABLE orders (
order_id BIGINT PRIMARY KEY,
customer_id INT,
total_amount DECIMAL(10,2),
create_time DATETIME
/* 其他静态字段 */
);
CREATE TABLE order_delivery_status (
order_id BIGINT PRIMARY KEY,
driver_id INT,
status ENUM('待分配','已接单','配送中','已完成','已取消'),
update_time DATETIME
);
3. 核心功能实现细节
3.1 智能配送调度算法
系统采用改进的贪心算法实现自动派单,核心逻辑在DeliveryScheduler类中实现:
java复制public class DeliveryScheduler {
private static final int MAX_ORDERS_PER_DRIVER = 5;
public List<Assignment> assignOrders(List<Order> orders, List<Driver> drivers) {
// 按订单创建时间排序
orders.sort(Comparator.comparing(Order::getCreateTime));
// 按司机评分和当前位置筛选
List<Driver> availableDrivers = drivers.stream()
.filter(d -> d.getStatus() == DriverStatus.IDLE)
.sorted(Comparator.comparing(Driver::getRating).reversed())
.collect(Collectors.toList());
List<Assignment> assignments = new ArrayList<>();
for (Order order : orders) {
// 查找3公里内评分最高的空闲司机
Optional<Driver> matchedDriver = availableDrivers.stream()
.filter(d -> distance(d.getLocation(), order.getAddress()) < 3)
.findFirst();
if (matchedDriver.isPresent()) {
Driver driver = matchedDriver.get();
assignments.add(new Assignment(order, driver));
driver.setCurrentOrders(driver.getCurrentOrders() + 1);
if (driver.getCurrentOrders() >= MAX_ORDERS_PER_DRIVER) {
availableDrivers.remove(driver);
}
}
}
return assignments;
}
}
3.2 高并发订单处理
在促销活动期间,系统需要处理突发流量。我们采用以下策略保证稳定性:
- 使用Redis缓存热门商品和库存数据
java复制@Service
public class InventoryService {
@Autowired
private RedisTemplate<String, Integer> redisTemplate;
@Transactional
public boolean reduceStock(Long productId, int quantity) {
String key = "stock:" + productId;
Long remaining = redisTemplate.opsForValue().decrement(key, quantity);
if (remaining != null && remaining >= 0) {
// 异步更新数据库
asyncUpdateDBStock(productId, quantity);
return true;
} else {
// 库存不足,回滚
redisTemplate.opsForValue().increment(key, quantity);
return false;
}
}
}
- 订单表采用分库分表策略,按日期范围分片
4. 项目部署与调优
4.1 IDEA开发环境配置
-
推荐使用IntelliJ IDEA 2022.3+版本,需要特别注意:
- 配置Tomcat 9.x服务器
- 设置Java Compiler为JDK 1.8
- 安装Lombok插件避免getter/setter报错
-
数据库连接池配置(druid推荐)
properties复制# application.properties
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/supermarket?useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.druid.initial-size=5
spring.datasource.druid.max-active=20
spring.datasource.druid.test-while-idle=true
4.2 性能优化实战
通过JProfiler分析发现,配送路线计算是性能瓶颈。优化方案:
- 引入Google OR-Tools进行路线规划
java复制public class RouteOptimizer {
public static List<Order> optimizeRoute(List<Order> orders, Location warehouse) {
RoutingModel routing = new RoutingModel(orders.size(), 1, 0);
// 设置距离计算回调
routing.SetArcCostEvaluatorOfVehicle(new DistanceCallback(), 0);
// 设置搜索参数
RoutingSearchParameters searchParameters =
RoutingModel.defaultSearchParameters();
searchParameters.setFirstSolutionStrategy(
FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC);
// 求解
Assignment solution = routing.solveWithParameters(searchParameters);
return extractOptimizedRoute(orders, routing, solution);
}
}
- 使用Caffeine缓存历史配送路线
java复制@Configuration
public class CacheConfig {
@Bean
public Cache<String, RoutePlan> routeCache() {
return Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(1, TimeUnit.HOURS)
.build();
}
}
5. 典型业务场景实现
5.1 订单状态机设计
采用状态模式实现订单生命周期管理:
java复制public interface OrderState {
void confirm(OrderContext context);
void cancel(OrderContext context);
void deliver(OrderContext context);
void complete(OrderContext context);
}
@Service
public class OrderServiceImpl implements OrderService {
private Map<OrderStatus, OrderState> states;
@PostConstruct
public void init() {
states = Map.of(
OrderStatus.PENDING, new PendingState(),
OrderStatus.CONFIRMED, new ConfirmedState(),
// 其他状态...
);
}
@Override
@Transactional
public void cancelOrder(Long orderId) {
Order order = orderDao.findById(orderId);
states.get(order.getStatus()).cancel(new OrderContext(order));
}
}
5.2 实时位置追踪
集成WebSocket实现配送员实时定位:
java复制@Controller
public class TrackingController {
@Autowired
private SimpMessagingTemplate messagingTemplate;
@MessageMapping("/tracking.update")
public void updateLocation(LocationUpdate update) {
// 更新数据库
driverService.updateLocation(update.getDriverId(),
update.getLatitude(), update.getLongitude());
// 广播给相关客户
messagingTemplate.convertAndSend(
"/topic/tracking." + update.getOrderId(),
new TrackingResponse(update));
}
}
前端配合使用高德地图JS API实现轨迹绘制:
javascript复制const map = new AMap.Map('map-container');
const marker = new AMap.Marker({ map: map });
const polyline = new AMap.Polyline({ map: map });
socket.subscribe(`/topic/tracking.${orderId}`, (response) => {
const position = [response.longitude, response.latitude];
marker.setPosition(position);
path.push(position);
polyline.setPath(path);
map.setCenter(position);
});
6. 项目扩展方向
- 智能预测:基于历史订单数据,使用TensorFlow Java API实现需求预测
java复制public class DemandPredictor {
public Map<Long, Integer> predictDailyDemand() {
try (SavedModelBundle model = SavedModelBundle.load("model/predict", "serve")) {
// 准备输入数据...
Tensor<?> input = Tensor.create(inputData);
List<Tensor<?>> outputs = model.session().runner()
.feed("input", input)
.fetch("output")
.run();
// 解析预测结果...
return predictionMap;
}
}
}
- 语音通知:集成阿里云语音服务实现配送状态自动通知
java复制public class VoiceNotifier {
public void sendDeliveryNotice(String phone, String message) {
DefaultProfile profile = DefaultProfile.getProfile(
"cn-hangzhou", accessKeyId, accessKeySecret);
IAcsClient client = new DefaultAcsClient(profile);
SingleCallByVoiceRequest request = new SingleCallByVoiceRequest();
request.setCalledNumber(phone);
request.setVoiceCode("TTS_123456");
request.setCalledShowNumber("4001234567");
request.setPlayTimes(2);
try {
SingleCallByVoiceResponse response = client.getAcsResponse(request);
log.info("语音通知已发送: {}", response.getRequestId());
} catch (Exception e) {
log.error("语音通知发送失败", e);
}
}
}
- 移动端适配:使用Uniapp快速构建管理端和小程序端
javascript复制// 在uniapp中调用后端API
export function getOrderDetail(orderId) {
return uni.request({
url: '/api/orders/' + orderId,
method: 'GET',
header: {
'Authorization': 'Bearer ' + store.state.token
}
});
}
