简介:一份基于JavaWeb技术实现的“华为商城”网上商城系统项目,面向JavaWeb与MySQL学习者,特别适合课程设计、毕业设计或综合实训时参考。资源共2个文件,合计58.24MB,包含RAR格式的完整项目源码包与SQL数据库脚本:源码覆盖Servlet、JSP、JavaBean等核心组件,SQL脚本用于初始化商品、用户、订单等数据表。已有961人学习下载。项目完整呈现用户注册、登录、商品浏览、购物车及订单处理等电商核心业务流程,可帮助读者理解JSP动态页面与MySQL数据库的交互方式,以及Web应用目录结构、配置文件和依赖包的组织方法;JSP页面还可结合JSTL标签库简化前端逻辑,SQL脚本中的表结构与示例数据便于快速还原运行环境。无论是对照实战还是二次开发,都具备较强的参考价值。
1. javaweb华为商城.zip:一份能跑通的JavaWeb实战项目
做 JavaWeb 课设或者毕业设计时,最怕的不是不会写代码,而是拿到一个 zip 包之后根本跑不起来。javaweb华为商城.zip 这个压缩包我解压过不止一次,它是一套用 JSP + Servlet + MySQL 搭出来的仿华为商城项目,从首页商品列表、登录注册、购物车到下单结算都有完整页面和后台逻辑。对于正在找“javaweb 项目完整案例 mysql”的人来说,它最大的价值是能让你在 IDEA 里把项目整个跑起来,再对着源码改功能,而不是从零敲一套商城出来。我在这篇笔记里把怎么做、参数怎么配、哪里会翻车都写清楚,照着做基本半小时内能看到首页。
2. 技术栈选型与项目结构:JSP+Servlet 这套老组合为什么还能用
2.1 为什么这种课设项目还在用 JSP+Servlet
很多人一看到 JSP 就觉得过时了,想着非得用 Spring Boot 才算“正规军”。但如果你只是做课程设计、期末大作业,或者想在简历里补一个 JavaWeb 完整项目,JSP + Servlet + MySQL 反而是最稳妥的选择。原因很简单:这类项目普遍运行在 Tomcat 8.5 / 9 上,依赖少,部署链路短,几乎所有高校机房环境都能直接跑,而且答辩时老师问的也就是 Servlet 生命周期、request 和 response 的用法、Session 怎么保持登录状态这些基础问题。
用 JSP 还有一个现实好处:页面改起来快。商城这种项目,页面量大,用 JSP 直接在 HTML 里嵌 Java 代码或 JSTL 标签,改个商品价格、调整页面布局都不需要重启整个应用,刷新页面就能看到效果。而 Spring Boot 那套虽然先进,但对新手来说启动报错排查成本高,一个依赖版本对不上能折腾一下午。
2.2 压缩包内的目录结构
拿到 javaweb华为商城.zip 之后,第一步是解压。常见做法是不要双击直接打开,而是先解压到一个全英文路径下,比如D:\javaweb-projects\huawei-mall。这类项目如果路径里带中文,IDEA 和 Tomcat 都容易在加载静态资源或编译 JSP 时报乱码错误。
解压后的标准结构一般是这样的(没有 Maven 的情况下):
huawei-mall/ ├── src/ │ ├── com.huawei.mall.dao/ // 数据库访问层:用户、商品、订单 DAO │ ├── com.huawei.mall.entity/ // 实体类:User、Product、Order 等 │ ├── com.huawei.mall.servlet/ // Servlet 控制层 │ ├── com.huawei.mall.util/ // 工具类:DBUtil、MD5加密等 │ └── com.huawei.mall.filter/ // 登录验证过滤器 ├── web/ │ ├── index.jsp // 首页 │ ├── product_list.jsp // 商品列表 │ ├── product_detail.jsp // 商品详情 │ ├── cart.jsp // 购物车 │ ├── login.jsp / register.jsp // 登录注册 │ ├── order/ // 下单选地址 │ ├── admin/ // 后台管理页面 │ └── WEB-INF/ │ ├── web.xml // Servlet 映射与过滤器配置 ├── sql/ │ └── huawei_mall.sql // 建库建表脚本,含数据 └── README.txt注意看这个结构里的分层:servlet只做请求转发和参数接收,业务逻辑在dao层直接操作数据库,实体类对应表结构。这虽然是老派写法,但分层清晰,适合照着理解 JavaWeb 的经典 MVC 流程。
2.3 数据库设计:五张核心表的字段与关系
商城类项目跑起来,最基础的是数据库。执行sql/huawei_mall.sql时我一般先打开看一眼表设计,再决定要不要改。这个项目里核心表一般有用户表、商品表、分类表、订单表、订单明细表,五个表的关系是这样的:用户和订单是一对多,订单和订单明细是一对多,商品和分类是多对一。
-- 用户表 CREATE TABLE `t_user` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `username` VARCHAR(50) NOT NULL, `password` VARCHAR(100) NOT NULL, -- 存的是 MD5 后的密文 `phone` VARCHAR(11) DEFAULT NULL, `address` VARCHAR(255) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- 商品表 CREATE TABLE `t_product` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(100) NOT NULL, `price` DECIMAL(10,2) NOT NULL, `stock` INT(11) NOT NULL DEFAULT 0, `image` VARCHAR(255) DEFAULT NULL, -- 图片路径,存在项目 web/images 下 `category_id` INT(11) DEFAULT NULL, `description` TEXT, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;密码字段用VARCHAR(100)而不是VARCHAR(32),原因是有可能部分项目用了MD5(密码+盐)的组合加密,长度会超过 32。如果你发现自己登录不上,先别怀疑代码逻辑,去数据库里把密码字段直接改成明文,再走一遍登录,如果通了就说明是加密方式的问题。
2.4 连接数据库的关键配置
数据库这块有个老坑:驱动包。压缩包里如果有lib文件夹,里面通常放着mysql-connector-java的 jar 包,版本可能是 5.x 或 8.x。如果用 MySQL 5.7,用 5.x 驱动没问题;如果本地装的是 MySQL 8.0+,必须换成 8.x 驱动,同时把连接 URL 里的com.mysql.jdbc.Driver改成com.mysql.cj.jdbc.Driver。
# src/com/huawei/mall/util/db.properties 或 DBUtil.java 中 driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/huawei_mall?useSSL=false&characterEncoding=utf-8 username=root password=123456这里的characterEncoding=utf-8必须加,不加就会出现商品名、用户名全是问号的情况。useSSL=false在本地开发时也建议加上,不然 MySQL 8 会提示 SSL 连接警告,虽然不影响运行,但是控制台日志看着闹心。
3. 本地复现:IDEA+Tomcat 环境配置与运行步骤
3.1 JDK 和 Tomcat 怎么选
我建过很多次 JavaWeb 运行环境,最省事的一套组合是 JDK 8 + Tomcat 8.5 + IDEA(老版本也一样操作)。JDK 8 兼容性最好,Tomcat 8.5 支持 Servlet 3.1 / JSP 2.3,和 JDK 8 配合不会出现版本类加载问题。如果你非要用 Tomcat 10,那要小心:Tomcat 10 把包名从javax.servlet.*换成了jakarta.servlet.*,这个项目如果用的是旧代码编译的,直接扔进 Tomcat 10 必然报ClassNotFoundException。
操作上,先在 IDEA 的File > Project Structure > SDK里确认 Project SDK 是 1.8,然后在File > Settings > Build, Execution, Deployment > Application Servers里添加 Tomcat Server,指向 Tomcat 解压目录。这一步很多人漏掉,导致后面运行配置里找不到 Tomcat 选项。
3.2 用 IDEA 打开项目并配置 Artifact
打开项目时,IDEA 会问你是信任这个项目还是以安全模式打开一个新项目,选择信任。如果压缩包解压出来的是.iml文件,说明对方是用 IDEA 建的项目,直接打开即可。如果只有.classpath/.project,那是 Eclipse 工程,这种情况也可以用 IDEA 打开,但需要把web目录手动标记为 Web 资源目录,否则部署时不会带上 JSP 页面。
接下来把项目构建成 Web Application,有两种路径:
# 方式一:在 Project Structure > Artifacts 里新建 # 选择 Web Application Exploded,然后设置 Output directory 和 Web Resource Directory # 方式二:如果你用的是社区版 IDEA,没有 Application Servers 功能 # 推荐直接下载 Tomcat 的 zip 包,把项目打成 war 扔到 webapps 下社区版 IDEA 不带 Tomcat 集成,很多学生卡在这一步。我的建议是:在 IDEA 右上角编辑运行配置,点加号选择 Tomcat Server > Local(旗舰版才有的选项);如果没有,就老实用 Tomcat 的webapps目录跑 war 包,这也是后端部署最经典的方式,部署出来还要手动到 Tomcat 的conf/server.xml配一个虚拟路径,把web/目录映射成根路径:
<Context docBase="D:/javaweb-projects/huawei-mall/web" path="/" reloadable="true"/>配好这个以后,启动 Tomcat,浏览器访问http://localhost:8080,就能看到商城首页。这个方式对新手来说反而是好事,因为它直接把“项目部署”这件事的黑匣子打开了。
3.3 启动时 JVM 参数与项目依赖
如果你的项目在 IDEA 里启动,还要检查一个细节:该项目的依赖是放在WEB-INF/lib下,还是由 Maven 管理。老式 JavaWeb 项目通常不是 Maven 工程,jar 包直接躺在web/WEB-INF/lib/下。但有些人拿到 zip 之后发现这个 lib 目录是空的,那多半是解压工具把空目录过滤掉了,或者原作者本来就忘记放进去。
这个时候别慌,分两步处理:
# 1. 检查 WEB-INF/lib 目录是否存在且非空 ls web/WEB-INF/lib/ # 2. 如果没有 mysql 驱动,从 Maven 中央仓库下载并放入该目录 # mysql-connector-java-5.1.49.jar 或 8.0.33.jar 二选一,取决于 MySQL 版本在 IDEA 里,把这三个 jar(servlet-api、mysql-connector、jstl 如果有)放进WEB-INF/lib后,右键Add as Library。这一步漏掉,编译阶段不一定会报错,但启动 Tomcat 时页面一旦触发 SQL 查询,就会抛ClassNotFoundException: com.mysql.jdbc.Driver。
3.4 首次启动与访问路径
启动前再检查一遍Run Configuration里的Deployment选项卡:Application context建议设为/,这样启动后访问http://localhost:8080就是项目首页,不需要再输入一长串项目名。如果设置了/huawei-mall,那首页就是http://localhost:8080/huawei-mall。
首次启动如果控制台没有报错,IDEA 会自动弹出浏览器。能看到商品列表说明数据库连接通了;如果页面是 500,把错误堆栈中Caused by那段复制出来搜,比查任何攻略都快。启动日志里出现INFO: Server startup in [xxx] milliseconds就说明一切正常,接下来就可以开始注册、登录、加购物车的测试流程了。
4. 功能模块与核心代码:从首页到生成订单的完整链路
4.1 首页商品列表:Servlet 到 JSP 的数据流转
整个项目里最能看懂 JavaWeb 工作流程的,是首页商品列表这个模块。用户在浏览器输入http://localhost:8080,Tomcat 根据web.xml里的欢迎页面配置,把请求交给index.jsp。而index.jsp里一般会创建一个ProductDao实例去查数据库。
// ProductDao.java 关键代码 public List<Product> findHotProducts() { List<Product> list = new ArrayList<Product>(); Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = DBUtil.getConnection(); String sql = "SELECT id, name, price, image, description FROM t_product ORDER BY id DESC LIMIT 8"; ps = conn.prepareStatement(sql); rs = ps.executeQuery(); while (rs.next()) { Product p = new Product(); p.setId(rs.getInt("id")); p.setName(rs.getString("name")); p.setPrice(rs.getDouble("price")); p.setImage(rs.getString("image")); p.setDescription(rs.getString("description")); list.add(p); } } catch (Exception e) { e.printStackTrace(); } finally { DBUtil.close(rs, ps, conn); } return list; }这段代码逻辑很简单:拿到数据库连接后,执行一个ORDER BY id DESC LIMIT 8的查询,把最近插入的 8 条商品数据封装成Product对象列表返回。这里的DBUtil.getConnection()是工具类,里面就是Class.forName加DriverManager.getConnection,很多新手喜欢在这里写死密码,改数据库密码时忘了同步,导致页面 500。
4.2 用户登录注册:Session 与 MD5 加密
登录注册是商城的入口。这个项目的登录流程通常是这样:用户在login.jsp输入用户名密码,表单提交到LoginServlet,LoginServlet调UserDao.findByUsernameAndPassword()查库比对,比对成功就把User对象放进 Session,然后重定向回首页;失败则forward回登录页并带上错误提示。
这里有个要注意的点:注册时密码到底存明文还是 MD5,直接决定你能不能“正常”登录。常见做法是注册时做一次加密存储,登录时把用户输入的密码也加密一次再比对。如果你在数据库里直接改密码为明文,而代码里用的是加密比对,那永远登录失败。
// 注册时加密 String encryptedPwd = MD5Util.md5(password); User user = new User(username, encryptedPwd, phone); userDao.add(user); // 登录时同样先加密再查询 String inputPwd = MD5Util.md5(password); User u = userDao.findByUsernameAndPassword(username, inputPwd);MD5 不是最安全的做法,但对于课程设计足够。如果做简历项目想秀一下,可以在MD5Util里加一个固定盐值拼接再加密,比如MD5Util.md5(password + "huawei_mall"),简单又显得懂行。需要注意的是加盐后,数据库里已有用户的密码就会全部失效,如果你要改这个,记得重新注册一遍测试账号。
4.3 购物车实现:Session 里存 Map 的经典写法
这个项目的购物车不是用数据库表实现的,而是把购物车对象直接放进了 Session,这也是 JavaWeb 课设最普遍的做法。好处是不用建表和写一堆持久化代码,刷新不丢;坏处是一清 Cookie、换浏览器,购物车就没了。对课程设计来说,这个取舍是合理的,你先跑通再想扩展。
购物车结构一般长这样:
// Cart.java 内部用 Map<Product, Integer> 保存商品和数量 public class Cart { private Map<Integer, CartItem> map = new LinkedHashMap<Integer, CartItem>(); private double totalPrice = 0.0; // 加入购物车:如果已存在则数量加一,否则新增 public void addProduct(Product product) { CartItem item = map.get(product.getId()); if (item == null) { map.put(product.getId(), new CartItem(product, 1)); } else { item.setCount(item.getCount() + 1); } calculateTotal(); } // 刷新总价 private void calculateTotal() { totalPrice = 0.0; for (CartItem item : map.values()) { totalPrice += item.getProduct().getPrice() * item.getCount(); } } }购物车相关的CartServlet里有三个关键操作:add、remove、clear。通常用action参数区分,比如CartServlet?action=add&productId=3。从页面触发时,商品详情的“加入购物车”按钮是一个表单,POST 到该 Servlet,Servlet 从 Session 里获取购物车对象(没有则新建),再把商品塞进去。
4.4 下单流程:事务控制和库存扣减
下单是商城项目的核心难点,这个资源里的订单模块一般会涉及两张表的写入:订单主表和订单明细表。如果这两步只做普通 INSERT 而不加事务,会出现一个问题:订单主表插入成功,但订单明细表插入失败,用户付款了却看不到买了啥。
正确写法是用Connection的事务控制把两步包起来:
conn.setAutoCommit(false); try { // 1. 插入订单主表,拿到自增 id String sqlOrder = "INSERT INTO t_order (user_id, total_price, status, create_time) VALUES (?, ?, ?, NOW())"; ps = conn.prepareStatement(sqlOrder, Statement.RETURN_GENERATED_KEYS); ps.setInt(1, userId); ps.setDouble(2, orderTotalPrice); ps.executeUpdate(); rs = ps.getGeneratedKeys(); int orderId = 0; if (rs.next()) orderId = rs.getInt(1); // 2. 批量插入订单明细 String sqlItem = "INSERT INTO t_order_item (order_id, product_id, product_name, price, count) VALUES (?, ?, ?, ?, ?)"; for (CartItem item : cart.getMap().values()) { ps = conn.prepareStatement(sqlItem); ps.setInt(1, orderId); ps.setInt(2, item.getProduct().getId()); ps.setString(3, item.getProduct().getName()); ps.setDouble(4, item.getProduct().getPrice()); ps.setInt(5, item.getCount()); ps.executeUpdate(); } // 3. 扣减库存 String sqlStock = "UPDATE t_product SET stock = stock - ? WHERE id = ?"; // 执行同样逻辑... conn.commit(); } catch (Exception e) { conn.rollback(); e.printStackTrace(); } finally { conn.setAutoCommit(true); DBUtil.close(rs, ps, conn); }这里的Statement.RETURN_GENERATED_KEYS是个关键点,先插入主表再用getGeneratedKeys()拿自增主键值,这样明细表才能关联上 order_id。如果不做这一步,你就得在插入前单独查一次SELECT MAX(id),在并发场景下极容易出问题。
4.5 后台管理模块:登录过滤器和商品管理
有前台就一定有后台,这个项目的后台一般放在admin/目录下,有商品管理、订单管理、用户管理三块。后台页面的保护是个重点:不能让人绕过登录直接访问admin/product_list.jsp。实现方式是在web.xml里配置一个过滤器,或者用 Servlet 的拦截逻辑。
<filter> <filter-name>AdminAuthFilter</filter-name> <filter-class>com.huawei.mall.filter.AdminAuthFilter</filter-class> </filter> <filter-mapping> <filter-name>AdminAuthFilter</filter-name> <url-pattern>/admin/*</url-pattern> </filter-mapping>同时在web.xml里的 Servlet 映射上注意一个细节:/admin/*是路径匹配,如果过滤器位置写错或者 URL 映射层级不对,后台管理页面就能被直接访问。这一点在答辩时经常被老师问到,你能答出来“我用过滤器拦了/admin/*下的所有请求,Session 里没有 admin 标志就重定向到登录页”,这就是一个加分项。
5. 避坑记录:部署 javaweb 商城项目最常见的五个坑
5.1 IDEA 社区版没有 Tomcat 集成
现象:打开 IDEA 社区版,右上角没有 Tomcat Server 的配置选项,新手直接卡在这里。
原因:Tomcat 集成是 IDEA 旗舰版(Ultimate)的功能,社区版免费但功能被砍掉了这一块。很多文章默认你用的是旗舰版,导致照着操作半天找不到按钮。
解决:两个办法任选。一是下载 Tomcat 的 zip 包,手动解压到本地,把项目打成 war 包放进tomcat/webapps下,再用tomcat/bin/startup.bat启动;二是项目结构改成 Maven 后加tomcat7-maven-plugin插件,执行mvn tomcat7:run,这样绕过 IDEA 内置的 Tomcat 集成。
提示:
tomcat7-maven-plugin虽然名叫 tomcat7,但实际在绝大多数老项目里都能跑,JDK 8 环境下兼容性没问题。
5.2 MySQL 8 驱动版本不匹配导致连接失败
现象:启动项目后首页报ClassNotFoundException: com.mysql.jdbc.Driver,或者报Public Key Retrieval is not allowed。
原因:本地是 MySQL 8,但WEB-INF/lib下的驱动是 mysql-connector-java 5.x。MySQL 8 默认使用caching_sha2_password认证插件,老驱动不支持这种认证方式,而且 MySQL 8 的官方驱动类名也换成了com.mysql.cj.jdbc.Driver。
解决:去 Maven 中央仓库下载mysql-connector-java-8.0.33.jar,替换掉老的 jar 包,然后同步修改DBUtil里的驱动名和 URL:
Class.forName("com.mysql.cj.jdbc.Driver"); url = "jdbc:mysql://localhost:3306/huawei_mall?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf-8";serverTimezone这个参数在 MySQL 8 里不加会直接报时区错误,别偷懒跳过。
5.3 数据库导入后中文变成问号
现象:用 Navicat 导入huawei_mall.sql之后,打开表一看,所有商品名称都是?????。
原因:SQL 文件里面的CHARSET=utf8没问题,但导入时连接 MySQL 的客户端字符集不对,Navicat 连接属性默认可能不是 UTF-8。
解决:在 Navicat 里右键连接选择“编辑连接 > 高级”,把“编码”设为UTF-8,删除数据库重新导入一遍。更快速的办法是在导入前先执行一句命令:
SET NAMES utf8mb4;导入后用SELECT * FROM t_product检查,如果能正常显示中文,再去本地打开项目看页面。
5.4 JSP 页面报 500:ClassNotFoundException: org.apache.jasper.runtime.HttpJspBase
现象:Tomcat 能正常启动,但访问任意 JSP 页面都报错,堆栈里出现org.apache.jasper.runtime.HttpJspBase找不到。
原因:tomcat 的servlet-api.jar被错误地放进了项目的WEB-INF/lib。项目部署时 Tomcat 会按“Web 应用类加载优先”的原则加载WEB-INF/lib下的 jar,里面如果混了一个老版本的servlet-api.jar,JSP 编译时就会因为 JSP 引擎的类被覆盖而崩溃。
解决:检查WEB-INF/lib,如果有servlet-api.jar或jsp-api.jar,直接删掉。Tomcat 本身就提供了这些 API,项目里根本不需要放。
5.5 修改代码后不生效:页面还是旧的
现象:改了product_list.jsp的标题,刷新浏览器死活不生效,还是显示原来的内容。
原因:JSP 页面被 Tomcat 编译成了 Servlet 的 class 文件,存放在 Tomcat 的work/Catalina/localhost/目录下。如果你用的是 IDEA 的 Tomcat 集成,点“刷新浏览器”只是重复请求,重编译 JSP 是需要触发的。
解决:每次修改 JSP 后用 DEBUG 模式重启 Tomcat,或者设置 IDEA 里的On frame deactivation为Update resources。如果修改的是 java 文件,必须重启应用才能生效。这一条看似简单,但实际排查时最容易浪费时间的坑。
6. 进阶:把课设项目改成简历项目的方法
拿到这份资源,跑通是底线,让它变成能写到简历上的项目才是目标。改造方向有三个,全部做完时间成本在一到两天,但对面试时的影响完全不同。
第一,给 SQL 语句全部加上预编译参数。原项目如果有些地方图省事用了字符串拼接 SQL,这点就是面试官一眼能看出来的问题。把所有Statement换成PreparedStatement,至少能体现你对 SQL 注入有概念。顺便在注册接口写一个参数校验,用户名只允许字母数字下划线,长度限制 6-20,这个改动几分钟,但简历上能写“项目实现了基础的输入校验与防 SQL 注入”。
第二,引入 Alibaba Druid 连接池替换 JDBC 直连。原项目DBUtil里每次getConnection都是DriverManager的直连,这样每次数据库操作都创建和销毁一个连接,性能很差。引入 Druid 只需要改一个工具类,配置数据源,其余 DAO 代码不用大改。简历上就能写“通过 Druid 连接池管理数据库连接,消除了连接频繁创建的开销”。
第三,就是给购物车加一个 redis 的实现。原项目的购物车放在 Session 里,这是 JavaWeb 课设的标准写法,但你可以在项目里加一个RedisCartServiceImpl,把Cart序列化成 JSON 存入 Redis,key 是用户 id,value 是购物车数据。注意给原来的CartServlet留一个接口切换的实现类,这样前台页面完全不动,底层存储换了。简历上的描述就更高级了。
做完这三步,再跑一遍完整流程:注册、登录、搜索商品、加入购物车、下单、后台改库存。记录下每一步的花费时间和踩坑点,面试被问的时候,直接讲你是怎么做这三个改造的就行。
我在帮人过一遍这个项目时,每次都强制自己先删掉WEB-INF/lib里的 servlet-api.jar,再固定用“JDK8 + Tomcat8.5 + MySQL8”这套组合测试,这样线上报错就少了一大半。从那以后,我拿到任何一份 javaweb 的 zip 包,都是先看 lib 再看 web.xml,最后才启动服务器。这套习惯帮我避开了大部分坑,希望你也能少走点弯路,希望帮到你。
本文还有配套的精品资源,点击获取