项目概述
功能需求
一个基础的学生管理系统应具备以下核心功能:

- 学生信息管理:
- 查看所有学生列表(分页)
- 添加新学生
- 根据ID查询学生信息
- 编辑学生信息
- 根据ID删除学生
- 登录功能:管理员登录系统,防止未授权访问。
技术选型
- 前端:
- HTML / CSS / JavaScript: 页面结构和样式。
- JSP (JavaServer Pages): 动态生成页面。
- JSTL (JSP Standard Tag Library): 简化 JSP 中的 Java 代码。
- EL (Expression Language): 在 JSP 中获取数据。
- 后端:
- Servlet: 处理 HTTP 请求,作为控制器。
- JDBC: 连接和操作 MySQL 数据库。
- JavaBean: 封装数据(如
Student类)。
- 数据库: MySQL
- 服务器: Apache Tomcat
- 构建工具: Maven (用于管理项目依赖)
- 开发工具: IntelliJ IDEA 或 Eclipse
项目结构 (MVC 架构)
一个典型的 Maven Web 项目结构如下:
student-management-system/
├── src/
│ ├── main/
│ │ ├── java/ // Java 源代码
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── sms/
│ │ │ ├── controller/ // Servlet 控制器
│ │ │ │ ├── StudentServlet.java
│ │ │ │ └── LoginServlet.java
│ │ │ ├── dao/ // 数据访问层
│ │ │ │ ├── impl/
│ │ │ │ │ └── StudentDaoImpl.java
│ │ │ │ └── StudentDao.java
│ │ │ ├── model/ // 实体/模型层
│ │ │ │ └── Student.java
│ │ │ ├── util/ // 工具类
│ │ │ │ └── DBUtil.java
│ │ │ └── filter/ // 过滤器
│ │ │ └── LoginFilter.java
│ │ ├── resources/ // 配置文件 (如 db.properties)
│ │ └── webapp/ // Web 应用根目录
│ │ ├── WEB-INF/
│ │ │ ├── lib/ // 第三方 JAR 包 (由 Maven 自动管理)
│ │ │ └── web.xml // 部署描述符
│ │ ├── css/ // CSS 样式文件
│ │ │ └── style.css
│ │ ├── js/ // JavaScript 文件
│ │ └── jsp/ // JSP 页面
│ │ ├── login.jsp
│ │ ├── student/
│ │ │ ├── list.jsp
│ │ │ ├── add.jsp
│ │ │ └── edit.jsp
│ │ └── index.jsp // 欢迎页,重定向到登录页
│ └── test/ // 测试代码
└── pom.xml // Maven 项目配置文件
详细实现步骤
步骤 1:环境准备与项目创建
- 安装 JDK, Maven, MySQL, Tomcat, IntelliJ IDEA。
- 在 IDEA 中创建一个新的 Maven 项目,选择
maven-archetype-webapp模板。 - 配置
pom.xml,添加项目依赖:<dependencies> <!-- Servlet API --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <!-- JSP API --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.3</version> <scope>provided</scope> </dependency> <!-- JSTL --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- MySQL Driver --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version> </dependency> </dependencies>
步骤 2:数据库设计
在 MySQL 中创建数据库和表。
CREATE DATABASE sms_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE sms_db;
-- 管理员表 (用于登录)
CREATE TABLE `admin` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`username` VARCHAR(50) NOT NULL UNIQUE,
`password` VARCHAR(50) NOT NULL
);
-- 学生表
CREATE TABLE `student` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
`gender` VARCHAR(10),
`age` INT,
`email` VARCHAR(100),
`phone` VARCHAR(20)
);
-- 插入一个默认管理员账户
INSERT INTO `admin` (username, password) VALUES ('admin', 'admin123');
步骤 3:创建数据库连接工具类 (DBUtil)
在 src/main/java/com/example/sms/util 目录下创建 DBUtil.java,用于管理数据库连接。
// DBUtil.java
package com.example.sms.util;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class DBUtil {
private static String url;
private static String user;
private static String password;
private static String driver;
static {
try {
// 读取 db.properties 文件
InputStream is = DBUtil.class.getClassLoader().getResourceAsStream("db.properties");
Properties props = new Properties();
props.load(is);
url = props.getProperty("url");
user = props.getProperty("user");
password = props.getProperty("password");
driver = props.getProperty("driver");
// 加载驱动
Class.forName(driver);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
public static void closeAll(ResultSet rs, Statement stmt, Connection conn) {
try {
if (rs != null) rs.close();
if (stmt != null) stmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
在 src/main/resources 目录下创建 db.properties 文件:

# db.properties driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/sms_db?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8 user=root password=your_mysql_password
步骤 4:创建 Model (JavaBean)
在 src/main/java/com/example/sms/model 目录下创建 Student.java。
// Student.java
package com.example.sms.model;
public class Student {
private int id;
private String name;
private String gender;
private int age;
private String email;
private String phone;
// Getters and Setters
// Constructor (no-args and all-args)
// toString()
// (省略,标准 JavaBean 代码)
}
步骤 5:创建 DAO (Data Access Object) 层
DAO 层负责与数据库进行交互。
-
创建接口
StudentDao.java// StudentDao.java package com.example.sms.dao; import com.example.sms.model.Student; import java.util.List; public interface StudentDao { List<Student> findAll(); Student findById(int id); void add(Student student); void update(Student student); void deleteById(int id); } -
创建实现类
StudentDaoImpl.java
(图片来源网络,侵删)// StudentDaoImpl.java package com.example.sms.dao.impl; import com.example.sms.dao.StudentDao; import com.example.sms.model.Student; import com.example.sms.util.DBUtil; import java.sql.*; import java.util.ArrayList; import java.util.List; public class StudentDaoImpl implements StudentDao { @Override public List<Student> findAll() { List<Student> students = new ArrayList<>(); String sql = "SELECT * FROM student"; Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = DBUtil.getConnection(); pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); while (rs.next()) { Student student = new Student(); student.setId(rs.getInt("id")); student.setName(rs.getString("name")); student.setGender(rs.getString("gender")); student.setAge(rs.getInt("age")); student.setEmail(rs.getString("email")); student.setPhone(rs.getString("phone")); students.add(student); } } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.closeAll(rs, pstmt, conn); } return students; } // ... 实现其他接口方法 (findById, add, update, deleteById) // (代码逻辑类似,只是 SQL 语句不同) }
步骤 6:创建 Controller (Servlet) 层
Servlet 作为控制器,接收请求,调用 DAO 处理数据,然后转发给 JSP 显示。
-
创建
StudentServlet.java// StudentServlet.java package com.example.sms.controller; import com.example.sms.dao.StudentDao; import com.example.sms.dao.impl.StudentDaoImpl; import com.example.sms.model.Student; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; @WebServlet("/student/*") // 匹配 /student/ 下的所有请求 public class StudentServlet extends HttpServlet { private StudentDao studentDao = new StudentDaoImpl(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String pathInfo = req.getPathInfo(); if (pathInfo == null || pathInfo.equals("/list")) { listStudents(req, resp); } else if (pathInfo.equals("/add")) { req.getRequestDispatcher("/jsp/student/add.jsp").forward(req, resp); } else if (pathInfo.equals("/edit")) { int id = Integer.parseInt(req.getParameter("id")); Student student = studentDao.findById(id); req.setAttribute("student", student); req.getRequestDispatcher("/jsp/student/edit.jsp").forward(req, resp); } else if (pathInfo.equals("/delete")) { int id = Integer.parseInt(req.getParameter("id")); studentDao.deleteById(id); resp.sendRedirect(req.getContextPath() + "/student/list"); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); String pathInfo = req.getPathInfo(); if (pathInfo.equals("/add")) { addStudent(req, resp); } else if (pathInfo.equals("/update")) { updateStudent(req, resp); } } private void listStudents(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { List<Student> students = studentDao.findAll(); req.setAttribute("students", students); req.getRequestDispatcher("/jsp/student/list.jsp").forward(req, resp); } private void addStudent(HttpServletRequest req, HttpServletResponse resp) throws IOException { Student student = new Student(); student.setName(req.getParameter("name")); student.setGender(req.getParameter("gender")); student.setAge(Integer.parseInt(req.getParameter("age"))); student.setEmail(req.getParameter("email")); student.setPhone(req.getParameter("phone")); studentDao.add(student); resp.sendRedirect(req.getContextPath() + "/student/list"); } private void updateStudent(HttpServletRequest req, HttpServletResponse resp) throws IOException { Student student = new Student(); student.setId(Integer.parseInt(req.getParameter("id"))); student.setName(req.getParameter("name")); student.setGender(req.getParameter("gender")); student.setAge(Integer.parseInt(req.getParameter("age"))); student.setEmail(req.getParameter("email")); student.setPhone(req.getParameter("phone")); studentDao.update(student); resp.sendRedirect(req.getContextPath() + "/student/list"); } } -
创建
LoginServlet.java// LoginServlet.java package com.example.sms.controller; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; javax.servlet.http.HttpSession; import java.io.IOException; @WebServlet("/login") public class LoginServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.getRequestDispatcher("/jsp/login.jsp").forward(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { String username = req.getParameter("username"); String password = req.getParameter("password"); // 这里应该查询数据库验证,我们为了简化,直接写死 if ("admin".equals(username) && "admin123".equals(password)) { HttpSession session = req.getSession(); session.setAttribute("admin", username); resp.sendRedirect(req.getContextPath() + "/student/list"); } else { resp.sendRedirect(req.getContextPath() + "/login?error=1"); } } }
步骤 7:创建 Filter (登录验证)
创建一个过滤器,检查用户是否已登录,如果未登录则重定向到登录页。
-
创建
LoginFilter.java// LoginFilter.java package com.example.sms.filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; javax.servlet.http.HttpSession; import java.io.IOException; @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 path = request.getRequestURI().substring(request.getContextPath().length()); // 如果是登录相关或静态资源,直接放行 if (path.startsWith("/login") || path.startsWith("/jsp/") || path.endsWith(".css") || path.endsWith(".js")) { chain.doFilter(req, resp); return; } HttpSession session = request.getSession(false); if (session == null || session.getAttribute("admin") == null) { response.sendRedirect(request.getContextPath() + "/login"); } else { chain.doFilter(req, resp); } } }
步骤 8:创建 View (JSP) 页面
在 webapp/jsp 目录下创建 JSP 文件。
-
login.jsp<%-- login.jsp --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>登录</title> </head> <body> <h2>学生管理系统 - 登录</h2> <%-- 显示错误信息 --%> <% if(request.getParameter("error") != null) { %> <p style="color: red;">用户名或密码错误!</p> <% } %> <form action="${pageContext.request.contextPath}/login" method="post"> 用户名: <input type="text" name="username"><br> 密码: <input type="password" name="password"><br> <input type="submit" value="登录"> </form> </body> </html> -
list.jsp(学生列表页)<%-- list.jsp --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>学生列表</title> <link rel="stylesheet" href="${pageContext.request.contextPath}/css/style.css"> </head> <body> <h2>学生信息列表</h2> <a href="${pageContext.request.contextPath}/student/add">添加新学生</a> <table border="1"> <tr> <th>ID</th> <th>姓名</th> <th>性别</th> <th>年龄</th> <th>邮箱</th> <th>电话</th> <th>操作</th> </tr> <c:forEach items="${students}" var="student"> <tr> <td>${student.id}</td> <td>${student.name}</td> <td>${student.gender}</td> <td>${student.age}</td> <td>${student.email}</td> <td>${student.phone}</td> <td> <a href="${pageContext.request.contextPath}/student/edit?id=${student.id}">编辑</a> <a href="${pageContext.request.contextPath}/student/delete?id=${student.id}" onclick="return confirm('确定删除吗?')">删除</a> </td> </tr> </c:forEach> </table> </body> </html> -
add.jsp和edit.jsp这两个页面类似,add.jsp是空表单,edit.jsp会从request中获取Student对象并填充表单,这里省略具体代码,逻辑与list.jsp中的链接和表单提交对应。
步骤 9:配置 web.xml
虽然我们使用了 @WebServlet 和 @WebFilter 注解,但为了确保完整性和兼容性,最好在 webapp/WEB-INF/web.xml 中进行基本配置。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>Student Management System</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
在 webapp/index.jsp 中,添加重定向到登录页的代码:
<%-- index.jsp --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <jsp:forward page="/login"/>
步骤 10:添加 CSS 样式
在 webapp/css/style.css 中添加一些基本样式,让页面看起来更美观。
/* style.css */
body {
font-family: Arial, sans-serif;
margin: 20px;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
a {
margin-right: 10px;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
运行与测试
- 配置 Tomcat:在 IDEA 中配置好 Tomcat 服务器。
- 部署项目:将项目部署到 Tomcat。
- 启动服务器:运行 Tomcat。
- 访问:在浏览器中输入
http://localhost:8080/your_project_name/。- 系统会自动跳转到登录页面。
- 输入用户名
admin,密码admin123登录。 - 登录成功后,进入学生列表页面,可以添加、编辑、删除学生信息。
进阶与优化方向
这个基础版本已经实现了核心功能,但还可以从以下几个方面进行优化和扩展:
- 分页功能:当学生数据很多时,列表页需要分页显示,可以在
StudentDao中添加findByPage(int page, int size)方法,并在StudentServlet和list.jsp中实现分页逻辑。 - 查询功能:添加按姓名、学号等条件查询学生的功能。
- 前端框架:使用 Bootstrap 或 Vue.js/React 等现代前端框架来优化 UI 交互体验。
- 框架整合:
- Spring MVC:用 Spring 框架替代原生 Servlet,实现更强大的依赖注入和面向切面编程。
- MyBatis / JPA:用 MyBatis 或 JPA (Hibernate) 框架替代原生 JDBC,简化数据库操作。
- 安全性增强:
- 对密码进行加密存储(如 MD5, BCrypt)。
- 使用
PreparedStatement防止 SQL 注入(当前代码已做到)。 - 实现更细粒度的权限控制。
- 异常处理:使用全局异常处理器 (
HandlerExceptionResolverin Spring) 来统一处理程序中的异常,避免直接在 Servlet 中 try-catch。 - 日志框架:集成 Log4j 或 SLF4J 来记录系统运行日志,方便排查问题。
这个项目是学习 Java Web 开发的绝佳实践,通过亲手实现,你可以深刻理解 HTTP 请求/响应、MVC 设计模式、数据库交互等核心概念。
