在传统生鲜采购模式面临信息不透明、选购流程繁琐等挑战的背景下,一个基于成熟技术栈的在线交易平台应运而生。该系统采用经典的JSP+Servlet架构,结合MySQL数据库,构建了一个功能完整的生鲜电商解决方案。平台严格遵循MVC设计模式,实现了前后端逻辑的有效分离,为消费者提供了从商品浏览、购物车管理到订单处理的完整购物体验。
系统架构采用分层设计,表现层使用JSP页面结合JSTL标签库进行动态内容渲染,控制层通过Servlet组件处理用户请求和业务逻辑调度,数据持久层基于JDBC技术实现与MySQL数据库的交互。这种架构确保了代码的可维护性和系统的可扩展性。
数据库设计亮点
数据库设计包含6个核心表,每个表都经过精心设计以满足业务需求。其中用户表、商品表和订单表的设计尤为关键。
用户表(user)采用合理的字段设计来保证数据完整性:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(50) NOT NULL,
`email` varchar(100) DEFAULT NULL,
`phone` varchar(20) DEFAULT NULL,
`address` varchar(200) DEFAULT NULL,
`role` int(11) DEFAULT '0',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `username_unique` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
该表通过自增主键确保唯一性,username字段设置唯一约束防止重复注册,role字段区分用户角色(普通用户和管理员),create_time字段自动记录注册时间。
商品表(fresh)的设计充分考虑了生鲜商品的特性:
CREATE TABLE `fresh` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`price` decimal(10,2) NOT NULL,
`stock` int(11) NOT NULL,
`description` text,
`image` varchar(200) DEFAULT NULL,
`category_id` int(11) NOT NULL,
`status` int(11) DEFAULT '1',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `category_id_index` (`category_id`),
CONSTRAINT `fresh_ibfk_1` FOREIGN KEY (`category_id`)
REFERENCES `category` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
价格字段使用decimal类型保证计算精度,库存字段实时跟踪商品数量,外键约束确保商品分类的一致性,状态字段控制商品上下架。
订单表(orders)采用多表关联设计支持复杂业务逻辑:
CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_number` varchar(50) NOT NULL,
`user_id` int(11) NOT NULL,
`total_amount` decimal(10,2) NOT NULL,
`status` int(11) DEFAULT '0',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `order_number_unique` (`order_number`),
KEY `user_id_index` (`user_id`),
CONSTRAINT `orders_ibfk_1` FOREIGN KEY (`user_id`)
REFERENCES `user` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
订单编号保证唯一性,双时间戳字段跟踪订单状态变化,外键约束维护用户与订单的关系完整性。
核心功能实现
用户认证与权限管理
系统采用基于Session的认证机制,用户登录验证通过后建立会话。LoginServlet处理认证逻辑:
@WebServlet("/login")
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");
UserService userService = new UserServiceImpl();
User user = userService.login(username, password);
if (user != null) {
HttpSession session = request.getSession();
session.setAttribute("user", user);
if (user.getRole() == 1) {
response.sendRedirect("admin/home.jsp");
} else {
response.sendRedirect("index.jsp");
}
} else {
request.setAttribute("error", "用户名或密码错误");
request.getRequestDispatcher("login.jsp").forward(request, response);
}
}
}

权限控制通过过滤器实现,确保未登录用户无法访问受保护资源:
@WebFilter("/*")
public class AuthFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
String path = req.getRequestURI();
if (path.contains("/admin/")) {
HttpSession session = req.getSession(false);
if (session == null || session.getAttribute("user") == null) {
res.sendRedirect(req.getContextPath() + "/login.jsp");
return;
}
User user = (User) session.getAttribute("user");
if (user.getRole() != 1) {
res.sendRedirect(req.getContextPath() + "/error/403.jsp");
return;
}
}
chain.doFilter(request, response);
}
}
商品浏览与分类展示
商品展示功能支持按分类浏览和关键词搜索。商品列表Servlet处理分页和筛选逻辑:
@WebServlet("/fresh/list")
public class FreshListServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int page = 1;
int pageSize = 12;
int categoryId = 0;
String keyword = request.getParameter("keyword");
try {
page = Integer.parseInt(request.getParameter("page"));
} catch (NumberFormatException e) {
page = 1;
}
try {
categoryId = Integer.parseInt(request.getParameter("categoryId"));
} catch (NumberFormatException e) {
categoryId = 0;
}
FreshService freshService = new FreshServiceImpl();
PageInfo<Fresh> pageInfo = freshService.getFreshList(page, pageSize, categoryId, keyword);
CategoryService categoryService = new CategoryServiceImpl();
List<Category> categories = categoryService.getAllCategories();
request.setAttribute("pageInfo", pageInfo);
request.setAttribute("categories", categories);
request.setAttribute("categoryId", categoryId);
request.setAttribute("keyword", keyword);
request.getRequestDispatcher("/fresh-list.jsp").forward(request, response);
}
}

前端JSP页面使用JSTL标签库动态渲染商品信息:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<div class="row">
<c:forEach items="${pageInfo.list}" var="fresh">
<div class="col-md-3 mb-4">
<div class="card fresh-card">
<img src="${fresh.image}" class="card-img-top" alt="${fresh.name}">
<div class="card-body">
<h5 class="card-title">${fresh.name}</h5>
<p class="card-text">¥${fresh.price}</p>
<p class="card-text text-muted small">${fresh.description}</p>
<a href="fresh/detail?id=${fresh.id}" class="btn btn-primary">查看详情</a>
<button class="btn btn-success add-to-cart" data-id="${fresh.id}">加入购物车</button>
</div>
</div>
</div>
</c:forEach>
</div>

购物车管理
购物车功能采用Session存储临时数据,支持商品添加、数量修改和删除操作:
@WebServlet("/cart/add")
public class AddToCartServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int freshId = Integer.parseInt(request.getParameter("freshId"));
int quantity = Integer.parseInt(request.getParameter("quantity"));
FreshService freshService = new FreshServiceImpl();
Fresh fresh = freshService.getFreshById(freshId);
if (fresh != null && fresh.getStock() >= quantity) {
HttpSession session = request.getSession();
Map<Integer, CartItem> cart = (Map<Integer, CartItem>) session.getAttribute("cart");
if (cart == null) {
cart = new HashMap<>();
}
if (cart.containsKey(freshId)) {
CartItem item = cart.get(freshId);
item.setQuantity(item.getQuantity() + quantity);
} else {
CartItem item = new CartItem(fresh, quantity);
cart.put(freshId, item);
}
session.setAttribute("cart", cart);
response.getWriter().write("success");
} else {
response.getWriter().write("error");
}
}
}
购物车实体类封装了业务逻辑:
public class CartItem {
private Fresh fresh;
private int quantity;
public CartItem(Fresh fresh, int quantity) {
this.fresh = fresh;
this.quantity = quantity;
}
public BigDecimal getSubtotal() {
return fresh.getPrice().multiply(new BigDecimal(quantity));
}
// Getter和Setter方法
public Fresh getFresh() { return fresh; }
public void setFresh(Fresh fresh) { this.fresh = fresh; }
public int getQuantity() { return quantity; }
public void setQuantity(int quantity) { this.quantity = quantity; }
}

订单处理流程
订单生成涉及复杂的业务逻辑,包括库存校验、价格计算和事务处理:
@WebServlet("/order/submit")
public class SubmitOrderServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession();
User user = (User) session.getAttribute("user");
Map<Integer, CartItem> cart = (Map<Integer, CartItem>) session.getAttribute("cart");
if (user == null || cart == null || cart.isEmpty()) {
response.sendRedirect("login.jsp");
return;
}
OrderService orderService = new OrderServiceImpl();
try {
String orderNumber = orderService.createOrder(user.getId(), cart);
session.removeAttribute("cart");
response.sendRedirect("order/success.jsp?orderNumber=" + orderNumber);
} catch (Exception e) {
request.setAttribute("error", "订单提交失败: " + e.getMessage());
request.getRequestDispatcher("cart.jsp").forward(request, response);
}
}
}
订单服务实现类处理核心业务逻辑:
public class OrderServiceImpl implements OrderService {
public String createOrder(int userId, Map<Integer, CartItem> cart) throws Exception {
Connection conn = null;
try {
conn = DBUtil.getConnection();
conn.setAutoCommit(false);
// 生成订单号
String orderNumber = generateOrderNumber();
// 计算总金额并验证库存
BigDecimal totalAmount = BigDecimal.ZERO;
for (CartItem item : cart.values()) {
if (item.getFresh().getStock() < item.getQuantity()) {
throw new Exception("商品库存不足: " + item.getFresh().getName());
}
totalAmount = totalAmount.add(item.getSubtotal());
}
// 插入订单主记录
String orderSql = "INSERT INTO orders (order_number, user_id, total_amount) VALUES (?, ?, ?)";
PreparedStatement orderStmt = conn.prepareStatement(orderSql, PreparedStatement.RETURN_GENERATED_KEYS);
orderStmt.setString(1, orderNumber);
orderStmt.setInt(2, userId);
orderStmt.setBigDecimal(3, totalAmount);
orderStmt.executeUpdate();
ResultSet rs = orderStmt.getGeneratedKeys();
int orderId = 0;
if (rs.next()) {
orderId = rs.getInt(1);
}
// 插入订单明细并更新库存
String detailSql = "INSERT INTO order_item (order_id, fresh_id, quantity, price) VALUES (?, ?, ?, ?)";
String updateStockSql = "UPDATE fresh SET stock = stock - ? WHERE id = ?";
PreparedStatement detailStmt = conn.prepareStatement(detailSql);
PreparedStatement updateStmt = conn.prepareStatement(updateStockSql);
for (CartItem item : cart.values()) {
// 插入订单明细
detailStmt.setInt(1, orderId);
detailStmt.setInt(2, item.getFresh().getId());
detailStmt.setInt(3, item.getQuantity());
detailStmt.setBigDecimal(4, item.getFresh().getPrice());
detailStmt.addBatch();
// 更新库存
updateStmt.setInt(1, item.getQuantity());
updateStmt.setInt(2, item.getFresh().getId());
updateStmt.addBatch();
}
detailStmt.executeBatch();
updateStmt.executeBatch();
conn.commit();
return orderNumber;
} catch (Exception e) {
if (conn != null) {
conn.rollback();
}
throw e;
} finally {
if (conn != null) {
conn.setAutoCommit(true);
conn.close();
}
}
}
private String generateOrderNumber() {
return "ORD" + System.currentTimeMillis() + (int)(Math.random() * 1000);
}
}

实体模型设计
系统采用面向对象的设计思想,核心实体模型之间建立了清晰的关联关系。用户实体(User)作为系统的基础,与订单实体(Order)形成一对多关系,体现了用户可创建多个订单的业务规则。商品实体(Fresh)通过分类实体(Category)进行组织,支持灵活的商品分类管理。购物车项实体(CartItem)作为临时数据载体,桥接了用户选购行为与订单生成过程。
实体间的关联通过外键约束在数据库层面得到保障,同时在业务逻辑层通过服务类进行协调。这种设计既保证了数据的一致性,又提供了良好的业务扩展性。
功能展望与优化方向
支付系统集成:当前系统尚未集成在线支付功能。未来可接入支付宝、微信支付等第三方支付平台,实现完整的交易闭环。技术上可通过实现支付接口、处理异步通知、管理支付状态等模块来完成。
库存预警机制:建立智能库存监控系统,当商品库存低于阈值时自动发送预警通知。可通过数据库触发器或定时任务扫描库存数据,结合邮件或短信通知管理员。
商品推荐算法:基于用户浏览和购买历史实现个性化推荐。可采用协同过滤算法,分析用户行为数据,在首页和商品详情页展示相关商品推荐。
物流跟踪集成:对接主流物流公司API,为用户提供实时的物流信息查询功能。需要设计物流数据表存储跟踪信息,并实现定时同步物流状态的机制。
性能优化与缓存策略:引入Redis缓存高频访问数据(如商品分类、热门商品),减少数据库压力。对商品列表查询实现分页缓存,对静态资源实施CDN加速,提升系统响应速度。
微服务架构改造:随着业务规模扩大,可将单体应用拆分为用户服务、商品服务、订单服务等微服务模块。使用Spring Cloud等技术栈实现服务治理、配置管理和链路追踪。
该系统作为生鲜电商领域的技术实践,展示了传统JSP+Servlet技术栈在现代Web应用开发中的可行性。其清晰的架构设计、严谨的数据库规划和完善的功能实现,为同类项目的开发提供了有价值的参考。通过持续的技术优化和功能扩展,平台有望在生鲜电商领域发挥更大的价值。