在数字化浪潮席卷传统零售业的背景下,音像制品销售面临渠道单一、库存管理低效、顾客体验不佳等多重挑战。针对这一市场痛点,一套基于JSP+Servlet技术栈的在线唱片销售解决方案应运而生。该系统通过将传统唱片零售业务全面迁移至线上,实现了商品展示、交易处理、库存管理和用户服务的全流程数字化,为中小型唱片零售商和音乐品牌提供了高效、低成本的电子商务平台。
系统采用经典的MVC架构模式,Servlet作为控制器层负责业务逻辑调度和请求处理,JSP页面承担视图渲染职责,JavaBean则封装实体对象和数据库操作。数据持久化层通过JDBC直接连接MySQL数据库,采用DAO设计模式实现对六张核心数据表的增删改查操作。这种分层架构确保了代码的模块化、可维护性和可扩展性。

在用户认证方面,系统通过Session机制管理登录状态,结合过滤器实现权限控制。用户登录后,系统会根据角色类型(普通用户或管理员)授予不同的操作权限。管理员可访问后台管理界面,进行商品管理、订单处理等操作,而普通用户则仅限于前台购物功能。
数据库设计深度解析
系统数据库包含六张核心表,其中用户表、唱片表和订单表的设计尤为关键。用户表采用自增主键设计,确保每个用户标识的唯一性:
CREATE TABLE users (
user_id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
phone VARCHAR(20),
address TEXT,
role ENUM('customer', 'admin') DEFAULT 'customer',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_login TIMESTAMP NULL
);
该表设计的亮点在于使用ENUM类型明确限定用户角色,通过UNIQUE约束保证用户名和邮箱的唯一性,created_at和last_login时间戳字段为后续用户行为分析提供了数据基础。
唱片表的设计充分考虑了商品管理的实际需求:
CREATE TABLE records (
record_id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(200) NOT NULL,
artist VARCHAR(100) NOT NULL,
category_id INT NOT NULL,
price DECIMAL(10,2) NOT NULL,
stock_quantity INT DEFAULT 0,
description TEXT,
image_url VARCHAR(500),
release_date DATE,
sales_count INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (category_id) REFERENCES categories(category_id)
);
该表通过price字段的DECIMAL(10,2)类型确保金额计算的精确性,stock_quantity和sales_count字段为库存管理和销售分析提供支持,外键约束维护了与分类表的数据一致性。
订单表的设计体现了电商系统的复杂性:
CREATE TABLE orders (
order_id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
total_amount DECIMAL(10,2) NOT NULL,
status ENUM('pending', 'confirmed', 'shipped', 'delivered', 'cancelled') DEFAULT 'pending',
shipping_address TEXT NOT NULL,
payment_method ENUM('credit_card', 'paypal', 'bank_transfer') NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(user_id)
);
status字段使用ENUM类型明确限定订单状态流转,updated_at字段的自动更新特性为订单跟踪提供了时间戳记录,这种设计确保了订单状态变更的可追溯性。
核心功能实现技术剖析
- 用户登录与权限控制
系统通过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");
UserDAO userDAO = new UserDAO();
User user = userDAO.authenticate(username, password);
if (user != null) {
HttpSession session = request.getSession();
session.setAttribute("user", user);
session.setMaxInactiveInterval(30 * 60); // 30分钟超时
if ("admin".equals(user.getRole())) {
response.sendRedirect("admin/dashboard.jsp");
} else {
response.sendRedirect("home.jsp");
}
} else {
request.setAttribute("errorMessage", "用户名或密码错误");
request.getRequestDispatcher("login.jsp").forward(request, response);
}
}
}
认证过滤器确保敏感操作需要登录权限:
@WebFilter("/admin/*")
public class AdminFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
HttpSession session = httpRequest.getSession(false);
if (session == null || session.getAttribute("user") == null) {
httpResponse.sendRedirect(httpRequest.getContextPath() + "/login.jsp");
return;
}
User user = (User) session.getAttribute("user");
if (!"admin".equals(user.getRole())) {
httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "权限不足");
return;
}
chain.doFilter(request, response);
}
}

- 商品浏览与搜索功能
商品展示页面通过RecordServlet处理分类查询和关键词搜索:
@WebServlet("/records")
public class RecordServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getParameter("action");
RecordDAO recordDAO = new RecordDAO();
List<Record> records = new ArrayList<>();
if ("search".equals(action)) {
String keyword = request.getParameter("keyword");
records = recordDAO.searchRecords(keyword);
} else if ("category".equals(action)) {
int categoryId = Integer.parseInt(request.getParameter("categoryId"));
records = recordDAO.getRecordsByCategory(categoryId);
} else {
records = recordDAO.getAllRecords();
}
request.setAttribute("records", records);
request.getRequestDispatcher("records.jsp").forward(request, response);
}
}
对应的DAO层搜索方法实现:
public class RecordDAO {
public List<Record> searchRecords(String keyword) {
List<Record> records = new ArrayList<>();
String sql = "SELECT * FROM records WHERE title LIKE ? OR artist LIKE ? OR description LIKE ?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
String searchPattern = "%" + keyword + "%";
stmt.setString(1, searchPattern);
stmt.setString(2, searchPattern);
stmt.setString(3, searchPattern);
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
records.add(extractRecordFromResultSet(rs));
}
} catch (SQLException e) {
e.printStackTrace();
}
return records;
}
}

- 购物车与订单处理
购物车功能通过Session实现临时数据存储:
@WebServlet("/cart")
public class CartServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getParameter("action");
HttpSession session = request.getSession();
Map<Integer, CartItem> cart = getOrCreateCart(session);
if ("add".equals(action)) {
int recordId = Integer.parseInt(request.getParameter("recordId"));
int quantity = Integer.parseInt(request.getParameter("quantity"));
RecordDAO recordDAO = new RecordDAO();
Record record = recordDAO.getRecordById(recordId);
if (cart.containsKey(recordId)) {
CartItem item = cart.get(recordId);
item.setQuantity(item.getQuantity() + quantity);
} else {
cart.put(recordId, new CartItem(record, quantity));
}
} else if ("remove".equals(action)) {
int recordId = Integer.parseInt(request.getParameter("recordId"));
cart.remove(recordId);
}
session.setAttribute("cart", cart);
response.sendRedirect("cart.jsp");
}
private Map<Integer, CartItem> getOrCreateCart(HttpSession session) {
Map<Integer, CartItem> cart = (Map<Integer, CartItem>) session.getAttribute("cart");
if (cart == null) {
cart = new HashMap<>();
}
return cart;
}
}

订单生成过程包含库存验证和事务处理:
public class OrderService {
public boolean createOrder(Order order, List<OrderItem> items) {
Connection conn = null;
try {
conn = DBUtil.getConnection();
conn.setAutoCommit(false);
// 验证库存
for (OrderItem item : items) {
if (!checkStock(conn, item.getRecordId(), item.getQuantity())) {
conn.rollback();
return false;
}
}
// 插入订单主表
OrderDAO orderDAO = new OrderDAO(conn);
int orderId = orderDAO.insertOrder(order);
// 插入订单明细并更新库存
for (OrderItem item : items) {
item.setOrderId(orderId);
orderDAO.insertOrderItem(item);
updateStock(conn, item.getRecordId(), -item.getQuantity());
}
conn.commit();
return true;
} catch (SQLException e) {
if (conn != null) {
try { conn.rollback(); } catch (SQLException ex) {}
}
e.printStackTrace();
return false;
} finally {
DBUtil.closeConnection(conn);
}
}
}

- 后台管理系统
管理员可以通过后台界面管理唱片信息和订单状态:
@WebServlet("/admin/records")
public class AdminRecordServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getParameter("action");
RecordDAO recordDAO = new RecordDAO();
if ("update".equals(action)) {
int recordId = Integer.parseInt(request.getParameter("recordId"));
double price = Double.parseDouble(request.getParameter("price"));
int stock = Integer.parseInt(request.getParameter("stock"));
Record record = recordDAO.getRecordById(recordId);
record.setPrice(price);
record.setStockQuantity(stock);
recordDAO.updateRecord(record);
} else if ("delete".equals(action)) {
int recordId = Integer.parseInt(request.getParameter("recordId"));
recordDAO.deleteRecord(recordId);
}
response.sendRedirect("records.jsp");
}
}

实体模型设计
系统的实体模型严格遵循数据库表结构,通过JavaBean实现数据封装:
public class Record {
private int recordId;
private String title;
private String artist;
private int categoryId;
private double price;
private int stockQuantity;
private String description;
private String imageUrl;
private Date releaseDate;
private int salesCount;
private Date createdAt;
// 构造函数、getter和setter方法
public Record() {}
public Record(int recordId, String title, String artist, double price) {
this.recordId = recordId;
this.title = title;
this.artist = artist;
this.price = price;
}
// 完整的getter和setter方法
public int getRecordId() { return recordId; }
public void setRecordId(int recordId) { this.recordId = recordId; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
// 其他属性的getter和setter...
}
订单实体包含复杂的业务逻辑关系:
public class Order {
private int orderId;
private int userId;
private double totalAmount;
private String status;
private String shippingAddress;
private String paymentMethod;
private Date createdAt;
private Date updatedAt;
private List<OrderItem> items;
public double calculateTotal() {
double total = 0;
if (items != null) {
for (OrderItem item : items) {
total += item.getUnitPrice() * item.getQuantity();
}
}
return total;
}
public boolean canBeCancelled() {
return "pending".equals(status) || "confirmed".equals(status);
}
}
数据库工具类实现
系统通过DBUtil类管理数据库连接,确保资源正确释放:
public class DBUtil {
private static final String URL = "jdbc:mysql://localhost:3306/record_store";
private static final String USERNAME = "root";
private static final String PASSWORD = "password";
static {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(URL, USERNAME, PASSWORD);
}
public static void closeConnection(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void closeStatement(Statement stmt) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void closeResultSet(ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
系统优化与功能扩展方向
性能优化:引入数据库连接池技术(如HikariCP)替代直接的JDBC连接管理,显著提升数据库访问性能。实现代码层面可增加连接池配置类,管理连接的创建和回收。
缓存机制:为高频访问的唱片分类信息、热门商品数据添加Redis缓存层,减少数据库直接查询压力。可在Service层添加缓存注解,实现自动缓存更新。
全文搜索增强:集成Elasticsearch替代传统的LIKE查询,提升搜索准确性和响应速度。需要设计索引映射关系,实现搜索服务的数据同步机制。
支付集成:增加支付宝、微信支付等主流支付渠道的API集成,完善电商交易闭环。需要设计支付回调接口,确保订单状态与支付结果的一致性。
移动端适配:开发RESTful API接口,支持iOS和Android移动应用的数据交互。需要重构控制器层,支持JSON格式的请求和响应处理。
数据分析功能:基于现有销售数据,开发销售趋势分析、用户行为分析等商业智能功能。可通过定时任务生成数据报表,为经营决策提供数据支持。
这套"音乐宝盒"在线唱片销售系统通过严谨的技术架构设计和完整的业务功能实现,为传统音像制品零售商提供了切实可行的数字化转型方案。系统采用的标准Java Web技术栈确保了项目的稳定性和可维护性,模块化的代码结构为后续功能扩展奠定了坚实基础。随着电子商务技术的不断发展,该系统具备持续演进和优化的潜力,能够适应更加复杂的商业场景需求。