ARTICLE DETAIL

资讯详情

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

JavaWeb美食网站项目实战:从部署调试到课设答辩

JavaWeb美食网站项目实战:从部署调试到课设答辩 简介基于JavaWeb的美食网站设计与实现项目源码面向JavaWeb初学者及课程设计人群。项目围绕美食信息浏览、食谱检索、心得分享等场景采用Servlet、JSP、JDBC实现用户注册登录、菜谱分类、搜索、评论等模块。压缩包约50.34MB源码按WebRoot、Servlets、JSP、DAO、Models、Utils分层对应静态资源、请求处理、动态页面、数据访问、业务实体与工具配置。已有1558人学习下载源码经实际运行验证有效。通过研读可掌握MVC模式、数据库增删改查、会话与权限控制、页面跳转及前后端交互等方法并了解AJAX异步刷新、响应式布局等Web技巧。1. 打开一个JavaWeb美食网站项目压缩包先搞清楚你拿到的是什么东西一个基于JavaWeb的美食网站说白了就是一套跑在浏览器里的完整点餐系统后端用Servlet/JSP处理请求前端用HTML/CSS/JavaScript渲染页面数据落在MySQL里。市面上这类项目的压缩包绝大多数是课程设计、毕业设计的交付物文件里通常是IDEA工程目录、SQL脚本、以及一份写好的设计文档。你把它解压出来的第一件事不是找代码而是先看清目录结构确认它是不是一个Maven工程、用的Servlet版本是2.5还是4.0、数据库脚本能不能在你的MySQL版本上直接执行。这一步决定你后面能不能在一个小时内跑起来还是要在配置上折腾一晚上。这个项目适合谁一类是刚学完JavaWeb、需要一个完整案例串起Filter、Session、JDBC、JSP这些知识点的学生另一类是接外包或做课设需要快速交付的开发者——拿现成项目做二次修改改个Logo、换个数据表、加个功能就交付。无论你属于哪一类都要先建立一套判断标准这份代码能不能跑、运行机制是什么、出了问题从哪里下手查。这篇文章就按我实际带项目、改代码、上线的顺序把这个方向的所有关键点和盘托出。2. JavaWeb美食网站的技术栈选型为什么老项目都用JSP而不是前后端分离2.1 从Servlet到JSP的设计逻辑拿到压缩包后先看web.xml或注解配置。老派的JavaWeb项目2015-2020年间的课程设计尤其多清一色是Servlet控制层 JSP视图层数据库连接用JDBC或MyBatis构建工具用Maven。这套组合的核心理念是“服务端渲染”浏览器请求一个URLServlet接收请求后调用DAO查询MySQL把结果封装到request域或session域里再forward到JSP页面去渲染HTML。整个数据流是单向的、同步的开发逻辑线很短很适合教学场景。从Servlet 3.0开始有了注解很多课程项目已经舍弃了web.xml里一大串servlet-mapping配置。但你打开任何一份毕业设计大概率看到的是两种情况要么Maven工程里pom.xml同时引入javax.servlet-api、jstl、mysql-connector-java要么WebContent目录下直接躺着几百KB的.class文件和web.xml的手写配置。后者是更老的构建方式用lib目录引入jar包不经过Maven没有依赖传递。我一般建议先把pom.xml看一遍如果发现没有JSTL依赖但JSP里全是c:forEach,html文字是中文的标题是“美食大全”“菜品详情”——这份是“本地直出”的JSP如果HTML源码干净整洁、没有那种由Java代码挤牙膏式输出的一大段DOM说明页面是静态原型或前后端分离的产物——这类代码是外包交付物的概率更高。用户路径还有利于你把项目分类需要改后台的、需要改前台UI的、需要换数据源的都一目了然。一个有说服力的做法是把WebContent的index.jsp改成.jspf片段让公共头部和尾部抽离复用。2.2 单体JSP结构在学习和外包里的取舍有一个关于复杂度的事实必须清晰JavaWeb没有SpringBoot那种注解驱动、自动配置、全家桶服务它的控制层是Servlet你必须在web.xml里声明映射或者用WebServlet注解稍有不慎就返回404、405错误页。一份精良的JavaWeb项目不会把数据库密码直接写死在DAO里它会用一个db.properties或jdbc.properties资源文件集中放URL、用户名、密码再写一个JDBCUtil工具类用静态代码块读进Properties。但是外行交付的课设往往把这个步骤省掉了——拿到手你会发现DAO类里硬编码了一串“jdbc:mysql://localhost:3306/food_db?characterEncodingutf8”。水电费和基础设施的含义我在代课时看到过。我处理过不下十个这样的项目MySQL8.0环境里连接驱动版本换成com.mysql.cj.jdbc.Driver服务器时区设置serverTimezoneAsia/Shanghai密码加密规则改为mysql_native_password之后项目就能跑。但有些项目连这一步都不需要折腾因为它用的MyBatis的ORM映射、或Spring框架的依赖注入数据访问越抽象数据库字段变更的影响越小。老派的JSP项目的构成依赖越少越适合教学——选型深层的逻辑就是你关注的是“跑通”还是“建成生产级系统”。一个选型判断直接给出来如果你是在校生为了应付课设答辩、并且半年内不会再碰JavaWeb选JSPServletJDBC的旧式项目最划算代码量少、逻辑直白、答辩好讲如果你是团队要快速上线一个内部餐厅菜单管理选MavenSpringMVCMyBatis的骨架更现实——这种工程在IntelliJ IDEA里打开后不会报一堆red error再用Tomcat8.5配JDK8很容易跑通。有的压缩包标题虽叫“基于javaweb的美食网站”其实内部已经引入Spring全家桶你就按Spring那套再往下接手。3. 从零跑通一个JavaWeb美食网站数据库脚本和工程导入怎么处理3.1 先建库还是先启动Tomcat数据库脚本的执行顺序不管之前有没有JavaWeb基础第一件要做的事是导入SQL文件。你会看到压缩包里有个food.sql或db_food.sql这是整套系统的地基。打开看一眼如果里面有DROP DATABASE IF EXISTS删除数据库的预防性语句说明作者给了你“后悔药”重装多次数据库都能安全重来如果是手写脚本用单表CREATE TABLE加INSERT逐条灌数据也没问题。需要注意的是字符集问题。一个高频坑属于老生常谈SQL文件本身是UTF-8编码但MySQL5.7服务端默认latin1建库语句写的却是DEFAULT CHARSETutf8mb4中文就变问号。所以执行建库前用如下语句把客户端会话切到UTF-8SET NAMES utf8mb4; CREATE DATABASE IF NOT EXISTS food_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE food_db; SOURCE /path/to/food.sql;第一行“SET NAMES utf8mb4”的作用是把客户端、连接器、结果集三处的字符集一并设定为utf8mb4避免导入中文数据时MySQL把多字节字符按单字节解释。后面建立food_db是的习惯做法——很多课设SQL文件的建库逻辑依赖你手动指定库名而不是用init脚本固定创建物理上压缩包里的food.sql只含建表和数据不含建库语句的话那你就要自己先建库再导表。3.2 IDEA中导入工程Maven刷新和JDK版本是一对冤家IDEA打开工程的方式通常有两种打开文件夹或者用Maven项目的pom.xml方式导入。有的压缩包导入后发现整个工程全红大多是三个原因没有配置本机JDK、没有让IDEA下载Maven依赖、或者web.xml里的servlet版本和Tomcat实际版本不匹配。先看JDK 版本。JavaWeb老古董项目在JDK8上跑得最稳JDK11以上会把javax.servlet报成红——因为高版本JDK不带Java EE模块。如果你用IDEA2023之后的版本系统默认给的JDK可能是17你需要手动切到1.8# 查看当前JDK版本 java -version # macOS / Linux 修改 .zshrc 或 .bash_profileWindows 在系统环境变量里改 export JAVA_HOME/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk export PATH$JAVA_HOME/bin:$PATH改了环境变量后IDEA里还要在Project Structure里把Project SDK改为1.8Language Level改成8。这一步是黑匣子发生地之一——IDEA显示了正确的JDK编译的时候还是报错“Error:java: 无效的源发行版”绝大多数是maven-compiler-plugin里source/target写的1.7或1.8不对齐。直接在pom.xml里加这一段就一劳永逸properties maven.compiler.source1.8/maven.compiler.source maven.compiler.target1.8/maven.compiler.target project.build.sourceEncodingUTF-8/project.build.sourceEncoding /properties注意这里的“maven.compiler.source和target”两个参数source决定Java源码按什么语法规则解析target决定编译出的字节码面向哪个JVM两个不匹配时编出来的.class在Tomcat里跑会出现UnsupportedClassVersionError。做完这些在IDEA右侧Maven面板点刷新让依赖下载到本地仓库。如果这一步因为网络原因下载不动常见的做法是换阿里云镜像但我见过不少项目压根不用MavenWebContent/WEB-INF/lib下直接放着jar包那就不用刷新了。两者别弄混——用lib目录的工程里再引入Maven会导致重复依赖、类冲突运行就报LinkageError。4. 美食网站核心模块拆解登录、菜品展示、购物车的实现逻辑4.1 用户模块Session和Cookie在你的业务里各自承担什么所有在线点餐系统第一个功能永远是用户的注册登录这也是答辩时最容易问到的部分。看代码的时候抓住一条主线登录成功后用户的身份信息是怎么保存的在很多课设里你会发现Servlet写完登录校验后调用request.getSession().setAttribute(user, user)后续每个页面的顶部导航都从session里捞这个user对象显示“欢迎你xxx”。这个机制能工作是因为session以JSESSIONID为key在服务端保留一份用户状态的映射浏览器每次请求自动携带Cookie里的JSESSIONID。这种方案的边界在哪里第一session默认存活30分钟Tomcat在web.xml里可以配置session-timeout,单位是分钟你要用户一周都保持登录那就得把记住登录状态的开关做成Cookie保存用户id再在Filter里判断Cookie有效与否。第二服务端重启后session全部丢失用户被强制下线。我在做外卖风格项目时模仿真实系统加了记住我功能的登录逻辑// 登录成功后判断是否勾选了记住密码 if (on.equals(request.getParameter(remember))) { Cookie cookie new Cookie(autoLogin, user.getUsername()); cookie.setMaxAge(7 * 24 * 3600); // 有效期一周 cookie.setPath(request.getContextPath()); response.addCookie(cookie); } else { // 清除旧的自动登录Cookie Cookie[] cookies request.getCookies(); if (cookies ! null) { for (Cookie c : cookies) { if (autoLogin.equals(c.getName())) { c.setMaxAge(0); c.setPath(request.getContextPath()); response.addCookie(c); break; } } } }上面这段里setMaxAge的单位是秒不是毫秒——这是我第一次写自动登录踩过的坑填了7243600*1000秒结果Cookie要两百年才过期。路径.setPath要带上contextPath否则Cookie作用在整个域名下项目部署在/aaa路径时Cookie无效。真正上线级做法应该把Cookie里的用户名替换成加密token并和数据库关联校验课设项目能做到这种程度已经能应付追问了。4.2 菜品模块JDBC分页查询带来的翻页问题美食网站的菜品列表必然是分页的。在JSP项目里最常见的实现不是用PageHelper这类插件而是手动写LIMIT ? OFFSET ?然后从request参数里拿页码。JavaWeb课设项目不可能用SpringData大都是底层DAO硬写。我之前用JavaWeb写过一版菜品分页核心DAO方法长这样public ListFood findPage(int pageNum, int pageSize, String keyword) throws SQLException { String sql SELECT * FROM food WHERE name LIKE ? LIMIT ? OFFSET ?; ListFood list new ArrayList(); try (Connection conn JDBCUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, % keyword %); ps.setInt(2, pageSize); ps.setInt(3, (pageNum - 1) * pageSize); try (ResultSet rs ps.executeQuery()) { while (rs.next()) { Food f new Food(); f.setId(rs.getInt(id)); f.setName(rs.getString(name)); f.setPrice(rs.getBigDecimal(price)); f.setPic(rs.getString(pic)); list.add(f); } } } return list; }逻辑说明LIMIT后面的第二个参数OFFSET是偏移量等于“跳过的行数”页码从1开始传第一页的偏移量是0第二页是pageSize。写这段代码有两处“翻车点”一是LIMIT和OFFSET的先后顺序不能反二是PreparedStatement的下标从1开始计数一共设置了三个占位符顺序不能串。还要注意try-with-resources写法里Connection和PreparedStatement都实现了AutoCloseable所以不用手写finally关闭连接如果用的是老式写法必须在finally里逐一close否则连接池耗尽报TooManyConnections。页码上我建议你算完总页数再渲染。总页数怎么算查COUNT加本页逻辑SELECT COUNT(*) FROM food WHERE name LIKE ?然后totalPage (int)Math.ceil(total / (double) pageSize);。有些项目偷懒直接不分页、把所有菜品一次查出来菜品一多页面就卡答辨时老师问“你再想想”就很尴尬。分页这件事建议你按上面这段写一遍变变参数理解偏移量。4.3 购物车需求与订单确认链路最短的“高并发高压场景”购物车在JavaWeb里不落库存session点“加入购物车”就是一个servlet把这个菜的ID加进购物车Map里点结算后生成订单落库。这是一条极短却完整的链路。看代码时先盯一个点购物车的Map的key是菜品ID还是菜名用菜名做key的一旦改价就会出现购物车里的价格和实时价格不一致用菜ID做key的结算时重新查库拿最新价格才是正确姿势。实现如下// CartItem 表示购物车中的一项foodId, foodName, price, quantity String foodId request.getParameter(foodId); int id Integer.parseInt(foodId); Food food foodDao.findById(id); HttpSession session request.getSession(); MapInteger, CartItem cart (MapInteger, CartItem) session.getAttribute(cart); if (cart null) { cart new HashMap(); session.setAttribute(cart, cart); } CartItem item cart.get(id); if (item null) { cart.put(id, new CartItem(food.getId(), food.getName(), food.getPrice(), 1)); } else { item.setQuantity(item.getQuantity() 1); } response.sendRedirect(cart.jsp);注意这是一个非线程安全的操作——Tomcat默认每个请求由独立线程处理多个用户同时操作同一个session里的Map理论上HashMap并发会出问题但课设项目量级不需要上ConcurrentHashMap。代码的关键点是判断购物车为null时新建Map放回session否则第一次点击加入购物车就是NullPointerException然后每次都要getParameter再parse参数传错就跳NumberFormatException常见做法是catch住后往request域塞一个错误提示并forward回菜品列表。在订单确认页要把购物车里的实时单价乘数量再加上配送费注意BigDecimal运算不能用double。5. 配置Tomcat和MySQL让项目在IDEA里可运行要动的三处配置文件5.1 数据库连接配置db.properties的读取策略绝大多数课上运行不起来的项目并不是代码逻辑错误而是数据库连接不对。压缩包里一般有一个resources目录放jdbc.properties内容大概长这样jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/food_db?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8 jdbc.usernameroot jdbc.password123456这里有两个高频“劝退”点。第一driver类名根据MySQL版本区分MySQL 5.x用com.mysql.jdbc.DriverMySQL 8.x用com.mysql.cj.jdbc.Driver写反了启动时直接ClassNotFoundException。第二URL里的serverTimezone必须要设尤其MySQL8默认时区是UTC不设会在第一次查询时报“The server time zone value ???ú±ê׼ʱ¼ä is unrecognized”。IDEA里通常用如下方式加载配置并创建连接池static { try (InputStream in JDBCUtil.class.getClassLoader().getResourceAsStream(db.properties)) { Properties props new Properties(); props.load(in); Class.forName(props.getProperty(jdbc.driver)); // 也可以用 DriverManager.getConnection 获取连接 } catch (Exception e) { throw new ExceptionInInitializerError(数据库配置加载失败); } }业务说明就一句这段静态代码块在类第一次被加载时执行一次后续所有DAO调用拿Connection都从DriverManager里取。IDEA的“Run Configuration”里还要确认工作目录有的环境路径不对导致getResourceAsStream返回null于是NullPointerException——这种现象我第一次见的时候以为是IDEA坏了后来发现是Working directory被改成了$MODULE_WORKING_DIR$把路径改回$PROJECT_DIR$即可。5.2 Tomcat运行配置Artifacts到底是war还是explodedIDEA里跑JavaWeb项目有两种方式配置Tomcat Server然后选Deployment或者直接用Maven的tomcat7插件。这里最容易困惑的是Artifacts类型一个是war把整个Web工程压缩成war包另一个是war exploded展开的目录结构。两种都能跑但课设阶段推荐exploded因为改JSP或静态资源后不用重新打包浏览器一刷新就看得到而war包每次改动后要rebuild放入webapps目录再重启Tomcat——效率差太多而且在debug模式下exploded方式能断点打到Servlet里。Tomcat的运行参数里还有一处必须核对的热词点Server标签页的HTTP port。默认8080但电脑上占用了导致启动失败时IDEA会弹窗提示“Port 8080 was already in use”在Run Configurations里把port改成8081浏览器访问时带端口号然后在Deployment标签页里的Application context设为/也可以自带路径浏览器输入http://localhost:8081就能打开美食网站首页。这里Application context的坑是如果不改默认是/项目名_war_exploded你访问时少写后缀就是404。所谓“构建、部署、启动”是有标准顺序的——IDEA里的绿色三角形启动按钮其实干了三件套你要留意Deployment里的“Build Artifact”选项以及Tomcat的“On frame deactivation”默认是“Update resources”还是“Restart Server”这决定你改个CSS要不要重启Tomcat。见过无数新手改了一个前端颜色重启了十次Tomcat最后发现IDEA根本没把resource同步到target目录。5.3 Maven版启动替代方案一条命令在命令行验证除了IDEA里点三角号Maven项目还有一种绕过IDEA图形界面的启动方式使用cargo插件或tomcat7-maven-plugin。具体这样配plugin groupIdorg.apache.tomcat.maven/groupId artifactIdtomcat7-maven-plugin/artifactId version2.2/version configuration port8088/port path//path uriEncodingUTF-8/uriEncoding /configuration /plugin然后在终端执行。mvn tomcat7:run这种方式的好处是不依赖IDEA改完代码直接在命令行跑适合部署到服务器上验证。注意groupID是org.apache.tomcat.maven不是org.codehaus.mojo很多项目pom里配的是cargo插件也是类似效果。无论哪种方式跑通后要回到浏览器里检查页面把JSP渲染出来的HTML源码按“查看源代码”过一次看看数据库里的中文有没有变成问号js/css路径有没有带版本号——这一步叫“验收性自测”经验多了你就会明白十有八九问题出在路径和编码而不是逻辑。6. 从拿到zip到上线运行六个高频坑和排查顺序6.1 启动报错与404、500的边界一个JavaWeb项目交付后用户那边最常见的错误就是404和500。404分两种一种是Tomcat起来了但项目没部署上浏览器访问http://localhost:8080/显示的是Tomcat默认首页你的项目完全没加载——检查Deployment里有没有加上Artifact另一种是项目部署了但URL路径不对——Servlet映射里写的urlPatterns是/hello,你就得访问/hello少写一个斜杠就出现“The requested resource is not available”。还有一种“薛定谔内容”——前端页面引了一堆css/js浏览器和控制台全绿但样式全无、按钮没反应F12看Network发现css路径下全404。这类问题在JSP项目里最常见根因是页面用了相对路径在不同目录层级下解析到了错误位置static资源统一放WebContent根目录下并使用${pageContext.request.contextPath}拼接绝对路径就对了link relstylesheet href${pageContext.request.contextPath}/css/bootstrap.css script src${pageContext.request.contextPath}/js/jquery-3.5.1.min.js/script500更复杂白屏加报错StackOverflow、NullPointerException、ClassCastException——排错顺序先看日志IDEA控制台里把异常堆栈拉到最后几行往上找Caused by。第一行是项目自己的代码下方才是Tomcat或框架的调用栈先解决Caused by再解决Exception。如果报ClassNotFoundException看是不是依赖没进Artifact报SQLException看数据库连的是不是localhost:3306用户名密码是否对驱动版本是否匹配MySQL版本。6.2 编码问题的三处割裂中文乱码在这次项目的出现率接近100%根因是浏览器、JSP、MySQL三套编码不一致。现象菜品名称在数据库里查出来是正常的但在JSP页面显示成问号或火星文。原因连接MySQL的URL没有加characterEncodingutf8或者JSP页面顶部没有指定pageEncoding。解决两步第一步在db.properties的URL末尾加上characterEncodingutf8第二步在JSP页面开头加上如下话术% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8 %注意这两个page指令缺一不可——pageEncoding决定JSP文件本身以什么编码读取和编译contentType决定响应给浏览器时用的字符集。乱码还有一种情况是Tomcat8.5之前默认URIEncoding是ISO-8859-1浏览器发送GET请求参数里带中文Servlet里取到的就全乱这时候要在server.xml的Connector上加URIEncodingUTF-8。现象表单提交POST到Servlet后中文变成“???”或“??”。原因Servlet里没有调用request.setCharacterEncoding(UTF-8)而且这个方法必须在第一次getParameter之前调用否则无效。解决request.setCharacterEncoding(UTF-8); response.setContentType(text/html; charsetUTF-8);第三处是MySQL5.7的表字段默认collation用了utf8_general_ci但JSP传的字符集是UTF-8对着能显示、写不进去。解决方法是建表时统一明确utf8mb4并在JDBC URL里追加useUnicodetruecharacterEncodingutf8。我记得有一回一个同学问我“中文菜品能查出来但是下单人姓名全是问号”排查后就是上面第三步——数据库客户端连接的字符集不对。6.3 依赖冲突和版本不匹配JavaWeb老项目的版本冲突极其隐蔽但结果致命。场景一Maven工程里同时引入了servlet-api 3.1和javax.servlet-api 4.0Tomcat生成的有效class里全乱了运行报NoSuchMethodError或方法签名不参数。场景二mysql-connector-java的5.1.49和MySQL8.0.33服务端做认证时抛javax.net.ssl.SSLHandshakeException换上8.0.33或更高的驱动断开SSL即可。场景三JDK版本太高JSP编译时引入的jasper.jar不认识高版本class文件。统一排查顺序的方法是直接看pom.xml里所有依赖的groupID和artifactID排除掉重复的servlet-api、jsp-api、jstl三个关键依赖mvn dependency:tree -Dincludesjavax.servlet这个命令列出所有servlet相关传递依赖看到两个不同的javax.servlet版本时用exclusion剔除掉低版本的那一份。不依赖Maven的工程就看WEB-INF/lib文件夹下有没有两个相同名字不同版本的jar把旧的手动删掉。这类问题在Tomcat启动时经常表现为“The method getParameter(String) is undefined for the type HttpServletRequest”听着很离谱其实就是servlet-api重复且版本错乱。6.4 页面样式能用但资源走了老缓存这是“玄学”现场有一种情况极其窝火改了半天代码页面样式和JS完全没变强制刷新CtrlF5才正常。这是浏览器的静态资源缓存策略在捣乱。JSP项目里的css/js通常没有版本号浏览器判断缓存有效就直接用旧的。肉眼可见的最终解决方案是给静态资源URL后面加版本参数link relstylesheet href${pageContext.request.contextPath}/css/style.css?v${applicationScope.version}或者在web.xml配置一个Filter设置no-cache响应头按住CtrlF5也能解决但治标不治本。这个问题从我带项目的经验看出现的概率不亚于数据库编码问题且新手几乎不怀疑浏览器只怀疑Tomcat重启不够彻底。6.5 数据库连接没释放引发连接耗尽现象项目跑个半小时后开始报“Too many connections”或“Connection is not available, request timed out”。原因DAO里每开一个Connection但finally里只关了ResultSet和StatementConnection忘关了或者try-with-resources没有让连接类实现AutoCloseable。解决全部换用try-with-resources并确认Connection的关闭动作try (Connection conn JDBCUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { // 业务代码 } catch (SQLException e) { e.printStackTrace(); }如果用的是连接池技术Druid或C3P0这个解决方式就变成了“归还连接”而不是“关闭连接”——close()方法内部调用的实际是连接池的回收逻辑。误用倒金字塔代码、查一下状态但忘记return连接池也会被挖空。排查办法是看Tomcat控制台有没有周期性打印连接池的wait_timeout警告有就说明活性连接未释放。6.6 浏览器兼容和路径穿越问题排查JSP里最容易一步踩坑的是“form提交后跳到ServletServlet转发到JSPURL没变但页面变了”这种经典的Forward vs Redirect问题。如果写成了response.sendRedirect浏览器URL会变request域里的数据会丢页面拿不到值表现为“查询后列表一直空白”。框架的Forward是服务端跳转数据的保存方式不同。要排这个错很简单在Servlet的转发前把查到的菜品列表放进request、然后写一句System.out.println(after set attribute, list sizelist.size())控制台输出正常就看页面。前端路径问题大多集中于“绝对路径和相对路径”的混乱。JSP页面里图片路径写的“images/food.jpg”在菜品列表页能显示因为URL是/list但当你跳转到菜品详情页URL变成/food/detail?id1时这个相对路径就找不到图片了。统一用绝对路径不要赌浏览器解析规则。7. 从“能跑”到“能答辩”功能验证清单、扩展方向与交给你的一个习惯7.1 一张验收表和三个自动化测试点项目跑通后不要急着交差先按用户视角把完整链路走一遍。拿一张表把模块、操作、预期结果、实际结果列出来注册一个新用户、用旧用户登录、查询菜品、加入购物车、修改数量、结算下单、支付模拟、查看订单、管理员后台添加菜品、上下架、查看总营收。每一行都手工过一遍有不对的就回到对应的Java类里去查。JavaWeb很容易写自动化冒烟测试。比如用一个JUnit测试类把DAO层直接连真实数据库测一遍让你在改代码后快速回归public class FoodDaoTest { private FoodDao foodDao new FoodDao(); Test public void testFindByIdReturnsFood() throws SQLException { Food food foodDao.findById(1); Assert.assertNotNull(food); Assert.assertEquals(鱼香肉丝, food.getName()); } }这种测试能证明DAO连接、SQL、结果集映射三个核心环节没问题而这三处恰恰是JavaWeb项目中最容易悄悄坏掉的地方。很多课设项目没有测试意识答辩时一紧张手抖改坏了一个字段就全线崩盘。7.2 三个可行的二期演进方向第一个方向是把JSP慢慢改成前后端分离即后端提供RESTful JSON接口前端用Vue或原生HTML fetch。JavaWeb项目在Java生态内的演进路径通常是保留现有Servlet和DAO增加JSON序列化和HttpServletResponse输出JSON的方法页面直接用AJAX拉数据渲染。改动量大但你可以先拿“菜品搜索”这个模块做试点控制成本。第二个方向是引入Redis做缓存。美食网站的高频操作就是看菜单列表把热度前十的菜品在Redis里缓存5分钟整体响应时间会从几百毫秒降到几毫秒。JavaWeb里用Jedis库连Redis代码量不大但答辩时可以讲得很有深度。第三个方向是把会话管理换成JWT。前面说过session在Tomcat重启后丢失换JWT后把用户身份写在加密token中无状态化这个改动在JavaWeb里比在SpringBoot里麻烦一点但能讲的道理反而更多——单点登录、多端互踢、防御伪造token。答辩老师基本都会沿着这条问下去你答清楚“无状态为什么能扛高并发”就能拿到不错的印象分。7.3 一个诚实的建议希望你少走弯路这个压缩包只是你进入JavaWeb世界的一级台阶它会时不时给你“惊喜”玄学一样的404、理由充分的500、猜不透的缓存。我见过太多人花一晚上修一个Typora语法错误却不舍得花半小时把代码从头点读一遍。JavaWeb的项目意识就是培养一种“从现象推测根因”的能力——看到404先查映射看到500先看堆栈看到乱码先查三处编码不要靠猜测碰运气。拿到任何代码包先读README没有README就通读web.xml和pom.xml这两个文件能告诉你项目的骨架是什么。最后说一句把你想跑的每一步都写下来操作完再勾掉你会在三周后发现自己已经从“读不懂项目”变成“能给别人改项目”了。希望帮到你。本文还有配套的精品资源点击获取
返回列表