Java Web学生成绩后台系统:含SQL脚本、JSP页面与Tomcat可运行工程
简介:直接导入就能跑的Java Web成绩管理后台,用Servlet做后端控制,JSP渲染页面,MySQL存数据。项目按MVC分层组织:src里有DAO操作数据库、Service封装业务逻辑、Servlet处理请求;web目录放登录页、成绩列表页等JSP文件和CSS/JS资源;sql文件夹里配好了建表语句和示例数据,复制粘贴到MySQL就能用。管理员账号密码预置,登录后能新增学生、录入成绩、修改分数、删除记录、按学号或姓名查成绩,所有功能都在标准HTTP请求流程里完成。本地用Tomcat 8或9部署,启动服务后浏览器访问localhost:8080自动跳转登录页,无额外依赖、无编译报错,适合Java Web初学者练手、课程作业快速交付或毕设基础框架参考。
1. 项目概述:为什么这个成绩系统值得你花30分钟跑起来
我带过六届Java Web课程设计,每年都有学生卡在“第一个能跑通的完整Web项目”上——不是不会写代码,而是被环境配置、包依赖冲突、路径404、数据库连不上这些琐碎问题拖垮信心。直到去年我把这套学生成绩后台系统从教学案例库里翻出来重跑了一遍,才真正意识到它为什么能在GitHub上被星标2800+次:它不是教科书式的Demo,而是一个经过真实课堂压力测试的最小可行产品(MVP)。核心关键词——Java Web、成绩管理系统、JSP、Tomcat、MySQL——每一个都不是孤立存在,而是被拧成一股绳:Servlet负责把HTTP请求翻译成业务动作,JSP把数据库里的学号、姓名、数学成绩这些冷冰冰的字段,变成浏览器里可点击的表格和输入框;MySQL不只存数据,它的建表脚本里藏着外键约束、非空校验、默认值这些生产级细节;Tomcat不是个摆设容器,它的web.xml配置决定了登录拦截器怎么生效、静态资源如何免鉴权访问。这套系统最硬核的地方在于:它用最朴素的技术栈(没用Spring Boot自动装配,没用Vue做前后端分离),却把MVC分层逻辑刻进了每一行代码里——DAO层里一个StudentDaoImpl.java文件,就完整演示了如何用JDBC原生API连接池获取Connection、预编译SQL防止注入、手动封装ResultSet到Student实体;Service层里ScoreService.java的updateScore()方法,会先查学生是否存在、再校验分数是否在0-100区间、最后才执行UPDATE语句,这种业务校验逻辑,比任何PPT讲的“高内聚低耦合”都来得实在。如果你正为课程设计发愁,或者想甩掉“只会写HelloWorld Servlet”的标签,这个项目就是你的第一块跳板:不需要改一行代码就能看到登录页弹出来,但只要你愿意多点开几个.java文件,就会发现所有“为什么这么写”的答案,都藏在那些看似平淡的try-catch块和if判断里。
2. 整体架构与MVC分层逻辑拆解
2.1 为什么坚持用原生Servlet而非Spring Boot?
很多初学者看到项目没用Spring Boot会下意识觉得“过时”,但恰恰是这种“笨办法”暴露了Web开发的本质。Spring Boot的@RestController自动把对象转成JSON,掩盖了HTTP协议里Request/Response对象的原始交互;而这个项目里,每个Servlet都显式调用request.getParameter("username")获取表单数据,用response.sendRedirect("success.jsp")控制跳转,用request.setAttribute("studentList", list)把查询结果塞进请求域——这些操作对应着HTTP状态码302重定向、HTML页面渲染、服务器端数据传递的真实链条。举个具体例子:登录功能不是靠注解扫描实现的,而是LoginServlet.java里一段硬编码的校验逻辑:
String inputUsername = request.getParameter("username");
String inputPassword = request.getParameter("password");
if ("admin".equals(inputUsername) && "123456".equals(inputPassword)) {
HttpSession session = request.getSession();
session.setAttribute("loginUser", "admin");
response.sendRedirect("scoreList.jsp");
} else {
request.setAttribute("errorMsg", "用户名或密码错误");
request.getRequestDispatcher("login.jsp").forward(request, response);
}
这段代码的价值在于:它强制你理解session机制(request.getSession()创建会话ID并写入Cookie)、理解请求转发与重定向的区别(forward在服务端跳转不改变URL,sendRedirect触发浏览器新请求)、理解作用域生命周期(request.setAttribute的数据只在本次请求有效)。而Spring Boot的ModelAndView会把这些细节封装掉,新手反而容易陷入“配置成功但不知道为什么成功”的困惑。所以这个项目选择原生Servlet,不是技术保守,而是教学策略——它把Web开发的“黑盒子”一层层剥开,让你亲手摸到HTTP协议的温度。
2.2 MVC三层如何在文件结构中落地?
项目目录树表面看是物理划分,实则暗含职责契约。我们以“新增学生成绩”功能为例,追踪一次完整请求链路:
- View层(web目录):用户在
addScore.jsp页面填写学号、姓名、数学成绩后点击提交,表单<form action="AddScoreServlet" method="post">将数据POST到AddScoreServlet这个URL; - Controller层(src/servlet目录):
AddScoreServlet.java接收到请求,调用request.getParameter()解析参数,实例化Score实体对象,然后把对象传给Service层; - Service层(src/service目录):
ScoreService.java的addScore(Score score)方法接收对象,先调用studentDao.findById(score.getStudentId())检查学号是否存在(避免插入不存在的学生),再调用scoreDao.add(score)执行数据库操作; - Model层(src/dao目录):
ScoreDaoImpl.java的add()方法通过JDBC执行INSERT语句,这里的关键是预编译处理:String sql = "INSERT INTO score (student_id, name, math_score) VALUES (?, ?, ?)"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, score.getStudentId());——问号占位符不仅防SQL注入,更让数据库能复用执行计划,这是生产环境必备意识。
这种分层不是为了炫技,而是解决实际问题。比如某次学生反馈“新增成绩后页面空白”,我让他按层级排查:先看addScore.jsp的form action路径是否拼错(View层);再检查AddScoreServlet.java里是否有response.getWriter().println("success")调试输出(Controller层);接着确认ScoreService.java的addScore()方法是否返回了布尔值表示成功(Service层);最后在ScoreDaoImpl.java的INSERT语句后加System.out.println("影响行数:" + ps.executeUpdate())(Model层)。四步下来,90%的问题都能定位到具体文件行号。这种可追溯性,正是MVC分层赋予项目的工程价值。
2.3 Tomcat部署结构与web.xml的核心配置
很多人以为把项目丢进Tomcat的webapps目录就完事了,其实关键在web/WEB-INF/web.xml这个文件。它就像系统的交通指挥中心,定义了URL路由、过滤器链、监听器等核心规则。本项目web.xml里最关键的三段配置:
<!-- 配置Servlet映射 -->
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.example.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/LoginServlet</url-pattern>
</servlet-mapping>
<!-- 配置欢迎文件 -->
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
<!-- 配置登录拦截器 -->
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>com.example.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/scoreList.jsp</url-pattern>
<url-pattern>/addScore.jsp</url-pattern>
</filter-mapping>
第一段servlet-mapping解释了为什么浏览器访问http://localhost:8080/LoginServlet会触发LoginServlet.java——Tomcat启动时会读取这个配置,建立URL路径与Java类的映射关系。第二段welcome-file-list决定了当用户只输入根路径http://localhost:8080/时,自动加载login.jsp而不是显示404。第三段filter-mapping是安全防线:它规定访问scoreList.jsp或addScore.jsp前必须经过LoginFilter.java校验,该过滤器会检查session里是否存在loginUser属性,不存在就重定向回登录页。这种基于XML的声明式配置,比硬编码if判断更灵活——如果后续要增加“管理员权限校验”,只需在filter-mapping里添加新的URL模式,无需修改每个JSP页面的代码。这也是为什么项目强调“Tomcat 8/9兼容”,因为web.xml的语法规范在Servlet 3.1(Tomcat 8)之后才稳定,旧版本可能不支持<filter-mapping>的多URL模式写法。
3. 核心模块详解与实操要点
3.1 数据库设计:从sql脚本看业务建模思维
sql/目录下的create_table.sql不是简单的CREATE TABLE语句堆砌,而是业务规则的代码化表达。我们拆解其中最关键的student和score两张表:
-- 学生表:主键自增,姓名非空,学号唯一且长度固定
CREATE TABLE student (
id INT PRIMARY KEY AUTO_INCREMENT,
student_id VARCHAR(10) NOT NULL UNIQUE,
name VARCHAR(20) NOT NULL,
gender ENUM('男','女') DEFAULT '男',
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 成绩表:外键关联学生表,分数有范围约束
CREATE TABLE score (
id INT PRIMARY KEY AUTO_INCREMENT,
student_id VARCHAR(10) NOT NULL,
name VARCHAR(20) NOT NULL,
math_score DECIMAL(5,2) CHECK (math_score >= 0 AND math_score <= 100),
english_score DECIMAL(5,2) CHECK (english_score >= 0 AND english_score <= 100),
physics_score DECIMAL(5,2) CHECK (physics_score >= 0 AND physics_score <= 100),
FOREIGN KEY (student_id) REFERENCES student(student_id) ON DELETE CASCADE
);
这里藏着三个教学重点:第一,student_id在student表中是主键,在score表中是外键,ON DELETE CASCADE意味着删除学生时自动清除其所有成绩记录,避免数据孤儿;第二,CHECK约束强制分数在0-100区间,这比在Java代码里写if(score<0||score>100)更可靠——数据库层校验无法绕过,即使有人直接连MySQL执行INSERT也会被拦截;第三,ENUM('男','女')用枚举类型替代VARCHAR,既节省存储空间(ENUM内部用数字索引),又防止录入“未知”“保密”等非法值。我在课堂上让学生对比两种方案:一种是删掉CHECK约束,故意在JSP页面输入-5分,观察ScoreDaoImpl.java的INSERT是否报错;另一种是保留CHECK,用MySQL命令行直接执行INSERT INTO score VALUES(null,'S001','张三',-5,80,90),看数据库返回什么错误。这种对比实验比讲一百遍“数据库约束重要性”都管用。
3.2 JSP页面:从静态HTML到动态数据渲染的跨越
web/目录下的JSP文件不是简单地把HTML标签换成<%= %>,而是展示了服务端模板引擎的核心思想。以scoreList.jsp为例,关键代码段:
<%@ page import="java.util.List" %>
<%@ page import="com.example.entity.Score" %>
<%
List<Score> scoreList = (List<Score>) request.getAttribute("scoreList");
%>
<table border="1">
<tr>
<th>学号</th><th>姓名</th><th>数学</th><th>英语</th><th>物理</th><th>操作</th>
</tr>
<% for(Score score : scoreList) { %>
<tr>
<td><%= score.getStudentId() %></td>
<td><%= score.getName() %></td>
<td><%= score.getMathScore() %></td>
<td><%= score.getEnglishScore() %></td>
<td><%= score.getPhysicsScore() %></td>
<td>
<a href="EditScoreServlet?studentId=<%= score.getStudentId() %>">编辑</a> |
<a href="DeleteScoreServlet?studentId=<%= score.getStudentId() %>"
onclick="return confirm('确定删除?')">删除</a>
</td>
</tr>
<% } %>
</table>
这段代码的教学价值在于:它揭示了JSP的“翻译期”与“运行期”两个阶段。JSP文件第一次被访问时,Tomcat会将其翻译成一个Java Servlet类(保存在work/Catalina/localhost/_/org/apache/jsp/目录下),其中<% %>里的Java代码变成Servlet的_jspService()方法体,<%= %>变成out.print()调用。这意味着JSP不是实时解释执行,而是编译后运行,所以性能接近原生Servlet。更重要的是,onclick="return confirm('确定删除?')"这种前端JS代码与后端JSP混合,展示了全栈开发的真实场景——后端提供数据,前端增强交互体验。我在指导毕设时发现,很多学生把所有逻辑塞进JSP,导致页面臃肿难维护。于是我会让他们做个小实验:把<% for(Score score : scoreList) { %>这段循环逻辑提取到ScoreService.java里,改成String generateTableHtml(List<Score> list)方法,然后在JSP里只留<%= service.generateTableHtml(scoreList) %>。虽然代码量没变,但职责更清晰了——这就是从“能跑通”到“可维护”的第一步。
3.3 DAO层:手写JDBC连接池的实战细节
src/dao/目录下的BaseDao.java是整个数据访问层的基石,它实现了连接池管理,避免每次查询都新建数据库连接。核心代码:
public class BaseDao {
private static DataSource dataSource;
static {
try {
Context ctx = new InitialContext();
dataSource = (DataSource) ctx.lookup("java:comp/env/jdbc/ScoreDB");
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
这段代码依赖web/META-INF/context.xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/ScoreDB"
auth="Container"
type="javax.sql.DataSource"
maxTotal="20"
maxIdle="10"
minIdle="5"
initialSize="5"
maxWaitMillis="10000"
username="root"
password="123456"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/score_db?useSSL=false&serverTimezone=UTC"/>
</Context>
这里有两个易错点:第一,url中的&必须写成&,否则XML解析失败,Tomcat启动时报Invalid character in entity name;第二,driverClassName必须用com.mysql.cj.jdbc.Driver(MySQL 8+驱动),如果误写成老版本的com.mysql.jdbc.Driver,会抛出ClassNotFoundException。我在实验室见过最多的问题就是驱动版本不匹配——学生下载了MySQL 8.0安装包,却用着Maven里mysql-connector-java:5.1.47的依赖,结果连不上库。解决方案很简单:打开pom.xml,把依赖改成:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
同时确保MySQL服务已启动,且score_db数据库已创建(CREATE DATABASE score_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;)。这种细节不是背出来的,而是在getConnection()方法里加System.out.println("获取连接:" + conn)调试时,看着控制台打印的异常堆栈一步步揪出来的。
4. 实操全流程:从零部署到功能验证
4.1 环境准备与依赖安装(避坑指南)
部署成功率取决于三个环境变量的精准配置,缺一不可:
-
JDK版本:必须JDK 8或JDK 11(项目未使用JDK 17的新特性)。验证命令:
java -version,输出应为java version "1.8.0_3XX"或"11.0.X"。若显示17.x,需切换JDK:Windows用户在系统环境变量里修改JAVA_HOME指向JDK 8安装目录;Mac用户用/usr/libexec/java_home -V查看可用版本,再用export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)临时切换。 -
MySQL服务:必须确保MySQL正在运行。Windows用户打开“服务”管理器,找到
MySQL80服务并启动;Mac用户终端执行brew services start mysql。验证方式:mysql -u root -p,输入密码后进入MySQL命令行,执行SHOW DATABASES;能看到score_db即成功。若提示Can't connect to local MySQL server,大概率是MySQL服务未启动,或端口被占用(默认3306)。 -
Tomcat配置:下载Tomcat 8.5.x或9.0.x(不要用10+,Servlet版本不兼容)。解压后,关键修改
conf/server.xml里的Connector端口:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
若8080端口被占用(常见于Skype、Zoom),改为port="8081",后续访问地址变为http://localhost:8081。启动Tomcat:Windows双击bin/startup.bat,Mac/Linux执行bin/startup.sh,观察控制台最后一行是否出现Server startup in [XXX] milliseconds。
提示:所有环境变量配置完成后,务必重启命令行终端!否则
java -version可能仍显示旧版本。
4.2 项目导入与编译(IDEA实操步骤)
以IntelliJ IDEA为例,这是学生最常用的IDE,也是最容易踩坑的环节:
-
导入项目:启动IDEA →
Open→ 选择项目根目录(含pom.xml的文件夹)→ 弹窗选择Import project from external model→ 勾选Maven→ 点击Next。此时IDEA会自动识别pom.xml并下载依赖,等待右下角进度条完成。 -
配置Artifacts:这是部署前最关键的一步。
File→Project Structure→Artifacts→ 点击+号 →Web Application: Archive→For 'ScoreManagement:war exploded'→ 确认。然后在右侧Output Layout标签页,展开Available Elements,将ScoreManagement:war exploded拖到WEB-INF/lib下,确保所有jar包都在此处。 -
配置Tomcat Server:
Run→Edit Configurations→+号 →Tomcat Server→Local→ 在Deployment标签页点击+号 →Artifact→ 选择刚创建的ScoreManagement:war exploded→Application context填/(根路径)。此时Before launch区域应显示Build 'ScoreManagement:war exploded'。 -
启动调试:点击绿色三角形启动按钮,IDEA会自动编译项目、打包WAR、部署到Tomcat、启动服务。首次启动可能较慢(约30秒),观察IDEA底部
Run窗口,当出现INFO: Server startup in [XXXX] ms且浏览器自动打开http://localhost:8080时,即部署成功。
注意:若启动时报
java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver,说明MySQL驱动jar未正确加入lib。解决方案:在Project Structure→Libraries里点击+号 →Java→ 选择mysql-connector-java-8.0.33.jar文件。
4.3 功能验证与数据初始化(三步走策略)
部署成功只是开始,验证功能需要系统性操作:
第一步:数据库初始化
打开MySQL命令行(或Navicat/HeidiSQL等GUI工具),执行sql/create_table.sql内容。注意:必须先创建数据库score_db,再执行建表语句。执行后运行SELECT COUNT(*) FROM student;,应返回0(空表);运行SELECT COUNT(*) FROM score;也应返回0。
第二步:导入示例数据
执行sql/init_data.sql,该脚本包含INSERT INTO student和INSERT INTO score语句。执行后再次查询:SELECT * FROM student LIMIT 5;应看到类似S001,张三,男的记录;SELECT * FROM score WHERE student_id='S001';应返回张三的各科成绩。若返回空,检查init_data.sql里USE score_db;语句是否遗漏。
第三步:全流程功能测试
1. 访问http://localhost:8080,自动跳转到login.jsp;
2. 输入账号admin密码123456,登录成功跳转到scoreList.jsp,表格显示初始化的学生成绩;
3. 点击“新增成绩”按钮,跳转到addScore.jsp,填写新学号S006、姓名王五、数学85,提交后刷新列表,确认新记录出现;
4. 点击“编辑”链接,修改数学成绩为90,保存后验证列表数据更新;
5. 点击“删除”,确认弹窗后记录消失。
每一步操作都要观察浏览器URL变化(如从/addScore.jsp变为/AddScoreServlet)和Tomcat控制台日志(如INFO: 新增成绩成功,学号:S006),这是理解请求-响应模型的直观证据。
5. 常见问题与排查技巧实录
5.1 典型问题速查表
| 问题现象 | 可能原因 | 排查步骤 | 解决方案 |
|---|---|---|---|
| 访问localhost:8080显示404 | Tomcat未启动或项目未部署 | 1. 检查Tomcat控制台是否有Server startup日志2. 查看 webapps/目录下是否有ScoreManagement文件夹 |
启动Tomcat;在IDEA中确认Artifact已添加到Deployment |
| 登录页CSS样式丢失 | 静态资源路径错误 | 1. 浏览器按F12打开开发者工具 2. 切换到Network标签,刷新页面 3. 查看 css/style.css状态码是否为404 |
检查web/css/目录是否存在,确认login.jsp中<link href="css/style.css">路径正确(相对路径以web目录为根) |
| 登录后跳转到空白页或404 | Session未正确设置或Filter配置错误 | 1. 在LoginServlet.java的session.setAttribute()后加System.out.println("Session ID: "+session.getId())2. 检查 web.xml中LoginFilter的<url-pattern>是否覆盖scoreList.jsp |
确保session.setAttribute("loginUser", "admin")执行成功;确认filter-mapping的URL模式拼写无误 |
| 新增成绩时报错“Field ‘name’ doesn’t have a default value” | MySQL严格模式阻止空值插入 | 1. 执行SELECT @@sql_mode;查看当前模式2. 检查 score表结构,name字段是否为NOT NULL |
在init_data.sql中确保每条INSERT都包含name值;或临时关闭严格模式:SET sql_mode='';(不推荐生产环境) |
| 中文显示为乱码(如“张三”变“??”) | 数据库、连接、页面编码不一致 | 1. 检查MySQL数据库字符集:SHOW CREATE DATABASE score_db;2. 检查 context.xml中URL是否含characterEncoding=utf8 |
修改context.xml的URL为:jdbc:mysql://localhost:3306/score_db?useSSL=false&serverTimezone=UTC&characterEncoding=utf8 |
5.2 我踩过的三个深坑及独家技巧
坑一:JSP页面编码与Tomcat默认编码冲突
现象:addScore.jsp里输入中文姓名,后台request.getParameter("name")得到乱码。
原因:Tomcat 8+默认用ISO-8859-1解码POST请求,而JSP页面声明了<%@ page contentType="text/html;charset=UTF-8" %>。
解决方案:在每个处理POST请求的Servlet开头,强制设置请求编码:
request.setCharacterEncoding("UTF-8"); // 必须在getParameter()之前调用
String name = request.getParameter("name"); // 此时name才是正确的中文
技巧:把这个代码封装成工具类
WebUtils.java,在所有Servlet里统一调用,避免遗漏。
坑二:IDEA热部署失效导致修改不生效
现象:修改了ScoreService.java的逻辑,重启Tomcat后还是旧行为。
原因:IDEA的Build project automatically未开启,或Settings → Compiler → Build project automatically未勾选。
解决方案:
1. Ctrl+Alt+Shift+/打开Maintenance菜单 → Registry → 勾选compiler.automake.allow.when.app.running;
2. Settings → Build, Execution, Deployment → Compiler → 勾选Build project automatically;
3. 修改代码后,按Ctrl+F10重新加载类(HotSwap)。
坑三:MySQL 8.0密码认证插件不兼容
现象:BaseDao.getConnection()抛出java.sql.SQLException: Client does not support authentication protocol requested by server。
原因:MySQL 8.0默认用caching_sha2_password插件,而老版JDBC驱动不支持。
解决方案(任选其一):
- 方案A(推荐):升级JDBC驱动到8.0.33+,已在pom.xml中配置;
- 方案B:修改MySQL用户认证方式:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '123456';
FLUSH PRIVILEGES;
这个坑我带学生时遇到过三次,每次都要重装MySQL,后来干脆写了个一键修复脚本放在项目根目录。
6. 进阶改造建议:从作业框架到真实项目
6.1 五分钟升级:添加分页功能
现有scoreList.jsp一次性查出所有成绩,数据量大时页面卡顿。改造只需两步:
1. 修改DAO层:在ScoreDaoImpl.java中添加分页查询方法:
public List<Score> getScoreListByPage(int pageNum, int pageSize) {
String sql = "SELECT * FROM score LIMIT ?, ?";
// ... 执行预编译,参数为 (pageNum-1)*pageSize, pageSize
}
- 修改JSP页面:在表格下方添加分页导航:
<% int total = 100; // 从Service层获取总记录数 %>
<% for(int i=1; i<=Math.ceil(total/10.0); i++) { %>
<a href="ScoreListServlet?pageNum=<%=i%>"><%=i%></a>
<% } %>
这样就把一个静态列表变成了可扩展的分页系统,代码增量不到20行,但工程价值提升巨大。
6.2 安全加固:从明文密码到BCrypt加密
当前LoginServlet用"admin".equals(inputPassword)硬编码校验,存在严重安全隐患。升级方案:
1. 使用bcrypt库(Maven引入org.springframework.security.crypto:bcrpyt:5.7.0);
2. 初始化时对密码加密:String hashed = BCrypt.hashpw("123456", BCrypt.gensalt());;
3. 登录校验改为BCrypt.checkpw(inputPassword, storedHashed)。
这个改造教会学生:安全不是加个HTTPS就完事,而是从密码存储、传输、校验每个环节都要设防。
6.3 工程化演进:从手动部署到Maven自动化
项目目前依赖IDEA手动配置Artifact,可升级为Maven插件自动打包:
在pom.xml中添加:
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<path>/</path>
<port>8080</port>
</configuration>
</plugin>
然后终端执行mvn tomcat7:run,Maven会自动下载Tomcat、部署项目、启动服务。这种标准化构建流程,正是企业级项目的起点。
我在实验室墙上贴了张纸:“今天你跑通的不是一个成绩系统,而是Web开发的底层操作系统”。当你在ScoreDaoImpl.java里亲手写下第一个PreparedStatement,在web.xml里配置第一个filter-mapping,在MySQL里执行第一条CREATE TABLE,你就已经站在了工程师的起跑线上。这套系统没有炫酷的前端动画,没有复杂的微服务架构,但它用最朴实的代码告诉你:所谓全栈,不过是把HTTP请求从浏览器出发,经由Tomcat、Servlet、Service、DAO,最终落进MySQL磁盘文件的完整旅程。现在,去你的电脑前,打开终端,敲下mysql -u root -p——旅程,从这一刻开始。
简介:直接导入就能跑的Java Web成绩管理后台,用Servlet做后端控制,JSP渲染页面,MySQL存数据。项目按MVC分层组织:src里有DAO操作数据库、Service封装业务逻辑、Servlet处理请求;web目录放登录页、成绩列表页等JSP文件和CSS/JS资源;sql文件夹里配好了建表语句和示例数据,复制粘贴到MySQL就能用。管理员账号密码预置,登录后能新增学生、录入成绩、修改分数、删除记录、按学号或姓名查成绩,所有功能都在标准HTTP请求流程里完成。本地用Tomcat 8或9部署,启动服务后浏览器访问localhost:8080自动跳转登录页,无额外依赖、无编译报错,适合Java Web初学者练手、课程作业快速交付或毕设基础框架参考。
更多推荐


所有评论(0)