黑马商城JDBC+Servlet项目完善

一、项目来源

项目来自于Github上ruanwenjun大佬的学习项目,链接:https://github.com/ruanwenjun/JAVAWeb-Project/tree/master/网络商城项目

二、运行环境与结果

1. 运行环境:

操作系统:Windows11 x64
硬件:11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz 2.42 GHz,8GB内存
IDE:IntelliJ IDEA 2024.3.1.1
后端:Java Servlet
前端:JSP、JavaScript、CSS
Java版本:Oracle OpenJDK 21.0.5
Tomcat版本:Tomcat 9.0.85
数据库:mysql 8.0
数据库连接池:C3P0

2. 运行结果:




三、项目结构

分层架构:

表现层:Servlet处理请求和响应
业务层:Service类处理业务逻辑
持久层:DAO类处理数据访问
工具类:位于cn.ruanwenjun.utils包

核心功能模块

1. 用户模块 (UserServlet)

用户注册
用户登录

验证码生成功能(CheckImgServlet)

2. 商品模块 (ProductServlet)

首页商品展示(热门商品、新品)
商品分类展示
商品详情查看
分页查询商品列表

3. 购物车模块 (CartServlet)

添加商品到购物车
更新购物车商品数量
删除购物车商品
清空购物车

4. 订单模块 (OrderServlet)

创建订单
确认订单信息(收货地址、联系方式等)
订单提交
订单查询
订单支付(集成第三方支付接口)

支付回调处理(CallBackServlet)

5. 后台管理模块 (AdminServlet)

订单管理:查看所有订单、订单详情
商品管理:查看所有商品

添加商品功能(AdminAddProductServlet)

四、主要问题与解决办法

1.购物车数据丢失问题

该项目目前没有把购物车的数据保存到数据库,关闭网页再开启后,购物车中的内容会被清空。为了提高用户使用满意度,我将用户每一次修改的购物车数据同步保存到数据库,解决了购物车数据丢失问题。

Show Code

package cn.ruanwenjun.dao;
import cn.ruanwenjun.domain.CartItem;
import cn.ruanwenjun.utils.DataSourceUtils;
import org.apache.commons.dbutils.QueryRunner;
import java.sql.SQLException;
import java.util.List;
public class CartDao {
    private QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
    // 保存购物车项
    public void saveCartItem(String userId, CartItem item) throws SQLException {
        String sql = "INSERT INTO cart_items (user_id, product_id, quantity, added_time) VALUES (?, ?, ?, NOW())";
        runner.update(sql, userId, item.getProduct().getId(), item.getQuantity());
    }
    // 读取用户购物车
    public List getCartItems(String userId) throws SQLException {
        String sql = "SELECT c.*, p.* FROM cart_items c JOIN product p ON c.product_id=p.id WHERE c.user_id=?";
        return null; // 实际返回查询结果
    }
}


2.用户收藏夹功能

目前市面上的网上购物平台都会有用户收藏夹功能,用户可以收藏喜欢的商品或店铺而不用加入购物车当中。为了使项目更加完善和便于使用,我增加了用户收藏夹功能,以便用户收藏自己喜欢的商品。
数据库:

Show Code
-- 创建收藏表
CREATE TABLE `favorite` (
  `id` varchar(32) NOT NULL COMMENT '收藏ID',
  `uid` varchar(32) NOT NULL COMMENT '用户ID',
  `pid` varchar(32) NOT NULL COMMENT '商品ID',
  `favorite_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '收藏时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uid_pid_idx` (`uid`,`pid`),
  KEY `pid_idx` (`pid`),
  CONSTRAINT `fk_favorite_user` FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON DELETE CASCADE,
  CONSTRAINT `fk_favorite_product` FOREIGN KEY (`pid`) REFERENCES `product` (`pid`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户收藏表';
模型类:
Show Code
package cn.ruanwenjun.domain;

import java.util.Date;

public class Favorite {
private String id;
private User user;
private Product product;
private Date favoriteTime;

// 构造方法
public Favorite() {}

// getter和setter方法
public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

public User getUser() {
    return user;
}

public void setUser(User user) {
    this.user = user;
}

public Product getProduct() {
    return product;
}

public void setProduct(Product product) {
    this.product = product;
}

public Date getFavoriteTime() {
    return favoriteTime;
}

public void setFavoriteTime(Date favoriteTime) {
    this.favoriteTime = favoriteTime;
}

}


Dao层:

Show Code
package cn.ruanwenjun.dao;

import cn.ruanwenjun.domain.Favorite;
import cn.ruanwenjun.domain.Product;
import cn.ruanwenjun.utils.DataSourceUtils;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.sql.SQLException;
import java.util.List;

public class FavoriteDao {

// 添加收藏
public void addFavorite(String id, String uid, String pid) throws SQLException {
    QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
    String sql = "INSERT INTO favorite (id, uid, pid) VALUES (?, ?, ?)";
    runner.update(sql, id, uid, pid);
}

// 取消收藏
public void removeFavorite(String uid, String pid) throws SQLException {
    QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
    String sql = "DELETE FROM favorite WHERE uid=? AND pid=?";
    runner.update(sql, uid, pid);
}

// 查询用户的收藏商品
public List<Product> findFavoritesByUid(String uid) throws SQLException {
    QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
    String sql = "SELECT p.* FROM product p JOIN favorite f ON p.pid=f.pid WHERE f.uid=? ORDER BY f.favorite_time DESC";
    return runner.query(sql, new BeanListHandler<Product>(Product.class), uid);
}

// 判断商品是否已被用户收藏
public boolean isFavorite(String uid, String pid) throws SQLException {
    QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
    String sql = "SELECT COUNT(*) FROM favorite WHERE uid=? AND pid=?";
    Long count = (Long) runner.query(sql, new ScalarHandler(), uid, pid);
    return count > 0;
}

// 获取用户收藏商品数量
public int getFavoriteCount(String uid) throws SQLException {
    QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
    String sql = "SELECT COUNT(*) FROM favorite WHERE uid=?";
    Long count = (Long) runner.query(sql, new ScalarHandler(), uid);
    return count.intValue();
}

}


Service层:

Show Code
package cn.ruanwenjun.service;

import cn.ruanwenjun.dao.FavoriteDao;
import cn.ruanwenjun.domain.Product;

import java.sql.SQLException;
import java.util.List;
import java.util.UUID;

public class FavoriteService {
private FavoriteDao favoriteDao = new FavoriteDao();

// 添加收藏
public boolean addFavorite(String uid, String pid) {
    try {
        // 先检查是否已收藏
        if (favoriteDao.isFavorite(uid, pid)) {
            return false;
        }
        
        // 生成收藏ID并添加收藏
        String id = UUID.randomUUID().toString();
        favoriteDao.addFavorite(id, uid, pid);
        return true;
    } catch (SQLException e) {
        e.printStackTrace();
        return false;
    }
}

// 取消收藏
public boolean removeFavorite(String uid, String pid) {
    try {
        favoriteDao.removeFavorite(uid, pid);
        return true;
    } catch (SQLException e) {
        e.printStackTrace();
        return false;
    }
}

// 获取用户收藏的商品列表
public List<Product> getFavoritesByUser(String uid) {
    try {
        return favoriteDao.findFavoritesByUid(uid);
    } catch (SQLException e) {
        e.printStackTrace();
        return null;
    }
}

// 判断商品是否已被用户收藏
public boolean isFavorite(String uid, String pid) {
    try {
        return favoriteDao.isFavorite(uid, pid);
    } catch (SQLException e) {
        e.printStackTrace();
        return false;
    }
}

// 获取用户收藏商品数量
public int getFavoriteCount(String uid) {
    try {
        return favoriteDao.getFavoriteCount(uid);
    } catch (SQLException e) {
        e.printStackTrace();
        return 0;
    }
}

}


Servlet层:

Show Code
package cn.ruanwenjun.web.servlet;

import cn.ruanwenjun.domain.Product;
import cn.ruanwenjun.domain.User;
import cn.ruanwenjun.service.FavoriteService;
import cn.ruanwenjun.service.ProductService;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

public class FavoriteServlet extends BasicServlet {

// 添加收藏
public void addFavorite(HttpServletRequest request, HttpServletResponse response) throws IOException {
    // 检查用户是否登录
    User user = (User) request.getSession().getAttribute("user");
    if (user == null) {
        // 未登录,返回登录页
        response.getWriter().write("{\"success\":false, \"message\":\"请先登录\"}");
        return;
    }
    
    // 获取商品ID
    String pid = request.getParameter("pid");
    
    // 调用Service添加收藏
    FavoriteService service = new FavoriteService();
    boolean success = service.addFavorite(user.getUid(), pid);
    
    // 返回结果
    response.getWriter().write("{\"success\":" + success + "}");
}

// 取消收藏
public void removeFavorite(HttpServletRequest request, HttpServletResponse response) throws IOException {
    // 检查用户是否登录
    User user = (User) request.getSession().getAttribute("user");
    if (user == null) {
        response.getWriter().write("{\"success\":false, \"message\":\"请先登录\"}");
        return;
    }
    
    // 获取商品ID
    String pid = request.getParameter("pid");
    
    // 调用Service取消收藏
    FavoriteService service = new FavoriteService();
    boolean success = service.removeFavorite(user.getUid(), pid);
    
    // 返回结果
    response.getWriter().write("{\"success\":" + success + "}");
}

// 我的收藏页面
public void myFavorites(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // 检查用户是否登录
    User user = (User) request.getSession().getAttribute("user");
    if (user == null) {
        response.sendRedirect(request.getContextPath() + "/login.jsp");
        return;
    }
    
    // 获取用户收藏的商品
    FavoriteService service = new FavoriteService();
    List<Product> favoriteList = service.getFavoritesByUser(user.getUid());
    
    // 将结果放入request
    request.setAttribute("favoriteList", favoriteList);
    
    // 转发到收藏页面
    request.getRequestDispatcher("/favorite.jsp").forward(request, response);
}

// 检查商品是否已收藏
public void isFavorite(HttpServletRequest request, HttpServletResponse response) throws IOException {
    // 检查用户是否登录
    User user = (User) request.getSession().getAttribute("user");
    if (user == null) {
        response.getWriter().write("{\"isFavorite\":false}");
        return;
    }
    
    // 获取商品ID
    String pid = request.getParameter("pid");
    
    // 调用Service检查是否已收藏
    FavoriteService service = new FavoriteService();
    boolean isFavorite = service.isFavorite(user.getUid(), pid);
    
    // 返回结果
    response.getWriter().write("{\"isFavorite\":" + isFavorite + "}");
}

}


五、总结(难点与思考)

在对这个JDBC+Servlet项目的完善过程中,我认为最困难的就是读懂项目本身。对于我这样一个没什么项目开发经验的大二学生来说,这个项目有些庞大了。我花费了一个小时将项目从github上clone下来,装在自己的IDEA上,配置好tomcat、JDK、mysql,成功运行后发现许多资源丢失了,又花了两天的时间去读项目、修改项目。在这个过程中我屡次想要放弃,想要换一个更简单一些的项目,但我已在上学期学习并独立完成了一个基于JDBC+Servlet的图书借阅系统,我想我有能力去搞懂这样一个商城项目。
在思考如何完善这个项目的过程中,我体悟到了从用户需求的角度出发,把自己当作用户,希望这样一个商城系统还可以有什么样的功能。通过开发者到用户的换位思考,我可以更加清醒地看到项目的不足之处。这为我之后的项目开发与设计提供了很好的思路和角度。

posted @ 2025-02-27 22:14  羲祐  阅读(188)  评论(0)    收藏  举报