ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

javaweb美食网站项目实战:从Servlet到部署的完整开发指南

javaweb美食网站项目实战:从Servlet到部署的完整开发指南 简介一款基于JavaWeb的美食网站设计与实现源码包面向正在学习Java服务端开发的学生、课程设计者以及希望快速搭建动态网站的初级工程师。项目聚焦美食信息浏览、食谱搜索、用户分享等核心业务场景完整呈现从需求分析到代码落地的实现路径有助于理解真实Web项目的工程组织与协作方式。压缩包整体约50.34MB采用zip格式封装内含项目源码、数据库脚本及相关配置文件代码结构主要涵盖WebRoot静态资源、Servlet控制层、JSP视图层、DAO数据访问层等经典分层目录组织清楚便于按模块检索与对照学习。目前已有1558人学习浏览源码经作者实测可正常运行具备可靠的参考价值。研读该工程可深入理解MVC设计模式、JDBC数据库交互、用户注册登录与权限校验、AJAX异步请求等关键技术点直接导入开发工具即可运行调试是课程设计、毕业设计或JavaWeb实战提升的实用参考资料。1. 美食网站项目javaweb 毕设与练手的完整落地路径拿到“基于 javaweb 的美食网站的设计与实现.zip”这个标题很多人的第一反应是又是一个典型的 Java Web 课设项目。实际拆开来看这个题目覆盖的技术面比想象中宽——它不只是写几个 JSP 页面再连个 MySQL而是把 Servlet、JSP、JDBC、Session 登录态、购物车、后台管理、文件上传、部署上线这一整条链路串在一起。对在校生来说这是把《Java Web 程序设计》课本知识变成可运行系统的一次完整演练对刚入行的新人来说这是一份能放进简历的“全栈入门级作品”。但同标题的 zip 压缩包质量参差不齐有的能直接导入 IDEA 跑起来有的缺依赖、缺数据库脚本甚至源码不全。这篇文章就沿着这个标题把技术选型、数据库设计、核心实现、运行配置到部署验证的完整路径讲清楚你拿到任何一份同标题的源码包都能照着这套方法检查、修复并跑通。2. 技术选型与项目结构为什么 javaweb 项目至今仍是练手首选2.1 三套主流方案怎么选JSPServlet、SSM、Spring Boot“javaweb”这个热搜词背后是三代技术栈的并存。纯 JSPServlet 是课程里最正统的“javaweb”也是大多数标题为“基于 javaweb 的 XX 系统设计与实现”的压缩包里最常见的形态。它的特点是请求直接打到 ServletServlet 调 DAO 层访问 MySQL再把数据塞进 request 域转发给 JSP 渲染。没有 Spring 的 IOC 和 AOP 概念所有对象都是 new 出来的代码直白到一眼能看懂。第二类是基于 SSMSpring Spring MVC MyBatis的版本这类包一般出现在“改进版”或“含框架”的题目里。特点是配置文件多applicationContext.xml、spring-mvc.xml、mybatis-config.xml 三件套对新手来说配置期容易劝退但跑通之后对框架原理的理解会深很多。第三类是 Spring Boot 重构版严格说已经不算“传统 javaweb”但它满足标题里的“javaweb”语义而且开发和部署体验最好。我的建议很明确如果你是为了交课程设计或毕业设计选 JSPServlet 版最容易讲清楚设计思路答辩时不会有框架黑匣子如果你是为了简历上有亮点选 SSM 版如果这个题目的评分标准允许偏离“javaweb”字面直接上 Spring Boot 反而加分。2.2 解压后先看这张清单一个好包该有哪些东西拿到 zip不要急着导入 IDEA先开文件管理器看目录结构。一个完整的“基于 javaweb 的美食网站”源码包应该包含以下至少五类内容前端页面目录一般是web/或WebContent/里面是 JSP、CSS、JS、图片资源首页index.jsp或login.jsp必须存在。Java 源码目录src/下按包名分层常见包名是com.xxx.servlet、com.xxx.dao、com.xxx.entity或bean/model、com.xxx.util。数据库脚本至少有一个.sql文件内容包含建库语句、建表语句和插入的测试数据。这个文件缺失或乱码是压缩包最常见的坑后面会专门讲怎么补救。配置文件web.xml必须有c3p0-config.xml、db.properties或jdbc.properties至少有一个。第三方依赖如果是 IDEA Tomcat 的经典组合依赖一般是WEB-INF/lib下的 jar 包如果是 Maven 工程则必须有pom.xml。看包名和web.xml里的 servlet-mapping 配置就能判断这个包是纯 Servlet 还是 SSM。web.xml里配了一堆servlet和servlet-mapping的是纯 Servlet 方案只配了DispatcherServlet和ContextLoaderListener的是 SSM 方案整个web.xml极短只声明 Spring Boot 入口的那是第三种。2.3 拿到代码后的第一件事把包结构和入口先读明白不要一上来就点绿色三角运行。先花 20 分钟把包结构读明白能省下后面排错的两小时。我一般按这个顺序读先从web.xml看有多少个 Servlet 映射注意welcome-file-list里的欢迎页配置这是访问路径的入口再看util包里的 JDBC 工具类确认数据库连接方式然后打开一个 Servlet 的 doGet/doPost 方法跟着它调用的 DAO 方法走一遍画出一条请求链路。这里有个很实用的经验一个质量合格的美食网站项目Servlet 类的数量通常在 8~15 个之间。太少说明功能不全太多说明代码重复严重。正常范围应该是——用户登录注册两个、菜品/分类展示两到三个、购物车两到三个、订单两个、后台管理两到三个、评论或收藏一到两个。如果你的包里只有四五个 Servlet说明功能被砍了如果有二十多个要先看是不是每个 Servlet 只是壳子。2.4 环境选型JDK、Tomcat、IDEA 的版本匹配javaweb 项目对环境版本的敏感度很高翻车大多翻在版本错配上。老项目是 JDK 7 时代写的也很正常但你现在机器上装的可能是 JDK 17。三步确认法先看pom.xml里的java.version或web.xml的web-app标签版本2.5表示 Servlet 2.5 规范配 Tomcat 7 或 8 没问题3.0以上配 Tomcat 8.5/9。本地开发环境我建议统一用这套组合绕开 80% 的环境坑IDEA 2022.1 或更高 JDK 8必装不要用 11 以上跑老项目 Tomcat 8.5.100 MySQL 5.7。Tomcat 8.5 兼容 Servlet 2.5 到 3.1 的所有写法JDK 8 是这些老代码的编译基线。MySQL 5.7 和 8.0 在连接驱动、密码认证方式上有差异下文数据库章节会细说。提示如果本机已经装了 JDK 17不用卸载。在 IDEA 的 Project Structure 里给这个项目单独指定 JDK 8 的 SDK 路径两个版本可以共存。3. 数据库设计美食网站的表结构、SQL 脚本与四类核心查询3.1 最少六张表不要贪多美食网站的功能边界决定表结构。一个能过答辩的最小系统需要六张表用户表、美食分类表、美食表、购物车表、订单表、订单明细表。如果压缩包里的源码有收藏、评论、地址管理功能再多加三张。用户表的核心字段是uid、username、password、nickname、phone。密码字段要看源码里是怎么处理的——如果注册时直接把明文密码 insert 进表这个项目演示可以但你在答辩时会被问到安全问题建议改成 MD5 加盐。分类表就三个字段cid、cname、cdesc。美食表是核心字段至少包括fid、cid外键关联分类、fname、price、description、image。这里有个技术点要注意image字段存的是图片路径不是图片本身路径有两种风格——一种是存相对项目路径/upload/xxx.jpg一种是存网络 URL。阅读源码时要认清它接的是哪种否则上传美食图片功能会出文件访问不到的问题。订单相关两张表的关联方式是订单表oid、uid、total_price、status、order_time订单明细表odid、oid、fid、quantity、price。这里price是拍下时的单价快照——如果用户下单后再改价订单明细里的价格不该跟着变好的项目源码会在这里做快照。3.2 建表脚本长什么样一份可以直接抄的 SQL 参考拿到压缩包里的.sql文件后常见的坏情况是SQL 文件缺失、只有建库没有插入数据、中文乱码。第三种特别坑——用 Notepad 或 VS Code 打开看起来是正常的导入 MySQL 后就变成???。这是因为 SQL 文件本身是 UTF-8 编码但 MySQL 客户端连接用的是latin1。解决方案是用命令行导入时显式声明字符集mysql -u root -p --default-character-setutf8 food_website.sql如果.sql文件缺失或者被你搞丢了就直接用下面这份建表脚本重建。这是最简版但结构完整的美食网站表结构覆盖登录、菜品展示、购物车和下单四类核心功能CREATE DATABASE IF NOT EXISTS food_website DEFAULT CHARSET utf8mb4; USE food_website; CREATE TABLE t_user ( uid INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(128) NOT NULL, nickname VARCHAR(50), phone VARCHAR(20), reg_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; CREATE TABLE t_category ( cid INT PRIMARY KEY AUTO_INCREMENT, cname VARCHAR(50) NOT NULL, cdesc VARCHAR(200) ) ENGINEInnoDB; CREATE TABLE t_food ( fid INT PRIMARY KEY AUTO_INCREMENT, cid INT NOT NULL, fname VARCHAR(100) NOT NULL, price DECIMAL(10,2) NOT NULL, description VARCHAR(500), image VARCHAR(200), sales INT DEFAULT 0, CONSTRAINT fk_food_cat FOREIGN KEY (cid) REFERENCES t_category(cid) ) ENGINEInnoDB; CREATE TABLE t_cart ( cart_id INT PRIMARY KEY AUTO_INCREMENT, uid INT NOT NULL, fid INT NOT NULL, quantity INT NOT NULL DEFAULT 1, add_time DATETIME DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_cart_user FOREIGN KEY (uid) REFERENCES t_user(uid), CONSTRAINT fk_cart_food FOREIGN KEY (fid) REFERENCES t_food(fid) ) ENGINEInnoDB; CREATE TABLE t_order ( oid INT PRIMARY KEY AUTO_INCREMENT, uid INT NOT NULL, total_price DECIMAL(10,2) NOT NULL, status TINYINT DEFAULT 0, order_time DATETIME DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_order_user FOREIGN KEY (uid) REFERENCES t_user(uid) ) ENGINEInnoDB; CREATE TABLE t_order_item ( odid INT PRIMARY KEY AUTO_INCREMENT, oid INT NOT NULL, fid INT NOT NULL, quantity INT NOT NULL, price DECIMAL(10,2) NOT NULL, CONSTRAINT fk_item_order FOREIGN KEY (oid) REFERENCES t_order(oid) ) ENGINEInnoDB;插入测试数据是让系统跑起来后页面不空的关键没有插入语句的项目导入后首页空空如也很难判断效果。至少要在分类表插入“家常菜、川菜、甜点饮品、小吃烧烤”四个分类美食表每个分类下插入两三道菜记得image字段填相对路径并在项目web/upload目录放对应的图片文件。用户表插入一个测试账号比如admin / 123456密码用 MD5 摘要后的值避免直接用明文。逻辑说明外键约束在这里作用是把表的关联关系交给数据库保证防止出现“订单明细指向一个不存在的菜品”这类脏数据。DECIMAL(10,2)存价格而不是用 FLOAT 或 DOUBLE——浮点类型在 Java 侧用float接也会出现精度问题用BigDecimal对应 DECIMAL 是最稳妥的。t_order_item里price字段的注释很重要它是订单生成瞬间从t_food复制过来的价格快照不是下单后再去 JOIN 菜品表临时取值。3.3 JDBC 连接配置c3p0 还是 druid以及 URL 里的三处玄学老牌 javaweb 项目最常用的是c3p0-config.xml这也是多数毕设源码包里的标配。新一点的项目会用 druid 连接池。不管是哪种核心配置都在一个地方——数据库 URL。JDBC URL 有三个参数缺一不可写错任何一个都会报Cannot create PoolableConnectionFactoryjdbc:mysql://localhost:3306/food_website?useUnicodetruecharacterEncodingUTF-8useSSLfalseserverTimezoneAsia/Shanghai参数说明useUnicodetruecharacterEncodingUTF-8解决插入中文变问号的问题这个是老项目最容易踩的坑。serverTimezoneAsia/Shanghai只在 MySQL 8.x 下必须加MySQL 5.7 可以省略但加了也没坏处。useSSLfalse是为了避免每次连接时 MySQL 8.0 默认尝试 SSL 握手导致的一串红字警告。MySQL 8.0 还有一个坑在驱动类名上老配置里写的是com.mysql.jdbc.Driver这个类在 MySQL 8.0 的驱动包mysql-connector-java-8.x.jar里已经改名成com.mysql.cj.jdbc.Driver。如果源码包的 lib 目录里是 5.x 驱动配的是com.mysql.jdbc.Driver本地却是 MySQL 8.0要么把驱动版本换掉要么把连接账号的密码插件改回mysql_native_password。3.4 分页查询怎么写LIMIT 参数和五个食物分类分页是美食网站列表页的核心功能。好的项目源码会用LIMIT ?, ?配合页号和页大小两个参数。在 MySQL 中LIMIT的第一个参数是偏移量不是页码所以计算方式是(currentPage - 1) * pageSize这个逻辑必须放在 Servlet 或 DAO 层处理不能把页码直接传给 SQL。以首页按分类展示美食为例核心 SQL 是这样的SELECT fid, fname, price, description, image, sales FROM t_food WHERE cid ? ORDER BY sales DESC LIMIT ?, ?这里cid为 0 或为空时查询条件应改为不拼接WHERE cid ?否则“全部美食”这个分类会查不出数据。不少项目在这里的处理是分类项“全部”的cid设为 0然后在 DAO 里判断——这个判断逻辑值得看它决定了首页的分类筛选是否正常。4. 代码实现拆解登录态、菜品展示、购物车与订单的核心链路4.1 登录会话管理用 Session 还是 Cookie源码里藏着什么美食网站登录功能是所有功能里答辩论最频繁的。看源码时关注三件事密码存没存明文、退出登录时有没有清 Session、登录成功后的跳转是sendRedirect还是forward。多数毕设项目用 Session 保存登录用户信息核心逻辑就是WebServlet(/login) public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username request.getParameter(username); String password request.getParameter(password); UserDao userDao new UserDao(); User user userDao.findByUsernameAndPassword(username, password); if (user ! null) { HttpSession session request.getSession(); session.setAttribute(loginUser, user); response.sendRedirect(request.getContextPath() /index); } else { request.setAttribute(msg, 用户名或密码错误); request.getRequestDispatcher(/login.jsp).forward(request, response); } } }这里有两个点容易被答辩老师抓request.getSession()默认参数是 true——如果 Session 不存在会创建一个新 Session但你已经准备登录成功了所以没问题但如果做“记住我”功能用 Cookie 存用户名密码而不是 Session要注意 Cookie 的setMaxAge(0)才是删除setMaxAge(-1)是关闭浏览器即失效的会话级 Cookie。4.2 登录拦截Filter 配置的两种方式和三个边界一个没有登录保护的美食网站等于把后台管理页和购物车页暴露在公网。大多数源码包里的做法是写一个LoginFilter在web.xml里配置拦截路径。filter filter-nameLoginFilter/filter-name filter-classcom.example.filter.LoginFilter/filter-class /filter filter-mapping filter-nameLoginFilter/filter-name url-pattern/*/url-pattern /filter-mapping注意/*会拦截所有路径包括登录页本身、注册请求、CSS/JS/图片资源这会造成死循环和页面完全无样式两种问题。成熟的写法在 Filter 的doFilter方法里放白名单逻辑public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) resp; String uri request.getRequestURI(); String contextPath request.getContextPath(); String path uri.substring(contextPath.length()); if (path.startsWith(/login) || path.startsWith(/register) || path.startsWith(/css/) || path.startsWith(/js/) || path.startsWith(/images/) || path.startsWith(/upload/) || path.endsWith(.jpg) || path.endsWith(.png)) { chain.doFilter(req, resp); return; } HttpSession session request.getSession(false); if (session ! null session.getAttribute(loginUser) ! null) { chain.doFilter(req, resp); } else { response.sendRedirect(request.getContextPath() /login.jsp); } }边界条件request.getSession(false)如果为 true会在 Session 不存在时创建一个新空 Session过滤会失效静态资源白名单如果漏了.css会导致登录页样式全丢这是新手排错时最容易忽视的方向——明明代码没错就是页面丑。4.3 菜品展示与详情按分类查询的 DAO 方法和图片路径拼接菜品展示页一般分为两类首页默认展示全部或推荐菜点击某个分类后展示该分类下的菜品列表。DAO 层方法通常是两个findAll()和findByCategoryId(int cid)。图片路径拼接是这里的高频 bug。如果数据库里存的是/upload/fish.jpg那么 JSP 页面用${pageContext.request.contextPath}/upload/fish.jpg拼接就能正确访问如果数据库里存的是相对路径upload/fish.jpgJSP 里直接${pageContext.request.contextPath}/${food.image}也能工作。但如果源码里两个方案混用——有的记录带前导/有的不带——页面就会出现一半图挂掉。我会在拿到源码后先执行一条 SQL 检查SELECT fid, fname, image FROM t_food;把image列所有值打出来统一格式再用 UPDATE 修正避免图片路径不一致。菜品详情页的编码要点是点击菜品卡片跳转到FoodDetailServlet?idxxServlet 中接收参数后调 DAO 的findById方法把 Food 对象放进 request 域后转发到food_detail.jsp。转发时要注意乱码——request.setCharacterEncoding(UTF-8)必须放在读取参数之前否则中文菜品名在接收端变问号。这是 Java Web 中文乱码的第一大来源。protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); int fid Integer.parseInt(request.getParameter(id)); FoodDao foodDao new FoodDao(); Food food foodDao.findById(fid); request.setAttribute(food, food); request.getRequestDispatcher(/food_detail.jsp).forward(request, response); }逻辑说明setCharacterEncoding(UTF-8)只对 POST 请求体的编码生效GET 请求参数的中文乱码问题它管不了。GET 乱码要在 Tomcat 的server.xml里给 Connector 加URIEncodingUTF-8属性解决。这是从页面搜索框提交中文关键词到 Servlet 后乱码的经典翻车现场。4.4 购物车与下单事务为什么购物车常用 Cookie订单必须用数据库表购物车有两种实现方式。第一种是把购物车数据放 Session——结构简单但刷新页面后购物车持续存在直到 Session 过期用户换浏览器就丢了。第二种是存数据库t_cart表——用户换设备购物车还在但是代码量翻倍每个购物车操作都要读写一次数据库。成熟的毕设项目一般用第二种因为答辩时“用户未登录也能浏览页面点击加入购物车时跳转登录页”是标准功能。下单链路是检验项目完整度的分水岭创建订单时要把购物车里的菜品明细插入t_order_item同时清空购物车这两个操作必须在同一个事务里。Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); OrderDao orderDao new OrderDao(); int oid orderDao.insertOrder(conn, uid, totalPrice); OrderItemDao itemDao new OrderItemDao(); for (CartItem item : cartItems) { itemDao.insertOrderItem(conn, oid, item.getFid(), item.getQuantity(), item.getPrice()); } CartDao cartDao new CartDao(); cartDao.clearCart(conn, uid); conn.commit(); } catch (Exception e) { conn.rollback(); throw new RuntimeException(下单失败事务已回滚, e); } finally { DBUtil.close(conn); }参数说明setAutoCommit(false)之后同一连接下所有 SQL 都在同一个事务内执行最后一个commit()一次性提交。任何时候中途抛异常rollback()保证之前插入的订单头和订单明细全部撤销不会出现“订单已创建但明细为空”的脏数据。这个点是最容易被问“项目里事务怎么控制的”时的标准回答。5. 在 IDEA 中从零导入到运行Tomcat 配置与全流程调试5.1 导入项目的三种姿势Maven、普通 Web、Gradle 项目的区分拿到压缩包解压后用 IDEA 打开项目时会有三种情况。第一种是 Maven 项目——目录最外层有pom.xml导入时选 OpenIDEA 识别到 pom.xml 会自动按 Maven 项目导入并下载依赖等待右下角进度条跑完即可如果进度条一直卡住多半是网络原因在settings.xml里换阿里云镜像仓库。第二种是纯 Web 项目——没有 pom.xmllib 里的 jar 是手动放的导入时选 Open 后 IDEA 把它当普通 Java 项目打开需要手动把它变成 Web 项目。打开 File Project Structure Facets点加号选 Web然后在 Web Resource Directories 里指定web目录作为 Web 根目录再点 Artifacts 里的加号选 Web Application: Exploded把模块加进去IDEA 就会生成一个 WEB-INF 下的 exploded war 结构。第三种是更老的 Eclipse 风格——有.classpath和.project文件。IDEA 的 Open 也能识别但建议先取消关联新建一个 Java 模块再把src目录设为 Sourcesweb目录设为 Web 资源目录。很多压缩包是从 Eclipse 导出的这种项目里面的 jar 包依赖在.classpath里写的是绝对路径换机器后全部失效处理办法是直接看WEB-INF/lib里有什么 jar全选后 Add as Library。5.2 Tomcat 配置全流程从下载到跑通首页的十步把项目成功运行到 Tomcat 上是这个标题最容易卡住的一步。完整流程如下第一步确认 Tomcat 版本。到 Apache Tomcat 官网下载 Tomcat 8.5 版本Windows 选 64-bit Windows zipmacOS 选 tar.gz。不要下载 Tomcat 10那是 Jakarta EE 命名空间Servlet 类从javax.servlet变成了jakarta.servlet老代码会直接报ClassNotFoundException。版本匹配是这里最多的翻车来源提前规避。第二步IDEA 里配 Tomcat。打开 Run Edit Configurations点左上角加号找到 Tomcat Server Local。Tomcat Server 下拉里如果没有点 Configure 按钮选择刚才解压的 Tomcat 目录。此时注意 Application server 的 libraries 里是否有 servlet-api.jar没有的话手动 Add 一下。第三步Deployment 选项卡是关键。点加号选 Artifact它会列出你项目的 exploded war 包。Application context 填/还是/food_website决定访问路径是localhost:8080还是localhost:8080/food_website。如果项目里有绝对路径写死了 contextPath 的地方填/food_website更稳。第四步Server 选项卡里把 On frame deactivation 设为 Update classes and resources。开发期改 JSP 不用重启 Tomcat 立即生效改 Java 文件也能热替换。注意 HTTPS port 不用管HTTP port 默认 8080 如果被占用改成 8081 即可。第五步启动前确认三件事数据库服务已经启动c3p0或 druid 配置文件中的数据库密码和本地一致项目的 JDK SDK 已指定。逐一排除后点 Debug 启动这时选中 Launch browser 和 Debug 启动模式没有区别重要的是看 Console 日志。第六步看启动日志。正常日志末尾会出现INFO: Server startup in [xxxx] milliseconds此时浏览器访问你配的 Application context 路径。如果跳过了欢迎页而是直接显示 404检查web.xml的welcome-file-list配置。第七步运行中改 JSP 后浏览器不刷新按住 CtrlF5 强刷。Tomcat 对 JSP 修改的检测有缓存延迟强刷能排除浏览器缓存干扰。第八步关停时点击红色方块不要直接杀进程否则 Tomcat 没来得及写日志的状态会导致下次启动报端口被占。第九步访问时如果看到 500 错误先看 IDEA 控制台有没有异常堆栈。最常见的ClassNotFoundException出现在 lib 里的 jar 没有正常打包进 Artifact打开 Project Structure Artifacts在 Output Layout 里的 WEB-INF/lib 下确认能列全所有 jar。第十步全部跑通后把地址栏 URL 和登录后的页面截图保存这些是你写开发文档时的素材也是答辩 PPT 里的系统展示页。5.3 IDEA 里运行 javaweb 项目的 5 个高频启动报错不要指望十步走完一次成功以下五个报错出现概率极高建议直接存在笔记里。第一个Error running Tomcat: Address localhost:1099 is already in use。原因很简单——上一次 Tomcat 没关干净残留的 Java 进程占用了 JMX 端口。解决命令行执行netstat -ano | findstr 1099拿到 PID 后taskkill /F /PID pid或者直接看任务管理器结束所有 java 进程。预防养成点红色方块关 Tomcat 的习惯。第二个java.lang.ClassNotFoundException: org.springframework.web.servlet.DispatcherServlet。出现在 SSM 项目的 Maven 导入后一直没有下载依赖。解决打开 Maven 工具窗口点刷新按钮重新下载检查本地仓库~/.m2/repository有没有对应的 jar没有就是没下下来给镜像源换阿里云。如果是普通 Web 项目把 Spring 相关 jar 一个一个加进 Artifact 的 Output Layout。第三个The server time zone value ???ú±ê׼ʱ¼ä is unrecognized。这是 MySQL 8.0 的serverTimezone配置缺失或 JDBC URL 里没加导致的乱码不是 серьёзный错误但日志刷起来很烦。解决JDBC URL 后面补serverTimezoneAsia/Shanghai重启 Tomcat。第四个java.sql.SQLException: Access denied for user rootlocalhost (using password: YES)。原因要么是数据库密码不对要么是配置文件的密码和你本地的不一致。解决检查db.properties或c3p0-config.xml里的 user/password把本地 MySQL 的密码改一致是成本最低的做法。第五个LiveReload或者 IDEA 自带的浏览器出现 404但直接手动输 URL 能访问。这是 IDEA 内置浏览器的缓存问题。解决不用纠结用 Chrome 手动访问localhost:8080/项目名/index.jsp一切正常即可。6. 美食网站项目避坑指南源码包里的 5 个经典陷阱6.1 数据库脚本乱码导入后页面显示问号现象food_website.sql在文本编辑器里显示正常中文导入 MySQL 后表里的分类名、菜品名全部变成???或者æ ¾ ï¼类似的乱码。原因SQL 文件本身的编码和 MySQL 客户端连接的字符集不一致。文件是 UTF-8 编码但mysql命令行连接的默认字符集是latin1中文被按单字节解析后就成了???。解决命令行指定--default-character-setutf8重新导入这条命令在本章 3.2 节已经给过实际用的时候还要配合 MySQL 端的SET NAMES utf8mb4一起。另外除了utf8MySQL 8.0 推荐用utf8mb4它能覆盖 emoji 表情字符老项目没有 emoji 需求用utf8也够。注意一点导入时用 HeidSQL 或 Navicat 这类图形客户端通常有“文件编码”选项它比命令行更直观但要确认编码选 UTF-8 而不是 GBK否则会出现生僻字乱码。6.2 依赖 jar 包缺失或版本冲突现象启动 Tomcat 后控制台刷出大量ClassNotFoundException点名报错的是com.mysql.jdbc.Driver找不到或者org.springframework.web.servlet.DispatcherServlet找不到。原因压缩包里的lib目录在某些分享网站上被压缩工具过滤了大的 jar 包或者它本来就没有把mysql-connector-java这类驱动 jar 打进包里。Maven 项目则是仓库没有依赖或者依赖版本互相不兼容。解决MySQL 驱动去 Maven 中央仓库直接搜索mysql-connector-java下载5.1.48这个版本最稳妥兼容 MySQL 5.7 和 MySQL 8.0但要在 JDBC URL 里写com.mysql.jdbc.Driver。Spring 相关的版本冲突很少出现但如果你把 Spring 4 和 Spring 5 的 jar 混在一起会报NoSuchMethodError处理方式是清空 lib 里所有 Spring jar只保留完整的一套——从 Maven 仓库下spring-webmvc-5.2.x.jar时就自动带上了它依赖的 spring-web、spring-core、spring-context 等宁可多不能少。6.3 文件上传功能本地能显示部署后图片全挂现象本地开发时上传美食图片预览正常一旦走导出 war 包部署到其他机器上传的图片全部加载失败而数据库里的记录还在。原因上传代码里把图片写到项目部署目录的绝对路径下如D:apache-tomcat-8.5.100/webapps/food_website/upload本地待的这台服务器有这块盘换机器后路径不存在图片自然消失。解决把上传目录改成 Tomcat 的webapps/ROOT/upload或单独建一个站外目录在项目的配置文件里写相对路径部署时手动创建目录。另一个更稳妥的替代方案直接把图片写入数据库LONGBLOB字段但这会影响查询性能且对代码改动大不建议对现有项目做这种改造。如果你答辩被问到回答“把图片保存到独立文件服务器或 OSS 是生产级方案课设项目用本地相对路径足够”这句话能接住追问。6.4 修改 JSP 后刷新无变化现象在 IDEA 里改了 JSP 的中文或样式浏览器强制刷新还是老的。原因IDEA 生成的 Artifact 是 exploded war 目录结构Tomcat 加载的是这个目录你改的是项目的源文件目录里的 JSP两个不是同一个位置。老版本 IDEA 常见这个坑新版 IDEA 做了文件同步但如果是直接改 Tomcat 的 webapps 里部署的 JSP那就是自动部署选项没开。解决Run Configuration 里 Server 选项卡把 On frame deactivation 和 On frame deactivation 都设为 Update classes and resources前者是 IDEA 窗口失焦时自动同步后者是改代码后手动触发。如果你改的是web目录下的 JSP 直接保存后跑一次 rebuild比重启 Tomcat 快得多。验证是否生效的办法打开 Tomcat 的部署目录里对应的 JSP看它内容是不是最新的。6.5 Session 超时和购物车丢失现象用户把菜加进购物车过几分钟后回来购物车空了或者登录后一段时间没操作点付款跳回登录页。原因Session 默认超时时间是 20 分钟Tomcat 默认sessionTimeout也是 20 分钟IDEA 开发模式下频繁重启还要看服务器对 Session 的处理。如果购物车数据全在 Session 里Session 一过期就全没了。解决在web.xml里显式配置session-config延长超时时间或者把购物车持久化到数据库t_cart表。前者两分钟改完但治标不治本后者是把购物车写入表结构且在每次请求查库代码量大但是正确的方案。如果源码里已经有t_cart表但把购物车数据往 Session 塞那说明没好好用表这是值得改的代码缺陷。7. 最后一步把美食网站部署到云服务器以及两个值得做的进阶改造本地跑通只是第一步把项目部署到云服务器才是完整交付。云服务器选 Linux 系统CentOS 7.9 或 Ubuntu 22.04 均可服务器配置入门级 2 核 4G 就够。部署流程我按自己常用的顺序过一遍先装 JDK 8 和 Tomcat 8.5tar -zxvf解压后把webapps/ROOT目录清空然后把 IDEA 打的 war 包上传到webapps目录下重启bin/startup.sh。注意 Linux 上 Tomcat 默认监听 8080 端口云安全组要在防火墙规则里放行这个端口否则公网IP:8080永远超时。数据库方面云服务器直接装 MySQL 5.7导入本地导出的 SQL 文件项目里的数据库地址从localhost改成服务器的内网 IP 或公网 IP。部署完成后验证三件事首页正常渲染不报 500登录、加购、下单全流程走一遍图片都能正常加载。身份证验证这点也很重要——如果点击购买出现 500 或数据库连接超时先看catalina.out日志多半是 JDBC URL 里的时区或者服务器的防火墙把 3306 端口拦了。如果你时间有余力我给两个进阶改造方向投入产出比最高的是第一个把密码明文改成 MD5 加盐。在UserDao的findByUsernameAndPassword里先查一次拿到用户记录再用盐值做摘要比对关于密码存储的完整性最终落到数据库不改字段类型。这个改造大概多写 30 行代码但答辩时可以从“安全意识”层面拉开跟其他同学的距离。第二个是给列表页加分页导航条——前端用bootstrap-paginator或手写一个ul分页组件后端加PageBeanT封装当前页、每页条数、总记录数、总页数。分页是最典型的“加分细节”。回头看我个人做这类 javaweb 项目的经验有一个习惯帮了我很多次拿到一份新源码第一件事不是急着跑而是先花半小时把包结构、数据库脚本、配置文件三样东西读一遍再动手。这一步能让后面排查问题时少走弯路。很多人一上来就点运行报错了再一个个猜时间全浪费在环境问题上。希望这篇从头拆到尾的落地笔记能帮到你——带着你的压缩包按章节一路操作跑通它只是开始把它改造成你自己的作品才是这个题目的真正价值。本文还有配套的精品资源点击获取
返回列表