简介:这份资源是面向计算机专业学生与Java Web初学者的一套水果销售管理网站完整项目,采用JSP技术结合MySQL数据库与B/S结构开发,可作为毕业设计、课程设计或Web开发练手参考。系统区分管理员与前台用户两类角色:后台涵盖个人中心、用户管理、水果信息与类别管理、销售单位管理、水果销售分析、会员分析、系统管理及订单管理;前台提供首页、水果信息、新闻资讯、购物车与个人中心等模块,功能划分较为完整。压缩包为rar格式,整体约23.1MB,内含源码、论文(lw)与答辩PPT等文件,源码用于项目运行与二次开发,论文与PPT可直接支撑毕业设计文档撰写与答辩展示。目前已有51人学习下载,适合需要一套结构清晰、模块齐全的JSP实战项目来快速理解MVC分层与数据库设计思路的读者参考借鉴。
1. 从一份 JSP 水果销售管理网站源码说起:它到底能跑出什么
很多做 Java Web 课程设计的人,第一次拿到「JSP水果销售管理网站(源码+lw+ppt).rar」这种压缩包时,心态是矛盾的:一方面觉得 JSP 已经是老技术,另一方面又确实需要一套能跑通、能答辩、能改的完整系统。我当年带人做课设,最常见的情况是——解压出来一堆.jsp、.java、.xml,Tomcat 一挂就报 404 或 500,然后卡在数据库连接上整整两天。这套东西的本质,是一个基于 JSP + Servlet + JDBC 的 B/S 架构管理系统,核心业务是水果商品的上架、下单、库存扣减和销售统计,配套的 lw 是论文文档,ppt 是答辩演示。它适合三类人:需要交课程设计的学生、想拿一套 CRUD 模板改造成自己项目的初学者、以及想复习传统 Java Web 分层写法的人。能不能用?能,但前提是你得先把运行环境和数据库这两关过了,否则源码再完整也只是个黑匣子。
2. 把 JSP 水果销售管理网站跑起来:环境、数据库与最小启动路径
2.1 先确认这套源码的技术栈边界
拿到压缩包后别急着导入 IDE,先做一件事:看目录结构。典型的 JSP 水果销售管理网站会包含src(Java 源码)、WebContent或webapp(JSP 页面和静态资源)、WebContent/WEB-INF/lib(依赖 jar 包)、WebContent/WEB-INF/web.xml(部署描述符),以及一个.sql数据库脚本。判断技术栈的关键点有三个:一看web.xml里的 servlet 版本,二看lib下有没有mysql-connector-java,三看 JSP 页面顶部有没有<%@ page import="java.sql.*" %>这类直连写法。很多课设级项目是 JSP 里直接写 JDBC,没有 Service 层,这种结构改起来快但维护差,你要心里有数。
常见做法是:JDK 用 1.8(JSP 老项目对高版本 JDK 兼容性差),Tomcat 用 8.5 或 9.0,MySQL 用 5.7 或 8.0。别一上来就 JDK 17 + Tomcat 10,Tomcat 10 把javax.servlet改成了jakarta.servlet,老项目直接全军覆没,这是血泪经验。
2.2 数据库导入与连接配置的实操步骤
第一步,建库导数据。用 Navicat 或命令行都行,命令行更稳:
# 登录 MySQL,创建数据库并导入脚本 mysql -u root -p CREATE DATABASE fruit_shop DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE fruit_shop; SOURCE /path/to/fruit_shop.sql;逻辑说明:utf8mb4是为了支持中文水果名和 emoji 备注,老项目常用utf8,遇到生僻字会乱码。SOURCE命令直接执行 sql 文件,比复制粘贴靠谱。参数上,库名要和源码里 JDBC URL 的库名一致,不一致就改代码或改库名,二选一。
第二步,改数据库连接。搜索整个项目里的jdbc:mysql,通常会命中一个DBUtil.java或DBHelper.java:
// DBUtil.java 典型写法 public class DBUtil { private static final String URL = "jdbc:mysql://localhost:3306/fruit_shop?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai"; private static final String USER = "root"; private static final String PASSWORD = "你的密码"; public static Connection getConnection() throws SQLException { try { Class.forName("com.mysql.cj.jdbc.Driver"); // MySQL 8 驱动类 return DriverManager.getConnection(URL, USER, PASSWORD); } catch (ClassNotFoundException e) { throw new SQLException("驱动未找到", e); } } }逻辑说明:serverTimezone不加,MySQL 8 会报时区错误;characterEncoding=utf8保证中文不乱码。参数上,驱动类 MySQL 5 用com.mysql.jdbc.Driver,MySQL 8 用com.mysql.cj.jdbc.Driver,写错就是ClassNotFoundException。如果你用的是连接池(Druid、C3P0),配置在druid.properties或c3p0-config.xml里,改法类似。
2.3 在 IDEA 里部署并验证首页能打开
导入项目时选「Existing Maven Project」或「Eclipse 项目」,取决于源码有没有pom.xml。没有 pom 的老项目,手动把lib下的 jar 加到 Module Dependencies。然后配置 Tomcat:
- Application server:指向本地 Tomcat 目录
- Deployment:添加 Artifact,通常是
项目名:war exploded - Application context:设成
/fruit或/
启动后访问http://localhost:8080/fruit/index.jsp。如果首页出来了但登录报错,八成是数据库没连上;如果直接 404,检查web.xml里的welcome-file和 context path。这一步过了,说明环境通了,后面才是改功能的事。
3. 读懂 JSP 水果销售管理网站的代码分层:从登录到下单的完整链路
3.1 登录模块:Session 与过滤器是怎么串起来的
课设级 JSP 项目的登录逻辑通常长这样:login.jsp提交表单到LoginServlet,Servlet 查数据库比对密码,成功则session.setAttribute("user", user),然后重定向到main.jsp。关键在权限控制——很多源码用一个LoginFilter拦截未登录请求:
// LoginFilter.java public class LoginFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; HttpSession session = request.getSession(); String uri = request.getRequestURI(); // 放行登录页、静态资源和登录接口 if (uri.contains("login.jsp") || uri.contains("LoginServlet") || uri.contains("/css/") || uri.contains("/js/")) { chain.doFilter(req, resp); return; } if (session.getAttribute("user") == null) { response.sendRedirect(request.getContextPath() + "/login.jsp"); return; } chain.doFilter(req, resp); } }逻辑说明:过滤器在web.xml里用<filter-mapping>配/*,拦截所有请求。参数上,放行列表要包含登录相关路径和静态资源,否则 CSS 加载不出来页面会很难看。这里有个常见坑:sendRedirect后必须return,不然代码继续往下走会报IllegalStateException。
3.2 商品与订单:JSP 页面直连 JDBC 的写法与改造点
水果销售的核心表一般有四张:user(用户)、fruit(水果商品)、orders(订单主表)、order_item(订单明细)。商品列表页fruitList.jsp常见写法是脚本段里查库:
<% Connection conn = DBUtil.getConnection(); String sql = "SELECT * FROM fruit WHERE status = 1 ORDER BY id DESC"; PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery(); while (rs.next()) { %> <tr> <td><%= rs.getString("name") %></td> <td><%= rs.getBigDecimal("price") %></td> <td><%= rs.getInt("stock") %></td> <td><a href="cartAdd.jsp?id=<%= rs.getInt("id") %>">加入购物车</a></td> </tr> <% } rs.close(); ps.close(); conn.close(); %>逻辑说明:这种写法把 Java 代码嵌在 HTML 里,可读性差但改起来直观。参数上,status = 1表示上架商品,下架改 0。改造建议:把查询逻辑抽到FruitDao.java,JSP 只负责渲染,这样加缓存或换 ORM 时不用动页面。下单时库存扣减要用事务:
// OrderService.java 下单核心 Connection conn = null; try { conn = DBUtil.getConnection(); conn.setAutoCommit(false); // 开启事务 // 1. 扣库存(带库存判断,防止超卖) String updateStock = "UPDATE fruit SET stock = stock - ? WHERE id = ? AND stock >= ?"; PreparedStatement ps1 = conn.prepareStatement(updateStock); ps1.setInt(1, qty); ps1.setInt(2, fruitId); ps1.setInt(3, qty); if (ps1.executeUpdate() == 0) throw new SQLException("库存不足"); // 2. 写订单主表和明细 // ... 省略插入语句 conn.commit(); } catch (Exception e) { if (conn != null) conn.rollback(); throw e; } finally { if (conn != null) conn.close(); }逻辑说明:stock >= ?这个条件很关键,它把库存判断和扣减放在一条 SQL 里,避免并发下超卖。参数上,setAutoCommit(false)后所有操作要么全成功要么全回滚。这是课设项目最容易忽略的地方,答辩时老师一问「两个人同时买最后一件怎么办」就露馅了。
3.3 销售统计:用 SQL 聚合代替 Java 循环
销售统计页通常要展示「今日销售额」「热销水果 Top 5」。新手容易查全部订单再在 Java 里循环累加,数据一多就慢。正确做法是交给数据库:
-- 今日销售额 SELECT IFNULL(SUM(total_amount), 0) AS today_sales FROM orders WHERE DATE(create_time) = CURDATE() AND status = 1; -- 热销水果 Top 5 SELECT f.name, SUM(oi.quantity) AS total_qty FROM order_item oi JOIN fruit f ON oi.fruit_id = f.id JOIN orders o ON oi.order_id = o.id WHERE o.status = 1 GROUP BY f.id, f.name ORDER BY total_qty DESC LIMIT 5;逻辑说明:IFNULL防止无订单时返回 null 导致页面报错;status = 1过滤掉已取消订单。参数上,DATE(create_time)会让索引失效,数据量大时改成create_time >= CURDATE() AND create_time < CURDATE() + INTERVAL 1 DAY。课设数据量小无所谓,但这是能体现你水平的地方。
4. 改这套源码时最容易翻车的地方:5 个排查记录
4.1 中文乱码:现象是页面显示问号,原因是编码链没统一
现象:水果名在数据库里正常,页面上显示???或æ°´æžœ。原因:JSP 页面pageEncoding、响应Content-Type、数据库连接characterEncoding、表字符集四者不一致。解决:JSP 顶部统一写<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>,JDBC URL 加characterEncoding=utf8,建库用utf8mb4,Tomcat 的server.xml里 Connector 加URIEncoding="UTF-8"。四处对齐,乱码必消。
4.2 404:现象是首页能开但点功能就找不到页面,原因是路径写死
现象:index.jsp正常,点「商品管理」跳 404。原因:源码里链接写成/fruitList.jsp绝对路径,但你的 context path 是/fruit,实际路径变成/fruitList.jsp而不是/fruit/fruitList.jsp。解决:所有链接和表单 action 前加${pageContext.request.contextPath},或者把 context path 设成/。这是部署配置问题,不是代码 bug。
4.3 数据库连接池耗尽:现象是跑一会儿就卡死,原因是连接没关
现象:系统用几分钟后所有请求卡住,日志报Too many connections。原因:JSP 脚本段里conn.close()写在while循环外或者异常路径没执行,连接泄漏。解决:用 try-with-resources 或把关闭放finally;更彻底的是引入 Druid 连接池,配置maxActive和removeAbandoned。课设项目手动关连接很容易漏,这是高频翻车点。
4.4 图片上传后不显示:现象是上传成功但页面裂图,原因是保存路径和访问路径不一致
现象:后台上传水果图片提示成功,前台<img src="...">裂开。原因:文件存到了服务器磁盘某目录,但该目录不在 Web 根路径下,或者存的是绝对路径D:\upload\1.jpg,浏览器无法访问。解决:存到webapp/upload下,数据库只存相对路径upload/1.jpg,页面用${pageContext.request.contextPath}/upload/1.jpg访问。注意 Tomcat 重新部署会清空webapp,生产环境要存到外部目录再配虚拟路径。
4.5 修改密码后登录失败:现象是新密码无效,原因是明文与加密混用
现象:用户改密码成功,但用新密码登不进去。原因:注册时密码明文存,改密码时用了 MD5 加密存,登录校验还是按明文比对。解决:统一加密策略,要么全明文(课设可接受),要么全 MD5 并在登录时同样加密后比对。改的时候搜全项目password字段的写入和读取点,别只改一处。
5. 让这套 JSP 水果销售管理网站拿得出手:三个进阶改造技巧
第一个技巧,把 JSP 里的 JDBC 抽成 DAO 层,用 DBUtil + 实体类 + DAO + Servlet 的四层结构重写一遍。这不是为了炫技,而是答辩时老师必问「你的项目分层吗」。改造顺序:先建entity包放Fruit、Order实体,再建dao包把 SQL 移进去,Servlet 只调 DAO。改完代码量可能多 30%,但可维护性和答辩分完全不一样。
第二个技巧,给列表页加分页。课设数据少时全查没问题,但你可以主动加上LIMIT分页,展示你懂性能。核心 SQL 是SELECT * FROM fruit LIMIT ?, ?,配合SELECT COUNT(*)算总页数。前端用简单的上一页/下一页即可,不用上插件。
第三个技巧,用 Filter 统一做字符编码和登录校验,别在每个 JSP 里写request.setCharacterEncoding("UTF-8")。一个EncodingFilter配/*,所有请求进来先设编码,代码干净且不会漏。
| 改造项 | 改动量 | 答辩加分点 | 风险 |
|---|---|---|---|
| DAO 分层 | 中 | 架构清晰 | 改错 SQL 导致功能挂 |
| 分页查询 | 小 | 性能意识 | LIMIT 参数越界 |
| 统一 Filter | 小 | 代码规范 | 放行列表漏配 |
最后说个我自己的习惯:每次改完一个模块,先把数据库备份一份再测,因为课设项目没有版本控制,改崩了想回退只能靠备份。这套源码本身不复杂,值不值得做取决于你的目标——如果只是交作业,跑通加改改界面就够;如果想借它把 Java Web 的请求链路、事务、分层真正搞明白,那它是个不错的练手靶子。希望帮到你。
本文还有配套的精品资源,点击获取