在传统家电零售行业向数字化转型的浪潮中,一个高效、直观的线上销售渠道已成为企业提升竞争力的关键。本系统正是基于这一背景,采用经典的JSP+Servlet技术栈,构建了一个功能完备的在线空调销售平台,我们可称其为“清风易购”。该系统不仅实现了商品展示、用户管理、购物车、订单处理等电商核心功能,还通过严谨的MVC架构设计,确保了系统的可维护性和可扩展性。
技术架构与设计模式
系统严格遵循模型-视图-控制器(MVC)设计模式,将业务逻辑、数据展示与用户请求处理清晰分离。Servlet作为系统的“大脑”——控制器(Controller),负责接收所有前端HTTP请求。它解析请求参数,调用相应的业务逻辑组件(Model,通常由JavaBean实现)进行数据处理,如用户身份验证、库存查询或订单生成。业务逻辑组件通过JDBC与MySQL数据库进行交互,完成数据的持久化操作。最终,处理结果被封装到请求对象或会话对象中,转发给JSP页面。JSP作为视图(View),利用JSTL和EL表达式动态渲染HTML,将最终的用户界面呈现给浏览器。这种架构有效降低了代码耦合度,提升了开发效率。
数据持久层采用标准的JDBC API直接连接MySQL数据库。通过数据库连接池(如DBCP或C3P0)管理连接资源,避免了频繁创建和关闭连接带来的性能开销。事务管理在Servlet或JavaBean层面进行控制,确保如“下单扣库存”这类操作的原子性。
核心数据库表结构设计
一个稳健的电商系统离不开精心设计的数据库。本系统包含20张数据表,支撑着从用户、商品到订单、评论等所有业务环节。以下是几个核心表的设计分析:
1. 用户表 (mall_member) 此表是系统用户体系的基石,设计上充分考虑了扩展性和安全性。
CREATE TABLE `mall_member` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '会员ID',
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(32) NOT NULL COMMENT '密码,MD5加密',
`mobile` varchar(11) DEFAULT NULL COMMENT '手机号',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '注册时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`status` tinyint(1) DEFAULT '1' COMMENT '状态(0:禁用,1:启用)',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_username` (`username`),
KEY `idx_mobile` (`mobile`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='会员表';
设计亮点分析:
- 安全性:
password字段使用MD5进行单向加密存储,即使数据库泄露,也无法直接获取用户明文密码。 - 唯一性约束: 通过
UNIQUE KEY确保用户名的唯一性,防止重复注册。 - 索引优化: 对
username(主键查询、登录)和mobile(手机号登录、找回密码)字段建立了索引,显著提升了高频查询的效率。 - 审计字段:
create_time和update_time字段自动记录数据的生命周期,便于问题追踪和数据分析。
2. 商品表 (mall_air_conditioner) 该表详细定义了空调商品的各项属性,是商品管理模块的核心。
CREATE TABLE `mall_air_conditioner` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '空调ID',
`category_id` int(11) NOT NULL COMMENT '分类ID',
`title` varchar(100) NOT NULL COMMENT '商品标题',
`sub_title` varchar(200) DEFAULT NULL COMMENT '副标题',
`main_image` varchar(500) DEFAULT NULL COMMENT '产品主图',
`sub_images` text COMMENT '子图JSON数组',
`spec` text COMMENT '规格参数JSON',
`detail` text COMMENT '商品详情HTML',
`price` decimal(10,2) NOT NULL COMMENT '价格',
`stock` int(11) NOT NULL DEFAULT '0' COMMENT '库存',
`status` tinyint(1) DEFAULT '1' COMMENT '商品状态(0:下架,1:上架)',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `fk_category_id` (`category_id`),
KEY `idx_status` (`status`),
CONSTRAINT `fk_category_id` FOREIGN KEY (`category_id`) REFERENCES `mall_category` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='空调商品表';
设计亮点分析:
- 结构化与灵活性并存: 基础信息如
title、price使用固定字段。而多变的信息,如多张商品图sub_images和复杂的spec(规格参数,如制冷量、能效等级),则采用JSON格式存储在text字段中。这种设计既保证了核心查询性能,又提供了极大的灵活性,无需因增加新属性而频繁修改表结构。 - 外键约束: 通过
FOREIGN KEY关联商品分类表(mall_category),确保了数据的一致性和完整性。 - 业务状态索引: 对
status字段建立索引,使得前台只查询上架商品、后台按状态筛选等操作非常高效。
3. 订单主表 (mall_order) 订单表是交易流程的最终载体,其设计复杂且关键。
CREATE TABLE `mall_order` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '订单ID',
`order_no` bigint(20) NOT NULL COMMENT '订单号(唯一)',
`member_id` int(11) NOT NULL COMMENT '用户ID',
`shipping_id` int(11) NOT NULL COMMENT '收货地址ID',
`payment` decimal(10,2) DEFAULT NULL COMMENT '实际付款金额',
`payment_type` tinyint(1) DEFAULT NULL COMMENT '支付类型(1:在线支付)',
`postage` int(11) DEFAULT NULL COMMENT '运费',
`status` tinyint(1) DEFAULT '0' COMMENT '订单状态(0:已取消,10:未付款,20:已付款,40:已发货,50:交易成功,60:交易关闭)',
`payment_time` datetime DEFAULT NULL COMMENT '支付时间',
`send_time` datetime DEFAULT NULL COMMENT '发货时间',
`end_time` datetime DEFAULT NULL COMMENT '交易完成时间',
`close_time` datetime DEFAULT NULL COMMENT '交易关闭时间',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_order_no` (`order_no`),
KEY `idx_member_id` (`member_id`),
KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='订单表';
设计亮点分析:
- 订单号独立设计: 主键
id是自增ID,用于内部关联。而order_no是一个独立的、唯一的业务订单号,通常由时间戳、随机数等生成,避免暴露业务量和自增规律,更安全且易于同外部系统(如支付网关)对接。 - 状态机设计:
status字段使用数字代码定义清晰的订单状态流(如10->20->40->50),逻辑清晰,便于程序进行状态判断和流转控制。 - 多时间戳记录: 记录了订单生命周期中各个关键节点的时间(创建、支付、发货、完成等),为后续的售后处理、数据分析和报表生成提供了完整的数据支持。
核心功能实现深度解析
1. 用户登录与会话管理
用户登录是系统的入口。Servlet控制器接收登录请求,与数据库中的加密密码进行比对。
// UserLoginServlet.java
public class UserLoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
// MD5加密输入密码
String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
MemberService memberService = new MemberService();
Member member = memberService.login(username, md5Password);
if (member != null && member.getStatus() == 1) {
// 登录成功,将用户信息存入Session
HttpSession session = request.getSession();
session.setAttribute("currentUser", member);
response.getWriter().write("success");
} else {
// 登录失败
response.getWriter().write("fail");
}
}
}
代码解析: 控制器获取用户名和密码后,使用Spring框架的DigestUtils(或类似工具)对密码进行MD5加密。然后调用MemberService的login方法进行验证。成功后,将完整的Member对象存入HttpSession中,键为"currentUser"。此后,在整个会话期间,任何页面或Servlet都可以通过session.getAttribute("currentUser")来获取当前登录用户的信息,无需重复查询数据库,实现了状态的保持。

2. 购物车功能实现
购物车是电商的核心功能,本系统采用基于Session的实现方式,在用户登录前即可添加商品,用户体验连贯。
// CartServlet.java - 添加商品到购物车
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Integer productId = Integer.parseInt(request.getParameter("productId"));
Integer quantity = Integer.parseInt(request.getParameter("quantity"));
// 从Session中获取购物车对象,如果为空则新建一个
HttpSession session = request.getSession();
Map<Integer, CartItem> cart = (Map<Integer, CartItem>) session.getAttribute("cart");
if (cart == null) {
cart = new HashMap<>();
session.setAttribute("cart", cart);
}
// 判断商品是否已在购物车,是则增加数量,否则新增条目
AirConditionerService productService = new AirConditionerService();
AirConditioner product = productService.getProductById(productId);
if (cart.containsKey(productId)) {
CartItem item = cart.get(productId);
item.setQuantity(item.getQuantity() + quantity);
} else {
CartItem newItem = new CartItem(product, quantity);
cart.put(productId, newItem);
}
// 返回更新后的购物车信息(如总数量)
int totalCount = cart.values().stream().mapToInt(CartItem::getQuantity).sum();
response.getWriter().write("add_success," + totalCount);
}
代码解析: 此段代码展示了购物车的添加逻辑。购物车数据结构的核心是一个Map<Integer, CartItem>,以商品ID为键,CartItem(自定义的购物车项类,包含商品对象和数量)为值。这个Map被存储在用户的Session中。添加商品时,先从Session获取购物车Map,然后检查商品是否存在,进行数量叠加或新增项。这种方式将状态保存在服务器内存中,响应速度快,且与数据库解耦。

3. 订单生成与库存校验
下单是高并发场景下最需谨慎处理的功能,涉及事务和库存校验。
// OrderServlet.java - 生成订单
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Member member = (Member) request.getSession().getAttribute("currentUser");
Integer shippingId = Integer.parseInt(request.getParameter("shippingId"));
// 1. 从Session中获取购物车
Map<Integer, CartItem> cart = (Map<Integer, CartItem>) request.getSession().getAttribute("cart");
if (cart == null || cart.isEmpty()) {
response.getWriter().write("cart_empty");
return;
}
// 2. 校验库存
OrderService orderService = new OrderService();
String stockCheckResult = orderService.checkStock(cart);
if (!"success".equals(stockCheckResult)) {
response.getWriter().write("stock_insufficient:" + stockCheckResult); // 返回具体缺货商品名
return;
}
// 3. 创建订单(包含事务)
try {
String orderNo = orderService.createOrder(member.getId(), shippingId, cart);
// 4. 清空购物车
request.getSession().removeAttribute("cart");
response.getWriter().write("order_success:" + orderNo);
} catch (Exception e) {
e.printStackTrace();
response.getWriter().write("order_fail");
}
}
代码解析: 订单生成是一个多步骤的原子操作。首先,从Session中获取已校验过的购物车数据。然后,关键的一步是调用orderService.checkStock进行库存校验,遍历购物车中的每一项,查询数据库实时库存,确保所有商品数量充足。如果库存不足,立即返回错误信息,避免超卖。校验通过后,在orderService.createOrder方法中,通常会开启数据库事务,执行以下操作:生成订单主记录、生成订单明细记录、扣减商品库存。这些操作必须在同一个事务中,要么全部成功,要么全部失败,保证数据一致性。成功后,清空Session中的购物车。

4. 后台商品管理
后台管理提供了对商品的全面CRUD操作,以下是商品上架/下架的Servlet控制逻辑。
// AdminProductServlet.java - 商品状态管理
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String action = request.getParameter("action");
Integer productId = Integer.parseInt(request.getParameter("id"));
AirConditionerService productService = new AirConditionerService();
boolean result = false;
switch (action) {
case "list": // 上架
result = productService.updateProductStatus(productId, 1);
break;
case "unlist": // 下架
result = productService.updateProductStatus(productId, 0);
break;
case "delete": // 删除(逻辑删除,设置标志位)
result = productService.logicalDeleteProduct(productId);
break;
default:
break;
}
if (result) {
response.getWriter().write("success");
} else {
response.getWriter().write("fail");
}
}
代码解析: 后台操作通过一个Servlet并传递action参数来区分不同的操作类型(上架、下架、删除)。这种设计减少了Servlet的数量,使代码更集中。updateProductStatus方法直接执行SQL更新商品的status字段。对于删除操作,最佳实践是进行逻辑删除(即软删除),通过更新一个如is_deleted的标志位为1,而不是物理删除记录。这样做可以保留历史数据,便于审计和恢复,避免了误操作带来的不可逆损失。

实体模型与业务逻辑
系统的核心实体(Entity)通过JavaBean进行建模,例如Member、AirConditioner、Order、OrderItem等。这些类通常属性与数据库表字段一一对应,并包含相应的getter和setter方法。业务逻辑集中在Service层(如MemberService、OrderService),负责处理复杂的业务规则,如计算订单总价、优惠券应用、库存检查等。DAO(Data Access Object)层则封装了所有与数据库交互的细节,Service通过调用DAO来完成数据持久化。这种分层架构使得代码职责清晰,易于单元测试和维护。
功能展望与系统优化方向
尽管“清风易购”平台已经实现了电商核心功能,但在实际生产环境中,仍有多个方向可以优化和扩展:
引入缓存机制提升性能: 对于首页商品列表、分类信息、热点商品详情等读多写少的数据,可以引入Redis等缓存中间件。将数据缓存到内存中,可以极大减少数据库的访问压力,提高系统响应速度。例如,商品信息变更时,同步更新或失效缓存即可。
集成第三方支付与物流API: 当前系统支付和物流可能为模拟状态。未来可以集成支付宝、微信支付等官方SDK,实现真实的支付流程。同时,对接顺丰、中通等物流公司的API,实现自动获取物流单号和实时物流轨迹跟踪,提升用户体验。
实现全文搜索功能: 目前商品搜索可能基于数据库的
LIKE语句,在数据量大时性能低下且功能单一。可以集成Elasticsearch或Solr等全文搜索引擎,实现商品标题、详情、参数的智能分词、高亮显示和复杂条件组合搜索,并支持按相关性、价格、销量等多维度排序。服务化改造与分布式部署: 随着业务增长,单一的WAR包部署可能成为瓶颈。可以考虑进行服务化拆分,例如将用户服务、商品服务、订单服务拆分为独立的微服务。使用Spring Cloud、Dubbo等框架进行治理,并部署到多台服务器上,实现负载均衡和高可用。
增强后台数据分析与报表功能: 在现有基础上,可以构建更强大的数据看板。通过定时任务统计销售数据、用户行为数据,并利用ECharts等图表库可视化展示,如热销商品排行、用户增长趋势、销售额月度报表等,为运营决策提供数据支持。

该系统作为一个采用经典J2EE技术栈的实现,其架构清晰,代码规范,很好地诠释了MVC模式在Web开发中的应用。它不仅是一个可用的电商平台,更是一个优秀的学习范例,展示了如何通过JSP和Servlet构建一个结构合理、功能完备的中小型Web应用。上述优化方向则为该系统从“