引言

在当今数字化教育时代,教育系统面临着海量数据处理、实时信息更新和个性化服务需求。JSP(JavaServer Pages)作为一种成熟的服务器端技术,凭借其与Java生态的无缝集成、强大的数据处理能力和灵活的页面渲染机制,为教育系统的动态网页开发与数据管理提供了高效解决方案。本文将深入探讨JSP技术如何在教育场景中发挥关键作用,并通过具体示例展示其实现细节。

一、JSP技术基础及其在教育系统中的优势

1.1 JSP技术概述

JSP是Sun Microsystems(现Oracle)推出的基于Java的动态网页技术标准。它允许开发者在HTML或XML文档中嵌入Java代码,由服务器端编译执行后生成动态内容。JSP的核心优势包括:

  • 与Java生态无缝集成:可直接使用Java类库、框架和工具
  • MVC架构支持:天然支持模型-视图-控制器设计模式
  • 高性能:JSP页面首次访问时被编译为Servlet,后续请求直接执行编译后的字节码
  • 跨平台性:基于Java的”一次编写,到处运行”特性

1.2 教育系统中的典型需求

教育系统通常需要处理以下复杂场景:

  • 学生信息管理:学籍、成绩、考勤等数据的CRUD操作
  • 课程管理:课程安排、选课系统、教学资源分发
  • 实时通知:考试安排、成绩发布、校园公告
  • 个性化服务:根据学生数据推荐学习资源
  • 多角色权限:管理员、教师、学生、家长的不同访问权限

二、JSP在教育系统中的核心应用场景

2.1 动态学生信息管理系统

2.1.1 数据库设计示例

首先,我们需要设计一个简单的学生信息表结构:

-- 学生信息表
CREATE TABLE students (
    student_id VARCHAR(20) PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    gender ENUM('男', '女') NOT NULL,
    birth_date DATE,
    class_id VARCHAR(10),
    enrollment_date DATE,
    status ENUM('在读', '休学', '毕业') DEFAULT '在读'
);

-- 成绩表
CREATE TABLE grades (
    grade_id INT AUTO_INCREMENT PRIMARY KEY,
    student_id VARCHAR(20),
    course_id VARCHAR(10),
    semester VARCHAR(20),
    score DECIMAL(5,2),
    exam_date DATE,
    FOREIGN KEY (student_id) REFERENCES students(student_id)
);

2.1.2 JSP页面实现学生列表展示

以下是一个完整的JSP页面示例,展示如何从数据库获取学生信息并动态渲染:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.sql.*, java.util.*" %>
<%@ page import="com.education.db.DatabaseConnection" %>

<!DOCTYPE html>
<html>
<head>
    <title>学生信息管理系统</title>
    <style>
        table { border-collapse: collapse; width: 100%; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        th { background-color: #4CAF50; color: white; }
        tr:nth-child(even) { background-color: #f2f2f2; }
        .search-box { margin: 20px 0; }
        .pagination { margin-top: 20px; }
    </style>
</head>
<body>
    <h1>学生信息管理系统</h1>
    
    <!-- 搜索功能 -->
    <div class="search-box">
        <form method="get" action="studentList.jsp">
            <input type="text" name="keyword" placeholder="按姓名或学号搜索" 
                   value="${param.keyword}">
            <button type="submit">搜索</button>
        </form>
    </div>
    
    <!-- 学生数据展示 -->
    <table>
        <thead>
            <tr>
                <th>学号</th>
                <th>姓名</th>
                <th>性别</th>
                <th>出生日期</th>
                <th>班级</th>
                <th>入学日期</th>
                <th>状态</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            <%
                // 获取搜索关键词
                String keyword = request.getParameter("keyword");
                String sql = "SELECT * FROM students WHERE 1=1";
                
                if (keyword != null && !keyword.trim().isEmpty()) {
                    sql += " AND (student_id LIKE ? OR name LIKE ?)";
                }
                
                // 分页参数
                int pageSize = 10;
                int currentPage = 1;
                if (request.getParameter("page") != null) {
                    currentPage = Integer.parseInt(request.getParameter("page"));
                }
                int offset = (currentPage - 1) * pageSize;
                
                // 数据库连接
                Connection conn = null;
                PreparedStatement pstmt = null;
                ResultSet rs = null;
                
                try {
                    conn = DatabaseConnection.getConnection();
                    
                    // 获取总记录数
                    String countSql = "SELECT COUNT(*) FROM students WHERE 1=1";
                    if (keyword != null && !keyword.trim().isEmpty()) {
                        countSql += " AND (student_id LIKE ? OR name LIKE ?)";
                    }
                    pstmt = conn.prepareStatement(countSql);
                    if (keyword != null && !keyword.trim().isEmpty()) {
                        pstmt.setString(1, "%" + keyword + "%");
                        pstmt.setString(2, "%" + keyword + "%");
                    }
                    rs = pstmt.executeQuery();
                    rs.next();
                    int totalRecords = rs.getInt(1);
                    int totalPages = (int) Math.ceil((double) totalRecords / pageSize);
                    
                    // 获取分页数据
                    sql += " LIMIT ? OFFSET ?";
                    pstmt = conn.prepareStatement(sql);
                    int paramIndex = 1;
                    if (keyword != null && !keyword.trim().isEmpty()) {
                        pstmt.setString(paramIndex++, "%" + keyword + "%");
                        pstmt.setString(paramIndex++, "%" + keyword + "%");
                    }
                    pstmt.setInt(paramIndex++, pageSize);
                    pstmt.setInt(paramIndex, offset);
                    
                    rs = pstmt.executeQuery();
                    
                    while (rs.next()) {
                        String studentId = rs.getString("student_id");
                        String name = rs.getString("name");
                        String gender = rs.getString("gender");
                        Date birthDate = rs.getDate("birth_date");
                        String classId = rs.getString("class_id");
                        Date enrollmentDate = rs.getDate("enrollment_date");
                        String status = rs.getString("status");
            %>
            <tr>
                <td><%= studentId %></td>
                <td><%= name %></td>
                <td><%= gender %></td>
                <td><%= birthDate != null ? birthDate.toString() : "未填写" %></td>
                <td><%= classId %></td>
                <td><%= enrollmentDate != null ? enrollmentDate.toString() : "未填写" %></td>
                <td><%= status %></td>
                <td>
                    <a href="editStudent.jsp?id=<%= studentId %>">编辑</a> |
                    <a href="deleteStudent.jsp?id=<%= studentId %>" 
                       onclick="return confirm('确定要删除吗?')">删除</a>
                </td>
            </tr>
            <%
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    out.println("<tr><td colspan='8' style='color:red;'>数据加载失败: " + 
                               e.getMessage() + "</td></tr>");
                } finally {
                    if (rs != null) rs.close();
                    if (pstmt != null) pstmt.close();
                    if (conn != null) conn.close();
                }
            %>
        </tbody>
    </table>
    
    <!-- 分页控件 -->
    <div class="pagination">
        <%
            if (totalPages > 1) {
                out.println("<span>第 " + currentPage + " / " + totalPages + " 页</span>");
                
                if (currentPage > 1) {
                    out.println("<a href='?page=" + (currentPage - 1) + 
                               (keyword != null ? "&keyword=" + keyword : "") + 
                               "'>上一页</a> ");
                }
                
                for (int i = 1; i <= totalPages; i++) {
                    if (i == currentPage) {
                        out.println("<strong>" + i + "</strong> ");
                    } else {
                        out.println("<a href='?page=" + i + 
                                   (keyword != null ? "&keyword=" + keyword : "") + 
                                   "'>" + i + "</a> ");
                    }
                }
                
                if (currentPage < totalPages) {
                    out.println("<a href='?page=" + (currentPage + 1) + 
                               (keyword != null ? "&keyword=" + keyword : "") + 
                               "'>下一页</a>");
                }
            }
        %>
    </div>
    
    <div style="margin-top: 20px;">
        <a href="addStudent.jsp">添加新学生</a> |
        <a href="exportStudents.jsp">导出Excel</a>
    </div>
</body>
</html>

2.1.3 数据库连接工具类

为了代码复用和安全性,我们创建一个数据库连接工具类:

// DatabaseConnection.java
package com.education.db;

import java.sql.*;
import java.util.Properties;

public class DatabaseConnection {
    private static final String DB_URL = "jdbc:mysql://localhost:3306/education_db";
    private static final String DB_USER = "root";
    private static final String DB_PASSWORD = "password";
    
    // 使用连接池(推荐生产环境使用)
    private static DataSource dataSource;
    
    static {
        try {
            // 初始化连接池(这里使用HikariCP示例)
            HikariConfig config = new HikariConfig();
            config.setJdbcUrl(DB_URL);
            config.setUsername(DB_USER);
            config.setPassword(DB_PASSWORD);
            config.setMaximumPoolSize(20);
            config.setMinimumIdle(5);
            config.setConnectionTimeout(30000);
            config.setIdleTimeout(600000);
            config.setMaxLifetime(1800000);
            
            dataSource = new HikariDataSource(config);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    // 获取数据库连接(使用连接池)
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
    
    // 关闭资源
    public static void close(Connection conn, Statement stmt, ResultSet rs) {
        try {
            if (rs != null) rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (stmt != null) stmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (conn != null) conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    
    // 批量操作示例:批量导入学生数据
    public static void batchInsertStudents(List<Student> students) throws SQLException {
        Connection conn = null;
        PreparedStatement pstmt = null;
        
        try {
            conn = getConnection();
            conn.setAutoCommit(false); // 开启事务
            
            String sql = "INSERT INTO students (student_id, name, gender, birth_date, class_id, enrollment_date) " +
                        "VALUES (?, ?, ?, ?, ?, ?)";
            pstmt = conn.prepareStatement(sql);
            
            for (Student student : students) {
                pstmt.setString(1, student.getStudentId());
                pstmt.setString(2, student.getName());
                pstmt.setString(3, student.getGender());
                pstmt.setDate(4, new java.sql.Date(student.getBirthDate().getTime()));
                pstmt.setString(5, student.getClassId());
                pstmt.setDate(6, new java.sql.Date(student.getEnrollmentDate().getTime()));
                pstmt.addBatch();
                
                // 每1000条提交一次,避免内存溢出
                if (students.indexOf(student) % 1000 == 0) {
                    pstmt.executeBatch();
                }
            }
            
            pstmt.executeBatch(); // 提交剩余批次
            conn.commit(); // 提交事务
        } catch (SQLException e) {
            if (conn != null) {
                conn.rollback(); // 回滚事务
            }
            throw e;
        } finally {
            if (pstmt != null) pstmt.close();
            if (conn != null) conn.close();
        }
    }
}

2.2 课程选课系统实现

2.2.1 选课业务逻辑

选课系统需要处理并发问题,防止超选。以下是使用JSP和JavaBean实现的选课功能:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="com.education.service.CourseService" %>
<%@ page import="com.education.model.Student" %>
<%@ page import="com.education.model.Course" %>
<%@ page import="java.util.List" %>

<!DOCTYPE html>
<html>
<head>
    <title>在线选课系统</title>
    <style>
        .course-card {
            border: 1px solid #ddd;
            padding: 15px;
            margin: 10px;
            border-radius: 5px;
            background: #f9f9f9;
            display: inline-block;
            width: 300px;
            vertical-align: top;
        }
        .course-card.selected {
            background: #e8f5e9;
            border-color: #4CAF50;
        }
        .course-card.full {
            background: #ffebee;
            border-color: #f44336;
            opacity: 0.7;
        }
        .btn {
            padding: 8px 15px;
            background: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            margin-top: 10px;
        }
        .btn:disabled {
            background: #ccc;
            cursor: not-allowed;
        }
        .btn-danger {
            background: #f44336;
        }
    </style>
</head>
<body>
    <h1>在线选课系统</h1>
    
    <%
        // 获取当前登录学生(实际应用中从session获取)
        Student student = (Student) session.getAttribute("student");
        if (student == null) {
            response.sendRedirect("login.jsp");
            return;
        }
        
        // 获取可选课程列表
        CourseService courseService = new CourseService();
        List<Course> availableCourses = courseService.getAvailableCourses(student.getStudentId());
        
        // 获取已选课程
        List<Course> selectedCourses = courseService.getSelectedCourses(student.getStudentId());
    %>
    
    <div style="display: flex; gap: 20px;">
        <!-- 可选课程区域 -->
        <div style="flex: 1;">
            <h2>可选课程</h2>
            <%
                for (Course course : availableCourses) {
                    boolean isSelected = selectedCourses.contains(course);
                    boolean isFull = course.getCurrentStudents() >= course.getMaxStudents();
                    String cardClass = isSelected ? "selected" : (isFull ? "full" : "");
            %>
            <div class="course-card <%= cardClass %>">
                <h3><%= course.getCourseName() %></h3>
                <p>课程代码: <%= course.getCourseCode() %></p>
                <p>教师: <%= course.getTeacherName() %></p>
                <p>学分: <%= course.getCredits() %></p>
                <p>时间: <%= course.getClassTime() %></p>
                <p>容量: <%= course.getCurrentStudents() %>/<%= course.getMaxStudents() %></p>
                
                <%
                    if (isSelected) {
                %>
                <button class="btn btn-danger" 
                        onclick="dropCourse('<%= course.getCourseCode() %>')">
                    退选
                </button>
                <%
                    } else if (isFull) {
                %>
                <button class="btn" disabled>已满员</button>
                <%
                    } else {
                %>
                <button class="btn" 
                        onclick="selectCourse('<%= course.getCourseCode() %>')">
                    选课
                </button>
                <%
                    }
                %>
            </div>
            <%
                }
            %>
        </div>
        
        <!-- 已选课程区域 -->
        <div style="flex: 1;">
            <h2>已选课程 (<%= selectedCourses.size() %>)</h2>
            <%
                for (Course course : selectedCourses) {
            %>
            <div class="course-card selected">
                <h3><%= course.getCourseName() %></h3>
                <p>课程代码: <%= course.getCourseCode() %></p>
                <p>教师: <%= course.getTeacherName() %></p>
                <p>学分: <%= course.getCredits() %></p>
                <p>时间: <%= course.getClassTime() %></p>
                <button class="btn btn-danger" 
                        onclick="dropCourse('<%= course.getCourseCode() %>')">
                    退选
                </button>
            </div>
            <%
                }
            %>
            
            <div style="margin-top: 20px; padding: 15px; background: #e3f2fd; border-radius: 5px;">
                <p><strong>总学分: <%= selectedCourses.stream().mapToInt(Course::getCredits).sum() %></strong></p>
                <p><strong>课程数量: <%= selectedCourses.size() %></strong></p>
            </div>
        </div>
    </div>
    
    <!-- 选课/退选操作的JavaScript -->
    <script>
        function selectCourse(courseCode) {
            if (confirm('确定要选择这门课程吗?')) {
                // 使用AJAX提交选课请求
                const xhr = new XMLHttpRequest();
                xhr.open('POST', 'CourseSelectionServlet', true);
                xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
                
                xhr.onload = function() {
                    if (xhr.status === 200) {
                        const response = JSON.parse(xhr.responseText);
                        if (response.success) {
                            alert('选课成功!');
                            location.reload(); // 刷新页面
                        } else {
                            alert('选课失败: ' + response.message);
                        }
                    } else {
                        alert('请求失败,状态码: ' + xhr.status);
                    }
                };
                
                xhr.onerror = function() {
                    alert('网络错误,请稍后重试');
                };
                
                const data = 'action=select&studentId=<%= student.getStudentId() %>&courseCode=' + courseCode;
                xhr.send(data);
            }
        }
        
        function dropCourse(courseCode) {
            if (confirm('确定要退选这门课程吗?')) {
                const xhr = new XMLHttpRequest();
                xhr.open('POST', 'CourseSelectionServlet', true);
                xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
                
                xhr.onload = function() {
                    if (xhr.status === 200) {
                        const response = JSON.parse(xhr.responseText);
                        if (response.success) {
                            alert('退选成功!');
                            location.reload();
                        } else {
                            alert('退选失败: ' + response.message);
                        }
                    } else {
                        alert('请求失败,状态码: ' + xhr.status);
                    }
                };
                
                xhr.onerror = function() {
                    alert('网络错误,请稍后重试');
                };
                
                const data = 'action=drop&studentId=<%= student.getStudentId() %>&courseCode=' + courseCode;
                xhr.send(data);
            }
        }
    </script>
</body>
</html>

2.2.2 选课Servlet处理类

// CourseSelectionServlet.java
package com.education.servlet;

import com.education.service.CourseService;
import com.education.util.JsonUtil;

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.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

@WebServlet("/CourseSelectionServlet")
public class CourseSelectionServlet extends HttpServlet {
    
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        
        PrintWriter out = response.getWriter();
        Map<String, Object> result = new HashMap<>();
        
        try {
            String action = request.getParameter("action");
            String studentId = request.getParameter("studentId");
            String courseCode = request.getParameter("courseCode");
            
            CourseService courseService = new CourseService();
            
            if ("select".equals(action)) {
                // 选课逻辑(包含并发控制)
                boolean success = courseService.selectCourse(studentId, courseCode);
                if (success) {
                    result.put("success", true);
                    result.put("message", "选课成功");
                } else {
                    result.put("success", false);
                    result.put("message", "选课失败,课程可能已满或已选");
                }
            } else if ("drop".equals(action)) {
                // 退选逻辑
                boolean success = courseService.dropCourse(studentId, courseCode);
                if (success) {
                    result.put("success", true);
                    result.put("message", "退选成功");
                } else {
                    result.put("success", false);
                    result.put("message", "退选失败");
                }
            } else {
                result.put("success", false);
                result.put("message", "未知操作");
            }
            
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "系统错误: " + e.getMessage());
            e.printStackTrace();
        }
        
        out.print(JsonUtil.toJson(result));
        out.flush();
    }
}

2.2.3 选课服务类(包含事务和锁机制)

// CourseService.java
package com.education.service;

import com.education.db.DatabaseConnection;
import com.education.model.Course;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class CourseService {
    
    /**
     * 选课方法(包含数据库锁和事务控制)
     */
    public boolean selectCourse(String studentId, String courseCode) throws SQLException {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        
        try {
            conn = DatabaseConnection.getConnection();
            conn.setAutoCommit(false); // 开启事务
            
            // 1. 检查课程是否已满(使用SELECT FOR UPDATE加锁)
            String checkSql = "SELECT current_students, max_students FROM courses " +
                             "WHERE course_code = ? FOR UPDATE";
            pstmt = conn.prepareStatement(checkSql);
            pstmt.setString(1, courseCode);
            rs = pstmt.executeQuery();
            
            if (!rs.next()) {
                conn.rollback();
                return false;
            }
            
            int currentStudents = rs.getInt("current_students");
            int maxStudents = rs.getInt("max_students");
            
            if (currentStudents >= maxStudents) {
                conn.rollback();
                return false;
            }
            
            // 2. 检查是否已选过该课程
            String checkSelectedSql = "SELECT COUNT(*) FROM course_selection " +
                                     "WHERE student_id = ? AND course_code = ?";
            pstmt = conn.prepareStatement(checkSelectedSql);
            pstmt.setString(1, studentId);
            pstmt.setString(2, courseCode);
            rs = pstmt.executeQuery();
            rs.next();
            
            if (rs.getInt(1) > 0) {
                conn.rollback();
                return false;
            }
            
            // 3. 插入选课记录
            String insertSql = "INSERT INTO course_selection (student_id, course_code, selection_time) " +
                              "VALUES (?, ?, NOW())";
            pstmt = conn.prepareStatement(insertSql);
            pstmt.setString(1, studentId);
            pstmt.setString(2, courseCode);
            pstmt.executeUpdate();
            
            // 4. 更新课程当前人数
            String updateSql = "UPDATE courses SET current_students = current_students + 1 " +
                              "WHERE course_code = ?";
            pstmt = conn.prepareStatement(updateSql);
            pstmt.setString(1, courseCode);
            pstmt.executeUpdate();
            
            // 5. 提交事务
            conn.commit();
            return true;
            
        } catch (SQLException e) {
            if (conn != null) {
                conn.rollback();
            }
            throw e;
        } finally {
            DatabaseConnection.close(conn, pstmt, rs);
        }
    }
    
    /**
     * 退选方法
     */
    public boolean dropCourse(String studentId, String courseCode) throws SQLException {
        Connection conn = null;
        PreparedStatement pstmt = null;
        
        try {
            conn = DatabaseConnection.getConnection();
            conn.setAutoCommit(false);
            
            // 1. 删除选课记录
            String deleteSql = "DELETE FROM course_selection " +
                              "WHERE student_id = ? AND course_code = ?";
            pstmt = conn.prepareStatement(deleteSql);
            pstmt.setString(1, studentId);
            pstmt.setString(2, courseCode);
            int deleted = pstmt.executeUpdate();
            
            if (deleted == 0) {
                conn.rollback();
                return false;
            }
            
            // 2. 更新课程当前人数
            String updateSql = "UPDATE courses SET current_students = current_students - 1 " +
                              "WHERE course_code = ? AND current_students > 0";
            pstmt = conn.prepareStatement(updateSql);
            pstmt.setString(1, courseCode);
            pstmt.executeUpdate();
            
            conn.commit();
            return true;
            
        } catch (SQLException e) {
            if (conn != null) {
                conn.rollback();
            }
            throw e;
        } finally {
            DatabaseConnection.close(conn, pstmt, null);
        }
    }
    
    /**
     * 获取可选课程列表
     */
    public List<Course> getAvailableCourses(String studentId) throws SQLException {
        List<Course> courses = new ArrayList<>();
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        
        try {
            conn = DatabaseConnection.getConnection();
            
            // 获取所有课程,排除已选课程
            String sql = "SELECT c.*, t.teacher_name " +
                        "FROM courses c " +
                        "LEFT JOIN teachers t ON c.teacher_id = t.teacher_id " +
                        "WHERE c.course_code NOT IN (" +
                        "    SELECT course_code FROM course_selection WHERE student_id = ?" +
                        ") AND c.current_students < c.max_students";
            
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, studentId);
            rs = pstmt.executeQuery();
            
            while (rs.next()) {
                Course course = new Course();
                course.setCourseCode(rs.getString("course_code"));
                course.setCourseName(rs.getString("course_name"));
                course.setCredits(rs.getInt("credits"));
                course.setMaxStudents(rs.getInt("max_students"));
                course.setCurrentStudents(rs.getInt("current_students"));
                course.setClassTime(rs.getString("class_time"));
                course.setTeacherName(rs.getString("teacher_name"));
                courses.add(course);
            }
            
        } finally {
            DatabaseConnection.close(conn, pstmt, rs);
        }
        
        return courses;
    }
    
    /**
     * 获取已选课程列表
     */
    public List<Course> getSelectedCourses(String studentId) throws SQLException {
        List<Course> courses = new ArrayList<>();
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        
        try {
            conn = DatabaseConnection.getConnection();
            
            String sql = "SELECT c.*, t.teacher_name " +
                        "FROM courses c " +
                        "JOIN course_selection cs ON c.course_code = cs.course_code " +
                        "LEFT JOIN teachers t ON c.teacher_id = t.teacher_id " +
                        "WHERE cs.student_id = ? " +
                        "ORDER BY cs.selection_time DESC";
            
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, studentId);
            rs = pstmt.executeQuery();
            
            while (rs.next()) {
                Course course = new Course();
                course.setCourseCode(rs.getString("course_code"));
                course.setCourseName(rs.getString("course_name"));
                course.setCredits(rs.getInt("credits"));
                course.setMaxStudents(rs.getInt("max_students"));
                course.setCurrentStudents(rs.getInt("current_students"));
                course.setClassTime(rs.getString("class_time"));
                course.setTeacherName(rs.getString("teacher_name"));
                courses.add(course);
            }
            
        } finally {
            DatabaseConnection.close(conn, pstmt, rs);
        }
        
        return courses;
    }
}

2.3 成绩管理系统

2.3.1 成绩录入与统计

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="com.education.service.GradeService" %>
<%@ page import="com.education.model.Grade" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.Map" %>

<!DOCTYPE html>
<html>
<head>
    <title>成绩管理系统</title>
    <style>
        .grade-input {
            width: 60px;
            padding: 5px;
            text-align: center;
            border: 1px solid #ddd;
            border-radius: 3px;
        }
        .grade-input.error {
            border-color: #f44336;
            background: #ffebee;
        }
        .stats-box {
            background: #f5f5f5;
            padding: 15px;
            margin: 10px 0;
            border-radius: 5px;
        }
        .chart-container {
            height: 300px;
            margin: 20px 0;
        }
    </style>
    <!-- 引入Chart.js用于数据可视化 -->
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
    <h1>成绩管理系统</h1>
    
    <%
        String courseCode = request.getParameter("courseCode");
        String semester = request.getParameter("semester");
        
        if (courseCode == null || semester == null) {
            out.println("<p>请选择课程和学期</p>");
            return;
        }
        
        GradeService gradeService = new GradeService();
        
        // 获取成绩列表
        List<Grade> grades = gradeService.getGrades(courseCode, semester);
        
        // 获取统计信息
        Map<String, Object> stats = gradeService.getGradeStatistics(courseCode, semester);
    %>
    
    <!-- 成绩统计信息 -->
    <div class="stats-box">
        <h3>成绩统计</h3>
        <p>总人数: <%= stats.get("totalStudents") %></p>
        <p>平均分: <%= String.format("%.2f", stats.get("averageScore")) %></p>
        <p>最高分: <%= stats.get("maxScore") %></p>
        <p>最低分: <%= stats.get("minScore") %></p>
        <p>及格率: <%= String.format("%.1f%%", stats.get("passRate")) %></p>
    </div>
    
    <!-- 成绩分布图表 -->
    <div class="chart-container">
        <canvas id="gradeChart"></canvas>
    </div>
    
    <!-- 成绩录入表格 -->
    <form method="post" action="GradeUpdateServlet">
        <input type="hidden" name="courseCode" value="<%= courseCode %>">
        <input type="hidden" name="semester" value="<%= semester %>">
        
        <table>
            <thead>
                <tr>
                    <th>学号</th>
                    <th>姓名</th>
                    <th>平时成绩(30%)</th>
                    <th>期中成绩(30%)</th>
                    <th>期末成绩(40%)</th>
                    <th>总评</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
                <%
                    for (Grade grade : grades) {
                        double total = grade.getDailyScore() * 0.3 + 
                                      grade.getMidScore() * 0.3 + 
                                      grade.getFinalScore() * 0.4;
                        String totalStr = String.format("%.1f", total);
                %>
                <tr>
                    <td><%= grade.getStudentId() %></td>
                    <td><%= grade.getStudentName() %></td>
                    <td>
                        <input type="number" name="daily_<%= grade.getStudentId() %>" 
                               class="grade-input" min="0" max="100" step="0.1"
                               value="<%= grade.getDailyScore() %>">
                    </td>
                    <td>
                        <input type="number" name="mid_<%= grade.getStudentId() %>" 
                               class="grade-input" min="0" max="100" step="0.1"
                               value="<%= grade.getMidScore() %>">
                    </td>
                    <td>
                        <input type="number" name="final_<%= grade.getStudentId() %>" 
                               class="grade-input" min="0" max="100" step="0.1"
                               value="<%= grade.getFinalScore() %>">
                    </td>
                    <td><strong><%= totalStr %></strong></td>
                    <td>
                        <button type="button" onclick="calculateTotal('<%= grade.getStudentId() %>')">
                            计算
                        </button>
                    </td>
                </tr>
                <%
                    }
                %>
            </tbody>
        </table>
        
        <div style="margin-top: 20px;">
            <button type="submit" class="btn">保存成绩</button>
            <button type="button" class="btn" onclick="exportGrades()">导出Excel</button>
        </div>
    </form>
    
    <!-- 成绩分析脚本 -->
    <script>
        // 计算单个学生的总评成绩
        function calculateTotal(studentId) {
            const daily = parseFloat(document.querySelector(`input[name="daily_${studentId}"]`).value) || 0;
            const mid = parseFloat(document.querySelector(`input[name="mid_${studentId}"]`).value) || 0;
            const final = parseFloat(document.querySelector(`input[name="final_${studentId}"]`).value) || 0;
            
            const total = daily * 0.3 + mid * 0.3 + final * 0.4;
            alert(`总评成绩: ${total.toFixed(1)}`);
        }
        
        // 导出成绩到Excel
        function exportGrades() {
            const courseCode = '<%= courseCode %>';
            const semester = '<%= semester %>';
            window.location.href = `ExportGradesServlet?courseCode=${courseCode}&semester=${semester}`;
        }
        
        // 初始化成绩分布图表
        document.addEventListener('DOMContentLoaded', function() {
            const ctx = document.getElementById('gradeChart').getContext('2d');
            
            // 从服务器获取成绩分布数据
            fetch('GetGradeDistributionServlet?courseCode=<%= courseCode %>&semester=<%= semester %>')
                .then(response => response.json())
                .then(data => {
                    new Chart(ctx, {
                        type: 'bar',
                        data: {
                            labels: data.labels,
                            datasets: [{
                                label: '人数',
                                data: data.values,
                                backgroundColor: 'rgba(75, 192, 192, 0.6)',
                                borderColor: 'rgba(75, 192, 192, 1)',
                                borderWidth: 1
                            }]
                        },
                        options: {
                            responsive: true,
                            scales: {
                                y: {
                                    beginAtZero: true,
                                    title: {
                                        display: true,
                                        text: '人数'
                                    }
                                },
                                x: {
                                    title: {
                                        display: true,
                                        text: '分数段'
                                    }
                                }
                            }
                        }
                    });
                });
        });
    </script>
</body>
</html>

2.3.2 成绩统计Servlet

// GetGradeDistributionServlet.java
package com.education.servlet;

import com.education.service.GradeService;
import com.education.util.JsonUtil;

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.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@WebServlet("/GetGradeDistributionServlet")
public class GetGradeDistributionServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        
        PrintWriter out = response.getWriter();
        
        try {
            String courseCode = request.getParameter("courseCode");
            String semester = request.getParameter("semester");
            
            GradeService gradeService = new GradeService();
            Map<String, Object> distribution = gradeService.getGradeDistribution(courseCode, semester);
            
            // 构建Chart.js需要的数据格式
            Map<String, Object> chartData = new HashMap<>();
            chartData.put("labels", distribution.get("labels"));
            chartData.put("values", distribution.get("values"));
            
            out.print(JsonUtil.toJson(chartData));
            
        } catch (Exception e) {
            Map<String, Object> error = new HashMap<>();
            error.put("error", e.getMessage());
            out.print(JsonUtil.toJson(error));
            e.printStackTrace();
        }
        
        out.flush();
    }
}

三、JSP技术在教育系统中的高级应用

3.1 使用JSTL和EL表达式简化开发

JSP标准标签库(JSTL)和表达式语言(EL)可以显著减少JSP页面中的Java代码,提高可维护性。

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>

<!DOCTYPE html>
<html>
<head>
    <title>使用JSTL的学生列表</title>
</head>
<body>
    <h1>学生信息列表</h1>
    
    <!-- 使用SQL标签直接查询数据库 -->
    <sql:setDataSource var="dataSource" 
                       driver="com.mysql.jdbc.Driver"
                       url="jdbc:mysql://localhost:3306/education_db"
                       user="root" 
                       password="password"/>
    
    <sql:query dataSource="${dataSource}" var="students">
        SELECT * FROM students ORDER BY name
    </sql:query>
    
    <!-- 使用JSTL循环显示数据 -->
    <table border="1">
        <tr>
            <th>学号</th>
            <th>姓名</th>
            <th>性别</th>
            <th>班级</th>
            <th>入学日期</th>
        </tr>
        
        <c:forEach var="student" items="${students.rows}">
            <tr>
                <td>${student.student_id}</td>
                <td>${student.name}</td>
                <td>${student.gender}</td>
                <td>${student.class_id}</td>
                <td>
                    <fmt:formatDate value="${student.enrollment_date}" 
                                    pattern="yyyy-MM-dd"/>
                </td>
            </tr>
        </c:forEach>
    </table>
    
    <!-- 使用条件判断 -->
    <c:if test="${students.rowCount == 0}">
        <p style="color: red;">暂无学生数据</p>
    </c:if>
    
    <!-- 使用choose-when-otherwise -->
    <c:choose>
        <c:when test="${students.rowCount > 10}">
            <p>学生人数较多,建议分页显示</p>
        </c:when>
        <c:when test="${students.rowCount > 0}">
            <p>共有 ${students.rowCount} 名学生</p>
        </c:when>
        <c:otherwise>
            <p>没有找到学生记录</p>
        </c:otherwise>
    </c:choose>
</body>
</html>

3.2 使用MVC架构重构教育系统

为了提高代码的可维护性和可扩展性,建议使用MVC架构:

3.2.1 模型层(Model)

// Student.java (实体类)
package com.education.model;

import java.io.Serializable;
import java.util.Date;

public class Student implements Serializable {
    private String studentId;
    private String name;
    private String gender;
    private Date birthDate;
    private String classId;
    private Date enrollmentDate;
    private String status;
    
    // 构造方法、getter和setter省略
}

// StudentDAO.java (数据访问对象)
package com.education.dao;

import com.education.model.Student;
import java.util.List;

public interface StudentDAO {
    List<Student> getAllStudents() throws Exception;
    Student getStudentById(String id) throws Exception;
    boolean addStudent(Student student) throws Exception;
    boolean updateStudent(Student student) throws Exception;
    boolean deleteStudent(String id) throws Exception;
    List<Student> searchStudents(String keyword) throws Exception;
}

// StudentDAOImpl.java (DAO实现)
package com.education.dao.impl;

import com.education.dao.StudentDAO;
import com.education.db.DatabaseConnection;
import com.education.model.Student;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class StudentDAOImpl implements StudentDAO {
    
    @Override
    public List<Student> getAllStudents() throws Exception {
        List<Student> students = new ArrayList<>();
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        
        try {
            conn = DatabaseConnection.getConnection();
            stmt = conn.createStatement();
            rs = stmt.executeQuery("SELECT * FROM students ORDER BY name");
            
            while (rs.next()) {
                students.add(mapResultSetToStudent(rs));
            }
        } finally {
            DatabaseConnection.close(conn, stmt, rs);
        }
        
        return students;
    }
    
    @Override
    public Student getStudentById(String id) throws Exception {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        
        try {
            conn = DatabaseConnection.getConnection();
            pstmt = conn.prepareStatement("SELECT * FROM students WHERE student_id = ?");
            pstmt.setString(1, id);
            rs = pstmt.executeQuery();
            
            if (rs.next()) {
                return mapResultSetToStudent(rs);
            }
        } finally {
            DatabaseConnection.close(conn, pstmt, rs);
        }
        
        return null;
    }
    
    // 其他方法实现...
    
    private Student mapResultSetToStudent(ResultSet rs) throws SQLException {
        Student student = new Student();
        student.setStudentId(rs.getString("student_id"));
        student.setName(rs.getString("name"));
        student.setGender(rs.getString("gender"));
        student.setBirthDate(rs.getDate("birth_date"));
        student.setClassId(rs.getString("class_id"));
        student.setEnrollmentDate(rs.getDate("enrollment_date"));
        student.setStatus(rs.getString("status"));
        return student;
    }
}

3.2.2 控制器层(Controller)

// StudentController.java
package com.education.controller;

import com.education.dao.StudentDAO;
import com.education.dao.impl.StudentDAOImpl;
import com.education.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("/students/*")
public class StudentController extends HttpServlet {
    
    private StudentDAO studentDAO = new StudentDAOImpl();
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        String pathInfo = request.getPathInfo();
        
        if (pathInfo == null || "/".equals(pathInfo)) {
            // 列表页
            listStudents(request, response);
        } else if (pathInfo.startsWith("/edit/")) {
            // 编辑页
            String studentId = pathInfo.substring(6);
            editStudent(request, response, studentId);
        } else if (pathInfo.startsWith("/delete/")) {
            // 删除操作
            String studentId = pathInfo.substring(8);
            deleteStudent(request, response, studentId);
        } else {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }
    
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        String pathInfo = request.getPathInfo();
        
        if ("/save".equals(pathInfo)) {
            saveStudent(request, response);
        } else {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }
    
    private void listStudents(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        try {
            List<Student> students = studentDAO.getAllStudents();
            request.setAttribute("students", students);
            request.getRequestDispatcher("/WEB-INF/views/student/list.jsp").forward(request, response);
        } catch (Exception e) {
            request.setAttribute("error", "获取学生列表失败: " + e.getMessage());
            request.getRequestDispatcher("/WEB-INF/views/error.jsp").forward(request, response);
        }
    }
    
    private void editStudent(HttpServletRequest request, HttpServletResponse response, String studentId) 
            throws ServletException, IOException {
        
        try {
            Student student = studentDAO.getStudentById(studentId);
            if (student == null) {
                response.sendError(HttpServletResponse.SC_NOT_FOUND, "学生不存在");
                return;
            }
            
            request.setAttribute("student", student);
            request.getRequestDispatcher("/WEB-INF/views/student/edit.jsp").forward(request, response);
        } catch (Exception e) {
            request.setAttribute("error", "获取学生信息失败: " + e.getMessage());
            request.getRequestDispatcher("/WEB-INF/views/error.jsp").forward(request, response);
        }
    }
    
    private void saveStudent(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        try {
            Student student = new Student();
            student.setStudentId(request.getParameter("studentId"));
            student.setName(request.getParameter("name"));
            student.setGender(request.getParameter("gender"));
            student.setClassId(request.getParameter("classId"));
            
            // 保存或更新
            if (studentDAO.getStudentById(student.getStudentId()) == null) {
                studentDAO.addStudent(student);
            } else {
                studentDAO.updateStudent(student);
            }
            
            response.sendRedirect(request.getContextPath() + "/students");
        } catch (Exception e) {
            request.setAttribute("error", "保存学生信息失败: " + e.getMessage());
            request.getRequestDispatcher("/WEB-INF/views/student/edit.jsp").forward(request, response);
        }
    }
    
    private void deleteStudent(HttpServletRequest request, HttpServletResponse response, String studentId) 
            throws ServletException, IOException {
        
        try {
            boolean success = studentDAO.deleteStudent(studentId);
            if (success) {
                response.sendRedirect(request.getContextPath() + "/students");
            } else {
                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "删除失败");
            }
        } catch (Exception e) {
            request.setAttribute("error", "删除学生失败: " + e.getMessage());
            request.getRequestDispatcher("/WEB-INF/views/error.jsp").forward(request, response);
        }
    }
}

3.2.3 视图层(View)

<%-- /WEB-INF/views/student/list.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<!DOCTYPE html>
<html>
<head>
    <title>学生管理 - 列表</title>
    <style>
        /* 样式与之前相同,省略 */
    </style>
</head>
<body>
    <h1>学生管理</h1>
    
    <div class="toolbar">
        <a href="${pageContext.request.contextPath}/students/edit/" class="btn">添加学生</a>
        <form action="${pageContext.request.contextPath}/students" method="get" style="display: inline;">
            <input type="text" name="keyword" placeholder="搜索学生" value="${param.keyword}">
            <button type="submit">搜索</button>
        </form>
    </div>
    
    <c:if test="${not empty error}">
        <div class="error-message">${error}</div>
    </c:if>
    
    <table>
        <thead>
            <tr>
                <th>学号</th>
                <th>姓名</th>
                <th>性别</th>
                <th>班级</th>
                <th>入学日期</th>
                <th>状态</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            <c:forEach var="student" items="${students}">
                <tr>
                    <td>${student.studentId}</td>
                    <td>${student.name}</td>
                    <td>${student.gender}</td>
                    <td>${student.classId}</td>
                    <td>
                        <fmt:formatDate value="${student.enrollmentDate}" pattern="yyyy-MM-dd"/>
                    </td>
                    <td>${student.status}</td>
                    <td>
                        <a href="${pageContext.request.contextPath}/students/edit/${student.studentId}">编辑</a> |
                        <a href="${pageContext.request.contextPath}/students/delete/${student.studentId}" 
                           onclick="return confirm('确定要删除吗?')">删除</a>
                    </td>
                </tr>
            </c:forEach>
        </tbody>
    </table>
    
    <c:if test="${empty students}">
        <p style="text-align: center; color: #666;">暂无学生数据</p>
    </c:if>
</body>
</html>

3.3 安全性考虑

教育系统涉及敏感数据,安全性至关重要:

3.3.1 SQL注入防护

// 使用PreparedStatement防止SQL注入
public Student getStudentById(String id) throws Exception {
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    
    try {
        conn = DatabaseConnection.getConnection();
        // 使用参数化查询,防止SQL注入
        pstmt = conn.prepareStatement("SELECT * FROM students WHERE student_id = ?");
        pstmt.setString(1, id); // 自动转义特殊字符
        rs = pstmt.executeQuery();
        
        if (rs.next()) {
            return mapResultSetToStudent(rs);
        }
    } finally {
        DatabaseConnection.close(conn, pstmt, rs);
    }
    
    return null;
}

3.3.2 XSS防护

<%-- 使用JSTL的c:out标签自动转义HTML --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!-- 不安全的方式 -->
<p>学生姓名: ${student.name}</p>

<!-- 安全的方式 -->
<p>学生姓名: <c:out value="${student.name}"/></p>

<!-- 在Servlet中手动转义 -->
<%
    String userInput = request.getParameter("comment");
    String safeOutput = org.apache.commons.text.StringEscapeUtils.escapeHtml4(userInput);
    out.println(safeOutput);
%>

3.3.3 会话管理

// 登录验证过滤器
@WebFilter("/*")
public class AuthenticationFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        
        String requestURI = httpRequest.getRequestURI();
        
        // 排除公开页面
        if (requestURI.endsWith("/login.jsp") || 
            requestURI.endsWith("/login") ||
            requestURI.endsWith("/css/") ||
            requestURI.endsWith("/js/")) {
            chain.doFilter(request, response);
            return;
        }
        
        // 检查会话
        HttpSession session = httpRequest.getSession(false);
        if (session == null || session.getAttribute("user") == null) {
            httpResponse.sendRedirect(httpRequest.getContextPath() + "/login.jsp");
            return;
        }
        
        // 权限验证
        String userRole = (String) session.getAttribute("role");
        if (requestURI.startsWith("/admin/") && !"admin".equals(userRole)) {
            httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "无权访问");
            return;
        }
        
        chain.doFilter(request, response);
    }
}

3.4 性能优化策略

3.4.1 连接池配置

// 使用HikariCP连接池(推荐)
public class DatabaseConnection {
    private static HikariDataSource dataSource;
    
    static {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/education_db");
        config.setUsername("root");
        config.setPassword("password");
        
        // 连接池配置
        config.setMaximumPoolSize(20);      // 最大连接数
        config.setMinimumIdle(5);           // 最小空闲连接
        config.setConnectionTimeout(30000); // 连接超时30秒
        config.setIdleTimeout(600000);      // 空闲超时10分钟
        config.setMaxLifetime(1800000);     // 连接最大存活时间30分钟
        config.setLeakDetectionThreshold(2000); // 连接泄漏检测
        
        // MySQL特定配置
        config.addDataSourceProperty("cachePrepStmts", "true");
        config.addDataSourceProperty("prepStmtCacheSize", "250");
        config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        config.addDataSourceProperty("useServerPrepStmts", "true");
        
        dataSource = new HikariDataSource(config);
    }
    
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
}

3.4.2 缓存策略

// 使用Ehcache缓存常用数据
public class StudentCache {
    private static CacheManager cacheManager;
    private static Cache studentCache;
    
    static {
        try {
            cacheManager = CacheManager.newInstance();
            CacheConfiguration config = new CacheConfiguration("studentCache", 1000)
                .memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LRU)
                .eternal(false)
                .timeToLiveSeconds(3600) // 缓存1小时
                .timeToIdleSeconds(1800); // 空闲1800秒后过期
            
            studentCache = new Cache(config);
            cacheManager.addCache(studentCache);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static Student getStudentFromCache(String studentId) {
        Element element = studentCache.get(studentId);
        if (element != null) {
            return (Student) element.getObjectValue();
        }
        return null;
    }
    
    public static void putStudentToCache(String studentId, Student student) {
        Element element = new Element(studentId, student);
        studentCache.put(element);
    }
    
    public static void removeStudentFromCache(String studentId) {
        studentCache.remove(studentId);
    }
}

3.4.3 分页优化

// 高效分页查询
public List<Student> getStudentsByPage(int page, int pageSize, String keyword) throws Exception {
    List<Student> students = new ArrayList<>();
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    
    try {
        conn = DatabaseConnection.getConnection();
        
        // 使用LIMIT和OFFSET进行分页
        String sql = "SELECT * FROM students WHERE 1=1 ";
        if (keyword != null && !keyword.trim().isEmpty()) {
            sql += " AND (student_id LIKE ? OR name LIKE ?) ";
        }
        sql += " ORDER BY name LIMIT ? OFFSET ?";
        
        pstmt = conn.prepareStatement(sql);
        int paramIndex = 1;
        
        if (keyword != null && !keyword.trim().isEmpty()) {
            pstmt.setString(paramIndex++, "%" + keyword + "%");
            pstmt.setString(paramIndex++, "%" + keyword + "%");
        }
        
        pstmt.setInt(paramIndex++, pageSize);
        pstmt.setInt(paramIndex, (page - 1) * pageSize);
        
        rs = pstmt.executeQuery();
        
        while (rs.next()) {
            students.add(mapResultSetToStudent(rs));
        }
        
    } finally {
        DatabaseConnection.close(conn, pstmt, rs);
    }
    
    return students;
}

// 优化:使用游标分页(避免OFFSET性能问题)
public List<Student> getStudentsByCursor(String lastStudentId, int pageSize) throws Exception {
    List<Student> students = new ArrayList<>();
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    
    try {
        conn = DatabaseConnection.getConnection();
        
        // 使用WHERE条件代替OFFSET,性能更好
        String sql = "SELECT * FROM students ";
        if (lastStudentId != null) {
            sql += "WHERE student_id > ? ";
        }
        sql += "ORDER BY student_id LIMIT ?";
        
        pstmt = conn.prepareStatement(sql);
        
        if (lastStudentId != null) {
            pstmt.setString(1, lastStudentId);
            pstmt.setInt(2, pageSize);
        } else {
            pstmt.setInt(1, pageSize);
        }
        
        rs = pstmt.executeQuery();
        
        while (rs.next()) {
            students.add(mapResultSetToStudent(rs));
        }
        
    } finally {
        DatabaseConnection.close(conn, pstmt, rs);
    }
    
    return students;
}

四、JSP技术在教育系统中的未来发展趋势

4.1 与现代前端框架集成

虽然JSP主要用于服务器端渲染,但可以与现代前端框架结合:

<%-- JSP作为后端API提供者 --%>
<%@ page contentType="application/json;charset=UTF-8" language="java" %>
<%@ page import="com.education.service.StudentService" %>
<%@ page import="com.education.model.Student" %>
<%@ page import="java.util.List" %>
<%@ page import="com.google.gson.Gson" %>

<%
    // 设置响应为JSON
    response.setContentType("application/json");
    response.setCharacterEncoding("UTF-8");
    
    // 获取参数
    String action = request.getParameter("action");
    String studentId = request.getParameter("studentId");
    
    StudentService studentService = new StudentService();
    Gson gson = new Gson();
    
    try {
        if ("getStudent".equals(action) && studentId != null) {
            Student student = studentService.getStudentById(studentId);
            out.print(gson.toJson(student));
        } else if ("getStudents".equals(action)) {
            List<Student> students = studentService.getAllStudents();
            out.print(gson.toJson(students));
        } else {
            out.print(gson.toJson(new {error = "Invalid action"}));
        }
    } catch (Exception e) {
        out.print(gson.toJson(new {error = e.getMessage()}));
    }
%>

4.2 微服务架构中的JSP

在微服务架构中,JSP可以作为轻量级服务提供者:

// 使用Spring Boot + JSP的微服务示例
@SpringBootApplication
public class StudentServiceApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(StudentServiceApplication.class, args);
    }
    
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }
}

// REST控制器
@RestController
@RequestMapping("/api/students")
public class StudentRestController {
    
    @Autowired
    private StudentService studentService;
    
    @GetMapping
    public List<Student> getAllStudents() {
        return studentService.getAllStudents();
    }
    
    @GetMapping("/{id}")
    public Student getStudentById(@PathVariable String id) {
        return studentService.getStudentById(id);
    }
    
    @PostMapping
    public Student createStudent(@RequestBody Student student) {
        return studentService.createStudent(student);
    }
}

五、总结

JSP技术在教育系统开发中展现出强大的生命力,其优势主要体现在:

  1. 成熟的生态系统:与Java生态无缝集成,拥有丰富的类库和框架支持
  2. 高性能:编译执行机制确保了良好的运行效率
  3. 安全性:成熟的Java安全机制和成熟的防护方案
  4. 可维护性:通过MVC架构和设计模式,代码结构清晰
  5. 扩展性:易于与现代技术栈集成,适应未来需求变化

通过本文的详细示例,我们可以看到JSP技术如何在教育系统的各个层面发挥作用:

  • 数据管理:通过JDBC和连接池高效处理学生、课程、成绩等数据
  • 动态网页:实时展示学生信息、课程安排、成绩统计等
  • 业务逻辑:实现选课、成绩录入、权限控制等复杂业务
  • 性能优化:通过缓存、分页、连接池等技术提升系统性能
  • 安全防护:防止SQL注入、XSS攻击等安全威胁

随着教育信息化的深入发展,JSP技术将继续在教育系统建设中发挥重要作用,特别是在需要快速开发、稳定运行和良好扩展性的场景中。通过合理的设计和优化,JSP完全可以构建出高效、安全、易维护的教育管理系统。