在传统的二手自行车交易市场中,信息不对称、交易渠道匮乏以及信任机制缺失是长期存在的痛点。为了有效解决这些问题,一个基于JSP+Servlet技术栈的线上交易平台应运而生。该系统严格遵循MVC设计模式,将业务逻辑、数据持久化和用户界面清晰分离,构建了一个高效、可靠的二手自行车流通环境。
技术架构与设计模式
平台采用经典的三层架构:表示层由JSP页面负责,通过JSTL标签库和EL表达式实现数据的动态渲染;控制层核心为Servlet,负责拦截并处理所有HTTP请求,进行业务逻辑调度和数据流转;数据持久层则基于JDBC直接操作MySQL数据库,并通过封装DAO模式来执行数据的增删改查操作。这种分层设计确保了代码的可维护性和可扩展性。
Servlet作为前端控制器(Front Controller),统一处理所有客户端请求。通过web.xml配置或注解方式定义URL映射,使得请求能够被准确路由到相应的业务处理器。例如,用户访问商品列表的请求会被ProductListServlet拦截,该Servlet调用底层的ProductDAO从数据库检索数据,然后将结果集设置到请求属性中,最后转发到JSP页面进行展示。
// 示例:商品列表Servlet核心代码片段
@WebServlet("/product/list")
public class ProductListServlet extends HttpServlet {
private ProductDAO productDao = new ProductDAOImpl();
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
String categoryId = request.getParameter("categoryId");
String keyword = request.getParameter("keyword");
List<Product> products;
if (categoryId != null && !categoryId.trim().isEmpty()) {
products = productDao.findByCategory(Integer.parseInt(categoryId));
} else if (keyword != null && !keyword.trim().isEmpty()) {
products = productDao.searchByKeyword(keyword);
} else {
products = productDao.findAll();
}
request.setAttribute("productList", products);
request.getRequestDispatcher("/WEB-INF/views/product/list.jsp").forward(request, response);
} catch (Exception e) {
throw new ServletException("Error retrieving product list", e);
}
}
}
数据库设计亮点分析
系统共设计6张核心数据表,支撑起用户管理、商品展示、订单交易等关键业务。其中,商品表(products)和订单表(orders)的设计尤为值得深入探讨。
商品表(products)设计:
该表不仅存储了自行车的基本信息(如标题、描述、价格),还通过外键关联了分类表(categories)和用户表(users),实现了商品数据的规范化存储。特别值得注意的是status字段的设计,它使用枚举类型定义了商品的可交易状态(如待审核、上架中、已下架、已售出),为平台管理商品生命周期提供了精细化的控制能力。view_count字段则用于记录商品被浏览的次数,为后续实现热门商品推荐等增值功能埋下伏笔。
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200) NOT NULL,
description TEXT,
price DECIMAL(10,2) NOT NULL,
category_id INT NOT NULL,
seller_id INT NOT NULL,
status ENUM('pending','active','inactive','sold') DEFAULT 'pending',
view_count INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (category_id) REFERENCES categories(id),
FOREIGN KEY (seller_id) REFERENCES users(id)
);
订单表(orders)设计:
订单表是整个交易流程的核心。它通过order_number字段确保每个订单的唯一性,该字段通常由时间戳和随机数生成,避免了订单号的重复。total_amount字段准确记录了订单的最终成交金额,而status字段则详细刻画了订单从创建到完成的整个状态流转(待付款、已付款、已发货、已完成、已取消)。买卖双方的用户ID均被记录,便于构建完整的交易关系链。
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
order_number VARCHAR(50) UNIQUE NOT NULL,
buyer_id INT NOT NULL,
product_id INT NOT NULL,
total_amount DECIMAL(10,2) NOT NULL,
status ENUM('pending_payment','paid','shipped','completed','cancelled') DEFAULT 'pending_payment',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (buyer_id) REFERENCES users(id),
FOREIGN KEY (product_id) REFERENCES products(id)
);
核心功能实现深度解析
1. 商品搜索与分类浏览
平台提供了强大的商品检索功能,用户既可以通过关键词进行全文搜索,也可以按自行车类别进行精准筛选。前端页面通过表单提交搜索条件,后端Servlet接收参数后调用相应的DAO方法。

DAO层使用预处理语句(PreparedStatement)构建动态SQL查询,有效防止SQL注入攻击,同时通过LIKE操作符实现模糊匹配。
// 商品DAO中的搜索方法实现
public class ProductDAOImpl implements ProductDAO {
public List<Product> searchByKeyword(String keyword) throws SQLException {
List<Product> products = new ArrayList<>();
String sql = "SELECT * FROM products WHERE status = 'active' AND " +
"(title LIKE ? OR description LIKE ?)";
try (Connection conn = DatabaseUtil.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, "%" + keyword + "%");
stmt.setString(2, "%" + keyword + "%");
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
products.add(extractProductFromResultSet(rs));
}
}
return products;
}
private Product extractProductFromResultSet(ResultSet rs) throws SQLException {
Product product = new Product();
product.setId(rs.getInt("id"));
product.setTitle(rs.getString("title"));
product.setDescription(rs.getString("description"));
product.setPrice(rs.getBigDecimal("price"));
product.setCategoryId(rs.getInt("category_id"));
product.setSellerId(rs.getInt("seller_id"));
product.setStatus(rs.getString("status"));
product.setViewCount(rs.getInt("view_count"));
product.setCreatedAt(rs.getTimestamp("created_at"));
product.setUpdatedAt(rs.getTimestamp("updated_at"));
return product;
}
}
2. 用户身份验证与会话管理
用户登录功能采用Session机制实现身份验证。系统验证用户凭证后,将用户对象存储在HttpSession中,作为后续请求中用户身份的凭证。
// 用户登录Servlet核心逻辑
@WebServlet("/auth/login")
public class LoginServlet extends HttpServlet {
private UserDAO userDao = new UserDAOImpl();
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
try {
User user = userDao.findByUsernameAndPassword(username, password);
if (user != null) {
HttpSession session = request.getSession();
session.setAttribute("currentUser", user);
response.sendRedirect(request.getContextPath() + "/");
} else {
request.setAttribute("errorMessage", "用户名或密码错误");
request.getRequestDispatcher("/WEB-INF/views/auth/login.jsp").forward(request, response);
}
} catch (SQLException e) {
throw new ServletException("Database error during login", e);
}
}
}
为确保安全,密码在数据库中使用MD5或更安全的bcrypt算法进行哈希存储,避免明文存储带来的安全风险。

3. 购物车与订单生成
用户可以将心仪的商品加入购物车,系统使用Session临时存储购物车信息。当用户决定购买时,系统生成唯一的订单号并创建订单记录。
// 购物车添加商品功能实现
@WebServlet("/cart/add")
public class AddToCartServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession();
ShoppingCart cart = (ShoppingCart) session.getAttribute("shoppingCart");
if (cart == null) {
cart = new ShoppingCart();
session.setAttribute("shoppingCart", cart);
}
int productId = Integer.parseInt(request.getParameter("productId"));
int quantity = Integer.parseInt(request.getParameter("quantity", "1"));
// 获取商品信息
ProductDAO productDao = new ProductDAOImpl();
try {
Product product = productDao.findById(productId);
if (product != null) {
cart.addItem(product, quantity);
response.getWriter().write("{\"success\": true, \"cartSize\": " + cart.getTotalItems() + "}");
} else {
response.getWriter().write("{\"success\": false, \"message\": \"商品不存在\"}");
}
} catch (SQLException e) {
response.getWriter().write("{\"success\": false, \"message\": \"系统错误\"}");
}
}
}
订单创建过程中,系统会进行库存检查(对于可批量购买的商品)和并发控制,确保数据的一致性。

4. 商品详情页与浏览记录
商品详情页是用户决策的关键页面,系统不仅展示商品的完整信息,还记录了用户的浏览行为。
// 商品详情查看Servlet,同时更新浏览次数
@WebServlet("/product/detail")
public class ProductDetailServlet extends HttpServlet {
private ProductDAO productDao = new ProductDAOImpl();
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int productId = Integer.parseInt(request.getParameter("id"));
try {
Product product = productDao.findById(productId);
if (product != null) {
// 增加浏览次数
productDao.incrementViewCount(productId);
// 获取卖家信息
UserDAO userDao = new UserDAOImpl();
User seller = userDao.findById(product.getSellerId());
request.setAttribute("product", product);
request.setAttribute("seller", seller);
request.getRequestDispatcher("/WEB-INF/views/product/detail.jsp").forward(request, response);
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
} catch (SQLException e) {
throw new ServletException("Error retrieving product details", e);
}
}
}
实体模型与业务逻辑封装
系统通过JavaBean实体类精确映射数据库表结构,每个实体类都封装了对应的业务属性和行为。以User实体为例:
public class User {
private Integer id;
private String username;
private String password;
private String email;
private String phone;
private String realName;
private String role; // 'admin' or 'user'
private Date createdAt;
private Date updatedAt;
// 构造函数、getter和setter方法
public User() {}
public User(String username, String password, String email) {
this.username = username;
this.password = password;
this.email = email;
}
// 省略其他getter和setter方法
public boolean isAdmin() {
return "admin".equals(this.role);
}
public boolean validatePassword(String inputPassword) {
// 实际应用中应使用密码哈希比较
return this.password.equals(hashPassword(inputPassword));
}
private String hashPassword(String plainText) {
// 使用BCrypt或其他安全哈希算法
return BCrypt.hashpw(plainText, BCrypt.gensalt());
}
}
这种封装不仅提供了数据的一致性访问接口,还能够在实体级别实现业务规则的校验,如密码验证、权限检查等。
前端交互与用户体验优化
平台前端采用响应式设计,确保在不同设备上都能提供良好的浏览体验。通过JavaScript增强用户交互,如表单验证、异步加载等。
// 前端商品搜索的Ajax实现
function searchProducts() {
var keyword = document.getElementById('searchKeyword').value;
var categoryId = document.getElementById('categoryFilter').value;
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
var products = JSON.parse(xhr.responseText);
updateProductList(products);
}
};
xhr.open('GET', '/api/products?keyword=' + encodeURIComponent(keyword) +
'&categoryId=' + categoryId, true);
xhr.send();
}
function updateProductList(products) {
var container = document.getElementById('productContainer');
container.innerHTML = '';
products.forEach(function(product) {
var productElement = createProductElement(product);
container.appendChild(productElement);
});
}

未来优化方向与功能扩展
引入Redis缓存层:针对商品列表、用户信息等高频访问数据,可以引入Redis作为缓存,显著提升系统响应速度。实现思路是在DAO层添加缓存逻辑,先查询缓存,缓存未命中时再查询数据库。
实现站内信与消息推送:构建完整的消息系统,支持买卖双方在线沟通、订单状态变更通知等功能。技术上可以采用WebSocket实现实时消息推送,数据库设计上需要新增消息表记录通信内容。
集成第三方支付接口:接入支付宝、微信支付等主流支付渠道,实现真正的在线交易闭环。需要设计支付记录表,并实现支付结果异步回调处理机制。
智能推荐系统:基于用户的浏览历史和购买行为,使用协同过滤算法实现个性化商品推荐。技术上需要收集用户行为数据,构建用户-商品矩阵,计算相似度并进行推荐。
多图片上传与云存储:改进商品图片管理,支持多图上传、图片裁剪优化,并考虑将图片存储迁移至云存储服务(如OSS),减轻服务器压力。
引入Spring框架重构:虽然JSP+Servlet组合成熟稳定,但考虑长期维护和开发效率,可以逐步引入Spring框架(特别是Spring Boot)进行重构,利用其依赖注入、声明式事务管理等特性提升开发体验。
总结
该二手自行车在线交易平台通过严谨的MVC架构设计和模块化开发,成功构建了一个功能完备、性能稳定的线上交易环境。数据库设计的合理性和代码结构的清晰度为系统的可维护性奠定了坚实基础。核心功能如商品搜索、用户认证、购物车和订单管理都实现了良好的用户体验和业务逻辑完整性。
尽管当前系统已满足基本交易需求,但在高并发处理、系统扩展性、用户体验精细化等方面仍有提升空间。通过引入缓存机制、消息系统、第三方支付集成等优化措施,平台将能够更好地服务于日益增长的二手自行车交易市场,为用户创造更大的价值。