技术演进中的开发沉思-190 JSP:电商实例
本文介绍了一个基于JSP技术的在线购物系统开发案例。系统采用MVC架构,实现了用户管理、商品展示、购物车和订单处理等核心功能模块。文章详细阐述了项目需求分析、数据库设计(包含5张核心表)、系统架构分层以及各模块的具体实现方案,重点讲解了用户注册登录、商品列表分页展示、购物车管理和订单生成等关键功能的实现逻辑和技术要点。该项目综合运用了JSP、Servlet、JSTL、过滤器等技术,并通过事务管理确
回顾一下之前用JSP做的一个项目,关于 Web 开发学习中,没有什么比亲手完成一个完整项目更能巩固知识的了。电商场景是我们经常说的,在线购物系统作为经典的 Web 应用场景,涵盖了用户管理、商品展示、购物流程、订单处理等核心模块,几乎能用到所有 JSP 相关技术。本文将带你从需求分析开始,一步步设计并实现一个功能完整的在线购物系统,让你在实战中掌握 JSP、Servlet、JSTL、过滤器、监听器等技术的综合应用。

一、项目需求分析
开发项目的第一步不是写代码,而是搞清楚 “要做什么”。在线购物系统的核心是 “让用户能在线浏览商品、下单购买”,围绕这个核心,我们梳理出以下需求:
1. 核心功能模块
| 模块 | 主要功能 |
|---|---|
| 用户模块 | 注册(用户名、密码、手机号等)、登录、个人信息修改、密码重置 |
| 商品模块 | 商品列表展示(分页)、商品详情、按分类 / 关键词搜索、商品分类浏览 |
| 购物车模块 | 添加商品(支持数量)、修改商品数量、删除商品、清空购物车、结算 |
| 订单模块 | 生成订单(从购物车)、订单列表查询、订单详情、订单状态更新(付款 / 发货等) |
2. 非功能需求
- 性能:商品列表页面加载时间≤2 秒,支持同时 100 人在线访问;
- 安全:密码加密存储,防 SQL 注入和 XSS 攻击,登录状态安全管理;
- 易用性:操作流程简洁(浏览→加购→结算→支付),页面响应及时。
3. 用户角色与流程
系统只有普通用户一种角色(简化版,暂不做管理员模块),核心流程:
用户注册→登录→浏览商品→加入购物车→结算→生成订单→查看订单
二、数据库设计
数据是系统的血液,合理的数据库设计是项目成功的基础。根据需求,我们设计 5 张核心表,用 MySQL 实现。
1. 表结构设计
① 用户表(t_user)
存储用户基本信息,密码需加密存储。
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | int | PK, AUTO_INCREMENT | 用户 ID(主键) |
| username | varchar(50) | NOT NULL, UNIQUE | 用户名(唯一) |
| password | varchar(100) | NOT NULL | 密码(BCrypt 加密) |
| phone | varchar(20) | UNIQUE | 手机号(唯一,用于找回密码) |
| address | varchar(200) | 默认收货地址 | |
| create_time | datetime | NOT NULL | 注册时间 |
② 商品分类表(t_category)
对商品进行分类(如电子产品、服装等)。
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | int | PK, AUTO_INCREMENT | 分类 ID |
| name | varchar(50) | NOT NULL | 分类名称(如 “手机”) |
| sort | int | DEFAULT 0 | 排序(数字越小越靠前) |
③ 商品表(t_product)
存储商品信息,关联分类表。
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | int | PK, AUTO_INCREMENT | 商品 ID |
| name | varchar(100) | NOT NULL | 商品名称 |
| price | decimal(10,2) | NOT NULL | 商品单价 |
| stock | int | NOT NULL, DEFAULT 0 | 库存数量 |
| category_id | int | FK | 所属分类 ID(关联 t_category) |
| image | varchar(200) | 商品图片路径 | |
| description | text | 商品描述 | |
| create_time | datetime | NOT NULL | 上架时间 |
④ 购物车表(t_cart)
存储用户的购物车信息,关联用户和商品。
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | int | PK, AUTO_INCREMENT | 购物车项 ID |
| user_id | int | FK, NOT NULL | 所属用户 ID(关联 t_user) |
| product_id | int | FK, NOT NULL | 商品 ID(关联 t_product) |
| quantity | int | NOT NULL, DEFAULT 1 | 商品数量(至少 1) |
| update_time | datetime | NOT NULL | 最后更新时间 |
| UNIQUE KEY (user_id, product_id) | 确保同一用户不会重复添加同一商品 |
⑤ 订单表(t_order)
存储订单主信息,关联用户。
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | varchar(50) | PK | 订单号(UUID 生成,如 “ORD20231005xxx”) |
| user_id | int | FK, NOT NULL | 所属用户 ID |
| total_price | decimal(10,2) | NOT NULL | 订单总金额 |
| status | int | NOT NULL, DEFAULT 0 | 订单状态(0:待付款,1:已付款,2:已发货,3:已完成,4:已取消) |
| address | varchar(200) | NOT NULL | 收货地址 |
| phone | varchar(20) | NOT NULL | 收货电话 |
| create_time | datetime | NOT NULL | 下单时间 |
⑥ 订单项表(t_order_item)
存储订单中的商品明细,关联订单和商品。
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | int | PK, AUTO_INCREMENT | 订单项 ID |
| order_id | varchar(50) | FK, NOT NULL | 所属订单号(关联 t_order) |
| product_id | int | FK, NOT NULL | 商品 ID |
| product_name | varchar(100) | NOT NULL | 商品名称(下单时快照,避免商品改名) |
| product_price | decimal(10,2) | NOT NULL | 商品单价(下单时快照) |
| quantity | int | NOT NULL | 购买数量 |
2. ER 图与表关系
- 用户与订单:1 对多(一个用户可有多笔订单);
- 用户与购物车:1 对多(一个用户可有多条购物车项);
- 分类与商品:1 对多(一个分类包含多个商品);
- 订单与订单项:1 对多(一笔订单包含多个商品明细);
- 商品与订单项:1 对多(一个商品可出现在多笔订单中)。
三、系统架构设计
采用MVC 分层架构,明确各层职责,便于后期维护和扩展。
1. 架构分层
| 层 | 职责 | 技术实现 |
|---|---|---|
| 视图层(View) | 展示数据,接收用户输入 | JSP、JSTL、EL、CSS、JavaScript |
| 控制层(Controller) | 接收请求,分发任务,响应结果 | Servlet、过滤器(Filter) |
| 业务层(Service) | 处理业务逻辑(如登录验证、订单生成) | Java 类(Service 接口 + 实现类) |
| 数据访问层(DAO) | 操作数据库(CRUD) | JDBC、DBUtils(简化数据库操作) |
| 模型(Model) | 封装数据(如用户、商品信息) | JavaBean(实体类) |
| 工具层(Util) | 提供通用功能(如数据库连接、加密) | 工具类(如 DBHelper、PasswordUtils) |
2. 核心技术选型
- Web 容器:Tomcat 9.0;
- 数据库:MySQL 8.0;
- 构建工具:Maven(管理依赖);
- 数据库连接池:HikariCP(高性能);
- JSP 标签库:JSTL 1.2、自定义标签(如分页标签);
- 前端技术:Bootstrap(简化 UI 开发)、jQuery(处理 DOM 和 AJAX)。
3. 项目目录结构
shopping/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ ├── com/
│ │ │ │ ├── shopping/
│ │ │ │ │ ├── controller/ // Servlet控制器
│ │ │ │ │ ├── service/ // 业务逻辑(接口+实现)
│ │ │ │ │ │ ├── impl/
│ │ │ │ │ ├── dao/ // 数据访问(接口+实现)
│ │ │ │ │ │ ├── impl/
│ │ │ │ │ ├── model/ // 实体类(JavaBean)
│ │ │ │ │ ├── filter/ // 过滤器(编码、权限)
│ │ │ │ │ ├── listener/ // 监听器(在线统计)
│ │ │ │ │ └── util/ // 工具类
│ ├── webapp/
│ │ ├── WEB-INF/
│ │ │ ├── classes/ // 编译后的class文件(Maven自动生成)
│ │ │ ├── lib/ // 依赖jar包(Maven自动管理)
│ │ │ ├── tags/ // 自定义标签文件(如分页标签)
│ │ │ ├── tlds/ // TLD文件
│ │ │ └── web.xml // 配置文件(Servlet、Filter等)
│ │ ├── static/ // 静态资源
│ │ │ ├── css/
│ │ │ ├── js/
│ │ │ └── images/
│ │ ├── user/ // 用户模块JSP
│ │ │ ├── login.jsp
│ │ │ ├── register.jsp
│ │ │ └── info.jsp
│ │ ├── product/ // 商品模块JSP
│ │ │ ├── list.jsp
│ │ │ └── detail.jsp
│ │ ├── cart/ // 购物车模块JSP
│ │ │ └── cart.jsp
│ │ ├── order/ // 订单模块JSP
│ │ │ ├── list.jsp
│ │ │ └── detail.jsp
│ │ ├── index.jsp // 首页
│ │ └── error.jsp // 错误页
└── pom.xml // Maven配置文件
四、核心模块实现
我们按模块逐步实现,重点讲解关键功能的核心代码和技术要点。
1. 基础准备工作
① 数据库连接工具类
使用 HikariCP 连接池,封装获取连接的方法:
public class DBHelper {
private static HikariDataSource dataSource;
static {
// 初始化连接池(从配置文件读取参数)
Properties props = new Properties();
try {
props.load(DBHelper.class.getClassLoader().getResourceAsStream("db.properties"));
HikariConfig config = new HikariConfig(props);
dataSource = new HikariDataSource(config);
} catch (IOException e) {
throw new RuntimeException("数据库配置文件加载失败", e);
}
}
// 获取连接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
// 关闭资源
public static void close(Connection conn, Statement stmt, ResultSet rs) {
if (rs != null) try { rs.close(); } catch (SQLException e) { e.printStackTrace(); }
if (stmt != null) try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); }
if (conn != null) try { conn.close(); } catch (SQLException e) { e.printStackTrace(); }
}
}
db.properties配置:
jdbcUrl=jdbc:mysql://localhost:3306/shopping?useUnicode=true&characterEncoding=UTF-8
username=root
password=123456
driverClassName=com.mysql.cj.jdbc.Driver
maximumPoolSize=10
minimumIdle=5
② 字符编码过滤器
解决全站中文乱码问题:
@WebFilter("/*")
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
chain.doFilter(request, response);
}
// init和destroy略
}
2. 用户模块:注册与登录
① 实体类(User.java)
public class User {
private int id;
private String username;
private String password; // 存储加密后的密码
private String phone;
private String address;
private Date createTime;
// getter和setter方法
}
② 注册功能实现
流程:用户提交表单→后端验证(用户名是否存在、密码强度等)→密码加密→存入数据库。
注册 Servlet(RegisterServlet.java):
@WebServlet("/user/register")
public class RegisterServlet extends HttpServlet {
private UserService userService = new UserServiceImpl();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String phone = req.getParameter("phone");
String address = req.getParameter("address");
// 前端验证(略,实际项目需JS验证非空、格式等)
// 后端验证
if (userService.existsUsername(username)) {
req.setAttribute("error", "用户名已存在");
req.getRequestDispatcher("/user/register.jsp").forward(req, resp);
return;
}
// 密码加密(BCrypt)
String encryptedPwd = PasswordUtils.encrypt(password);
// 封装用户对象
User user = new User();
user.setUsername(username);
user.setPassword(encryptedPwd);
user.setPhone(phone);
user.setAddress(address);
user.setCreateTime(new Date());
// 调用Service保存
boolean success = userService.register(user);
if (success) {
// 注册成功,跳转到登录页
resp.sendRedirect(req.getContextPath() + "/user/login.jsp?msg=注册成功,请登录");
} else {
req.setAttribute("error", "注册失败,请重试");
req.getRequestDispatcher("/user/register.jsp").forward(req, resp);
}
}
}
注册页面(register.jsp):
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>注册</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h2>用户注册</h2>
<c:if test="${not empty error}">
<div class="alert alert-danger">${error}</div>
</c:if>
<form action="${pageContext.request.contextPath}/user/register" method="post">
<div class="form-group">
<label>用户名:</label>
<input type="text" name="username" class="form-control" required>
</div>
<div class="form-group">
<label>密码:</label>
<input type="password" name="password" class="form-control" required>
</div>
<div class="form-group">
<label>手机号:</label>
<input type="tel" name="phone" class="form-control">
</div>
<div class="form-group">
<label>地址:</label>
<input type="text" name="address" class="form-control">
</div>
<button type="submit" class="btn btn-primary">注册</button>
</form>
</div>
</body>
</html>
③ 登录功能实现
流程:用户提交账号密码→验证用户名和密码→登录成功则创建 Session。
登录 Servlet(LoginServlet.java):
@WebServlet("/user/login")
public class LoginServlet extends HttpServlet {
private UserService userService = new UserServiceImpl();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
// 调用Service验证
User user = userService.login(username, password);
if (user != null) {
// 登录成功:创建Session,存储用户信息(只存必要字段)
HttpSession session = req.getSession();
session.setAttribute("loginUser", user);
// 防Session固定攻击:重置Session ID
session.invalidate();
session = req.getSession(true);
session.setAttribute("loginUser", user);
// 跳转到首页
resp.sendRedirect(req.getContextPath() + "/index.jsp");
} else {
req.setAttribute("error", "用户名或密码错误");
req.getRequestDispatcher("/user/login.jsp").forward(req, resp);
}
}
}
UserService 登录验证逻辑:
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
@Override
public User login(String username, String password) {
// 1. 根据用户名查询用户
User user = userDao.findByUsername(username);
if (user == null) {
return null; // 用户名不存在
}
// 2. 验证密码(BCrypt比对)
if (PasswordUtils.verify(password, user.getPassword())) {
return user; // 验证通过
}
return null; // 密码错误
}
}
3. 商品模块
① 商品列表(带分页)
流程:Servlet 接收分页参数(页码、每页条数)→调用 Service 查询商品列表和总条数→转发到 JSP 展示。
商品列表 Servlet(ProductListServlet.java):
@WebServlet("/product/list")
public class ProductListServlet extends HttpServlet {
private ProductService productService = new ProductServiceImpl();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取分页参数(默认第1页,每页10条)
int pageNum = 1;
int pageSize = 10;
try {
pageNum = Integer.parseInt(req.getParameter("pageNum"));
pageSize = Integer.parseInt(req.getParameter("pageSize"));
} catch (NumberFormatException e) {
// 参数无效则用默认值
}
// 获取分类ID(可选,用于分类筛选)
String categoryId = req.getParameter("categoryId");
// 获取搜索关键词(可选)
String keyword = req.getParameter("keyword");
// 调用Service查询:分页数据和总条数
PageBean<Product> pageBean = productService.findPage(pageNum, pageSize, categoryId, keyword);
// 存入request域,转发到列表页
req.setAttribute("pageBean", pageBean);
req.setAttribute("categoryId", categoryId);
req.setAttribute("keyword", keyword);
req.getRequestDispatcher("/product/list.jsp").forward(req, resp);
}
}
分页 Bean(PageBean.java):
public class PageBean<T> {
private int pageNum; // 当前页码
private int pageSize; // 每页条数
private long totalCount; // 总记录数
private int totalPage; // 总页数
private List<T> list; // 当前页数据
// 构造方法:计算总页数
public PageBean(int pageNum, int pageSize, long totalCount, List<T> list) {
this.pageNum = pageNum;
this.pageSize = pageSize;
this.totalCount = totalCount;
this.list = list;
// 计算总页数(向上取整)
this.totalPage = (int) (totalCount == 0 ? 1 : (totalCount + pageSize - 1) / pageSize);
}
// getter和setter
}
商品列表 JSP(list.jsp):
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="my" tagdir="/WEB-INF/tags" %> <%-- 导入分页标签 --%>
<html>
<head>
<title>商品列表</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<!-- 搜索框 -->
<form action="${pageContext.request.contextPath}/product/list" method="get" class="form-inline">
<input type="text" name="keyword" placeholder="搜索商品" class="form-control"
value="${not empty keyword ? keyword : ''}">
<button type="submit" class="btn btn-default">搜索</button>
</form>
<!-- 商品列表 -->
<div class="row">
<c:forEach items="${pageBean.list}" var="p">
<div class="col-md-3" style="margin-top: 20px;">
<div class="thumbnail">
<img src="${pageContext.request.contextPath}/static/images/${p.image}" alt="${p.name}">
<div class="caption">
<h3>${p.name}</h3>
<p>价格:<fmt:formatNumber value="${p.price}" type="currency"/></p>
<p>库存:${p.stock > 0 ? p.stock + '件' : '无货'}</p>
<p>
<a href="${pageContext.request.contextPath}/product/detail?id=${p.id}"
class="btn btn-info">查看详情</a>
<a href="${pageContext.request.contextPath}/cart/add?productId=${p.id}&quantity=1"
class="btn btn-primary"
<c:if test="${p.stock <= 0}">disabled</c:if>>加入购物车</a>
</p>
</div>
</div>
</div>
</c:forEach>
</div>
<!-- 分页控件(使用自定义分页标签) -->
<my:pagination
totalCount="${pageBean.totalCount}"
pageSize="${pageBean.pageSize}"
currentPage="${pageBean.pageNum}"
url="/product/list?categoryId=${categoryId}&keyword=${keyword}"
/>
</div>
</body>
</html>
4. 购物车模块
购物车数据存储在Session中(未登录用户)或数据库中(登录用户),这里实现登录用户的购物车(持久化)。
① 添加商品到购物车
流程:用户点击 “加入购物车”→Servlet 接收商品 ID 和数量→验证库存→调用 Service 添加(已存在则更新数量)。
添加购物车 Servlet(CartAddServlet.java):
@WebServlet("/cart/add")
public class CartAddServlet extends HttpServlet {
private CartService cartService = new CartServiceImpl();
private ProductService productService = new ProductServiceImpl();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 验证登录
User loginUser = (User) req.getSession().getAttribute("loginUser");
if (loginUser == null) {
// 未登录,重定向到登录页
resp.sendRedirect(req.getContextPath() + "/user/login.jsp?msg=请先登录");
return;
}
// 获取参数
int productId = Integer.parseInt(req.getParameter("productId"));
int quantity = Integer.parseInt(req.getParameter("quantity"));
// 验证库存
Product product = productService.findById(productId);
if (product == null || product.getStock() < quantity) {
resp.sendRedirect(req.getContextPath() + "/product/detail?id=" + productId + "&error=库存不足");
return;
}
// 调用Service添加到购物车
cartService.add(loginUser.getId(), productId, quantity);
// 重定向到购物车页面
resp.sendRedirect(req.getContextPath() + "/cart/cart.jsp");
}
}
5. 订单模块
① 生成订单(从购物车结算)
流程:用户点击 “结算”→验证购物车商品库存→创建订单和订单项→扣减库存→清空购物车。
生成订单 Servlet(OrderCreateServlet.java):
@WebServlet("/order/create")
public class OrderCreateServlet extends HttpServlet {
private OrderService orderService = new OrderServiceImpl();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 验证登录
User loginUser = (User) req.getSession().getAttribute("loginUser");
if (loginUser == null) {
resp.sendRedirect(req.getContextPath() + "/user/login.jsp");
return;
}
// 获取收货信息
String address = req.getParameter("address");
String phone = req.getParameter("phone");
// 调用Service生成订单(事务管理)
String orderId = orderService.createOrder(loginUser.getId(), address, phone);
if (orderId != null) {
// 生成成功,跳转到订单详情页
resp.sendRedirect(req.getContextPath() + "/order/detail?id=" + orderId);
} else {
req.setAttribute("error", "创建订单失败,请重试");
req.getRequestDispatcher("/cart/cart.jsp").forward(req, resp);
}
}
}
OrderService 核心逻辑(事务管理):
public class OrderServiceImpl implements OrderService {
// 注意:所有DAO操作需使用同一个Connection,确保事务统一
private Connection conn;
@Override
public String createOrder(int userId, String address, String phone) {
try {
// 1. 获取连接,关闭自动提交
conn = DBHelper.getConnection();
conn.setAutoCommit(false);
// 2. 查询用户购物车
CartDao cartDao = new CartDaoImpl(conn);
List<Cart> cartList = cartDao.findByUserId(userId);
if (cartList.isEmpty()) {
return null; // 购物车为空
}
// 3. 验证库存并计算总金额
ProductDao productDao = new ProductDaoImpl(conn);
BigDecimal totalPrice = BigDecimal.ZERO;
for (Cart cart : cartList) {
Product product = productDao.findById(cart.getProductId());
if (product.getStock() < cart.getQuantity()) {
throw new RuntimeException("商品《" + product.getName() + "》库存不足");
}
// 累加总金额
totalPrice = totalPrice.add(
product.getPrice().multiply(new BigDecimal(cart.getQuantity()))
);
}
// 4. 创建订单
String orderId = "ORD" + System.currentTimeMillis() + RandomStringUtils.randomNumeric(4);
Order order = new Order();
order.setId(orderId);
order.setUserId(userId);
order.setTotalPrice(totalPrice);
order.setStatus(0); // 待付款
order.setAddress(address);
order.setPhone(phone);
order.setCreateTime(new Date());
OrderDao orderDao = new OrderDaoImpl(conn);
orderDao.insert(order);
// 5. 创建订单项并扣减库存
OrderItemDao itemDao = new OrderItemDaoImpl(conn);
for (Cart cart : cartList) {
Product product = productDao.findById(cart.getProductId());
// 创建订单项
OrderItem item = new OrderItem();
item.setOrderId(orderId);
item.setProductId(product.getId());
item.setProductName(product.getName());
item.setProductPrice(product.getPrice());
item.setQuantity(cart.getQuantity());
itemDao.insert(item);
// 扣减库存
product.setStock(product.getStock() - cart.getQuantity());
productDao.updateStock(product);
}
// 6. 清空购物车
cartDao.deleteByUserId(userId);
// 7. 提交事务
conn.commit();
return orderId;
} catch (Exception e) {
// 回滚事务
try { if (conn != null) conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); }
e.printStackTrace();
return null;
} finally {
DBHelper.close(conn, null, null);
}
}
}
五、核心流程走通
1. 注册与登录
- 访问
http://localhost:8080/shopping/user/register.jsp,填写注册信息提交; - 注册成功后跳转到登录页,输入账号密码登录;
- 登录成功后,Session 中存储用户信息,跳转到首页。
2. 浏览与搜索商品
- 首页展示商品分类和热门商品;
- 点击分类或输入关键词搜索,进入商品列表页(带分页);
- 点击商品查看详情,可看到价格、库存、描述等信息。
3. 加入购物车与结算
- 在商品详情页点击 “加入购物车”,跳转至购物车页面;
- 购物车中可修改商品数量(需验证库存)或删除商品;
- 点击 “结算”,填写收货地址和电话,提交生成订单。
4. 订单管理
- 生成订单后,跳转到订单详情页,显示订单号、商品明细、总金额、状态(待付款);
- 访问 “我的订单” 列表,可查看所有订单及状态;
- 点击 “付款”“确认收货” 等按钮更新订单状态(简化版可手动修改状态演示)。
六、项目扩展与优化方向
本项目实现了核心功能,实际开发中还可扩展和优化:
-
功能扩展:
- 管理员模块(商品管理、订单管理、用户管理);
- 支付集成(对接支付宝、微信支付);
- 商品评价、收藏功能;
- 优惠券、积分系统。
-
技术优化:
- 加入 Redis 缓存热门商品和分类数据,减轻数据库压力;
- 异步处理订单通知(如短信提醒),使用消息队列;
- 前端使用 Vue.js 重构,实现前后端分离,提升用户体验;
- 加入日志系统(如 Logback),记录操作日志和异常。
-
安全增强:
- 实现图形验证码,防止注册和登录接口被恶意调用;
- 敏感操作(如支付、修改密码)增加短信验证;
- 定期备份数据库,防止数据丢失。
最后小结:
通过这个在线购物系统的实战,你已经综合运用了 JSP、Servlet、JSTL、EL、过滤器、事务管理等核心技术,理解了 MVC 分层架构的实际应用。从需求分析到数据库设计,从模块实现到流程串联,每个环节都是对 Web 开发能力的锻炼。项目开发的过程,也是解决问题的过程:如何设计合理的表结构?如何处理事务确保数据一致性?如何防范安全漏洞?这些问题的解决经验,比代码本身更有价值。虽然 JSP 技术已逐渐被前后端分离架构取代,但其中蕴含的 Web 开发思想(如 MVC、请求处理流程、数据交互)是相通的。掌握这些思想,再学习 Spring Boot、Vue 等新技术时,会更容易理解其设计理念。未完待续..........
更多推荐


所有评论(0)