资讯动态

Java+JSP+MySQL订餐系统搭建与调试全指南

发布时间:2026/9/11 17:11:46 来源:尧图企业网站定制
简介这是一套面向Java Web初学者与课程设计者的简易网上订餐系统实战源码基于JavaJSPMySQL技术栈实现MVC分层架构覆盖用户注册登录、菜单浏览、在线下单、订单管理等核心业务流程适用于高校Web开发实训、毕业设计参考及Servlet/JSP入门项目实践。压缩包共1262个文件含48个JSP页面负责前端交互与展示、44个Java类涵盖Servlet控制器、DAO数据访问及实体模型、44个编译后Class文件、42个Jar依赖库以及491个CSS样式文件和415个PNG图片资源完整支撑界面渲染与功能运行另有1个SQL脚本用于快速初始化MySQL数据库配合WebContent与src标准目录结构开箱即用。资源包大小为47.38MB目前已有383人学习下载提供清晰的项目组织、典型三层代码划分及可直接部署调试的完整工程助读者深入理解Java Web请求流转、数据库连接池应用与前后端协同逻辑。1. 一个能跑起来的 JavaJSPMySQL 网上订餐系统不是 Demo是真实可调试的最小闭环你下载到的基于javajspmysql简单网上订餐系统源码.zip不是教学幻灯片也不是空壳工程。它是一套完整走通「用户浏览菜单 → 加入购物车 → 提交订单 → 后台查看订单」全流程的 Web 应用底层用 Servlet 处理请求、JSP 渲染页面、MySQL 存储数据所有代码都在src/和WebContent/下没有隐藏依赖或外部服务。这套源码适合两类人刚学完 Java Web 基础Servlet/JSP/MySQL 连接想验证知识闭环的新手以及需要快速搭建内部测试环境、临时演示订餐逻辑的运维或产品同学。它不追求高并发或微服务架构但每一步——从数据库建表语句、web.xml的 servlet 映射、JSP 中 EL 表达式取值到Class.forName(com.mysql.cj.jdbc.Driver)的驱动加载——都保留了 Java EE 传统开发的真实痕迹。如果你正被java.lang.ClassNotFoundException: com.mysql.jdbc.Driver卡住或发现 JSP 页面里${user.name}不渲染说明你已经站在了调试这个系统的正确起点上。2. 搭建运行环境从 JDK 8 到 MySQL 5.7 的四步落地清单要让这个.zip包真正跑起来必须按顺序确认四个基础组件的版本与配置。跳过任一环节后续所有“页面打不开”“数据库连不上”问题都会反复出现。这不是可选步骤而是这个 JavaJSPMySQL 架构的硬性前提。2.1 确认 JDK 版本并配置 JAVA_HOME该系统源码中web.xml使用的是version2.5pom.xml如果存在或build.xml中未声明 Java 11 语法特性因此必须使用 JDK 8推荐 u202 或更高。JDK 11 会因模块化导致javax.servlet.*类找不到而 JDK 17 更会直接拒绝加载sun.misc.BASE64Encoder部分旧版 JDBC 驱动仍引用。验证方式不是看java -version而是执行# 在命令行中运行确认输出包含 1.8.0_ java -version # 再检查 JAVA_HOME 是否指向 JDK 8 根目录非 JRE echo $JAVA_HOME # Linux/macOS echo %JAVA_HOME% # Windows提示若JAVA_HOME指向 JDK 11请立即修改系统环境变量。Tomcat 启动脚本如catalina.sh会优先读取JAVA_HOME而非PATH中的 java。常见错误是java.lang.NoClassDefFoundError: javax/servlet/Servlet根源就是 JDK 版本错配。2.2 部署 Tomcat 8.5 并校验 webapps 目录结构该系统未使用 Maven 打包为 WAR而是以传统目录结构存放因此必须部署到 Tomcat 8.5兼容 Servlet 3.1且对 JSP 2.3 支持稳定。Tomcat 9 默认禁用org.apache.jasper.compiler.TldLocationsCache的自动扫描会导致 JSP 中自定义标签库如c:forEach报org.apache.taglibs.standard.tag.common.core.ForEachTag错误。部署时需严格遵循以下路径映射tomcat/webapps/food/ ← 解压后的根目录必须叫 food因 web.xml 中 context-root 设为 /food ├── WEB-INF/ │ ├── web.xml ← 关键确认 servlet-mapping 中 url-pattern 为 /login.do 等 │ ├── lib/ │ │ ├── mysql-connector-java-5.1.47.jar ← 必须是 5.x 版本8.x 驱动需改 URL 和 Driver 类名 │ │ └── jstl-1.2.jar ← JSTL 标签库缺则 c:if 等全部失效 │ └── classes/ ← 编译后的 .class 文件存放处src/ 下的 Java 文件需先编译至此 ├── index.jsp ← 入口页面应能直接访问 http://localhost:8080/food/index.jsp └── css/ js/ images/ ← 静态资源目录注意不要将整个.zip解压后直接拖进webapps/—— 必须确保最外层文件夹名为food且其下直接是WEB-INF和index.jsp。否则 Tomcat 无法识别为 Web 应用日志中会出现No Context configured to process this request。2.3 初始化 MySQL 数据库并验证连接参数系统使用的 MySQL 版本需为5.7.x非 8.0因为源码中 JDBC URL 为jdbc:mysql://localhost:3306/fooddb?useUnicodetruecharacterEncodingUTF-8未启用serverTimezoneUTC或allowPublicKeyRetrievaltrue。若强行使用 MySQL 8.0会抛出java.sql.SQLException: The server time zone value XXX is unrecognized。建库与授权命令如下-- 1. 创建数据库字符集必须为 utf8mb4避免中文乱码 CREATE DATABASE fooddb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 2. 创建专用用户禁止 root 直连生产环境此处仅开发用 CREATE USER fooduserlocalhost IDENTIFIED BY foodpass123; GRANT ALL PRIVILEGES ON fooddb.* TO fooduserlocalhost; -- 3. 刷新权限 FLUSH PRIVILEGES;然后在源码的数据库工具类如DBUtil.java或ConnectionManager.java中确认以下三处参数完全匹配参数位置示例值必须一致项JDBC URLjdbc:mysql://localhost:3306/fooddb?useUnicodetruecharacterEncodingUTF-8localhost、3306、fooddb、UTF-8用户名fooduser与CREATE USER命令一致密码foodpass123与IDENTIFIED BY后字符串一致提示若连接失败先在 MySQL 命令行执行SELECT USER(), CURRENT_USER();确认当前登录用户是否为fooduserlocalhost。CURRENT_USER()返回值必须与授权语句中的fooduserlocalhost完全一致否则权限不生效。2.4 编译 Java 源码并放置到 WEB-INF/classes源码中的 Java 文件如LoginServlet.java,OrderDAO.java必须手动编译为.class文件并放入WEB-INF/classes/对应包路径下。不能依赖 IDE 自动部署因为传统 JSP 系统对类路径敏感。操作步骤# 进入源码 src 目录假设解压后路径为 ~/food-src/src cd ~/food-src/src # 编译所有 Java 文件输出到 WEB-INF/classes需提前创建该目录 javac -encoding UTF-8 -d ../WebContent/WEB-INF/classes \ *.java \ dao/*.java \ model/*.java \ servlet/*.java # 验证编译结果classes 目录下应有对应包结构 ls ../WebContent/WEB-INF/classes/ # 输出应包含LoginServlet.class, dao/OrderDAO.class, model/User.class 等注意-encoding UTF-8参数不可省略。若源码中含中文注释或字符串如用户名不能为空未指定编码会导致编译后 class 文件中文字乱码JSP 页面显示????。这是新手最常忽略却最难排查的问题之一。3. 核心功能链路解析从 login.do 到 orderlist.jsp 的七层调用栈该系统虽标称“简单”但其请求处理链路清晰体现了 Java Web 经典分层JSP → Servlet → Service → DAO → JDBC → MySQL → JSP。理解每一层的职责与数据流向是调试“点击登录无反应”或“订单列表为空”的关键。我们以用户登录为例逐层拆解。3.1 JSP 表单提交触发 Servlet 映射login.jsp中的表单必须严格匹配web.xml中的servlet-mapping配置!-- login.jsp 中的 form -- form actionlogin.do methodpost input typetext nameusername / input typepassword namepassword / input typesubmit value登录 / /form对应web.xml中servlet servlet-nameLoginServlet/servlet-name servlet-classservlet.LoginServlet/servlet-class /servlet servlet-mapping servlet-nameLoginServlet/servlet-name url-pattern/login.do/url-pattern !-- 必须与 form action 完全一致 -- /servlet-mapping提示若修改了url-pattern为/login但 JSP 中仍写actionlogin.do则 Tomcat 日志会记录SEVERE: Servlet.service() for servlet [jsp] threw exception实际请求根本未到达LoginServlet。务必用浏览器开发者工具 Network 标签页确认提交的请求 URL 是http://localhost:8080/food/login.do。3.2 Servlet 接收参数并调用 Service 层LoginServlet.java的核心逻辑是获取请求参数、调用业务方法、根据结果转发页面。关键点在于request.setCharacterEncoding(UTF-8)必须在getParameter()之前调用否则中文用户名会乱码protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); // ← 必须第一行 String username request.getParameter(username); // 此时才能正确获取中文 String password request.getParameter(password); UserService userService new UserService(); User user userService.login(username, password); // 调用 service if (user ! null) { request.getSession().setAttribute(user, user); // 登录成功存 session response.sendRedirect(main.jsp); // 重定向避免刷新重复提交 } else { request.setAttribute(error, 用户名或密码错误); request.getRequestDispatcher(login.jsp).forward(request, response); // 转发回登录页 } }注意sendRedirect与forward的选择直接影响用户体验。此处用sendRedirect(main.jsp)是因为登录成功后需跳转新页面且避免用户刷新login.do导致重复登录而登录失败则用forward保持 URL 不变方便用户直接修改表单重试。3.3 Service 层协调 DAO 并处理业务规则UserService.java不直接操作数据库而是调用UserDAO并封装业务逻辑。例如密码比对不应在 Servlet 中硬编码而应由 Service 控制public class UserService { private UserDAO userDAO new UserDAO(); public User login(String username, String password) { User dbUser userDAO.findByUsername(username); if (dbUser null) return null; // 业务规则密码为明文存储仅限此简单系统实际项目必须加密 if (dbUser.getPassword().equals(password)) { return dbUser; } return null; } }提示源码中若存在password.equals(inputPassword)这类明文比对是此系统“简单”的体现但也是安全漏洞。调试时可在此处加System.out.println(DB pwd: dbUser.getPassword())打印数据库密码确认是否与输入一致快速定位登录失败原因。3.4 DAO 层执行 SQL 查询并映射结果UserDAO.java负责 JDBC 操作。其findByUsername方法展示了传统 JDBC 的标准流程获取连接 → 创建 PreparedStatement → 设置参数 → 执行查询 → 处理 ResultSet → 关闭资源public User findByUsername(String username) { String sql SELECT id, username, password, phone FROM users WHERE username ?; User user null; try (Connection conn DBUtil.getConnection(); PreparedStatement pstmt conn.prepareStatement(sql)) { pstmt.setString(1, username); // 防止 SQL 注入 try (ResultSet rs pstmt.executeQuery()) { if (rs.next()) { user new User(); user.setId(rs.getInt(id)); user.setUsername(rs.getString(username)); user.setPassword(rs.getString(password)); // 明文存储 user.setPhone(rs.getString(phone)); } } } catch (SQLException e) { e.printStackTrace(); // 开发期必须打印否则异常静默 } return user; }注意try-with-resources语法JDK 7确保Connection、PreparedStatement、ResultSet自动关闭避免连接泄漏。若源码中使用老式finally手动关闭请检查finally块内是否有if (rs ! null) rs.close()等逻辑缺失会导致java.sql.SQLException: Too many connections。3.5 数据库表结构与关键字段约束系统依赖的users表和orders表结构决定了前端传参和后端查询的合法性。以下是users表的建表语句来自源码 SQL 文件或文档CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, -- 用户名唯一登录依据 password VARCHAR(100) NOT NULL, -- 明文存储长度需足够 phone VARCHAR(20), email VARCHAR(100), created_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;而orders表通过user_id关联用户CREATE TABLE orders ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, total_price DECIMAL(10,2) NOT NULL, status ENUM(pending,confirmed,delivered) DEFAULT pending, created_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) -- 外键约束确保数据一致性 );提示若插入订单时user_id为 0 或不存在的 IDMySQL 会报Cannot add or update a child row: a foreign key constraint fails。调试时可在OrderDAO.saveOrder()方法中打印user.getId()确认传入的user_id是否为有效正整数。4. 常见运行故障的三层定位法日志、网络、SQL当系统启动后页面空白、按钮无响应或数据不显示不要盲目重启 Tomcat。按“日志层 → 网络层 → SQL 层”三级递进排查90% 的问题能在 5 分钟内定位。4.1 第一层解读 Tomcat catalina.out 日志中的关键线索Tomcat 启动和运行时的所有异常都输出到logs/catalina.out。打开该文件搜索以下三类关键词关键词代表问题解决动作ClassNotFoundException缺少 JAR 包如mysql-connector-java.jar未放入WEB-INF/lib/检查lib/目录确认 JAR 文件存在且无拼写错误SQLException: Access denied for userMySQL 用户名/密码错误或主机名不匹配执行mysql -ufooduser -pfoodpass123 -hlocalhost fooddb测试命令行连接NullPointerException某个对象为 null如userDAO未 new 成功或rs.next()为 false 时仍调用rs.getString()在报错行前加System.out.println(Debug: variable)打印变量值提示若日志中出现org.apache.jasper.JasperException: /index.jsp (line: 12, column: 3) Unable to compile class for JSP说明index.jsp第 12 行有语法错误如%后缺少%或 EL 表达式${user.name}中user未在 request/session 中设置。此时需检查对应 JSP 行号而非看堆栈顶层。4.2 第二层用浏览器开发者工具验证 HTTP 请求与响应当点击“提交订单”按钮后页面无变化不是后端问题而是前端未发出请求。打开 Chrome DevToolsF12→ Network 标签页 → 点击按钮观察是否有新请求生成若无检查 JSP 中form action或 JS 中fetch()URL 是否拼写错误如order.do写成oder.do。请求方法是否为 POST若为 GET检查form methodpost是否被 JS 覆盖。响应状态码是否为 200若为 404说明 Servlet 映射路径错误若为 500说明后端抛异常需查catalina.out。响应内容是否为 HTML若为纯文本如{success:true}说明后端返回了 JSON但前端 JSP 未正确解析需检查response.setContentType(text/html;charsetUTF-8)是否被覆盖。注意JSP 页面中若使用c:forEach items${orderList} varorder但orderList为 nullJSTL 会静默失败页面显示空白。此时应在OrderServlet.java中添加System.out.println(Order list size: orderList.size())确认 List 是否为空。4.3 第三层直连 MySQL 执行相同 SQL 验证数据与逻辑当 JSP 页面显示“暂无订单”但你确信数据库中有数据问题必在 SQL 查询本身。此时绕过 Java 代码用 MySQL 命令行执行 DAO 中的 SQL-- 假设 OrderDAO.java 中查询语句为 -- SELECT o.id, o.total_price, o.status, u.username -- FROM orders o JOIN users u ON o.user_id u.id -- WHERE o.user_id ? ORDER BY o.created_time DESC -- 在 MySQL 中手动执行将 ? 替换为实际用户 ID如 1 SELECT o.id, o.total_price, o.status, u.username FROM orders o JOIN users u ON o.user_id u.id WHERE o.user_id 1 ORDER BY o.created_time DESC;若命令行返回空结果说明user_id 1的用户确实无订单或orders表中user_id字段值为NULL外键未设NOT NULL或created_time格式与ORDER BY不兼容如存为字符串。提示在OrderDAO.findAllByUserId(int userId)方法中打印最终执行的 SQLSystem.out.println(Executing SQL: sql with userId userId);。将日志中的 SQL 复制到 MySQL 命令行执行结果一致即证明 Java 层无逻辑错误。5. JSP 页面调试技巧EL 表达式失效、中文乱码、JS 与后端协同的三个实操方案JSP 是此系统最易出问题的环节EL 表达式不渲染、中文显示为??、JavaScript 获取不到后端数据。这些问题不涉及复杂架构只需三招精准解决。5.1 强制启用 EL 表达式并验证作用域JSP 2.0 默认启用 EL但若web.xml中web-app版本低于 2.4或页面顶部有% page isELIgnoredtrue %EL 将失效。验证方法在index.jsp顶部添加测试代码% page contentTypetext/html;charsetUTF-8 languagejava % html body !-- 测试 EL 是否工作 -- pPage scope: ${pageScope.test}/p pRequest scope: ${requestScope.user?.username}/p pSession scope: ${sessionScope.user?.username}/p pApplication scope: ${applicationScope.appName}/p /body /html然后在LoginServlet.java登录成功后添加request.setAttribute(test, Hello from request); session.setAttribute(user, user); getServletContext().setAttribute(appName, Food System);若页面显示Page scope:空、Request scope:空但Session scope: admin有值说明request.setAttribute未生效需检查forward或redirect使用是否正确redirect会丢失 request 属性。注意${user?.username}中的?是安全导航操作符避免user为 null 时抛NullPointerException。若源码中为${user.username}且user为 null页面将报错。5.2 彻底解决 JSP 中文乱码的四点配置中文乱码是此系统最高频问题根源在字符集未统一。必须同时满足以下四点JSP 页面声明% page contentTypetext/html;charsetUTF-8 %必须存在且charsetUTF-8不能写成utf-8大小写敏感HTML meta 标签meta charsetUTF-8必须在head中且位于所有 CSS/JS 引用之前Tomcat server.xml 配置conf/server.xml中Connector标签需添加URIEncodingUTF-8Connector port8080 protocolHTTP/1.1 connectionTimeout20000 redirectPort8443 URIEncodingUTF-8 / !-- 关键解决 GET 请求中文参数乱码 --MySQL 连接 URLjdbc:mysql://...?useUnicodetruecharacterEncodingUTF-8中UTF-8必须大写。提示若login.jsp中输入中文用户名后端request.getParameter(username)得到????说明第 3 点URIEncoding未配置。此时在LoginServlet中添加System.out.println(Raw username: username)确认控制台输出是否为乱码。5.3 JavaScript 与 JSP 协同将后端 List 转为 JS 数组的两种安全方式JSP 页面常需将 Java List 传递给 JavaScript 处理如动态渲染菜单。错误做法是直接拼接字符串!-- 危险可能 XSS 或 JSON 格式错误 -- script var menuItems [% menuList.toString() %]; // menuList[{name:米饭},{name:面条}] /script正确方案一用 JSTL 生成 JSON 字符串推荐% taglib prefixc urihttp://java.sun.com/jsp/jstl/core % % taglib prefixfn urihttp://java.sun.com/jsp/jstl/functions % script var menuItems [ c:forEach items${menuList} varitem varStatusstatus {name: ${fn:escapeXml(item.name)}, price: ${item.price}}c:if test${!status.last},/c:if /c:forEach ]; /script正确方案二后端生成 JSON前端 fetch更现代// 在 MenuServlet.java 中 response.setContentType(application/json;charsetUTF-8); PrintWriter out response.getWriter(); out.print(new Gson().toJson(menuList)); // 需引入 gson-2.8.9.jar// menu.jsp 中 fetch(menu.json) .then(res res.json()) .then(data { data.forEach(item { document.getElementById(menu).innerHTML div${item.name} - ¥${item.price}/div; }); });注意方案一依赖fn:escapeXml()防止 XSS方案二需额外引入 Gson 库。若源码中已存在gson-*.jar优先用方案二逻辑更清晰。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价