在餐饮行业数字化转型的浪潮中,一套高效、稳定的在线订餐平台成为餐饮商家提升运营效率、优化顾客体验的关键工具。本文介绍的企业级外卖管理平台,采用经典的SSH(Struts2 + Spring + Hibernate)框架技术栈,实现了从菜单展示、在线下单到订单管理的全流程自动化处理。
系统架构与技术栈
该平台采用典型的三层架构设计,各层职责分明,实现了高内聚低耦合的软件工程原则。
表现层基于Struts2框架构建,通过配置struts.xml文件定义请求路由,Action类负责接收前端参数并调用业务逻辑。Struts2的拦截器机制提供了统一的权限验证、数据校验等功能。
<!-- struts.xml 配置示例 -->
<struts>
<package name="food" extends="struts-default">
<action name="goods_*" class="goodsAction" method="{1}">
<result name="success">/goods_{1}.jsp</result>
</action>
<action name="order_*" class="orderAction" method="{1}">
<result name="success">/order_{1}.jsp</result>
</action>
</package>
</struts>
业务逻辑层由Spring框架托管,通过IoC容器管理Bean的生命周期和依赖关系。@Service注解标识的业务组件处理核心业务规则,并通过@Transactional注解实现声明式事务管理。
@Service("orderService")
@Transactional
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderDAO orderDAO;
@Autowired
private GoodsDAO goodsDAO;
@Override
public void createOrder(Order order, List<OrderItem> items) {
// 保存订单主信息
orderDAO.save(order);
// 保存订单明细并更新库存
for (OrderItem item : items) {
orderDAO.saveItem(item);
goodsDAO.updateStock(item.getGoods_id(),
-item.getGoods_quantity());
}
}
}
数据持久层采用Hibernate实现ORM映射,实体类通过注解方式定义与数据库表的对应关系,DAO层使用HibernateTemplate简化数据库操作。
@Entity
@Table(name = "t_order")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer order_id;
private String order_bianhao;
private String order_date;
private String order_zhuangtai;
private String order_songhuodizhi;
private String order_fukuangfangshi;
private Integer order_jine;
private Integer order_user_id;
// 一对多关联订单项
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private Set<OrderItem> orderItems = new HashSet<>();
// getter/setter方法
}
数据库设计亮点分析
订单模块的规范化设计
订单表(t_order)和订单项表(t_orderitem)的设计体现了良好的数据库规范化原则。订单表存储订单的核心信息,而订单项表通过order_id外键关联,实现了一对多的关系映射。
-- 订单表核心字段设计
CREATE TABLE `t_order` (
`order_id` int(11) NOT NULL COMMENT '订单ID',
`order_bianhao` varchar(50) DEFAULT NULL COMMENT '订单编号',
`order_date` varchar(50) DEFAULT NULL COMMENT '订单日期',
`order_zhuangtai` varchar(50) DEFAULT NULL COMMENT '订单状态',
`order_songhuodizhi` varchar(50) DEFAULT NULL COMMENT '送货地址',
`order_fukuangfangshi` varchar(50) DEFAULT NULL COMMENT '付款方式',
`order_jine` int(11) DEFAULT NULL COMMENT '订单金额',
`order_user_id` int(11) DEFAULT NULL COMMENT '用户ID',
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 订单项表设计,支持一个订单多个商品
CREATE TABLE `t_orderitem` (
`orderItem_id` int(11) NOT NULL COMMENT '订单项ID',
`order_id` int(11) DEFAULT NULL COMMENT '订单ID',
`goods_id` int(11) DEFAULT NULL COMMENT '商品ID',
`goods_quantity` int(11) DEFAULT NULL COMMENT '商品数量',
PRIMARY KEY (`orderItem_id`),
KEY `fk_order` (`order_id`),
KEY `fk_goods` (`goods_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
这种分离设计的好处在于:
- 数据一致性:订单总金额通过应用程序计算确保准确
- 扩展性:轻松支持订单中包含多个不同商品
- 查询效率:通过索引优化关联查询性能
商品信息管理的完整性约束
商品表(t_goods)的设计考虑了电商平台的完整需求,包含了价格策略、库存管理、分类体系等核心业务字段。
CREATE TABLE `t_goods` (
`goods_id` int(11) NOT NULL COMMENT '商品ID',
`goods_name` varchar(50) DEFAULT NULL COMMENT '商品名称',
`goods_miaoshu` text DEFAULT NULL COMMENT '商品描述',
`goods_pic` varchar(50) DEFAULT NULL COMMENT '商品图片',
`goods_ISBN` varchar(50) DEFAULT NULL COMMENT '商品ISBN',
`goods_shichangjia` int(11) DEFAULT NULL COMMENT '商品市场价',
`goods_tejia` int(11) DEFAULT NULL COMMENT '商品特价',
`goods_isnottejia` varchar(50) DEFAULT NULL COMMENT '是否特价',
`goods_isnottuijian` varchar(50) DEFAULT NULL COMMENT '是否推荐',
`goods_catelog_id` int(11) DEFAULT NULL COMMENT '商品分类ID',
`goods_kucun` int(11) DEFAULT NULL COMMENT '商品库存',
`goods_Del` varchar(50) DEFAULT NULL COMMENT '删除标记',
PRIMARY KEY (`goods_id`),
KEY `idx_catelog` (`goods_catelog_id`),
KEY `idx_tejia` (`goods_isnottejia`),
KEY `idx_tuijian` (`goods_isnottuijian`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
索引策略分析:
- 分类索引(idx_catelog):加速按分类筛选商品的查询
- 特价商品索引(idx_tejia):快速定位促销商品
- 推荐商品索引(idx_tuijian):优化首页推荐商品的加载速度
核心功能实现详解
购物车与订单生成机制
购物车功能采用Session临时存储的方式,用户在浏览商品过程中可以随时添加商品到购物车。系统通过Struts2 Action处理添加请求,并维护购物车商品列表。
public class CartAction extends ActionSupport {
private List<CartItem> cartItems;
private Integer goodsId;
private Integer quantity;
// 添加商品到购物车
public String addToCart() {
Goods goods = goodsService.getGoodsById(goodsId);
CartItem item = new CartItem(goods, quantity);
// 从Session获取当前购物车
Map<Integer, CartItem> cart = getCartFromSession();
if (cart.containsKey(goodsId)) {
// 更新数量
CartItem existing = cart.get(goodsId);
existing.setQuantity(existing.getQuantity() + quantity);
} else {
cart.put(goodsId, item);
}
return SUCCESS;
}
// 生成订单
public String createOrder() {
Order order = new Order();
order.setOrder_bianhao(generateOrderNumber());
order.setOrder_date(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
order.setOrder_zhuangtai("待处理");
order.setOrder_jine(calculateTotalAmount());
List<OrderItem> orderItems = convertCartToOrderItems();
orderService.createOrder(order, orderItems);
// 清空购物车
clearCart();
return SUCCESS;
}
}

多维度商品管理后台
管理员后台提供了完整的商品生命周期管理功能,包括商品上架、信息修改、价格调整、库存管理等。
@Service("goodsService")
public class GoodsServiceImpl implements GoodsService {
@Override
public void addGoods(Goods goods) {
// 验证数据完整性
validateGoodsInfo(goods);
// 设置默认值
if (goods.getGoods_kucun() == null) {
goods.setGoods_kucun(0);
}
if (goods.getGoods_Del() == null) {
goods.setGoods_Del("否");
}
goodsDAO.save(goods);
}
@Override
public PageBean<Goods> getGoodsByPage(int page, int pageSize,
Map<String, Object> params) {
// 构建查询条件
DetachedCriteria criteria = DetachedCriteria.forClass(Goods.class);
if (params.containsKey("catelogId")) {
criteria.add(Restrictions.eq("goods_catelog_id",
params.get("catelogId")));
}
if (params.containsKey("isTejia")) {
criteria.add(Restrictions.eq("goods_isnottejia",
params.get("isTejia")));
}
// 执行分页查询
return goodsDAO.findByPage(criteria, page, pageSize);
}
@Override
@Transactional
public void updateGoodsStock(Integer goodsId, Integer quantity) {
Goods goods = goodsDAO.findById(goodsId);
if (goods != null) {
int newStock = goods.getGoods_kucun() + quantity;
if (newStock < 0) {
throw new RuntimeException("库存不足");
}
goods.setGoods_kucun(newStock);
goodsDAO.update(goods);
}
}
}

订单状态流转与跟踪
系统实现了完整的订单状态机,从"待处理"到"制作中"、"已送出"、"已完成"等状态流转,每个状态变更都记录相应的时间戳和操作人。
@Entity
@Table(name = "t_order")
public class Order {
// ... 其他字段
/**
* 订单状态流转处理
*/
public void changeStatus(String newStatus, String operator) {
// 验证状态流转合法性
if (!isValidStatusTransition(this.order_zhuangtai, newStatus)) {
throw new IllegalStateException("无效的状态流转: "
+ this.order_zhuangtai + " -> " + newStatus);
}
this.order_zhuangtai = newStatus;
// 记录状态变更日志
addStatusLog(newStatus, operator);
}
private boolean isValidStatusTransition(String from, String to) {
Map<String, List<String>> validTransitions = new HashMap<>();
validTransitions.put("待处理", Arrays.asList("制作中", "已取消"));
validTransitions.put("制作中", Arrays.asList("已送出", "已取消"));
validTransitions.put("已送出", Arrays.asList("已完成"));
return validTransitions.containsKey(from)
&& validTransitions.get(from).contains(to);
}
}

用户权限管理与安全控制
系统采用基于角色的访问控制(RBAC)模型,区分普通用户和管理员两种角色,通过拦截器实现统一的权限验证。
<!-- Spring Security 配置示例 -->
<beans:bean id="securityFilter" class="com.xxx.util.SecurityInterceptor">
<beans:property name="excludeActions">
<beans:list>
<beans:value>user_login</beans:value>
<beans:value>goods_list</beans:value>
<beans:value>index_*</beans:value>
</beans:list>
</beans:property>
</beans:bean>
public class SecurityInterceptor extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation invocation) throws Exception {
ActionContext context = invocation.getInvocationContext();
Map<String, Object> session = context.getSession();
// 检查排除列表
String actionName = invocation.getProxy().getActionName();
if (isExcludedAction(actionName)) {
return invocation.invoke();
}
// 验证用户登录状态
User user = (User) session.get("currentUser");
if (user == null) {
return "login"; // 跳转到登录页面
}
// 管理员权限验证
if (actionName.startsWith("admin_") && !user.isAdmin()) {
return "accessDenied";
}
return invocation.invoke();
}
}

实体模型设计精要
系统的实体模型设计充分体现了领域驱动设计(DDD)的思想,每个实体都封装了相应的业务逻辑和行为。
订单聚合根设计
Order作为订单聚合的根实体,负责维护订单项的一致性边界和业务规则。
@Entity
@Table(name = "t_order")
public class Order {
/**
* 计算订单总金额
*/
public void calculateTotalAmount() {
this.order_jine = 0;
for (OrderItem item : orderItems) {
Goods goods = item.getGoods();
int price = "是".equals(goods.getGoods_isnottejia())
? goods.getGoods_tejia() : goods.getGoods_shichangjia();
this.order_jine += price * item.getGoods_quantity();
}
}
/**
* 验证订单完整性
*/
public void validate() {
if (orderItems == null || orderItems.isEmpty()) {
throw new IllegalArgumentException("订单必须包含至少一个商品");
}
for (OrderItem item : orderItems) {
if (item.getGoods_quantity() <= 0) {
throw new IllegalArgumentException("商品数量必须大于0");
}
// 检查库存
if (item.getGoods().getGoods_kucun() < item.getGoods_quantity()) {
throw new IllegalArgumentException(
"商品[" + item.getGoods().getGoods_name() + "]库存不足");
}
}
}
}
商品值对象与业务逻辑
Goods实体不仅包含基本属性,还封装了价格计算、库存检查等业务方法。
@Entity
@Table(name = "t_goods")
public class Goods {
/**
* 获取当前有效价格
*/
public Integer getCurrentPrice() {
return "是".equals(goods_isnottejia) ? goods_tejia : goods_shichangjia;
}
/**
* 检查库存是否充足
*/
public boolean isStockSufficient(Integer requiredQuantity) {
return goods_kucun != null && goods_kucun >= requiredQuantity;
}
/**
* 减少库存
*/
public void reduceStock(Integer quantity) {
if (!isStockSufficient(quantity)) {
throw new IllegalArgumentException("库存不足");
}
this.goods_kucun -= quantity;
}
}
功能展望与系统优化方向
性能优化与缓存策略
当前系统在高并发场景下可能存在性能瓶颈,未来可以考虑引入Redis缓存层来提升系统响应速度。
@Service
public class GoodsServiceWithCache {
@Autowired
private RedisTemplate<String, Goods> redisTemplate;
private static final String GOODS_KEY_PREFIX = "goods:";
private static final long CACHE_EXPIRE_HOURS = 24;
public Goods getGoodsByIdWithCache(Integer goodsId) {
String cacheKey = GOODS_KEY_PREFIX + goodsId;
// 先查缓存
Goods goods = redisTemplate.opsForValue().get(cacheKey);
if (goods != null) {
return goods;
}
// 缓存未命中,查询数据库
goods = goodsDAO.findById(goodsId);
if (goods != null) {
// 写入缓存
redisTemplate.opsForValue().set(cacheKey, goods,
CACHE_EXPIRE_HOURS, TimeUnit.HOURS);
}
return goods;
}
}
微服务架构改造
随着业务规模扩大,可以将单体应用拆分为多个微服务,如用户服务、商品服务、订单服务等,提高系统的可维护性和扩展性。
# Spring Cloud 微服务配置示例
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
loadbalancer:
enabled: true
server:
port: 8081
# Feign客户端配置
feign:
client:
config:
user-service:
connectTimeout: 5000
readTimeout: 5000
移动端适配与PWA技术
开发响应式前端界面,并引入PWA(渐进式Web应用)技术,使系统在移动设备上具备原生应用的体验。
// Service Worker 缓存策略
self.addEventListener('install', event => {
event.waitUntil(
caches.open('food-delivery-v1').then(cache => {
return cache.addAll([
'/',
'/static/css/main.css',
'/static/js/app.js',
'/static/images/logo.png'
]);
})
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request);
})
);
});
智能推荐与数据分析
基于用户历史订单数据,构建推荐算法模型,实现个性化菜品推荐,提升用户粘性和订单转化率。
# 基于协同过滤的推荐算法示例
from sklearn.metrics.pairwise import cosine_similarity
import pandas as pd
def recommend_items(user_id, user_item