在传统奶茶行业数字化转型的浪潮中,一个高效、稳定的线上销售平台成为提升竞争力的关键。本系统采用经典的JSP+Servlet技术栈,构建了一个功能完善的在线奶茶订购与管理系统,实现了从商品展示、购物车管理、订单处理到后台管理的全流程数字化。
系统采用浏览器/服务器架构,严格遵循MVC设计模式。Servlet作为控制器层负责处理所有业务逻辑和请求转发,JSP作为视图层实现数据展示,JavaBean作为模型层封装业务数据,MySQL数据库提供持久化存储。这种分层架构确保了代码的可维护性和系统的可扩展性。
数据库架构设计与技术亮点
数据库设计是整个系统的核心基础,采用了8张核心表来支撑业务逻辑。其中几个关键表的设计体现了良好的规范化思想和性能考量。
商品表(easybuy_product)的设计体现了电商系统的核心要素:
CREATE TABLE `easybuy_product` (
`EP_ID` int(10) NOT NULL AUTO_INCREMENT COMMENT '商品ID',
`EP_NAME` varchar(255) NOT NULL COMMENT '商品名称',
`EP_DESCRIPTION` varchar(512) DEFAULT NULL COMMENT '商品描述',
`EP_PRICE` decimal(10,2) NOT NULL COMMENT '商品价格',
`EP_STOCK` decimal(10,0) NOT NULL COMMENT '商品库存',
`EPC_ID` decimal(10,0) DEFAULT NULL COMMENT '分类ID',
`EPC_CHILD_ID` decimal(10,0) DEFAULT NULL COMMENT '子分类ID',
`EP_FILE_NAME` varchar(255) DEFAULT NULL COMMENT '商品图片文件名',
PRIMARY KEY (`EP_ID`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=58 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT
该表设计的亮点在于:使用decimal(10,2)类型精确存储价格,避免浮点数精度问题;通过EPC_ID和EPC_CHILD_ID实现商品的多级分类;EP_FILE_NAME字段存储图片路径而非直接存储图片,优化数据库性能;采用BTREE索引提升查询效率。
订单详情表(easybuy_order_detail) 采用与主订单表分离的设计:
CREATE TABLE `easybuy_order_detail` (
`EOD_ID` int(10) NOT NULL AUTO_INCREMENT COMMENT '订单详情ID',
`EO_ID` decimal(10,0) NOT NULL COMMENT '订单ID',
`EP_ID` decimal(10,0) NOT NULL COMMENT '商品ID',
`EOD_QUANTITY` decimal(6,0) NOT NULL COMMENT '商品数量',
`EOD_COST` decimal(10,2) NOT NULL COMMENT '商品金额',
PRIMARY KEY (`EOD_ID`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8
这种设计支持一个订单包含多个商品,符合实际业务场景。EOD_COST字段存储下单时的商品快照价格,确保历史订单数据的准确性,即使商品后续调价也不受影响。
购物车表(easybuy_shop) 的设计考虑了用户并发操作:
CREATE TABLE `easybuy_shop` (
`es_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '购物车ID',
`es_ep_file_name` varchar(255) DEFAULT NULL COMMENT '商品图片文件名',
`es_ep_name` varchar(64) DEFAULT NULL COMMENT '商品名称',
`es_ep_price` decimal(10,0) DEFAULT NULL COMMENT '商品价格',
`es_eod_quantity` int(11) DEFAULT NULL COMMENT '商品数量',
`es_ep_stock` int(11) DEFAULT NULL COMMENT '商品库存',
`es_ep_id` int(11) DEFAULT NULL COMMENT '商品ID',
`es_eu_user_id` varchar(64) DEFAULT NULL COMMENT '用户ID',
`es_valid` int(11) DEFAULT NULL COMMENT '是否有效',
PRIMARY KEY (`es_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8
该表通过es_valid字段实现软删除,保留用户购物车历史记录;冗余存储商品名称、价格等信息,减少联表查询,提升性能。
实体模型与数据封装
系统采用标准的JavaBean作为实体类,实现数据与业务的分离。以评论实体为例:
package com.hr.entity;
public class EASYBUY_COMMENT {
private int EC_ID;
private String EC_CONTENT;
private String EC_CREATE_TIME;
private String EC_REPLY;
private String EC_REPLY_TIME;
private String EC_NICK_NAME;
public EASYBUY_COMMENT(int eCID, String eCCONTENT, String eCCREATETIME,
String eCREPLY, String eCREPLYTIME, String eCNICKNAME) {
EC_ID = eCID;
EC_CONTENT = eCCONTENT;
EC_CREATE_TIME = eCCREATETIME;
EC_REPLY = eCREPLY;
EC_REPLY_TIME = eCREPLYTIME;
EC_NICK_NAME = eCNICKNAME;
}
public EASYBUY_COMMENT() {
}
// Getter和Setter方法
public int getEC_ID() {
return EC_ID;
}
public void setEC_ID(int eCID) {
EC_ID = eCID;
}
// 其他getter/setter方法...
}
这种设计符合JavaBean规范,支持反射操作,便于Servlet和JSP之间的数据传递。实体类通过重载构造方法支持不同的初始化场景。
核心功能实现深度解析
1. 用户登录与身份验证
用户登录功能通过Servlet实现安全的身份验证机制。系统采用Session管理用户状态,确保不同角色用户的权限隔离。

登录Servlet的核心处理逻辑包含密码验证、Session创建和权限判断:
// 伪代码示例:登录验证逻辑
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
UserDAO userDAO = new UserDAO();
User user = userDAO.findByUsername(username);
if (user != null && user.getPassword().equals(encrypt(password))) {
HttpSession session = request.getSession();
session.setAttribute("currentUser", user);
session.setMaxInactiveInterval(30 * 60); // 30分钟超时
// 根据用户角色跳转到不同页面
if ("admin".equals(user.getRole())) {
response.sendRedirect("admin/index.jsp");
} else {
response.sendRedirect("index.jsp");
}
} else {
request.setAttribute("errorMsg", "用户名或密码错误");
request.getRequestDispatcher("login.jsp").forward(request, response);
}
}
}
2. 商品分类浏览与搜索
系统实现多级商品分类展示,用户可按类别浏览商品,支持关键词搜索。

商品查询Servlet处理分类查询和搜索请求:
public class ProductServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String categoryId = request.getParameter("categoryId");
String keyword = request.getParameter("keyword");
String pageStr = request.getParameter("page");
int page = (pageStr == null) ? 1 : Integer.parseInt(pageStr);
int pageSize = 12;
ProductDAO productDAO = new ProductDAO();
List<Product> productList;
int totalCount;
if (categoryId != null && !categoryId.isEmpty()) {
// 按分类查询
productList = productDAO.findByCategory(categoryId, page, pageSize);
totalCount = productDAO.countByCategory(categoryId);
} else if (keyword != null && !keyword.isEmpty()) {
// 按关键词搜索
productList = productDAO.search(keyword, page, pageSize);
totalCount = productDAO.countBySearch(keyword);
} else {
// 查询所有商品
productList = productDAO.findAll(page, pageSize);
totalCount = productDAO.countAll();
}
int totalPages = (int) Math.ceil((double) totalCount / pageSize);
request.setAttribute("productList", productList);
request.setAttribute("currentPage", page);
request.setAttribute("totalPages", totalPages);
request.getRequestDispatcher("product-list.jsp").forward(request, response);
}
}
对应的JSP页面使用JSTL和EL表达式展示商品列表:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<div class="product-grid">
<c:forEach var="product" items="${productList}">
<div class="product-item">
<img src="images/${product.epFileName}" alt="${product.epName}">
<h3>${product.epName}</h3>
<p class="price">¥${product.epPrice}</p>
<p class="description">${product.epDescription}</p>
<a href="productDetail?id=${product.epId}" class="btn-detail">查看详情</a>
<button class="btn-cart" onclick="addToCart(${product.epId})">加入购物车</button>
</div>
</c:forEach>
</div>
<!-- 分页控件 -->
<div class="pagination">
<c:if test="${currentPage > 1}">
<a href="?page=${currentPage - 1}">上一页</a>
</c:if>
<c:forEach begin="1" end="${totalPages}" var="i">
<c:choose>
<c:when test="${i == currentPage}">
<span class="current">${i}</span>
</c:when>
<c:otherwise>
<a href="?page=${i}">${i}</a>
</c:otherwise>
</c:choose>
</c:forEach>
<c:if test="${currentPage < totalPages}">
<a href="?page=${currentPage + 1}">下一页</a>
</c:if>
</div>
3. 购物车管理与订单生成
购物车功能实现商品添加、数量修改、删除等操作,支持实时价格计算。

购物车Servlet处理商品添加逻辑:
public class CartServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getParameter("action");
String productId = request.getParameter("productId");
String quantityStr = request.getParameter("quantity");
HttpSession session = request.getSession();
User user = (User) session.getAttribute("currentUser");
if (user == null) {
response.getWriter().write("请先登录");
return;
}
CartDAO cartDAO = new CartDAO();
if ("add".equals(action)) {
int quantity = Integer.parseInt(quantityStr);
CartItem existingItem = cartDAO.findByUserAndProduct(user.getUserId(),
Integer.parseInt(productId));
if (existingItem != null) {
// 更新数量
cartDAO.updateQuantity(existingItem.getEsId(),
existingItem.getEsEodQuantity() + quantity);
} else {
// 新增商品
cartDAO.addItem(user.getUserId(), Integer.parseInt(productId), quantity);
}
response.getWriter().write("success");
} else if ("update".equals(action)) {
int quantity = Integer.parseInt(quantityStr);
cartDAO.updateQuantity(Integer.parseInt(request.getParameter("cartId")), quantity);
response.getWriter().write("success");
} else if ("delete".equals(action)) {
cartDAO.deleteItem(Integer.parseInt(request.getParameter("cartId")));
response.getWriter().write("success");
}
}
}
订单生成过程中涉及库存检查和事务处理:
public class OrderService {
public boolean createOrder(Order order, List<OrderDetail> details) {
Connection conn = null;
try {
conn = DatabaseUtil.getConnection();
conn.setAutoCommit(false);
// 检查库存
for (OrderDetail detail : details) {
Product product = productDAO.findById(detail.getEpId(), conn);
if (product.getEpStock() < detail.getEodQuantity()) {
throw new RuntimeException("商品库存不足: " + product.getEpName());
}
}
// 生成订单
int orderId = orderDAO.insert(order, conn);
// 生成订单详情并更新库存
for (OrderDetail detail : details) {
detail.setEoId(orderId);
orderDetailDAO.insert(detail, conn);
// 更新商品库存
productDAO.updateStock(detail.getEpId(),
-detail.getEodQuantity(), conn);
}
// 清空购物车
cartDAO.clearByUser(order.getEuUserId(), conn);
conn.commit();
return true;
} catch (Exception e) {
if (conn != null) {
try { conn.rollback(); } catch (SQLException ex) {}
}
return false;
} finally {
DatabaseUtil.closeConnection(conn);
}
}
}
4. 后台管理系统
后台管理提供商品管理、订单处理、用户管理等功能,实现业务全流程监控。

订单管理Servlet实现多状态订单查询和处理:
public class AdminOrderServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String status = request.getParameter("status");
String pageStr = request.getParameter("page");
int page = (pageStr == null) ? 1 : Integer.parseInt(pageStr);
OrderDAO orderDAO = new OrderDAO();
List<Order> orders;
int totalCount;
if (status != null && !status.isEmpty()) {
orders = orderDAO.findByStatus(status, page, 10);
totalCount = orderDAO.countByStatus(status);
} else {
orders = orderDAO.findAll(page, 10);
totalCount = orderDAO.countAll();
}
request.setAttribute("orders", orders);
request.setAttribute("currentPage", page);
request.setAttribute("totalPages", (int) Math.ceil((double) totalCount / 10));
request.getRequestDispatcher("/admin/order-list.jsp").forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getParameter("action");
String orderId = request.getParameter("orderId");
if ("updateStatus".equals(action)) {
String newStatus = request.getParameter("newStatus");
OrderDAO orderDAO = new OrderDAO();
boolean success = orderDAO.updateStatus(Integer.parseInt(orderId), newStatus);
response.setContentType("application/json");
PrintWriter out = response.getWriter();
out.write("{\"success\": " + success + "}");
}
}
}
系统优化与功能扩展方向
基于当前系统架构,未来可从以下几个方向进行深度优化和功能扩展:
1. 性能优化与缓存机制 引入Redis缓存层,缓存热点商品数据、用户会话信息:
// Redis缓存示例
public class ProductService {
private static final String PRODUCT_CACHE_KEY = "product:";
private static final int CACHE_EXPIRE = 3600; // 1小时
public Product findById(int productId) {
String cacheKey = PRODUCT_CACHE_KEY + productId;
String cached = redisClient.get(cacheKey);
if (cached != null) {
return JSON.parseObject(cached, Product.class);
} else {
Product product = productDAO.findById(productId);
if (product != null) {
redisClient.setex(cacheKey, CACHE_EXPIRE, JSON.toJSONString(product));
}
return product;
}
}
}
2. 支付系统集成 集成微信支付、支付宝等第三方支付平台:
public class PaymentService {
public PaymentResult wechatPay(Order order, String openid) {
WechatPayRequest request = new WechatPayRequest();
request.setAppid(wechatConfig.getAppid());
request.setMchId(wechatConfig.getMchId());
request.setBody("奶茶订单-" + order.getOrderNumber());
request.setOutTradeNo(order.getOrderNumber());
request.setTotalFee(order.getTotalAmount().multiply(new BigDecimal(100)).intValue());
request.setOpenid(openid);
return wechatPayClient.unifiedOrder(request);
}
}
3. 智能推荐系统 基于用户行为数据实现个性化推荐:
public class RecommendationService {
public List<Product> recommendProducts(String userId, int limit) {
// 基于协同过滤算法
List<UserBehavior> behaviors = behaviorDAO.findByUser(userId);
Map<String, Double> userVector = buildUserVector(behaviors);
return productDAO.findSimilarProducts(userVector, limit);
}
private Map<String, Double> buildUserVector(List<UserBehavior> behaviors) {
// 构建用户兴趣向量
return behaviors.stream()
.collect(Collectors.groupingBy(
UserBehavior::getProductId,
Collectors.summingDouble(UserBehavior::getWeight)
));
}
}
4. 移动端适配与PWA支持 开发响应式界面,支持PWA技术实现原生应用体验:
<!-- PWA Manifest -->
<link rel="manifest" href="/manifest.json">
<!-- Service Worker注册 -->
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(registration => console.log('SW registered'))
.catch(error => console