资讯动态

学生信息管理系统实战:JSP+Servlet+JavaEE全流程解析

发布时间:2026/9/26 8:00:39 来源:尧图企业网站定制
做学生管理信息管理系统基本是学JavaWeb绕不开的一道坎。当年我在学校课程设计里折腾这个JSPJavaEE项目从对着Tomcat日志发呆到能把自己的系统跑起来中间踩过的坑攒下来足够写好几篇记录了。这篇就把我做学生信息管理系统时从环境准备、数据库设计、功能实现到部署上线的全过程和关键细节都整理出来给正在做课程设计、毕设或者刚开始接触JavaEE这套东西的同学做参考。这个项目的名字看起来啰嗦其实核心就一个用JSP做页面展示用Servlet处理和调度请求用JavaBean或者DAO层访问数据库最终在浏览器里完成学生信息的增删改查。它能锻炼的东西很实在——HTTP请求怎么走的、Session会话怎么保持、JDBC连接怎么管理、MVC分层为什么要把代码拆开再加上最后的war包部署。这一条链路跑通了后面再碰Spring Boot这类框架很多东西一眼就能看明白。1. 这个项目到底在做什么1.1 一套最典型的学生管理系统包含哪些功能先别急着写代码把需求理清楚。一个合格的学生信息管理系统至少要能完成这几件事登录认证管理员输入账号密码登录系统未登录的用户不能访问后台页面。学生信息列表分页展示学生记录而不是一次性把几千条数据全扔到页面上。新增学生表单填写学号、姓名、性别、班级、联系电话等信息提交后写入数据库。编辑学生列表页点“编辑”表单回填原有信息修改后保存。删除学生确认后删除对应记录数据库里真正执行DELETE。模糊查询按学生姓名或者学号、班级做关键字搜索。个人资料展示登录用户可以查看和修改自己的基本信息对应热搜里提到的“jsp个人信息展示页面”。不要觉得这些功能简单。它们几乎覆盖了JavaWeb入门阶段最核心的知识点Servlet生命周期、JSP内置对象、Session会话管理、JDBC预编译语句、PreparedStatement防SQL注入、分页SQL的LIMIT写法、过滤器统一处理编码和登录校验。把这些功能一个个啃下来比水十份课程设计都有用。1.2 为什么还在用JSPJavaEE这套老组合很多同学会有疑惑现在前后端分离都成主流了Spring Boot加Vue才是常规套路为什么课程和毕设还在用JSP这里说句大实话——JSP这套技术确实老但它有一个不可替代的价值它把Web底层的执行细节暴露得很彻底。用JSP做项目的时候你得亲眼看到一个.jsp文件第一次被访问时Tomcat把它编译成了.java文件再编译成class你得手动配web.xml或者写WebServlet注解自己去处理一个请求从哪里进、往哪里出你得自己写JDBC连接数据库手动关闭Connection、Statement、ResultSet。这些经验对打基础非常关键因为框架再怎么封装底层的本质还是那套东西。JSP本身可能不再被新项目采用但它跑在Servlet之上搞清楚JSP的运行原理再回头看Thymeleaf、FreeMarker甚至前端项目的模板渲染思路都会觉得通透很多。1.3 先搞清楚JSP和JavaEE的边界很多人把“JSP”和“JavaEE”混在一起说其实它们是两码事。JavaEE是一个技术体系早期叫J2EE后来改名Java EE、Jakarta EE包含Servlet、JSP、EJB、JMS、JTA等一堆规范而JSP只是JavaEE体系里负责视图展示的那一块。做我们这套学生系统实际用到的JavaEE组件主要是Servlet、JSP、Filter、Listener这几个并没有用到EJB这种重量级的家伙。搞清楚这层关系就不会被“JSP是过时的技术”“JavaEE太老”这些说法带偏。我们学习JavaEE的表达方式核心是掌握它定义的Web开发模型请求交给Servlet处理Servlet把数据塞进request或者session再转发或重定向到某个JSP页面JSP负责把数据渲染成HTML返回浏览器。这个模型一直到Spring MVC里依然能看到它的影子。2. 核心技术点拆解这套组合的原理与分工2.1 JSP页面是在浏览器里跑的很多新手都理解错了先纠正一个很常见的误会JSP文件不是直接在浏览器里执行的。用户请求student_list.jsp的时候真正的执行流程是Tomcat里的Jasper引擎把这个JSP文件转译成一个Servlet的Java源码然后编译成class文件最终执行的其实是这个编译后的Servlet。举一个生活化的例子JSP文件就像一份菜谱Tomcat是一个自动炒菜机它拿到菜谱后不是把菜谱端给食客而是自己把菜谱翻译成一套烹饪程序然后执行程序炒出菜来。客户端浏览器拿到的是炒好的菜——也就是HTML页面绝对看不到JSP源码本身。这也解释了为什么JSP第一次访问会莫名慢一点。因为第一次访问要做转译和编译生成_jsp.java和_jsp.class文件后续访问直接用编译好的class速度就正常了。在Tomcat的work目录下你可以直接找到这些文件打开看一眼所有HTML标签都变成了out.write()输出所有Java代码片段都进了_jspService方法。这个动作非常值得亲自做一次看完你会彻底明白JSP的本质。2.2 Servlet才是JavaWeb的主角JSP只是它的“展示替身”既然JSP最终会被编译成Servlet那我们完全可以直接用Servlet输出HTML为什么还要绕一圈用JSP因为直接在Servlet里拼接HTML字符串实在太反人类了既难维护又容易出错。JSP的价值就是把HTML展示和Java逻辑拆开。但要注意拆开归拆开业务逻辑仍然不应该写在JSP里。正确的分工应该是这样Servlet担任控制层接收请求、解析参数、调用业务方法、决定跳转到哪个页面。JSP担任视图层只负责展示Servlet传过来的数据不写复杂的业务判断。JavaBean/DAO担任模型层封装数据、操作数据库、把结果返回给Servlet。用MVC的理论去套这就是最标准的Web MVC结构。很多同学一上来就在JSP里写%循环和%JDBC代码页面被塞得乱七八糟。短期能跑但功能一多页面和逻辑纠缠在一起改一个查询条件都要翻半天代码。我在实际开发里最深的体会就是Servlet里只留下“取参、调用、转发”三件事页面里只用EL表达式和JSTL标签去取数据代码会清爽非常多。2.3 JavaBean与DAO层数据访问的正确姿势学生信息管理系统里最绕不开的是数据库操作。初学者最常见的写法是把JDBC代码直接写到JSP里这种写法能出效果但绝对是反面教材。更规范的做法是分两层实体层一个Student类字段对应数据库表t_student的列比如studentNo、name、gender、classId、phone等加上对应的getter和setter。DAO层一个StudentDao类提供findAll()、findByPage()、findById()、insert()、update()、delete()等方法每个方法负责具体的JDBC操作。为什么非得加一个DAO层说白了就是解耦。假如有一天你想把数据库从MySQL换成Oracle只需要改DAO层的SQL方言Servlet和JSP完全不用动。这就是分层带来的维护价值。在学生管理系统这种量级的项目里分层会显得有一点“多此一举”但养成这个习惯之后做任何后端项目都会自然而然地保持代码清晰。2.4 连接池别让数据库连接拖垮系统JDBC操作数据库的第一步是拿到连接但每次请求都新建一个Connection是非常糟糕的做法。建立数据库连接涉及网络握手、权限校验开销很大如果系统并发一高连接数一多数据库马上会被拖垮。所以项目里一定要配连接池。典型的做法是在src下放一个c3p0-config.xmlC3P0或者用阿里的Druid、Apache的DBCP。以Druid为例核心配置是这样driverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/student_db?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingUTF-8 usernameroot password123456 initialSize5 maxActive20 minIdle5 maxWait60000配置里最重要的两个参数是maxActive和initialSize。initialSize表示启动时先初始化5个连接maxActive表示最多同时有20个连接。如果超过maxActive新的请求就要排队等待maxWait超时了就报错。对于课程设计这种场景20个连接完全够用但我也见过有些同学把maxActive调到200结果小项目把本地MySQL拖到时不时假死的教训很实在。连接池选型上Druid胜在自带监控页面调试时方便查看连接情况C3P0是老牌框架资料多适合入门。其实现在新项目早就在用HikariCP理解原理都一样不必纠结选谁关键是别裸用JDBC。3. 实操从零搭出一套学生管理系统3.1 数据库设计表结构和字段别乱起名搞这套系统我推荐三张核心表管理员表t_admin、班级表t_class、学生表t_student。如果想让功能更完整还能再加一张成绩表t_score用于展示学生多科成绩。建表SQL可以参考这个简化版本CREATE DATABASE student_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE student_db; CREATE TABLE t_admin ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE t_class ( id INT PRIMARY KEY AUTO_INCREMENT, class_name VARCHAR(100) NOT NULL, grade VARCHAR(20) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE t_student ( id INT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(20) NOT NULL UNIQUE, name VARCHAR(50) NOT NULL, gender CHAR(1), age INT, class_id INT, phone VARCHAR(20), email VARCHAR(100), create_time DATETIME DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_student_class FOREIGN KEY (class_id) REFERENCES t_class(id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这里有几个细节非常值得注意。第一数据库字符集一定要用utf8mb4不要用老的utf8。utf8mb4是完整的UTF-8编码能存emoji和一些生僻字虽然这套系统大概率不会存emoji但从开始就配好没坏处。第二字段命名尽量避开SQL关键字。比如不要把班级字段命名为class因为它在不少SQL方言里有特殊含义容易埋坑。我用class_id做外键用class_name存储班名从而避开冲突。第三学号student_no一定要加唯一约束现实中一个学号只能对应一个学生这是数据完整性的底线。3.2 开发环境与项目骨架老组合也要注意版本兼容环境这一块我最推荐的组合是JDK 8 Tomcat 8.5或者9 IDEA MySQL 5.7或者8.0。不建议直接用Tomcat 10以上因为Tomcat 10开始Servlet规范的包名从javax.*换成了jakarta.*网上大量老教程和课程案例还在用javax.servlet写法版本对不上会出现一堆诡异的报错纯属给自己找麻烦。用IDEA搭建项目时可以从Maven的maven-archetype-webapp模板来创建也可以直接用IDEA的Java Enterprise向导。如果用的是IDEA Community版本没有Java Enterprise的选项可以加一个Smart Tomcat插件来启动Tomcat调试。项目骨架的标准结构是这样src/main/java cn/student/entity/Student.java cn/student/dao/StudentDao.java cn/student/servlet/LoginServlet.java cn/student/servlet/StudentServlet.java cn/student/filter/LoginFilter.java src/main/resources db.properties c3p0-config.xml src/main/webapp login.jsp student_list.jsp student_form.jsp welcome.jsp WEB-INF/web.xml用Maven的话记得在pom.xml里添加Servlet API、JSP API和MySQL驱动依赖。注意任何Servlet相关依赖的scope配成provided因为Tomcat自带了打包时不要重复打进去否则可能产生冲突。3.3 登录模块Session会话与权限控制系统所有功能的前提是登录。开发登录模块时除了明白“查一下用户名密码对不对”更关键的是理解Session这套机制。登录流程可以这样设计login.jsp提交表单到LoginServletServlet从request里取出username和password调用AdminDao.findByUsernameAndPassword(username, password)查库。如果查到了就把管理员对象存进session.setAttribute(loginUser, admin)然后response.sendRedirect(welcome.jsp)。如果没查到就往request里放一个错误提示然后转发回login.jsp由页面把错误信息渲染出来。为什么要用sendRedirect而不是forward因为重定向会改变浏览器地址栏的URL用户看到的是欢迎页地址。而直接转发的话地址栏一直是loginServlet地址用户刷新页面时会再次提交表单出现“重复提交”的毛病。这个问题我在课设答辩现场见过好多回一个刷新操作直接弹窗问“是否重新发送表单”演示效果非常差。登录功能的完整度还要靠过滤器来配合。在web.xml或注解里配置一个LoginFilter拦截所有以.jsp结尾的请求登录页除外在doFilter里检查Session是否有用户信息没有就强制跳回登录页。这个过滤器的写法非常经典WebFilter(/*) public class LoginFilter 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(login.jsp) || uri.endsWith(/login) || uri.contains(/static/)) { chain.doFilter(req, resp); return; } Object loginUser request.getSession().getAttribute(loginUser); if (loginUser null) { response.sendRedirect(request.getContextPath() /login.jsp); return; } chain.doFilter(req, resp); } }有一个细节我提醒过很多人静态资源比如CSS、JS文件夹一定要在过滤器里放行。不然你明明登录了页面样式却因为被过滤器拦截而加载不出来白屏加无样式的表现会让人误以为自己代码出了问题。3.4 学生信息的增删改查与分页查询学生管理模块是系统的核心主体。最省事的做法是写一个StudentServlet让它一个人把所有动作都接管了用一个method参数区分操作类型。例如URL写成studentServlet?methodlistpage2Servlet里通过分支去调不同方法。等以后学了Spring MVC你会发现这个思路就是后来RequestMapping(/list)的雏形只不过现在全靠手动判断。分页查询的SQL是整个功能里最有技术含量的一块。先数总记录数SELECT COUNT(*) FROM t_student;再查询当前页的数据SELECT * FROM t_student LIMIT #{offset}, #{pageSize};这里的offset等于当前页码 - 1乘以每页条数。每页10条数据第一页LIMIT 0, 10第二页LIMIT 10, 10第三页LIMIT 20, 10。页面里同时需要总记录数、总页数、当前页、上一页、下一页这些信息所以推荐封装一个PageBeanT里面放currentPage、pageSize、totalCount、totalPage、ListT data等字段把分页的所有状态都集中管理。查询时一定要养成用PreparedStatement的习惯。不要用Statement去拼接字符串否则如果用户输入的是 or 11这种内容你的SQL就可能变成不可控的查询条件这就是最典型的SQL注入。PreparedStatement用?占位符参数由驱动处理从根源上避免了这个问题。模糊查询也是常见的考点。搜索框里输入关键字对应的SQL是SELECT * FROM t_student WHERE name LIKE ? LIMIT ?, ?在Java里传参数时需要先拼接通配符dao.executeQuery(% keyword %)。这里还有一个很容易踩的坑分页和条件是同时存在的所以COUNT语句也要带LIKE条件否则搜索后页码会算错。我建议做的时候把buildCountSql和buildPageSql单独抽出来根据条件动态拼接这样逻辑会清晰很多。4. 部署打包与线上问题排查实录4.1 传统JSP项目打包war与部署到Tomcat传统JSP项目通常以war包形式部署。如果你的项目是用IDEA的Maven构建可以在Maven侧边栏执行package命令。打包完成之后在target目录下能看到一个xxx.war文件。如果用的不是Maven也可以手动用IDEA的Artifacts导出但Maven更规范化一些。war包本质上是一个zip压缩文件它的内部结构是有讲究的student-system.war ├── login.jsp ├── student_list.jsp └── WEB-INF ├── web.xml ├── classes │ └── cn/student/... └── lib └── mysql-connector-java.jar从war包结构能看到两个关键信息编译好的class文件必须放在WEB-INF/classes下面第三方jar包必须放在WEB-INF/lib下面。部署的时候把这个war文件丢到Tomcat的webapps目录启动Tomcat就会自动解压自动发布。这时候通过浏览器访问http://localhost:8080/student-system/就能进入系统其中student-system是war包名也是访问时的上下文路径。很多同学部署的时候习惯直接把项目文件夹整个拷进去这样也能跑但正规做法还是打war。因为war包干净卸载和升级都很方便删除一个文件就行不会残留零散的class文件。4.2 中文乱码问题全排查乱码问题绝对是学生管理系统最折磨人的问题之一而且它不只在代码层面还会出现在数据库层面。最常见的几种情况页面显示乱码JSP头部缺少contentTypetext/html;charsetUTF-8或者两个编码不一致。表单提交的中文变成问号POST请求收到的参数没做编码处理。从数据库查出来的中文乱码数据库表本身字符集不对或者JDBC连接URL没指定编码。我的标准做法是四步走。第一步确保所有JSP页面头部统一写% page contentTypetext/html;charsetUTF-8 languagejava %。第二步给项目配一个字符编码过滤器在过滤器里统一调用request.setCharacterEncoding(UTF-8)。第三步JDBC连接URL后面加?characterEncodingUTF-8同时数据库表用utf8mb4。第四步确认MySQL服务端字符集是UTF-8必要时检查my.ini的配置文件。这里补充一个重要经验使用Tomcat 8.5以上版本时GET请求的参数默认用的是UTF-8所以URL上带中文一般不会出问题。但POST请求的参数必须靠setCharacterEncoding来设而且必须在第一次读取参数之前设置放太晚就没用了。过滤器是最靠谱的做法用注解或者web.xml把它配置在最早执行位置。4.3 404、500与数据库连接池相关的高频报错这套系统的报错翻来覆去就那么几类把这几张“脸”认熟了排错效率能提高一大截。出现404通常是URL路径配置有问题。看看自己请求的是/studentServlet但注解写的WebServlet(/student)或者忘了加项目上下文路径在直接用getContextPath()拼接的地方写死了绝对路径。出现500九成是空指针或SQL异常这时直接去Tomcat的catalina.out日志或者IDEA控制台看异常栈那行带at cn.student.dao.StudentDao.xxx的代码就是问题所在。还有一个比较隐蔽的坑ClassNotFoundException或者找不到com.mysql.cj.jdbc.Driver。驱动包忘了放进WEB-INF/lib导致代码编译通过但运行时检查不到jar包。所以打包war之后一定要检查WEB-INF/lib下面是不是真的有MySQL驱动jar。如果用的是Maven还要检查依赖是不是被排除了。另外连接池配置和数据库连接不上也会闹脾气。错误信息里出现Access denied for user说明账号密码不对出现Communications link failure通常是MySQL服务没启动或者端口写错或者serverTimezone没配置引发时区问题。这些报错的中文解释在网上都有但只看报错不如主动看配置先把url的IP、端口、库名、用户名、密码一个个对着确认一遍能排查掉至少八成问题。4.4 连接池耗尽、没有关闭连接引发的假死说实话学生管理系统这种低并发场景最容易出现的不是并发崩溃而是“跑着跑着突然卡死”。这个“卡死”绝大多数是数据库连接没有被关闭。初学者写JDBC经常只写了conn ...却忘了在finally里关闭conn、stmt、rs日子一长连接池里的连接全被占满后续所有请求都在排队表现就是Tomcat卡住页面一直转圈。Java 7以后有一个非常好的语法糖叫try-with-resources它可以在代码块结束时自动关闭资源try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, name); try (ResultSet rs ps.executeQuery()) { while (rs.next()) { ... } } } catch (SQLException e) { e.printStackTrace(); }一定要把ResultSet的关闭逻辑也放在try里。很多同学只关了连接和语句结果集对象还一直开着本质上还是存在资源泄漏的风险。养成这个好习惯之后连接池假死的问题基本不会再碰见。5. 给后来人几句实在话最后再说几句心里话。这套系统做起来并不难难点在于它像一面镜子照出来你到底有没有真正理解JavaWeb的运行链路。我曾经见过不少同学从网上找一份“成品毕设”改个名字交上来问他为什么第一次访问JSP会慢为什么session能存登录状态他支支吾吾说不出所以然。这其实非常可惜因为学生管理系统最大的价值就是它足够小小到你能亲手把每一条链路都看清楚又足够完整完整到可以当成一个正式的Web项目来理解。我的建议是无论做课设还是毕设一定要亲手敲一遍代码然后打开Tomcat的work目录看看JSP被编译出来的Java文件长什么样故意写错一个SQL去日志里读一遍异常栈再给自己的项目加上一个分页功能从LIMIT语句开始把页码逻辑捋直。这些笨功夫比装一万个框架都值钱把底层的东西吃透了你再看Spring Boot、MyBatis、Spring MVC会发现它们不过是在Servlet这个地基上盖起来的高楼。这套学生管理系统也可以继续往更完整的业务方向扩展。比如增加年级、专业、教师、成绩、课程这几个模块把学生信息从单一管理升级成一套完整的信息化流程。只要数据库设计合理分层的代码结构不烂扩展这些功能一点都不难。做技术就是这样打好地基后面盖楼才有底气。

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

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

免费获取报价 →
↑