1. 项目概述
作为一个Java Web开发的入门项目,Servlet网上书店系统是一个典型的电子商务应用案例。这个项目让我从零开始构建了一个完整的B/S架构应用,涵盖了用户管理、商品展示、购物车、订单处理等核心电商功能模块。
在开发过程中,我选择了经典的Java EE技术栈:Servlet作为控制器层处理业务逻辑,JSP负责视图展示,MySQL作为数据存储,Tomcat作为应用服务器。这套组合虽然传统,但对于理解Web应用的底层原理非常有帮助。
2. 系统架构设计
2.1 技术选型考量
选择Servlet而非Spring MVC等框架是出于教学目的考虑:
- Servlet是Java Web开发的基础,理解其工作原理对后续学习框架很有帮助
- 轻量级,不需要复杂的配置,适合小型项目快速开发
- 直接操作Request/Response对象,有助于理解HTTP协议细节
数据库选用MySQL 5.7版本,主要因为:
- 开源免费,社区支持完善
- 对事务支持良好,适合电商场景
- 与Java生态集成成熟,JDBC驱动稳定
2.2 三层架构实现
系统采用典型的三层架构:
code复制表示层(JSP)
↓
业务逻辑层(Servlet)
↓
数据访问层(DAO)
↓
数据库(MySQL)
这种分层设计使得各层职责清晰,便于维护和扩展。例如当需要更换数据库时,只需修改DAO层实现,不影响上层业务逻辑。
3. 核心功能实现
3.1 用户认证模块
用户模块实现了注册、登录、权限控制等基础功能。关键技术点包括:
- 密码安全存储:
java复制// 使用SHA-256加盐哈希存储密码
public static String encryptPassword(String password, String salt) {
String saltedPassword = password + salt;
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(saltedPassword.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(hash);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("加密算法不可用", e);
}
}
- 会话管理:
- 使用HttpSession维持用户登录状态
- 设置合理的会话超时时间(30分钟)
- 关键操作需要重新验证密码
- 权限控制:
java复制// 过滤器检查登录状态
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("user") == null) {
// 未登录,重定向到登录页
((HttpServletResponse)res).sendRedirect("login.jsp");
} else {
chain.doFilter(req, res);
}
}
3.2 图书展示与搜索
图书模块实现了分类浏览、搜索、详情查看等功能:
- 数据库设计优化:
- 建立适当的索引(书名、作者、分类)
- 使用外键关联图书和分类表
- 添加全文检索字段(图书简介)
- 分页查询实现:
java复制// 分页查询SQL
String sql = "SELECT * FROM books WHERE category_id = ? LIMIT ? OFFSET ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setInt(1, categoryId);
stmt.setInt(2, pageSize);
stmt.setInt(3, (pageNum - 1) * pageSize);
- 搜索功能:
- 支持按书名、作者、ISBN等多条件查询
- 使用LIKE实现模糊匹配
- 对高频查询结果考虑缓存
3.3 购物车与订单系统
购物车采用Session存储临时数据,订单则持久化到数据库:
- 购物车数据结构:
java复制public class CartItem {
private Book book;
private int quantity;
// getters & setters
}
// 在Session中存储
List<CartItem> cart = (List<CartItem>)session.getAttribute("cart");
if (cart == null) {
cart = new ArrayList<>();
session.setAttribute("cart", cart);
}
- 订单处理流程:
- 验证库存
- 创建订单主表记录
- 创建订单明细记录
- 扣减库存
- 事务管理确保数据一致性
java复制// 订单创建事务示例
Connection conn = null;
try {
conn = dataSource.getConnection();
conn.setAutoCommit(false);
// 1. 创建订单
orderDao.create(conn, order);
// 2. 添加订单项
for (OrderItem item : order.getItems()) {
orderItemDao.create(conn, item);
}
// 3. 更新库存
inventoryDao.decrease(conn, item.getBookId(), item.getQuantity());
conn.commit();
} catch (SQLException e) {
if (conn != null) conn.rollback();
throw e;
} finally {
if (conn != null) conn.close();
}
4. 数据库设计与优化
4.1 核心表结构
主要表包括:
- 用户表(users)
- 图书表(books)
- 图书分类表(categories)
- 订单表(orders)
- 订单明细表(order_items)
- 库存表(inventory)
4.2 索引设计
为提高查询性能,针对性地创建了以下索引:
- 用户表:username(唯一索引)
- 图书表:主键id、category_id(外键)、name(普通索引)
- 订单表:user_id(外键)、create_time(用于按时间查询)
4.3 事务隔离级别
考虑到电商系统对数据一致性的要求,采用了REPEATABLE_READ隔离级别,在关键操作如订单创建时使用悲观锁防止超卖:
java复制// 库存扣减使用SELECT FOR UPDATE
String sql = "SELECT quantity FROM inventory WHERE book_id = ? FOR UPDATE";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setInt(1, bookId);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
int current = rs.getInt("quantity");
if (current >= quantity) {
// 执行扣减
} else {
throw new InventoryShortageException();
}
}
5. 安全防护措施
5.1 输入验证
对所有用户输入进行严格验证:
- 使用正则表达式验证邮箱、电话等格式
- 对特殊字符进行转义处理防止XSS
- 使用预编译语句防止SQL注入
java复制// 使用PreparedStatement防止SQL注入
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, username);
stmt.setString(2, encryptedPassword);
5.2 敏感数据保护
- 密码加盐哈希存储
- 支付信息加密传输
- 日志中过滤敏感信息
- 关键操作记录审计日志
5.3 CSRF防护
为关键表单添加CSRF Token:
jsp复制<!-- JSP页面生成Token -->
<input type="hidden" name="csrfToken" value="${sessionScope.csrfToken}">
java复制// Servlet验证Token
String sessionToken = (String)request.getSession().getAttribute("csrfToken");
String paramToken = request.getParameter("csrfToken");
if (sessionToken == null || !sessionToken.equals(paramToken)) {
throw new SecurityException("CSRF验证失败");
}
6. 性能优化实践
6.1 数据库连接池
使用HikariCP作为连接池,配置如下:
properties复制# HikariCP配置
jdbcUrl=jdbc:mysql://localhost:3306/bookstore
username=root
password=123456
maximumPoolSize=20
minimumIdle=5
connectionTimeout=30000
idleTimeout=600000
maxLifetime=1800000
6.2 缓存策略
- 使用Ehcache缓存热门图书数据
- 首页静态化减少数据库查询
- 合理设置HTTP缓存头
6.3 前端优化
- 合并CSS/JS文件减少请求
- 使用CDN分发静态资源
- 图片懒加载
- 异步加载非关键内容
7. 测试与部署
7.1 测试策略
- 单元测试:对DAO层和服务层进行隔离测试
- 集成测试:验证各模块协同工作
- 性能测试:使用JMeter模拟并发用户
7.2 部署方案
- 使用Tomcat 9作为Servlet容器
- Nginx作为反向代理和负载均衡
- MySQL主从复制提高可用性
- 日志集中收集和分析
8. 项目总结与改进方向
通过这个项目,我系统性地实践了Java Web开发的完整流程,从需求分析到部署上线。最大的收获是对MVC模式、数据库事务、Web安全等核心概念有了更深入的理解。
值得改进的方面包括:
- 前端可以引入Vue.js等框架提升交互体验
- 考虑微服务架构拆分单体应用
- 增加推荐算法提升个性化体验
- 引入消息队列处理高并发场景
这个项目代码已开源,包含了完整的文档和数据库脚本,非常适合Java Web初学者作为学习参考。在实际开发中,可以根据业务规模逐步引入Spring等框架,但理解Servlet底层原理对于排查问题非常有帮助。