ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

JavaWeb宾馆管理系统实战:从环境配置到Tomcat部署排错

JavaWeb宾馆管理系统实战:从环境配置到Tomcat部署排错 简介一套面向JavaWeb期末大作业与课程设计的宾馆管理系统完整源码基于MySQL数据库、IDEA开发环境、Tomcat服务器以及JSP和Servlet技术构建配有详细文档说明项目内含充分代码注释新手也能快速读懂。资源包共1370个文件约22.34MB核心包含Java源文件、JSP页面、Servlet类以及SQL数据库脚本同时附带大量CSS、JS、LESS等前端样式与交互资源目录结构清晰便于导入IDE后直接部署运行。目前已有375人学习与下载经过多人实际使用验证适合作为高分课程设计参考。系统功能完善覆盖登录验证、客房信息管理、订单预约、后台服务等典型宾馆业务模块文档说明与代码注释相互配合能够有效降低上手难度下载后简单配置数据库与Tomcat即可使用可帮助读者高效完成期末作业并理解项目整体架构是一份实操性很强的学习资料。1. 期末作业不是玩具先把“宾馆管理系统”拆成能落地的JavaWeb骨架如果你是计算机相关专业的学生大概率在期末周见过这类题目基于JSPServletMySQL做一个宾馆管理系统。它听起来像个“课程设计标配”但真动手时你会发现卡住你的往往不是业务逻辑而是环境配置、版本匹配、Tomcat部署这些“看起来很简单”的环节。很多人在IDEA里点了一下午“Run”看到的还是404或者500。这篇笔记就围绕这个技术栈把从环境搭建、数据库设计到Servlet路由、JSP页面渲染、最终部署排错的完整路径讲清楚。我默认你用的是IDEA社区版或专业版、Tomcat 8.5/9.x、MySQL 5.7或8.0这几个版本组合是当下javaweb期末作业最主流的搭配也最不容易在“版本玄学”上翻车。2. 开发环境IDEA Tomcat MySQL 三件套怎么配才能一次跑通2.1 JDK、IDEA与Tomcat的版本匹配这是第一条命门先解决一个很多人都栽过的坑Tomcat 10 和 Tomcat 9 的Servlet API包名不一样。Tomcat 10 把javax.servlet改成了jakarta.servlet而绝大多数JavaWeb教材和期末作业源码还在用javax.servlet。这意味着如果你把一份基于Tomcat 9写的源码直接丢进Tomcat 10编译阶段就会报“程序包javax.servlet不存在”。所以我一般最先确认三件事JDK版本8 或 11 都行但JDK 17 Tomcat 9的组合有时会遇到模块访问限制问题Tomcat版本作业源码里如果import的是javax.servlet就老老实实用Tomcat 8.5或9.0IDEA内部Tomcat集成IDEA 2021以上版本基本都原生支持Tomcat不需要额外装插件。对应的安装路径上Windows用户用.zip包比.exe安装包更干净——解压到D:\tomcat9不需要注册服务IDEA直接指向这个目录即可。这里要特别说明Tomcat的startup.bat是给独立启动用的但在IDEA里跑项目时会绕过它由IDEA通过CATALINA_BASE环境变量管理一个隔离的运行实例所以不要纠结于双击startup.bat能不能出猫那和你最终要交付的“期末作业演示”是两回事。提示CATALINA_BASE和CATALINA_HOME是两个不同概念。IDEA跑Tomcat时用的是前者指向的临时目录日志输出在logs子目录下。遇到启动报错优先看IDEA的Console窗口而不是Tomcat安装目录的logs。2.2 在IDEA里把Tomcat挂上来不要只盯着“Run”按钮在IDEA里配置Tomcat的路径是Run→Edit Configurations→ 左上角→Tomcat Server→Local。如果这一步找不到Tomcat Server选项不是IDEA坏了而是你还没装或者没有识别到本地Tomcat。在Application server那栏点Configure...选中你的Tomcat解压目录。IDEA会要求选择Tomcat主页一般为D:\apache-tomcat-9.0.x。部署这步也很容易卡住很多人直接点右上角运行结果浏览器弹出404然后怀疑人生。原因是Tomcat配置里“Deployment”标签页没有添加Artifact。正确做法是Deployment→→Artifact→ 选择你这个项目的war exploded展开目录模式Application context填成/hotel或/前者意味着访问地址是http://localhost:8080/hotel/index.jsp后者意味着直接访问根路径。我通常把context设为项目名这样多个作业项目在同一个Tomcat实例下互不干扰也不用反复改Tomcat端口。2.3 MySQL 5.7 与 8.0连接驱动、编码和时区设置MySQL 5.7 和 8.0 的安装包在Windows上略有不同。5.7 推荐用.msi的安装向导8.0 也可以但8.0的root账户默认认证插件是caching_sha2_password旧版JDBC驱动5.x连不上。如果你拿到的是老源码它的lib目录里放的是mysql-connector-java-5.1.x.jar而你本地装的是MySQL 8.0就会报Unable to load authentication plugin caching_sha2_password。解决方式有两种在MySQL命令行执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码;改回旧式认证去Maven仓库下载mysql-connector-java-8.0.x.jar替换掉源码里的旧驱动。连接URL里的编码参数也很关键。我习惯写成jdbc:mysql://localhost:3306/hotel_db?useUnicodetruecharacterEncodingUTF-8useSSLfalseserverTimezoneAsia/ShanghaiuseSSLfalse是为了省去证书警告serverTimezone是8.0以上版本必填的参数否则会报The server time zone value Öйú±ê׼ʱ¼ä is unrecognized。这个报错在mysql 8.0里几乎是必踩的原因就是默认时区配置和JDBC的时区解析不一致。你如果懒得改代码里的URL也可以在MySQL里执行set global time_zone 8:00;但这样重启MySQL就丢了不如写在连接串里一劳永逸。2.4 验证链路通不通用一张JSP页面打通MVC配置到位之后不要急着写业务代码先做一个“最小链路验证”。新建一个test.jsp内容只有一行% page contentTypetext/html;charsetUTF-8 languagejava % % new java.util.Date() %把它放进webapp目录启动Tomcat访问http://localhost:8080/hotel/test.jsp。能看到当前时间说明JSP引擎即Tomcat的Jasper编译器工作正常。然后在这个页面里加一段JDBC测试代码用Class.forName(com.mysql.jdbc.Driver)建立连接并输出SELECT 1的结果。注意5.1版驱动和8.0版驱动的Driver类名不同前者是com.mysql.jdbc.Driver后者是com.mysql.cj.jdbc.Driver。这一步能跑通就说明IDEA、Tomcat、MySQL三者之间没有拦路虎了。注意如果你用的是Maven管理的项目驱动是通过pom.xml引入的但很多期末作业源码不是Maven项目而是直接往WEB-INF/lib里丢jar包。两种方式无所谓对错但千万别混用——你往pom.xml里加了一个8.0驱动又往lib目录里丢了一个5.1驱动ClassLoader会优先加载其中一个运行时行为不可预测这种“黑匣子”问题排查起来非常消耗时间。3. 拿下一张基于Servlet的软件工程专业JSP作业进阶路线怎么选与避坑经验帖3.1 项目结构的成熟选型不要让Servlet全堆在一起很多初学的代码把所有Servlet写在一个类里用if/else判断请求参数来分发业务这在期末答辩时往往会被问到“你这里的设计模式是什么”答不上来就尴尬了。更稳妥的做法是每一个业务入口单独写一个Servlet比如LoginServlet、RoomServlet、OrderServlet并用URL约定去匹配。web.xml里的映射写法有两种WebServlet注解与web.xml配置。IDEA里的JSP/Servlet项目常见的是在web.xml里手动声明注解方式在Servlet 3.0Tomcat 8以上才支持。期末作业往往用web.xml老写法因为教材还在用这种模板。非法请求以外的资源路径也要管理好这属于优化后面在“加分项”章节里我会给出具体的Filter写法。现在的关键是每一个Servlet负责接收请求、读参数、调用DAO层、把结果放进request域然后forward到JSP页面。JSP里只做展示和表单提交不写Java业务代码至少不要在JSP里用scriptlet写一大段JDBC连接代码。3.2 从Servlet转发到JSPrequest、response、session 的使用边界Servlet和JSP之间的数据流常见的是这三种载体request.setAttribute()生命周期只到本次请求结束适合从Servlet传查询结果给JSP渲染session.setAttribute()生命周期覆盖整个会话适合保存登录用户身份application.setAttribute()全局共享适合保存系统配置或在线人数统计。先给一个简单的LoginServlet片段然后说明关键参数WebServlet(/login) public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); String username request.getParameter(username); String password request.getParameter(password); UserDao dao new UserDao(); User user dao.findByUsernameAndPassword(username, password); if (user ! null) { request.getSession().setAttribute(currentUser, user); response.sendRedirect(index.jsp); } else { request.setAttribute(error, 用户名或密码错误); request.getRequestDispatcher(login.jsp).forward(request, response); } } }这里最容易忽略的一点request.setCharacterEncoding(UTF-8)只对POST请求体有效。如果登录页是GET方式提交中文用户名和密码会出现乱码。处理办法是写一个Filter统一设置编码后面章节给代码或者直接改用POST提交表单。至于response.sendRedirect和request.getRequestDispatcher().forward的区别——前者是浏览器发出第二次请求地址栏会变request域数据丢失后者是服务器内部转发地址栏不变request域数据保留。写作业时用后者展示查询结果更自然但注意如果JSP里有相对路径引用CSS或JSforward不会改变基础路径容易被误认为“资源找不到”。3.3 JSP页面渲染EL表达式、JSTL标签、以及前端资源的路径坑JSP页面里出现%的脚本片段在评审老师眼中是减分项。更好的方式是使用EL表达式${}和JSTL标签库c:forEach等。JSTL不是JSP内置的需要额外引入两个jar包jstl.jar和standard.jar。老版本Tomcat自带一部分但更稳定的做法是把这两个jar放到WEB-INF/lib下。下面是一段房间列表页面的核心渲染逻辑数据由RoomServlet提前放进request域% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % html head title房间列表/title link relstylesheet href${pageContext.request.contextPath}/css/style.css /head body table border1 tr th房号/th th类型/th th价格/晚/th th状态/th th操作/th /tr c:forEach varroom items${roomList} tr td${room.roomNumber}/td td${room.type}/td td${room.price}/td td${room.status}/td tda href${pageContext.request.contextPath}/order?roomId${room.id}预订/a/td /tr /c:forEach /table /body /html${pageContext.request.contextPath}是为了拿到当前项目的context path比如/hotel。如果不加这个前缀直接写css/style.css在更深层URL下引用CSS就会失效——这是JSP页面最常见的样式丢失原因我用血缘经验告诉你这是每个人至少踩一次的坑。另外如果你用的是JSTL 1.x注意jstl.jar里还分jakarta和javax的命名空间Tomcat 9 时钟下的命名空间是http://java.sun.com/jsp/jstl/core而Tomcat 10以上有些写法改成了jakarta.tags.core。你在网上敲教程代码时如果遇到can not find the tag library descriptor先检查这个URI而不是怀疑自己的代码。3.4 数据库连接DAO层用连接池还是用DriverManager期末作业规模不大很多示例代码直接在每个DAO方法里写DriverManager.getConnection这能跑但每次请求都经历建立连接、认证、断开的过程并发高一点数据库就顶不住。另外一个更现实的问题是不同方法里分散着好几处连接代码数据库密码一改要全局搜索替换维护起来很难受。我建议至少做一个简单的DBUtil工具类里面用一个静态方法返回连接public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/hotel_db?useUnicodetruecharacterEncodingUTF-8useSSLfalseserverTimezoneAsia/Shanghai; private static final String USER root; private static final String PASSWORD 123456; static { try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }这个类很简单但它的价值在于把数据库配置集中到一个文件里。答辩老师问“数据库连接改动怎么办”时你可以回答引导到配置文件或db.properties去改。更进阶的用法是引入Druid或HikariCP连接池但对期末作业来说过重除非你的文档里明确写到“使用连接池优化了数据库性能”否则不推荐增加这个复杂度。注意Class.forName在JDBC 4.0之后其实可以省略因为META-INF/services里会自动加载驱动。但老教材会写、老代码会写保留它也没有任何副作用反而能兼容更老的环境。4. 把宾馆管理系统源码跑起来导入配置、目录结构、Tomcat部署实战4.1 拿到源码包先看什么别急着点运行你如果从网上拿到一份“宾馆管理系统源码”压缩包里通常有这些内容.sql数据库脚本、源码目录、README.txt或“使用说明.docx”。第一步永远是把数据库脚本先导进去而不是先解压项目。因为JSP页面不管多复杂运行的前提是JDBC能连上对应的库。导入MySQL的命令是mysql -u root -p hotel_db.sqlWindows下如果你没有把mysql.exe加入环境变量先踩一遍命令行找不到命令的坑然后要么把MySQL的bin目录加入PATH要么在MySQL安装目录下执行上面这条命令。导入成功后用mysql -u root -p登录执行use hotel_db; show tables;确认表都建好了。常见的表有t_user管理员/用户、t_room房间、t_order订单、t_room_type房间类型如果你的源码表名不一样注意对应关系。4.2 IDEA导入项目的两种方式New vs Open拿到源码打开IDEA选File → Open选择源码根目录过程别选成New Project——很多人点错之后得到一个空项目然后一脸疑惑“源码在哪”。老式JavaWeb项目通常不是Maven或Gradle项目IDEA打开后会出现一个提示Unregistered VCS root detected忽略即可。此时IDEA右下角可能提示Setup SDK点击并选择你本地的JDK 8或11。如果源码里有.idea目录说明发送者是用IDEA创建的项目直接打开通常能保留他本地的运行配置如果只有src、web、WEB-INF等目录就需要手动配置。在Project Structure快捷键CtrlAltShiftS里的Modules标签页检查Sources标签下src目录是否标记为蓝色源码根目录web目录是否被识别为Web资源目录。如果IDEA没有自动识别Web模块点击→Web添加一个然后把web或webapp目录设置为Web资源目录在Deployment Descriptors里绑定到WEB-INF/web.xml。这一步漏了Tomcat能启动但访问时只有404——IDEA根本不知道把哪个目录作为网站根目录发布。4.3 Artifact与Libary控制台报ClassNotFoundException的根源属于常见问题编译通过、Tomcat启动不报错但一访问页面就报java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver。原因是jar包没有被打进Artifact的WEB-INF/lib目录。确认方式File → Project Structure → Artifacts选中你的war exploded右侧列表里应有一项Available Elements里面能找到你的数据库驱动jar右键 →Put into /WEB-INF/lib。更省事的方式是把jar直接复制粘贴到源码的web/WEB-INF/lib目录下IDEA通常会自动识别并添加到Artifact的WEB-INF/lib输出列表里。如果你同时用了Maven要检查pom.xml里对应依赖的scope是不是provided——如果是Maven不会把它复制到war包里而Tomcat的lib目录里又没有这个jar运行就挂。期末作业不推荐用Maven就是这个原因多了一层配置学习成本反而更高。4.4 启动时端口冲突和JVM内存参数的设置8080端口被占是最常见的“双击startup.bat后秒退”的原因之一。在IDEA里启动Tomcat如果端口被占Console会输出java.net.BindException: Address already in use。解决方案要么关掉占用进程要么改端口。Tomcat 8.5/9.x需要改三个端口server.xml里的8080连接端口、8005关闭端口、8009AJP端口。在IDEA配置Tomcat时也可以直接设置HTTP portIDEA会帮你覆盖server.xml的配置但关闭端口和AJP端口仍然以server.xml为准。如果机器上同时开了多个Tomcat实例三个端口必须全部错开否则后启动的那个一定会报端口冲突。4.5 部署路径的最后一个坑Application context 和项目路径在IDEA运行配置里Deployment标签页下方的Application context字段天然是/开头。如果你的配置是空IDEA保存时可能会自动补/。context设为/hotel后访问首页的URL是http://localhost:8080/hotel/。而如果你在代码里写的response.sendRedirect(index.jsp)浏览器最终会跳到/hotel/index.jsp没有加context前缀的写法也能正常工作因为相对路径会解析到当前请求的基础路径。但如果你写成sendRedirect(/index.jsp)这个绝对路径就会把用户带到http://localhost:8080/index.jspTomcat发现根路径下没有任何应用直接404。这又是一个“前后端联调时看代码半天没看出问题”的血泪经验。5. 宾馆管理系统避坑期末前最容易翻车的九个细节按现象→原因→解决排查5.1 页面中文乱码JSP和数据库两边都显示问号现象首页正常但中文用户名、房间类型显示为或者湾室这种乱码。原因有三层JSP文件本身的编码方式、HTTP响应头的字符集、数据库表的字符集。解决先统一JSP页面编码在JSP顶部写死% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8%然后检查IDEA右下角的文件编码是否为UTF-8有时虽然写入了pageEncodingUTF-8但文件的物理编码是GBKWindows中文系统默认两者不匹配照样乱码。最后确认数据库表字符集执行SHOW CREATE TABLE t_room;查看DEFAULT CHARSET如果是latin1或gbk执行ALTER TABLE t_room CONVERT TO CHARACTER SET utf8mb4;如果只是某个字段乱码也可以只改字段。这里有个细节utf8mb4是utf8的超集能存储emoji等四字节字符如果你连接的8.0版本的UTF8会默认使用utf8mb4而JSP客户端的编码是UTF-8两边也是兼容的。最简单的检查方法是在DBUtil里查到一条含中文的数据在Servlet里System.out.println打印到IDEA控制台。如果控制台显示正常而浏览器乱码问题出在HTTP响应的ContentType或JSP的pageEncoding如果控制台都乱就要回到数据库那层排查。5.2 Tomcat启动后网页显示“HTTP状态404 - 未找到”首页资源定位不出来现象Tomcat启动没有报错控制台输出了项目部署成功的信息但访问首页404。原因一是Artifact没有正确发布没有指定Web资源目录二是首页文件名和访问路径不匹配。解决先在浏览器访问http://localhost:8080/hotel/test.jsp如果test.jsp能访问而/不能说明welcome-file没有配置。打开web.xml确认有以下内容welcome-file-list welcome-fileindex.jsp/welcome-file /welcome-file-list如果welcome-file配置没错问题就出在Artifact的output目录是不是空的。这个检查IDE的Build菜单下有一个Rebuild Project重建后看控制台有没有编译错误。如果没有任何错误、且WEB-INF/classes下有编译好的class文件但网页仍然404就要看IDEA的Deployment配置里Application context到底是/hotel还是/不要凭记忆猜直接打开配置文件核对。5.3 连接数据库失败Access denied for user rootlocalhost现象页面报错堆栈中出现Access denied for user rootlocalhost (using password: YES)。原因多数情况是DBUtil里的密码和你本地MySQL的不一致源代码里的123456不是你安装时设置的root密码。解决先用命令行验证自己能不能登录MySQLmysql -u root -p如果能正常进入检查DBUtil里的PASSWORD字符串拼写——看仔细了原始代码里可能是123456 带了一个看不见的空格或者123456;把分号也当成了密码的一部分。这一类问题完全可以做一条排除路径从MySQL命令行 → 客户端工具 → JDBC驱动逐层缩小范围。另一种情况是MySQL 8.0下密码正确但认证插件不兼容前面章节说过此时可以先登录MySQL执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码; FLUSH PRIVILEGES;然后重启Tomcat再试一次。5.4 浏览器地址栏变了 session里用户身份却丢“未登录”用了response.sendRedirect(index.jsp)之后首页显示“未登录”或无法显示用户信息。问题在于request和session混淆。解决方式是查一下 JSP 中获取用户信息用的到底是${sessionScope.currentUser}还是${requestScope.currentUser}。登录后我设置的是session.setAttribute(currentUser, user)那么页面必须用${sessionScope.currentUser}来取。如果误写了requestScope当然永远为null。不熟悉EL隐式对象的话可以把session.setAttribute改成同时往request里也放一份但答辩时这会被问“为什么两个作用域都有数据是不是分不清区别”建议正确写法是只在session保留身份页面里用sessionScope取只在request保留当前页面的查询结果比如roomList。5.5 启动Tomcat秒退却没有任何提示现象双击startup.bat黑框闪一下就没了。原因Java环境变量没配好或者Tomcat找不到JRE。这是Tomcat安装及配置教程里最常见的“第一课坑”。解决不要靠弹窗闪现的内容定位用命令行方式启动cd D:\apache-tomcat-9.0.x\bin catalina.bat run这种方式遇到的错误会直接打印在终端而不是闪退。最常见的是JAVA_HOME is not defined correctly检查系统环境变量里JAVA_HOME是不是指向了JDK安装目录不是bin目录然后Path里加上%JAVA_HOME%\bin。Windows下修改完环境变量要重新打开终端才生效。如果你用的是IDEA内部集成运行这个方法不一定复现因为IDEA会自己把JDK路径传给Tomcat。所以排查时先分清“独立启动”和“IDEA启动”两种模式它们用的脚本不同报错也藏在不同地方。5.6 复选框、下拉框的表单数据提交后变null页面上有多个同名的checkbox比如选多个“附带服务”Servlet端用request.getParameter(service)只能拿到第一个值。原因同名参数在HTTP协议里可以重复getParameter只返回第一个。解决对这种多值参数用String[] services request.getParameterValues(service);注意getParameterValues返回 null 而不是空数组——如果用户一个都没勾选这个数组是null直接for遍历会抛空指针。稳妥写法是Arrays.toString(services)或者if (services ! null)。另外提交过来的所有参数都是String需要数值的比较在Servlet里用Double.parseDouble或Integer.parseInt转一下转之前要判空否则用户不填写就提交解析直接抛NumberFormatException。5.7 Tomcat报内存溢出java.lang.OutOfMemoryError: PermGen space这个问题在JDK 8里其实很少见了PermGen在JDK 8中被Metaspace取代。但如果你还在用老版本JDK 7或者IDEA的Tomcat配置里继承了老模板的JVM参数仍可能遇到。解决在IDEA的Tomcat运行配置里VM options处加入-XX:MaxMetaspaceSize256m -Xms128m -Xmx512m对于一个小型宾馆管理系统512m堆内存绰绰有余。关键词是IDEA里这样设置的是运行应用的JVM参数不是Tomcat本身的catalina.bat里的JAVA_OPTS。两处都可以调但IDEA里配置的优先级更高因为它以run方式启动而不是startup.bat的方式。5.8 正则匹配路径用filter拦截了所有静态资源如果用Shiro或自写Filter做权限拦截常见配置是把所有URL都拦截/*然后静态资源css/js/images也被拦下页面裸奔没有样式。解决如果是WebFilter(/*)在doFilter里对资源路径放行比如if (request.getRequestURI().endsWith(.css) || request.getRequestURI().endsWith(.js)) { chain.doFilter(request, response); return; }更优雅的做法是Filter的URL pattern写成/pages/*或*.do只拦业务请求不拦静态资源。但要注意JSP页面本身要不要拦如果JSP是需要登录才能看的页面建议把JSP也放在某个子目录下如/view然后Filter拦/view/*。如果JSP和登录页在同级目录Filterpatterns就会变得别扭这也是开发期规划目录结构时该多想一步的地方。5.9 用JDBC做模糊查询时中文查不出来英文可以现象搜索“豪华”返回空列表搜索“luxury”能查到。原因绝大多数情况不是SQL错了而是请求参数在进入SQL之前已经乱码数据库根本没收到“豪华”这两个字。解决在Servlet最前面加request.setCharacterEncoding(UTF-8)或者用Filter统一编码。然后确认数据库连接URL里带了characterEncodingUTF-8。最后在数据库命令行里用SELECT * FROM t_room WHERE room_type LIKE %豪华%;如果命令行能查出而页面查不出100%是编码链路问题如果命令行也查不出说明数据表里存的根本不是“豪华”这两个字可能是导入时就已经乱码了。这种逐层隔离的方法在处理中文字符类问题时总是最好用的我每次遇到“中文查不出来”都用这个顺序来定位。6. 加点分从“能跑”到“能答辩”三个付出少回报高的小改造6.1 用Filter统一编码和登录拦截展示一层再讲一层的结构第一个改造是把“登录拦截”从每个Servlet里抽出来用Filter实现。写法如下WebFilter(/*) public class AuthFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) resp; String uri request.getRequestURI(); if (uri.endsWith(.css) || uri.endsWith(.js) || uri.endsWith(.png)) { chain.doFilter(request, response); return; } if (uri.endsWith(login.jsp) || uri.endsWith(LoginServlet)) { chain.doFilter(request, response); return; } Object user request.getSession().getAttribute(currentUser); if (user null) { response.sendRedirect(login.jsp); return; } chain.doFilter(request, response); } }这里要说明两点。第一Filter拦截的范围是/*而放行的条件靠endsWith逐一判断这是一种低成本的写法如果项目页面多了更好的办法是把需要登录的页面统一放进view/目录Filter改为拦截/view/*静态资源放在外面逻辑更清晰。第二Filter的执行顺序由web.xml里filter-mapping的顺序决定如果配了两个Filter先声明的会先执行。答辩老师如果问“你Filter的排序怎么控制的”能答出这一点就很加分。6.2 用PreparedStatement替代Statement讲清楚SQL注入怎么防的很多示例代码里写的是Statement 字符串拼接String sql SELECT * FROM t_user WHERE username username AND password password ;这种写法最大的问题是SQL注入。比如用户名输入admin --密码随便填拼接出来的SQL就成了SELECT * FROM t_user WHERE usernameadmin -- AND passwordxxx--后面的内容变成了注释密码校验直接失效。改成PreparedStatement之后SQL骨架预先编译参数通过占位符传入无论用户输入什么特殊字符数据库都把它当数据而不是SQL指令这是标准解法。代码如下String sql SELECT * FROM t_user WHERE username? AND password?; try (PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, username); ps.setString(2, password); try (ResultSet rs ps.executeQuery()) { if (rs.next()) { // 登录成功 } } }你需要意识到的是PreparedStatement还有一个好处是预编译过的SQL可以复用多次执行能减少数据库端的解析开销虽然这个小系统完全感受不到性能差异但答辩时可以提一句“用预编译语句提升查询效率”。这个改造不仅让代码更安全也是评分表里“代码规范性”的一个明显加分点。6.3 文档说明不只是把需求分析抄一遍更重要的是“环境说明”表期末作业文档基本上要覆盖需求分析、数据库设计、核心代码说明、测试结果几块。但评审老师最看重的其实是“这份代码在你机器上能不能跑起来”因为很多老师拿到源码后第一件事就是尝试运行而不是读你的万字需求文档。所以文档里专门拿出一页表格列清楚项目值JDK版本1.8.0_202Tomcat版本9.0.78MySQL版本8.0.32数据库名hotel_db数据库账号/密码root / 123456连接驱动版本mysql-connector-java-8.0.32导入步骤1. 执行hotel_db.sql 2. IDEA打开项目 3. 修改DBUtil密码 4. Tomcat运行我第一次交作业时文档里没写数据库密码老师发邮件说“代码跑不通连不上数据库”我秒回“密码是123456”但已经迟了——就因为少写这行印象分掉了不少。后来我每份作业的README里都会把这些信息用同样的格式写清楚看到“能一次跑通”的评价比写一万字架构设计都开心。毕竟期末作业的本质是“完整走一遍JavaWeb开发的流程”让老师能顺利复现才是第一要务。这些改造加起来不到100行代码但带来的答辩效果比闷头多写两个业务模块更明显。做JavaWeb项目真正值钱的能力是链路打通之后的系统性验证——知道每一步在哪看日志、哪看控制台、哪看数据库。靠背报错单词解决不了面问题踩过一次坑、记录一次解法、把它写进自己的笔记下次再遇到才能不慌。希望这篇笔记能给你的期末作业省下几个通宵祝顺利。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进