ARTICLE DETAIL

资讯详情

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

Servlet+JSP+MySQL实战:JavaWeb学生宿舍管理系统开发详解

Servlet+JSP+MySQL实战:JavaWeb学生宿舍管理系统开发详解 简介基于 ServletJSPMySQL 开发的学生宿舍管理系统 Java Web 项目面向 Java Web 初学者、在校生及毕业设计人群覆盖宿舍楼栋、宿舍分配、学生信息、管理员登录等日常管理业务是理解 JSPServletJDBC 分层开发的常见课程设计题目。压缩包共收录 295 个文件整体大小约 16.88MB包含 JSP 动态页面、Java 源码及编译产物、SQL/DB 数据库脚本、项目依赖 JAR 包以及 CSS/JS/图片等前端静态资源按功能模块分包存放导入 IDE 并配置好 MySQL 后即可运行调试适合快速体验从登录到宿舍分配的全流程。该资源已有 5921 人学习下载具备较高的参考与复用价值。源码覆盖登录验证码、学生管理、宿舍分配、楼栋管理、宿舍管理员等功能模块从数据访问层到控制层再到视图层调用关系清晰可帮助读者理清请求处理、数据库操作、页面渲染等关键流程也可在此之上扩展改造作为课程设计或毕业设计的实用基础。1. 这个JavaWeb学生宿舍管理系统为什么还值得用ServletJSP做一遍看到“基于Servletjspmysql开发javaWeb学生宿舍管理系统”这个标题很多人的第一反应是“这都什么年代了还在用JSP”。但如果你正处于大二大三做课程设计、准备毕设选题或者刚学完JavaWeb想找一个能完整串起知识链的项目练手这个组合恰恰是最合适的——SpringBoot再好也掩盖不了Servlet规范、JSP生命周期、HTTP请求响应模型这些底层知识。宿舍管理系统业务边界清晰学生信息管理、宿舍分配、入住退宿、访客登记每一个模块都能对应到一张表、一个Servlet、一个JSP页面非常适合用来把javaWeb的完整链路走通。我见过太多人一上来就上SpringBootMyBatis-Plus结果连请求是怎么从Tomcat走到Controller的都说不上来更别提调试一个404要花半天。用ServletJSPMySQL做宿舍管理系统你会在一个项目里同时接触JDBC连接、MVC分层、Session会话管理、过滤器拦截这些最核心的javaWeb技能点。这套东西弄明白了后面看任何javaWeb项目完整案例都会快很多。如果你正在纠结用什么技术栈做毕设我的建议很直接就用这个组合它不会让你翻车。2. 先把环境跑通IDEA、Tomcat、MySQL 8.0 的配置顺序与常见坑2.1 环境版本怎么选才不会一开始就踩坑做ServletJSP项目环境版本组合是个玄学乱配真的会让人崩溃。我的建议是直接按下面这套来别追求最新JDKJDK 8 或 JDK 11。JDK 8 兼容性最好很多老教材和Tomcat版本都基于它JDK 11 也能跑但要注意Tomcat版本。Tomcat9.x 或 8.5.x。Tomcat 10 以后把javax.servlet改成了jakarta.servlet包名完全不同网上大部分Servlet教程和代码都是基于javax.servlet的用Tomcat 10 会让你在导包阶段就卡住。MySQL5.7 或 8.0。8.0 是当前主流但驱动和连接配置上有几个注意点后面会专门说。IDEIDEA 社区版或专业版都行社区版足够。这组搭配是经过大量实践验证的网上能搜到的javaweb教学案例和javaweb项目完整案例绝大多数都能在这套环境里直接跑。2.2 IDEA 里创建 JavaWeb 项目的步骤用 IDEA 创建 javaweb 项目网上教程很多但版本差异大。我按 IDEA 2023 之后的主流界面给你捋一遍第一步新建 Project选择 Jakarta EE 或 Java Enterprise不同版本叫法不太一样然后勾选 Web Application。如果你用的是社区版可能没有这个选项那就先创建普通 Java 项目再手动右键项目选 “Add Framework Support”勾选 Web Application。后一种方式更通用我一般推荐新手用这个。第二步配置 Tomcat。在 IDEA 右上角点 “Add Configuration” - “” - “Tomcat Server” - “Local”在 Application server 那里选到你本地 Tomcat 的根目录。这一步如果找不到 Tomcat Server 选项通常是 Tomcat 没配置好IDEA 需要识别到 Tomcat 的安装路径。第三步在 Deployment 标签页点 “”把当前项目以war exploded方式部署Application context 填/dormitory或者你喜欢的任何上下文路径。这一步决定了你访问项目的 URL 前缀比如http://localhost:8080/dormitory。第四步在 Server 标签页把 On frame deactivation 设为 Update classes and resources。这样你改了 JSP 或 Java 类后快捷键CtrlF10就能热更新不用反复重启 Tomcat。这是最常见的配置方式也是“idea运行javaweb项目配置”搜索量最高的答案。有个容易忽略的点如果 JSP 页面改了但浏览器看到的还是旧内容多半是浏览器缓存按CtrlF5强制刷新。2.3 MySQL 8.0 的安装与连接参数MySQL 安装教程网上很多这里只强调几个和 JavaWeb 项目强相关但在安装时容易被忽略的选项安装时选择 Server only 还是 Developer Default 都可以但一定要记住 root 密码。MySQL 8.0 默认使用 caching_sha2_password 认证插件而旧版 JDBC 驱动5.x不认识这个插件会报Unable to load authentication plugin caching_sha2_password。解决方式有两个一是用 mysql-connector-java 8.0.x 的驱动二是在 MySQL 里执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码;把认证改回旧版。我用的是第一种方案。在项目的WEB-INF/lib下放mysql-connector-java-8.0.33.jar或者用 Maven 依赖然后在 JDBC 连接字符串里这样写Class.forName(com.mysql.cj.jdbc.Driver); String url jdbc:mysql://localhost:3306/dormitory?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue; String user root; String password 你的密码; Connection conn DriverManager.getConnection(url, user, password);这段代码里的参数每个都很关键。useUnicode和characterEncodingutf8保证中文不乱码useSSLfalse关闭 SSL本地开发没必要开serverTimezoneAsia/Shanghai处理 MySQL 8.0 时区报错allowPublicKeyRetrievaltrue解决Public Key Retrieval is not allowed的问题。四个参数缺一个你都可能遇到莫名其妙的报错。注意 8.0 驱动类名是com.mysql.cj.jdbc.Driver不是老版本的com.mysql.jdbc.Driver。3. 数据库设计与项目骨架五张表怎么设计MVC 分层怎么搭3.1 宿舍管理系统的五张核心表学生宿舍管理系统的业务不复杂但表设计会直接影响后面所有 Servlet 和 JSP 的写法。我一般会设计五张表楼栋表、宿舍表、学生表、管理员表、入住记录表。先看建表 SQL这里只列最关键的三张表其他两张按同样思路补CREATE TABLE building ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL COMMENT 楼栋名称如A栋、B栋, floors INT DEFAULT 6 COMMENT 楼层数, rooms_per_floor INT DEFAULT 8 COMMENT 每层房间数 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE dorm ( id INT PRIMARY KEY AUTO_INCREMENT, building_id INT NOT NULL, room_number VARCHAR(20) NOT NULL COMMENT 房间号如A-501, bed_count INT DEFAULT 4 COMMENT 床位数, bed_used INT DEFAULT 0 COMMENT 已住人数, CONSTRAINT fk_dorm_building FOREIGN KEY (building_id) REFERENCES building(id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(20) UNIQUE NOT NULL COMMENT 学号, name VARCHAR(50) NOT NULL, gender ENUM(男,女) NOT NULL, major VARCHAR(100) COMMENT 专业, phone VARCHAR(20), dorm_id INT, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_student_dorm FOREIGN KEY (dorm_id) REFERENCES dorm(id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;注意几个细节。第一个是字符集用utf8mb4不是utf8因为 MySQL 的utf8最多存 3 字节而很多生僻字和 emoji 需要 4 字节虽然宿舍管理系统一般用不到 emoji但统一用 utf8mb4 能避免后续导入 Excel 数据时的乱码问题。第二个是宿舍表里的bed_used字段这个字段是用来做“宿舍入住率”查询的每次学生入住或退宿时要用update语句同步更新它这个字段如果不同步维护你后面写统计报表的时候会非常痛苦只能全表遍历去数。3.2 一个 JDBC 工具类别在每个类里重复写连接代码很多新手喜欢在每一个 DAO 类里都写一遍DriverManager.getConnection写了三次以上就应该抽工具类了。我一般会写一个DBUtil把连接获取和资源关闭统一管理public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/dormitory?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue; 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); } public static void close(Connection conn, PreparedStatement ps, ResultSet rs) { if (rs ! null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if (ps ! null) { try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn ! null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }这个工具类有两点值得说。第一Class.forName放在静态代码块里保证类加载时驱动只注册一次。第二连接参数直接写在常量里方便修改但如果你的项目要用 MySQL 的数据库连接池比如后面要接 Druid 或 C3P0这个工具类就要改成从配置文件读取数据源而不是用DriverManager。宿舍管理系统这种小项目直接用DriverManager没问题但你要清楚它每次请求都要新建连接并发高时会成为性能瓶颈。3.3 一个标准 MVC 分层Entity、DAO、Service、Servlet、JSP很多教程会把 Servlet 和 JSP 混在一起写比如在 Servlet 里拼 HTML 字符串或者在 JSP 里直接写 JDBC 代码。这种写法在几十行的demo里看起来很直接但功能一多就变成黑匣子改一个需求要翻好几个文件还互相纠缠。我一般按标准 javaWeb 分层来组织代码包这也是按照 JSP Model2 思想实现的src/ com.dormitory.entity/ Student.java Dorm.java Admin.java com.dormitory.dao/ StudentDao.java DormDao.java AdminDao.java com.dormitory.service/ StudentService.java DormService.java com.dormitory.servlet/ LoginServlet.java StudentListServlet.java StudentAddServlet.java ... web/ WEB-INF/ web.xml jsp/ login.jsp student_list.jsp student_add.jspEntity 是实体类字段和数据库表一一对应。DAO 层只负责 SQL 执行。Service 层处理业务逻辑比如入住时要同时更新宿舍的bed_used字段这种跨表操作必须在 Service 层做事务控制。Servlet 只做三件事接收参数、调用 Service、转发或重定向到 JSP。JSP 只负责展示。web.xml里配置欢迎页和 Servlet 映射welcome-file-list welcome-filejsp/login.jsp/welcome-file /welcome-file-list servlet servlet-nameStudentListServlet/servlet-name servlet-classcom.dormitory.servlet.StudentListServlet/servlet-class /servlet servlet-mapping servlet-nameStudentListServlet/servlet-name url-pattern/student/list/url-pattern /servlet-mapping一个刚学完 Servlet 的人可能会问为什么用WebServlet注解而不是在 web.xml 里配注解当然可以但很多学校的毕设要求里明确写了要有配置文件而且 web.xml 里集中看 Servlet 映射关系比翻代码方便。我一般建议 Servlet 类上用WebServlet(/student/list)注解这样少写很多 web.xml 样板代码如果想再简化可以去听一下黑马javaweb相关的免费课但核心思路都一样。4. 从登录到入住四大核心功能的代码实现与参数调优4.1 登录功能Session 会话管理与表单安全登录是宿舍管理系统的入口也是最容易出现安全问题的模块。先看 LoginServlet 的核心逻辑WebServlet(/login) public class LoginServlet extends HttpServlet { private AdminService adminService new AdminService(); Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding(UTF-8); String username req.getParameter(username); String password req.getParameter(password); Admin admin adminService.login(username, password); if (admin ! null) { HttpSession session req.getSession(); session.setAttribute(admin, admin); session.setMaxInactiveInterval(30 * 60); resp.sendRedirect(req.getContextPath() /student/list); } else { req.setAttribute(error, 用户名或密码错误); req.getRequestDispatcher(/jsp/login.jsp).forward(req, resp); } } }这里有个很重要的细节登录成功后用req.sendRedirect重定向而不是forward转发。如果用 forward用户刷新页面时会重复提交表单导致重复登录动作重定向让浏览器重新发起一个 GET 请求到目标页面刷新不会有副作用。这是“POST-Redirect-GET”模式的经典应用。session.setMaxInactiveInterval(30 * 60)设置会话超时时间是 30 分钟这个值要按实际场景调如果管理员喜欢挂机不动时间设短了会经常被踢下线需要重新登录设太长又有安全风险别人碰你电脑时 session 还有效。这个参数就是典型的需要根据使用节奏调整的配置项。再往下就是登录的 SQL 查询。永远不要用字符串拼接 SQL// 错误写法SQL注入风险 String sql SELECT * FROM admin WHERE username username AND password password ; // 正确写法PreparedStatement 预编译 String sql SELECT * FROM admin WHERE username ? AND password ?; PreparedStatement ps conn.prepareStatement(sql); ps.setString(1, username); ps.setString(2, password);用 PreparedStatement 不是一种风格偏好而是安全底线。 OR 11这种攻击字符串只要拼接一次就能绕过登录验证网上搜“javaweb头歌实训答案jsp”都能看到相关练习题强调了这一点。4.2 学生入住分配事务控制的典型场景入住分配是宿舍管理系统里最有业务含量的一个操作。逻辑是查询某个宿舍的已住人数如果没满就分配同时把该宿舍的bed_used加 1。这两个操作必须在一个事务里完成否则会出现宿舍空位没了但学生还是被分配进去的数据不一致问题。Service 层的代码是这样组织的public boolean allocateDorm(int studentId, int dormId) throws SQLException { Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 手动管理事务 DormDao dormDao new DormDao(); Dorm dorm dormDao.findById(conn, dormId); if (dorm.getBedUsed() dorm.getBedCount()) { return false; // 宿舍已满此时不需要回滚因为还没有写操作 } StudentDao studentDao new StudentDao(); studentDao.updateDorm(conn, studentId, dormId); // 更新学生的宿舍ID dormDao.increaseUsed(conn, dormId); // 宿舍已住人数1 conn.commit(); return true; } catch (SQLException e) { conn.rollback(); throw e; } finally { if (conn ! null) { conn.setAutoCommit(true); conn.close(); } } }注意这里的事务边界conn.setAutoCommit(false)之后所有 SQL 都在同一个事务里直到commit()或rollback()。关键在于 DAO 层的方法要接收conn参数并从外部传入而不是在 DAO 内部自己获取连接——否则两个 DAO 各开各的连接事务就失效了。bed_used自增的 SQL 可以写为// 用 set 子句让数据库自己执行 原值1更安全避免并发访问时的脏写 UPDATE dorm SET bed_used bed_used 1 WHERE id ?不要先 SELECT 查到当前值、在 Java 里加一、再 UPDATE 写回这种“读-改-写”三步在并发时一定会出问题。同理退宿就是把bed_used减一改成UPDATE dorm SET bed_used bed_used - 1 WHERE id ? AND bed_used 0防止减成负数。4.3 学生列表查询JSP 里用 JSTL 和 EL 表达式渲染宿舍管理系统的占大头页面就是学生列表查询。Servlet 查询出 List 后转发给 JSPJSP 页面负责展示。代码如下ListStudent students studentService.findAll(); req.setAttribute(students, students); req.getRequestDispatcher(/jsp/student_list.jsp).forward(req, resp);对应的 JSP 片段% taglib urihttp://java.sun.com/jsp/jstl/core prefixc % table border1 cellpadding8 cellspacing0 tr th学号/th th姓名/th th性别/th th专业/th th宿舍号/th th操作/th /tr c:forEach varstu items${students} tr td${stu.studentNo}/td td${stu.name}/td td${stu.gender}/td td${stu.major}/td td${stu.dormName}/td td a href${pageContext.request.contextPath}/student/edit?id${stu.id}编辑/a a href${pageContext.request.contextPath}/student/delete?id${stu.id} onclickreturn confirm(确定删除吗)删除/a /td /tr /c:forEach /table这里有几个点新手容易卡住。第一页面最上面要引入 JSTL 的 taglib并且要在WEB-INF/lib里放jstl-1.2.jar不放的话运行时会直接报 500这个错误信息还不直观很多人会以为是代码逻辑问题排查半天。第二${pageContext.request.contextPath}是 JSP 里获取项目上下文路径的标准 EL 表达式写死/dormitory也可以但一旦部署时改了应用名所有硬编码链接都会失效。第三删除操作加一个confirm确认弹窗是成本最低的防误删手段。4.4 分页在 SQL 层面做 LIMIT别把全表数据都查出来学生数量多了之后一次SELECT * FROM student会把几千条数据全部塞到内存里然后再往 JSP 页面上渲染这既不专业也影响性能。分页是宿舍管理系统里非常容易拿到加分项的优化点。SELECT * FROM student WHERE major LIKE CONCAT(%, ?, %) ORDER BY id LIMIT ? OFFSET ?;Java 代码里计算分页参数int page 1; int pageSize 10; String pageStr req.getParameter(page); if (pageStr ! null !pageStr.isEmpty()) { page Integer.parseInt(pageStr); } int offset (page - 1) * pageSize; ListStudent list studentDao.findByPage(offset, pageSize, keyword); int total studentDao.count(keyword); int totalPages (int) Math.ceil((double) total / pageSize);注意LIMIT ? OFFSET ?里两个问号要分别用setInt赋值你可能会遇到LIMIT 1, 10和LIMIT 10 OFFSET 0两种等价写法MySQL 两种都支持。这里要留意一个坑OFFSET值过大会导致查询变慢因为 MySQL 要扫描前 N 行再丢弃但管理系统数据量在万级以内分页性能完全够用不用上什么深分页优化。参数绑定的写法也规避了 Page 参数被注入恶意字符串的风险。5. 避坑手册这些坑不解决你的 javaWeb 项目跑不起来5.1 页面上全是中文乱码现象浏览器显示的 JSP 页面中文正常但表单提交到服务器后数据库里存的中文变成问号或乱码或者反向数据库里中文正常JSP 页面显示乱码。原因字符编码链路有三段——浏览器请求编码、Servlet 处理请求参数的编码、MySQL 存储编码。任何一段不一致都会出乱码。最常见的组合错误是JSP 页面用 UTF-8但 Servlet 里没有设置请求编码IDEA 默认用 GBK 解码或者 MySQL 表用了 latin1 字符集。解决三处都统一为 UTF-8。第一JSP 第一行写% page contentTypetext/html;charsetUTF-8 languagejava %。第二所有 Servlet 的doPost和doGet开头都执行req.setCharacterEncoding(UTF-8)。第三可以用一个 Filter 统一设置不用每个类都写一遍。第四MySQL 建表时用DEFAULT CHARSETutf8mb4连接 URL 里也带上characterEncodingutf8。5.2 Tomcat 404访问 JSP 和访问 Servlet 的结果不一样现象浏览器访问http://localhost:8080/dormitory/jsp/login.jsp能打开但访问http://localhost:8080/dormitory/student/list报 404或者反过来 Servlet 通 JSP 404。原因JSP 是文件路径直接映射Servlet 是 web.xml 或注解里的 url-pattern 映射。404 要么是 url-pattern 写错了要么是部署时项目没有正确打包。另一个很蠢但常见的坑是Servlet 类上忘了加WebServlet注解或加了注解但类没有编译进 classes 目录。解决先在 IDEA 的 Project Structure 里确认src目录被标记为 Sources。然后用浏览器直接访问http://localhost:8080/dormitory/看 Tomcat 默认页面是否正常再逐级排查 context path 和 url-pattern。最有效的排查法在 Servlet 的doGet加一行System.out.println(servlet entered)看 Tomcat 控制台有没有输出能帮你判断请求到底有没有到达这个类。这一步能让你快速把问题限定在“路由没走到”还是“视图渲染出错”。5.3 MySQL 连接报错: Public Key Retrieval is not allowed现象第一次启动项目连数据库就报Public Key Retrieval is not allowed连接不到数据库。原因MySQL 8.0 默认用 caching_sha2_password 认证客户端首次连接时要向服务器请求公钥来加密密码如果 JDBC 驱动认为“这个请求不合法”就会直接拒绝。解决连接 URL 尾部追加allowPublicKeyRetrievaltrueuseSSLfalse。这是 MySQL 8.0 Connector/J 8.0 最常见的连接坑之一。顺便说一下mysql 下载哪个版本这个问题也值得展开驱动 jar 包要和 MySQL 版本匹配MySQL 5.7 建议用 5.1.49 或 8.0.x 驱动均可但 MySQL 8.0 建议直接用 8.0.x 驱动。5.4 宿舍的 bed_used 和实际学生数对不上现象宿舍明明住了 3 个人列表里显示 2或者宿舍显示满了但退宿后还是满的。原因没有在事务里同步更新bed_used。比如学生入住时只更新了student.dorm_id忘了UPDATE dorm SET bed_used bed_used 1或者这两条 SQL 没有在同一个事务里执行中途异常导致只执行了一条。这个字段是冗余字段冗余字段依赖代码逻辑去同步维护最怕的就是逻辑遗漏。解决把入住和退宿都做成事务操作bed_used的更新用bed_used bed_used 1或bed_used - 1的方式不要先查再算再写。另外加一个对账工具方法SELECT COUNT(*) FROM student WHERE dorm_id ?和SELECT bed_used FROM dorm WHERE id ?比对写成一个管理页面的自检按钮能快速发现数据不一致的宿舍。5.5 Tomcat 端口被占用现象IDEA 启动 Tomcat 时报Port 8080 was already in useTomcat 起不来。原因上一个 Tomcat 实例没关干净或者别的程序比如其他 Java 进程占用了 8080 端口。解决在命令行执行netstat -ano | findstr 8080Windows或lsof -i:8080Mac/Linux查出占用端口的进程 PID然后taskkill /PID pid /F或kill -9 pid。更省事的做法IDEA 里点 Tomcat 配置把 HTTP port 改成 8081反正端口号只是本地访问路径的一部分。这不影响项目本身也不会出现在最终交付的代码里。6. 给项目加一层统一编码 Filter 与登录拦截让代码更规范这一节我们来做一个能让项目品质感明显提升的小改造用一个 Filter 统一处理字符编码再用另一个 Filter 做登录状态拦截。这两个 Filter 加完后你就不用在每个 Servlet 里重复写req.setCharacterEncoding和检查 Session 了。先写一个请求编码过滤器WebFilter(/*) public class EncodingFilter implements Filter { Override public void init(FilterConfig filterConfig) throws ServletException {} Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; request.setCharacterEncoding(UTF-8); resp.setCharacterEncoding(UTF-8); chain.doFilter(req, resp); } Override public void destroy() {} }注意这里有一点要强调setCharacterEncoding(UTF-8)必须在第一次读取请求参数之前调用。如果有代码在 Filter 之前就通过request.getParameter()拿了参数编码就定型了再设置也无济于事。所以才把 Filter 的 url-pattern 配成/*保证它最先被执行。再写一个登录拦截过滤器WebFilter(/*) public class LoginFilter implements Filter { Override 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(/login) || uri.endsWith(/jsp/login.jsp) || uri.endsWith(.css) || uri.endsWith(.js) || uri.endsWith(.png)) { chain.doFilter(req, resp); return; } HttpSession session request.getSession(false); if (session ! null session.getAttribute(admin) ! null) { chain.doFilter(req, resp); } else { response.sendRedirect(request.getContextPath() /jsp/login.jsp); } } }登录拦截器的逻辑很简单检查 session 里有没有管理员对象没有就跳回登录页。但这里有个新手很容易掉进去的坑——放行条件的顺序。/login是 Servlet 路径/jsp/login.jsp是 JSP 文件路径两个都要放行否则会出现登录页面本身被拦截导致死循环跳转。另外req.getSession(false)带参数false表示“如果当前没有 session 就返回 null 而不是创建新 session”避免每次访问都强制生成一个 session浪费服务器内存。这个拦截器过滤了/*下所有请求但你得有“把 JSP 文件直接放在webapp/jsp/目录下可以通过浏览器 URL 直接访问”这个概念。如果你不希望未登录用户直接通过 URL 访问某个 JSP 页面可以把页面挪到WEB-INF/目录下Tomcat 对WEB-INF下的资源默认禁止直接访问只能通过 Servlet 转发进入这是更严的隔离手段。不过代价是 JSP 里的超链接和静态资源路径要相应调整你自己权衡。这两个 Filter 加起来大约 50 行代码就能让你后续统一修改编码策略、调整登录校验逻辑时只改一处。宿舍管理系统这种小项目代码规范性的体现不在用了什么高深框架而在这些基础设施层的细节里。最后说一个我的习惯每次启动 Tomcat 后我会先把系统里所有页面都点一遍再开始写新功能。因为 JSP 的语法错误要等到第一次被访问才会暴露出来不像 Java 类在编译期就能报错。这些页面报错往往是英文一大篇看着吓人其实大多是某个 JSP 标签写漏了一个}或者标签闭合错了。先把页面全部跑一遍相当于给你的项目做了一遍冒烟测试省得后面边写功能边跟旧 bug 捉迷藏。希望帮到你。本文还有配套的精品资源点击获取
返回列表