ARTICLE DETAIL

资讯详情

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

JavaWeb学生成绩管理系统实战:从Servlet到Tomcat部署全解析

JavaWeb学生成绩管理系统实战:从Servlet到Tomcat部署全解析 简介JavaWeb的学生成绩管理系统完整项目包面向Java初学者及需要落地课程设计的开发者聚焦成绩录入、查询、统计、报表等典型教务场景。项目基于Servlet、JSP、JSTL、EL等JavaWeb核心技术结合SQL Server数据库与Eclipse开发环境包含用户权限管理、成绩合法性校验、多条件查询、平均分与及格率统计等模块。压缩包共138个文件约3.87MB涵盖27个Java源码、27个class编译文件、20个JSP页面、23个SQL脚本以及Eclipse工程配置、数据库设计模型PDM/CDM和说明文档可完整还原项目结构。已有12753人学习下载尤其适合高校学生作为课程设计或毕业设计的参考蓝本也能帮助自学者理解JavaWeb项目的完整开发链路。通过源码可学习登录过滤、分页查询、成绩关联表设计等关键实现还可借助附带的统计报表与数据库脚本快速启动并运行直观体验各功能模块的协作关系。 做JavaWeb练手项目学生成绩管理系统算是经典中的经典。不管你是刚学完Servlet和JSP的在校生还是准备找实习需要拿项目撑门面的初学者这套系统的技术覆盖面都很合适从前端页面到后端逻辑从数据库设计到部署上线几乎把JavaWeb开发的主干知识点全串起来了。很多培训机构的项目实战阶段也会拿它当作业像黑马程序员的JavaWeb笔记里就有类似的综合案例。这篇文章我就基于自己的实际开发经历把这个系统的完整实现思路、核心代码细节、IDEA 2023的创建步骤、Tomcat部署发布以及我在开发过程中踩过的坑一次性讲清楚。内容不整虚的全部是可复现的实操内容。1. 项目整体设计思路拆解1.1 为什么选择这套技术栈学生成绩管理系统最常见的形态就是浏览器访问的Web应用用户通过页面登录进行学生信息、课程信息、成绩数据的维护和查询。这个场景用JavaWeb来落地是非常自然的Servlet负责接收HTTP请求和处理业务逻辑JSP负责渲染动态页面MySQL负责数据持久化Tomcat负责运行和发布。这套技术栈虽然听起来老但恰恰是理解Java后端开发的基础。现在流行的SpringBoot本质上也是建立在Servlet容器之上的只是把配置封装得更简单了。如果直接上手SpringBoot很多人对请求怎么进来、响应怎么出去、Session怎么保持都是一头雾水。而用纯JavaWeb写一遍成绩管理系统你会把HTTP、请求转发、重定向、过滤器、监听器这些底层机制看得明明白白。1.2 系统功能模块怎么划分我在做的时候把系统分成两个角色管理员和普通教师。管理员可以管理教师账号和学生信息教师负责录入和查询成绩。当然如果课程设计有更高要求还可以加入学生角色让学生登录后查看自己的成绩。核心功能模块我建议这样划分登录模块账号密码校验、验证码可选、Session保存登录状态、未登录拦截学生管理模块学生信息的增删改查、按学号或姓名模糊查询、分页展示课程管理模块课程信息的维护为成绩录入提供课程维度成绩管理模块成绩录入、修改、删除按学生查看成绩列表按课程统计平均分和及格率这个划分不是拍脑袋想的而是遵循了一个模块只干一类事的原则。很多初学者喜欢把功能堆在一个Servlet里写出来的代码又长又乱后期改一个需求浑身难受。我自己第一版就是这么干的一个StudentServlet里塞了增删改查四套逻辑全用if-else判断action参数代码量爆炸查起bug来更是折磨。后来拆成不同的Servlet和Service层清爽太多了。1.3 数据库表结构设计数据库设计是整个系统的地基。我见过不少人一上来就建表做到后面发现缺字段又回去改表连带Java代码一起改非常痛苦。成绩管理系统最少需要四张表用户表t_user、学生表t_student、课程表t_course、成绩表t_score。-- 用户表 CREATE TABLE t_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, real_name VARCHAR(50), role VARCHAR(20) DEFAULT teacher ); -- 学生表 CREATE TABLE t_student ( id INT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(20) NOT NULL UNIQUE COMMENT 学号, name VARCHAR(50) NOT NULL, gender VARCHAR(10), class_name VARCHAR(50), phone VARCHAR(20), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 课程表 CREATE TABLE t_course ( id INT PRIMARY KEY AUTO_INCREMENT, course_name VARCHAR(50) NOT NULL, credit DECIMAL(3,1), teacher_name VARCHAR(50) ); -- 成绩表 CREATE TABLE t_score ( id INT PRIMARY KEY AUTO_INCREMENT, student_id INT NOT NULL, course_id INT NOT NULL, score DECIMAL(5,2), exam_date DATE, FOREIGN KEY (student_id) REFERENCES t_student(id), FOREIGN KEY (course_id) REFERENCES t_course(id), UNIQUE KEY uk_student_course (student_id, course_id) );这里有一个关键设计成绩表通过外键关联学生表和课程表同时用联合唯一键保证同一个学生同一门课程只能有一条成绩记录。这个唯一键在录入成绩时可以直接捕获重复数据避免业务层写一堆判断逻辑。外键关系也保证了不会出现成绩所属的学生被删了成绩还在这种脏数据。2. 开发环境准备与项目初始化2.1 IDEA 2023创建JavaWeb项目的完整过程很多人在2023版IDEA里卡在创建JavaWeb项目这一步原因是新版IDEA的菜单结构和老版本差别挺大而且内置的骨架模板里Web选项藏得比较深。我实际操作下来的流程是这样的打开IDEA选择New Project左侧选Jakarta EE右侧勾选Web Application和RESTful Web Service也可以只选Web Application。设置项目名称和JDK版本点击Create后IDEA会自动生成一个标准的Web项目结构src/main/java、src/main/resources、src/main/webapp。如果创建时没选Java EE也可以手动补右键项目选择Add Framework Support勾选Web ApplicationIDEA会帮你生成webapp目录和web.xml文件。有一点提醒一下2023版IDEA创建出来的Web项目默认会带一个index.jsp路径是src/main/webapp/index.jsp。很多人在配置Tomcat后访问项目根路径发现Tomcat主页或者404往往就是index.jsp没有正确部署到Tomcat的webapps目录。2.2 Tomcat版本选型9还是10这一步是很多新手容易踩的大坑。Tomcat 9和Tomcat 10的Servlet API包名不一样Tomcat 9用的是javax.servletTomcat 10开始换成了jakarta.servlet。如果你用的是IDEA 2023里Jakarta EE模板创建的项目代码里自动生成的Servlet导入的是jakarta.servlet.http.HttpServlet那你就必须用Tomcat 10或更高版本否则编译直接报“程序包javax.servlet不存在”。反过来如果你是在老项目里用javax.servlet写的代码硬塞进Tomcat 10也一样跑不起来。做这个成绩管理系统我建议直接用Tomcat 9因为网上大部分JavaWeb教程和笔记包括很多培训机构的资料默认还是基于Tomcat 8/9的javax.servlet语法遇到问题搜解决方案时匹配度最高。2.3 JDBC驱动和项目结构连接MySQL需要mysql-connector-java驱动包。这里有个非常常见的坑mysql-connector-java 8.x版本的驱动类名是com.mysql.cj.jdbc.Driver而不是老版本的com.mysql.jdbc.Driver同时URL里必须加上时区参数serverTimezoneAsia/Shanghai不然会报时区相关的异常。我在项目里通常这样组织目录结构src/main/java/com/example/score ├── controllerServlet类 ├── service业务逻辑 ├── dao数据访问层 ├── entity实体类 └── util数据库连接工具类 src/main/webapp ├── jsp页面文件 └── WEB-INF实体类对应数据库表结构DAO层负责JDBC操作Service层处理业务判断Controller层的Servlet负责接收参数和跳转页面。分层核心的原则是表现层不直接操作数据库数据访问层不写业务判断。这样后期把系统升级成SpringBoot版本直接复用DAO和Service层迁移成本非常低。3. 核心功能实现与实操要点3.1 登录模块与Session校验登录逻辑看起来简单但它是整个系统安全的第一道门。我实现的时候分三步第一步从请求中获取用户名和密码第二步调用UserDao的findByUsername方法查询用户第三步比对密码并处理结果。WebServlet(/login) public class LoginServlet extends HttpServlet { private UserDao userDao new UserDao(); 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); User user userDao.findByUsername(username); if (user ! null user.getPassword().equals(password)) { HttpSession session req.getSession(); session.setAttribute(loginUser, user); resp.sendRedirect(req.getContextPath() /student/list); } else { req.setAttribute(errorMsg, 用户名或密码错误); req.getRequestDispatcher(/login.jsp).forward(req, resp); } } }登录成功后把用户对象存进Session后续所有需要登录才能访问的页面都通过过滤器统一校验。第3章我不展开过滤器的完整代码但建议写一个LoginFilter拦截除login和静态资源以外的所有请求判断Session中是否存在loginUser不存在就重定向到登录页面。比在每个Servlet开头手动判断要省力得多也符合Servlet规范里过滤器的设计本意。3.2 学生信息增删改查的实现细节增删改查是最能体现编码基本功的部分。以学生列表分页为例需要接收两个参数当前页码page和页面大小pageSize然后通过SQL语句LIMIT offset, pageSize查询当前页数据同时计算总页数在页面渲染分页按钮。public ListStudent findPage(int page, int pageSize) throws SQLException { String sql SELECT * FROM t_student ORDER BY id LIMIT ?, ?; int offset (page - 1) * pageSize; // 使用PreparedStatement执行查询并封装结果 }这里有个容易被忽略的点模糊查询时不要用字符串拼接SQL否则除了SQL注入风险还可能因为参数里有单引号直接报错。要使用PreparedStatement的占位符比如WHERE name LIKE ?传入参数时写成% keyword %。删除操作建议用逻辑删除或者物理删除对于课程设计级别的系统物理删除就够用了。但如果成绩表里已经有该学生的成绩记录直接删除学生会触发外键约束报错所以我的实现是先删除该学生在t_score表中的记录再删除学生本身并且用事务包裹这两个操作保证数据的一致性。这也是一个容易出彩的细节面试官问起来能说明你具备事务意识。3.3 成绩录入与统计查询成绩录入页面通常做成表格形式按行展示学生信息每行带一个输入框用于填写分数。提交时通过Servlet循环接收request参数逐条插入数据库。由于t_score表上有uk_student_course唯一键重复提交同一条成绩时数据库会直接抛异常我在录入前先做一次查询判断如果已存在就调用更新方法否则执行插入。这样录入功能同时兼顾了修改的语义。成绩统计这块我实现了两个维度按学生维度查询某个学生的所有课程成绩并计算总分和平均分按课程维度查询某门课程的选课人数、最高分、最低分、平均分和及格率SQL示例SELECT c.course_name, COUNT(s.id) AS total_count, AVG(sc.score) AS avg_score, MAX(sc.score) AS max_score, MIN(sc.score) AS min_score, SUM(CASE WHEN sc.score 60 THEN 1 ELSE 0 END) / COUNT(s.id) AS pass_rate FROM t_course c LEFT JOIN t_score sc ON c.id sc.course_id LEFT JOIN t_student s ON s.id sc.student_id GROUP BY c.id;这种统计SQL建议先直接在MySQL客户端里跑通确认结果没问题再搬进Java代码不要边写Java边调SQL那样排查效率很低。另外要注意LEFT JOIN的使用保证没有成绩的课程也出现在结果里而不是被INNER JOIN过滤掉。4. 项目部署与发布经验4.1 IDEA内直接部署调试开发阶段最省事的方式就是把项目部署到IDEA内置集成的Tomcat中。点击右上角的Add Configuration选择Tomcat Server - Local在Deployment选项卡里点加号选择Artifact把项目以war exploded方式部署。这里解释一下为什么选exploded它直接把编译后的class、jsp等资源目录映射到Tomcat容器中不需要打war包修改JSP或者Java代码后在Debug模式下按CtrlF10重新编译再刷新浏览器就能看到效果开发效率最高。配置Tomcat时还要注意两个细节。一个是Application context也就是访问路径前缀我习惯设置成/score这样启动后访问地址是http://localhost:8080/score/。另一个是On Update Action建议设置成Update classes and resources这样日常改动Java类时能自动热更新而不是每次都要重启Tomcat。4.2 Windows Server Apache Tomcat联合发布结课验收或者实际部署时项目常常要发布到一台Windows Server上。如果是中小型应用Tomcat单节点就能跑但如果服务器上已经装了Apache即httpd监听80端口而你又想让用户直接通过域名访问不走8080端口就需要做Apache和Tomcat的整合。最常用的方式是Apache加载mod_jk模块通过Ajp协议把请求转发给Tomcat。具体的配置步骤将mod_jk.so复制到Apache的modules目录同时在httpd.conf末尾添加加载配置创建mod_jk.conf配置文件设置JkWorkersFile指向workers.properties设置JkMountFile指向uriworkermap.properties在uriworkermap.properties中配置哪些URL前缀交给Tomcat处理比如/score/*tomcat1在workers.properties中配置Tomcat的地址和端口默认Ajp端口是8009这套配置我之前踩了不少坑最容易出问题的点就是AJP端口冲突和路径映射范围写错。如果Apache和Tomcat装在同一台机器上workers.properties中的worker.tomcat1.host写localhost就行worker.tomcat1.port必须是Tomcat配置里AJP/1.3 Connector的实际端口。我最初照着网上教程配没注意Tomcat 9的AJP端口默认是8009被我手动改成了8010结果Apache转发全部503。当然如果只想简单演示直接用Tomcat监听80端口也是可以的。修改Tomcat的server.xml把Connector的port从8080改成80再把redirectPort改成443或直接去掉。这种方式配置量最小适合课程设计和内部系统演示。4.3 部署中的路径与资源问题打包发布的时候我最推荐用Maven的clean package命令生成war包然后把war包扔进Tomcat的webapps目录启动Tomcat后它会自动解压部署。这种方式最接近生产环境也最不容易有IDEA环境差异带来的问题。但需要注意war包部署时如果代码里用了绝对路径访问文件比如上传图片保存到D:/upload/avatar.jpg那在IDEA里能跑通换到服务器上可能就找不到路径了。所以在写代码时应该用相对路径或者从配置文件中读取路径不要硬编码绝对路径。另外JSP页面里引用CSS、JS、图片时一定要使用${pageContext.request.contextPath}拼接项目上下文路径否则部署时换了上下文名静态资源会全部404。5. 常见问题与排查技巧实录5.1 数据库中文乱码问题乱码问题几乎每个做JavaWeb的人都会遇到成绩管理系统里更是高频问题。中文乱码的原因说到底是编码不一致涉及的环节有页面编码、请求编码、响应编码和数据库编码四个环节任何一个环节不一致都会乱码。我的排查顺序是先确认数据库表字符集是utf8mb4再确认JDBC连接URL里加上characterEncodingutf-8然后在Servlet里统一设置req.setCharacterEncoding(UTF-8)和resp.setContentType(text/html;charsetUTF-8)最后确认JSP页面顶部有% page contentTypetext/html;charsetUTF-8 languagejava %。四个环节都设好基本不会乱码。如果是从老项目迁移过来的还要检查MySQL配置文件my.ini里character_set_server的值。5.2 端口占用和项目无法访问Tomcat启动时报端口被占用是典型新手问题。Windows下用netstat -ano | findstr 8080查出占用端口的进程PID再到任务管理器里结束进程或者直接用taskkill /PID xxx /F强行结束。但我更建议直接改Tomcat端口打开conf/server.xml把Connector的port改成8081等不常用端口同时注意把Server配置里的shutdown端口默认8005和AJP端口默认8009也一并改掉避免冲突。还有一种情况是项目启动不报错但访问http://localhost:8080/score/显示404。这时候先去Tomcat的webapps目录下检查有没有解压成功如果war包存在但没解压目录说明解压失败基本是war包损坏或者JDK版本不兼容。如果解压正常但还404就要看访问路径对不对很多人把Application context设置成了/score访问时却带了/score_war_exploded这样的IDEA自动生成的路径自然打不开。5.3 Session失效和登录拦截失效登录拦截失效是个老问题用户没登录直接输入管理页面的URL竟然也能访问。这个通常不是过滤器写得不对而是过滤器映射的URL匹配范围写错了。注意如果你用WebFilter(/*)它会拦截所有请求包括登录页面本身不做放行处理的话会死循环。所以过滤器里必须放行这些路径登录页面/login.jsp、登录接口/login、静态资源/css/、/js/、/images/*。Session失效的问题通常和Session超时时间设置有关。默认Tomcat的Session过期时间是30分钟如果想调整可以在web.xml里配置session-config session-timeout60/session-timeout /session-config但这里要提醒一个细节如果你设置了Session超时用户长时间挂着页面不操作再点提交时Session已经过期请求会被过滤器拦截并重定向到登录页用户填的表单数据全丢了。想改善体验可以把提交表单和Session验证做异步处理前端先通过AJAX请求检查登录状态过期时弹窗提示用户重新登录而不是直接丢掉页面数据。5.4 常见问题速查表现象常见原因解决办法编译报javax.servlet不存在Tomcat版本与Servlet API不匹配使用Tomcat 9或把代码改为jakarta包名中文乱码请求/响应/数据库编码不一致统一设置为UTF-8JDBC URL加characterEncoding8080端口被占用其他程序占用端口改Tomcat端口或结束占用进程启动后404部署路径错误或war包未解压检查webapps目录和Application context数据库连接超时驱动类名或时区参数配置错误使用com.mysql.cj.jdbc.Driver加serverTimezone未登录也能访问页面过滤器放行路径配置错误在过滤器中显式放行登录页和静态资源做这个系统时我最大的体会是JavaWeb项目的难点不在某个单独的技术点而在于各个组件之间的衔接。数据库、后端、前端、容器、部署每一个环节都是独立的但它们必须协同工作。学生成绩管理系统虽然老但它把这条链路完整地走了一遍走通之后再看任何Java Web框架都会有一种原来它只是把这里封装了的豁然开朗感。最后再分享一个小技巧开发时一定要养成看日志的习惯。Tomcat的logs目录下有catalina.out、localhost.log等日志文件很多看似诡异的问题比如部署后页面样式丢失、列表数据查不出来其实根因早就在日志里写明了。遇到问题先查日志再动手改代码能省下大量瞎试的时间。本文还有配套的精品资源点击获取
返回列表