引言

在当今数字化教育时代,教育系统需要处理大量的动态数据,包括学生信息、课程安排、成绩记录、在线测试等。传统的静态HTML页面无法满足这些需求,而JSP(JavaServer Pages)技术作为Java EE体系中的重要组成部分,为教育系统提供了强大的动态网页开发和数据交互能力。本文将深入探讨JSP技术如何在教育系统中发挥作用,从技术原理到实际应用,全面解析其价值。

一、JSP技术基础概述

1.1 JSP是什么?

JSP(JavaServer Pages)是一种基于Java的服务器端网页技术,它允许开发者在HTML或XML文档中嵌入Java代码,从而生成动态网页内容。JSP页面在服务器端被编译成Servlet,然后执行并生成HTML响应发送给客户端。

1.2 JSP的核心优势

  • 动态内容生成:能够根据用户请求和数据库数据实时生成页面内容
  • 与Java生态无缝集成:可以使用所有Java类库和框架
  • MVC模式支持:与Servlet、JavaBean等技术配合,实现清晰的架构分离
  • 跨平台性:基于Java,可在任何支持Java的服务器上运行

1.3 JSP在教育系统中的适用场景

  • 学生信息管理系统
  • 在线课程平台
  • 成绩查询系统
  • 教学资源库
  • 在线考试系统
  • 教师工作台

二、JSP在教育系统中的动态网页开发

2.1 动态页面生成示例

以下是一个简单的JSP页面示例,展示如何动态显示学生列表:

<%@ page import="java.util.*,java.sql.*" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<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; }
    </style>
</head>
<body>
    <h1>学生信息列表</h1>
    <table>
        <tr>
            <th>学号</th>
            <th>姓名</th>
            <th>专业</th>
            <th>年级</th>
            <th>操作</th>
        </tr>
        <%
            // 连接数据库
            try {
                Class.forName("com.mysql.jdbc.Driver");
                Connection conn = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/education_db", 
                    "username", 
                    "password");
                
                Statement stmt = conn.createStatement();
                String sql = "SELECT student_id, name, major, grade FROM students";
                ResultSet rs = stmt.executeQuery(sql);
                
                while (rs.next()) {
                    String studentId = rs.getString("student_id");
                    String name = rs.getString("name");
                    String major = rs.getString("major");
                    String grade = rs.getString("grade");
        %>
        <tr>
            <td><%= studentId %></td>
            <td><%= name %></td>
            <td><%= major %></td>
            <td><%= grade %></td>
            <td>
                <a href="student_detail.jsp?id=<%= studentId %>">查看详情</a> |
                <a href="edit_student.jsp?id=<%= studentId %>">编辑</a>
            </td>
        </tr>
        <%
                }
                rs.close();
                stmt.close();
                conn.close();
            } catch (Exception e) {
                out.println("数据库连接错误: " + e.getMessage());
            }
        %>
    </table>
</body>
</html>

2.2 表单处理与用户交互

教育系统中经常需要处理用户输入,如学生注册、课程报名等:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>学生注册</title>
</head>
<body>
    <h2>学生注册表单</h2>
    <form action="register_process.jsp" method="post">
        <table>
            <tr>
                <td>学号:</td>
                <td><input type="text" name="studentId" required></td>
            </tr>
            <tr>
                <td>姓名:</td>
                <td><input type="text" name="name" required></td>
            </tr>
            <tr>
                <td>密码:</td>
                <td><input type="password" name="password" required></td>
            </tr>
            <tr>
                <td>专业:</td>
                <td>
                    <select name="major">
                        <option value="计算机科学">计算机科学</option>
                        <option value="数学">数学</option>
                        <option value="物理">物理</option>
                        <option value="化学">化学</option>
                    </select>
                </td>
            </tr>
            <tr>
                <td>年级:</td>
                <td>
                    <select name="grade">
                        <option value="大一">大一</option>
                        <option value="大二">大二</option>
                        <option value="大三">大三</option>
                        <option value="大四">大四</option>
                    </select>
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    <input type="submit" value="注册">
                    <input type="reset" value="重置">
                </td>
            </tr>
        </table>
    </form>
</body>
</html>

对应的处理页面 register_process.jsp:

<%@ page import="java.sql.*" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>注册结果</title>
</head>
<body>
    <%
        request.setCharacterEncoding("UTF-8");
        String studentId = request.getParameter("studentId");
        String name = request.getParameter("name");
        String password = request.getParameter("password");
        String major = request.getParameter("major");
        String grade = request.getParameter("grade");
        
        // 简单的验证
        if (studentId == null || studentId.trim().isEmpty() ||
            name == null || name.trim().isEmpty() ||
            password == null || password.trim().isEmpty()) {
            out.println("<h3>错误:所有字段都必须填写!</h3>");
            out.println("<a href='register.jsp'>返回注册页面</a>");
            return;
        }
        
        try {
            Class.forName("com.mysql.jdbc.Driver");
            Connection conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/education_db", 
                "username", 
                "password");
            
            // 检查学号是否已存在
            String checkSql = "SELECT COUNT(*) FROM students WHERE student_id = ?";
            PreparedStatement checkStmt = conn.prepareStatement(checkSql);
            checkStmt.setString(1, studentId);
            ResultSet rs = checkStmt.executeQuery();
            rs.next();
            int count = rs.getInt(1);
            
            if (count > 0) {
                out.println("<h3>错误:该学号已存在!</h3>");
                out.println("<a href='register.jsp'>返回注册页面</a>");
            } else {
                // 插入新记录
                String insertSql = "INSERT INTO students (student_id, name, password, major, grade) VALUES (?, ?, ?, ?, ?)";
                PreparedStatement insertStmt = conn.prepareStatement(insertSql);
                insertStmt.setString(1, studentId);
                insertStmt.setString(2, name);
                insertStmt.setString(3, password); // 实际应用中应该加密存储
                insertStmt.setString(4, major);
                insertStmt.setString(5, grade);
                
                int rows = insertStmt.executeUpdate();
                
                if (rows > 0) {
                    out.println("<h3>注册成功!</h3>");
                    out.println("<p>欢迎你," + name + "!</p>");
                    out.println("<a href='login.jsp'>登录</a>");
                } else {
                    out.println("<h3>注册失败,请稍后重试。</h3>");
                    out.println("<a href='register.jsp'>返回注册页面</a>");
                }
                
                insertStmt.close();
            }
            
            checkStmt.close();
            rs.close();
            conn.close();
            
        } catch (Exception e) {
            out.println("<h3>系统错误:" + e.getMessage() + "</h3>");
            out.println("<a href='register.jsp'>返回注册页面</a>");
        }
    %>
</body>
</html>

2.3 分页显示功能

教育系统中数据量通常较大,分页显示是必不可少的功能:

<%@ page import="java.sql.*" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>学生信息分页显示</title>
    <style>
        .pagination { margin: 20px 0; }
        .pagination a, .pagination span {
            display: inline-block;
            padding: 8px 12px;
            margin: 0 2px;
            border: 1px solid #ddd;
            text-decoration: none;
            color: #333;
        }
        .pagination a:hover { background-color: #f0f0f0; }
        .pagination .current { background-color: #4CAF50; color: white; border-color: #4CAF50; }
    </style>
</head>
<body>
    <h1>学生信息分页显示</h1>
    
    <%
        // 获取当前页码,默认为1
        int currentPage = 1;
        String pageParam = request.getParameter("page");
        if (pageParam != null && !pageParam.isEmpty()) {
            currentPage = Integer.parseInt(pageParam);
        }
        
        // 每页显示记录数
        int pageSize = 10;
        
        // 计算偏移量
        int offset = (currentPage - 1) * pageSize;
        
        try {
            Class.forName("com.mysql.jdbc.Driver");
            Connection conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/education_db", 
                "username", 
                "password");
            
            // 获取总记录数
            String countSql = "SELECT COUNT(*) FROM students";
            Statement countStmt = conn.createStatement();
            ResultSet countRs = countStmt.executeQuery(countSql);
            countRs.next();
            int totalRecords = countRs.getInt(1);
            
            // 计算总页数
            int totalPages = (int) Math.ceil((double) totalRecords / pageSize);
            
            // 获取当前页数据
            String dataSql = "SELECT student_id, name, major, grade FROM students LIMIT ?, ?";
            PreparedStatement dataStmt = conn.prepareStatement(dataSql);
            dataStmt.setInt(1, offset);
            dataStmt.setInt(2, pageSize);
            ResultSet dataRs = dataStmt.executeQuery();
    %>
    
    <table>
        <tr>
            <th>学号</th>
            <th>姓名</th>
            <th>专业</th>
            <th>年级</th>
        </tr>
        <%
            while (dataRs.next()) {
        %>
        <tr>
            <td><%= dataRs.getString("student_id") %></td>
            <td><%= dataRs.getString("name") %></td>
            <td><%= dataRs.getString("major") %></td>
            <td><%= dataRs.getString("grade") %></td>
        </tr>
        <%
            }
        %>
    </table>
    
    <div class="pagination">
        <%
            // 显示分页链接
            if (currentPage > 1) {
        %>
        <a href="?page=<%= currentPage - 1 %>">上一页</a>
        <%
            }
            
            // 显示页码
            int startPage = Math.max(1, currentPage - 2);
            int endPage = Math.min(totalPages, currentPage + 2);
            
            for (int i = startPage; i <= endPage; i++) {
                if (i == currentPage) {
        %>
        <span class="current"><%= i %></span>
        <%
                } else {
        %>
        <a href="?page=<%= i %>"><%= i %></a>
        <%
                }
            }
            
            if (currentPage < totalPages) {
        %>
        <a href="?page=<%= currentPage + 1 %>">下一页</a>
        <%
            }
        %>
        <span>共 <%= totalPages %> 页,<%= totalRecords %> 条记录</span>
    </div>
    
    <%
            dataRs.close();
            dataStmt.close();
            countRs.close();
            countStmt.close();
            conn.close();
            
        } catch (Exception e) {
            out.println("错误:" + e.getMessage());
        }
    %>
</body>
</html>

三、JSP在教育系统中的数据交互

3.1 数据库连接与操作

教育系统需要频繁与数据库交互,JSP提供了多种方式:

3.1.1 使用JDBC直接连接

// 数据库连接工具类 DatabaseUtil.java
package com.education.util;

import java.sql.*;

public class DatabaseUtil {
    private static final String URL = "jdbc:mysql://localhost:3306/education_db";
    private static final String USER = "username";
    private static final String PASSWORD = "password";
    
    public static Connection getConnection() throws SQLException {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            throw new SQLException("数据库驱动未找到", e);
        }
        return DriverManager.getConnection(URL, USER, PASSWORD);
    }
    
    public static void close(Connection conn, Statement stmt, ResultSet rs) {
        try {
            if (rs != null) rs.close();
            if (stmt != null) stmt.close();
            if (conn != null) conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

3.1.2 使用连接池(推荐)

在实际生产环境中,使用连接池可以提高性能和资源利用率:

<%@ page import="javax.sql.*, javax.naming.*, com.education.util.*" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    // 使用JNDI获取数据源
    try {
        Context ctx = new InitialContext();
        DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/educationDB");
        Connection conn = ds.getConnection();
        
        // 使用连接...
        
        conn.close();
    } catch (Exception e) {
        out.println("数据库连接错误: " + e.getMessage());
    }
%>

3.2 会话管理

教育系统需要跟踪用户状态,如登录状态、购物车(课程选择)等:

<%@ page import="java.sql.*" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    // 检查用户是否登录
    String username = (String) session.getAttribute("username");
    String role = (String) session.getAttribute("role");
    
    if (username == null) {
        response.sendRedirect("login.jsp");
        return;
    }
    
    // 显示欢迎信息
    out.println("<h1>欢迎回来," + username + "!</h1>");
    
    // 根据角色显示不同内容
    if ("student".equals(role)) {
        // 学生视图
        String studentId = (String) session.getAttribute("studentId");
        out.println("<p>你的学号: " + studentId + "</p>");
        
        // 显示已选课程
        try {
            Connection conn = DatabaseUtil.getConnection();
            String sql = "SELECT c.course_name, c.teacher, c.credit FROM courses c " +
                         "JOIN enrollment e ON c.course_id = e.course_id " +
                         "WHERE e.student_id = ?";
            PreparedStatement stmt = conn.prepareStatement(sql);
            stmt.setString(1, studentId);
            ResultSet rs = stmt.executeQuery();
            
            out.println("<h3>已选课程:</h3>");
            out.println("<ul>");
            while (rs.next()) {
                out.println("<li>" + rs.getString("course_name") + 
                           " - " + rs.getString("teacher") + 
                           " (" + rs.getInt("credit") + "学分)</li>");
            }
            out.println("</ul>");
            
            DatabaseUtil.close(conn, stmt, rs);
        } catch (Exception e) {
            out.println("错误: " + e.getMessage());
        }
    } else if ("teacher".equals(role)) {
        // 教师视图
        out.println("<p>教师工作台</p>");
        out.println("<a href='manage_courses.jsp'>管理课程</a>");
    }
%>

3.3 AJAX与JSP结合实现异步数据交互

现代教育系统需要更流畅的用户体验,AJAX与JSP结合可以实现异步数据加载:

<%@ page import="java.sql.*" %>
<%@ page contentType="application/json;charset=UTF-8" %>
<%
    // 这是一个JSON API,用于AJAX调用
    String courseId = request.getParameter("courseId");
    
    if (courseId == null || courseId.trim().isEmpty()) {
        out.print("{\"error\": \"缺少课程ID\"}");
        return;
    }
    
    try {
        Connection conn = DatabaseUtil.getConnection();
        String sql = "SELECT * FROM courses WHERE course_id = ?";
        PreparedStatement stmt = conn.prepareStatement(sql);
        stmt.setString(1, courseId);
        ResultSet rs = stmt.executeQuery();
        
        if (rs.next()) {
            out.print("{");
            out.print("\"course_id\": \"" + rs.getString("course_id") + "\",");
            out.print("\"course_name\": \"" + rs.getString("course_name") + "\",");
            out.print("\"teacher\": \"" + rs.getString("teacher") + "\",");
            out.print("\"credit\": " + rs.getInt("credit") + ",");
            out.print("\"description\": \"" + rs.getString("description") + "\"");
            out.print("}");
        } else {
            out.print("{\"error\": \"课程不存在\"}");
        }
        
        DatabaseUtil.close(conn, stmt, rs);
    } catch (Exception e) {
        out.print("{\"error\": \"" + e.getMessage() + "\"}");
    }
%>

对应的前端AJAX调用:

<!DOCTYPE html>
<html>
<head>
    <title>课程详情</title>
    <script>
        function loadCourseDetails(courseId) {
            var xhr = new XMLHttpRequest();
            xhr.open('GET', 'course_api.jsp?courseId=' + courseId, true);
            xhr.onreadystatechange = function() {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    var data = JSON.parse(xhr.responseText);
                    if (data.error) {
                        document.getElementById('courseInfo').innerHTML = 
                            '<p style="color: red;">' + data.error + '</p>';
                    } else {
                        var html = '<h3>' + data.course_name + '</h3>';
                        html += '<p><strong>教师:</strong> ' + data.teacher + '</p>';
                        html += '<p><strong>学分:</strong> ' + data.credit + '</p>';
                        html += '<p><strong>简介:</strong> ' + data.description + '</p>';
                        document.getElementById('courseInfo').innerHTML = html;
                    }
                }
            };
            xhr.send();
        }
        
        // 页面加载时自动加载第一门课程
        window.onload = function() {
            loadCourseDetails('C001');
        };
    </script>
</head>
<body>
    <h1>课程详情查看</h1>
    <div>
        <button onclick="loadCourseDetails('C001')">计算机科学导论</button>
        <button onclick="loadCourseDetails('C002')">高等数学</button>
        <button onclick="loadCourseDetails('C003')">大学物理</button>
    </div>
    <div id="courseInfo" style="margin-top: 20px; padding: 15px; border: 1px solid #ccc;">
        <!-- 课程信息将在这里显示 -->
    </div>
</body>
</html>

四、JSP在教育系统中的高级应用

4.1 在线考试系统

JSP可以构建完整的在线考试系统,包括题目管理、考试计时、自动评分等:

<%@ page import="java.sql.*, java.util.*, java.text.SimpleDateFormat" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    // 检查登录状态
    String studentId = (String) session.getAttribute("studentId");
    if (studentId == null) {
        response.sendRedirect("login.jsp");
        return;
    }
    
    // 获取考试ID
    String examId = request.getParameter("examId");
    if (examId == null) {
        out.println("错误:未指定考试ID");
        return;
    }
    
    // 检查是否已参加过该考试
    try {
        Connection conn = DatabaseUtil.getConnection();
        String checkSql = "SELECT * FROM exam_results WHERE student_id = ? AND exam_id = ?";
        PreparedStatement checkStmt = conn.prepareStatement(checkSql);
        checkStmt.setString(1, studentId);
        checkStmt.setString(2, examId);
        ResultSet checkRs = checkStmt.executeQuery();
        
        if (checkRs.next()) {
            out.println("<h3>您已经参加过该考试</h3>");
            out.println("<p>您的成绩: " + checkRs.getInt("score") + "分</p>");
            out.println("<a href='student_dashboard.jsp'>返回首页</a>");
            DatabaseUtil.close(conn, checkStmt, checkRs);
            return;
        }
        
        // 获取考试信息
        String examSql = "SELECT * FROM exams WHERE exam_id = ?";
        PreparedStatement examStmt = conn.prepareStatement(examSql);
        examStmt.setString(1, examId);
        ResultSet examRs = examStmt.executeQuery();
        
        if (!examRs.next()) {
            out.println("错误:考试不存在");
            DatabaseUtil.close(conn, examStmt, examRs);
            return;
        }
        
        String examName = examRs.getString("exam_name");
        int duration = examRs.getInt("duration"); // 分钟
        int totalScore = examRs.getInt("total_score");
        
        // 获取题目
        String questionSql = "SELECT * FROM questions WHERE exam_id = ? ORDER BY RAND()";
        PreparedStatement questionStmt = conn.prepareStatement(questionSql);
        questionStmt.setString(1, examId);
        ResultSet questionRs = questionStmt.executeQuery();
        
        // 生成考试页面
        out.println("<html><head><title>" + examName + "</title>");
        out.println("<style>");
        out.println("body { font-family: Arial, sans-serif; margin: 20px; }");
        out.println(".question { margin-bottom: 20px; padding: 15px; border: 1px solid #ddd; }");
        out.println(".options { margin-left: 20px; }");
        out.println("input[type='radio'] { margin-right: 5px; }");
        out.println(".timer { position: fixed; top: 10px; right: 10px; background: #f0f0f0; padding: 10px; }");
        out.println("</style>");
        out.println("<script>");
        out.println("var timeLeft = " + (duration * 60) + ";"); // 转换为秒
        out.println("var timer;");
        out.println("function startTimer() {");
        out.println("    timer = setInterval(function() {");
        out.println("        timeLeft--;");
        out.println("        var minutes = Math.floor(timeLeft / 60);");
        out.println("        var seconds = timeLeft % 60;");
        out.println("        document.getElementById('timerDisplay').innerHTML = ");
        out.println("            '剩余时间: ' + minutes + '分' + seconds + '秒';");
        out.println("        if (timeLeft <= 0) {");
        out.println("            clearInterval(timer);");
        out.println("            alert('考试时间到,正在提交...');");
        out.println("            document.getElementById('examForm').submit();");
        out.println("        }");
        out.println("    }, 1000);");
        out.println("}");
        out.println("window.onload = startTimer;");
        out.println("</script>");
        out.println("</head><body>");
        out.println("<h1>" + examName + "</h1>");
        out.println("<div class='timer' id='timerDisplay'>剩余时间: " + duration + "分</div>");
        out.println("<form id='examForm' action='submit_exam.jsp' method='post'>");
        out.println("<input type='hidden' name='examId' value='" + examId + "'>");
        
        int questionCount = 0;
        while (questionRs.next()) {
            questionCount++;
            String questionId = questionRs.getString("question_id");
            String questionText = questionRs.getString("question_text");
            String options = questionRs.getString("options");
            String correctAnswer = questionRs.getString("correct_answer");
            
            out.println("<div class='question'>");
            out.println("<p><strong>" + questionCount + ". " + questionText + "</strong></p>");
            out.println("<div class='options'>");
            
            // 解析选项(假设选项以逗号分隔)
            String[] optionArray = options.split(",");
            for (int i = 0; i < optionArray.length; i++) {
                String optionLetter = String.valueOf((char) ('A' + i));
                out.println("<label>");
                out.println("<input type='radio' name='q_" + questionId + "' value='" + optionLetter + "'>");
                out.println(optionLetter + ". " + optionArray[i]);
                out.println("</label><br>");
            }
            out.println("</div>");
            out.println("</div>");
        }
        
        out.println("<div style='margin-top: 20px;'>");
        out.println("<input type='submit' value='提交试卷'>");
        out.println("</div>");
        out.println("</form>");
        
        out.println("</body></html>");
        
        DatabaseUtil.close(conn, questionStmt, questionRs);
        DatabaseUtil.close(conn, examStmt, examRs);
        
    } catch (Exception e) {
        out.println("错误:" + e.getMessage());
    }
%>

4.2 教学资源管理系统

JSP可以构建教学资源库,支持文件上传、下载和在线预览:

<%@ page import="java.sql.*, java.io.*, javax.servlet.http.*" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    // 文件上传处理
    if ("POST".equalsIgnoreCase(request.getMethod())) {
        String courseName = request.getParameter("courseName");
        String description = request.getParameter("description");
        
        // 处理文件上传
        Part filePart = request.getPart("file");
        String fileName = filePart.getSubmittedFileName();
        
        // 保存文件到服务器
        String uploadPath = getServletContext().getRealPath("https://www.21xqjy.com/uploads");
        File uploadDir = new File(uploadPath);
        if (!uploadDir.exists()) {
            uploadDir.mkdir();
        }
        
        String filePath = uploadPath + File.separator + fileName;
        try (InputStream fileContent = filePart.getInputStream()) {
            FileOutputStream outStream = new FileOutputStream(filePath);
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fileContent.read(buffer)) != -1) {
                outStream.write(buffer, 0, bytesRead);
            }
            outStream.close();
            
            // 保存到数据库
            Connection conn = DatabaseUtil.getConnection();
            String sql = "INSERT INTO resources (course_name, file_name, file_path, description, upload_time) VALUES (?, ?, ?, ?, NOW())";
            PreparedStatement stmt = conn.prepareStatement(sql);
            stmt.setString(1, courseName);
            stmt.setString(2, fileName);
            stmt.setString(3, filePath);
            stmt.setString(4, description);
            stmt.executeUpdate();
            
            DatabaseUtil.close(conn, stmt, null);
            
            out.println("<h3>文件上传成功!</h3>");
            out.println("<a href='resource_list.jsp'>查看资源列表</a>");
        } catch (Exception e) {
            out.println("上传失败: " + e.getMessage());
        }
    } else {
        // 显示上传表单
%>
<!DOCTYPE html>
<html>
<head>
    <title>上传教学资源</title>
</head>
<body>
    <h1>上传教学资源</h1>
    <form action="upload_resource.jsp" method="post" enctype="multipart/form-data">
        <table>
            <tr>
                <td>课程名称:</td>
                <td><input type="text" name="courseName" required></td>
            </tr>
            <tr>
                <td>资源描述:</td>
                <td><textarea name="description" rows="3" cols="40"></textarea></td>
            </tr>
            <tr>
                <td>选择文件:</td>
                <td><input type="file" name="file" required></td>
            </tr>
            <tr>
                <td colspan="2">
                    <input type="submit" value="上传">
                </td>
            </tr>
        </table>
    </form>
</body>
</html>
<%
    }
%>

五、JSP在教育系统中的最佳实践

5.1 安全性考虑

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

<%@ page import="java.sql.*, java.security.MessageDigest, java.math.BigInteger" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    // 密码加密存储示例
    public static String hashPassword(String password) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(password.getBytes());
        byte[] digest = md.digest();
        BigInteger bigInt = new BigInteger(1, digest);
        return bigInt.toString(16);
    }
    
    // SQL注入防护示例
    String userInput = request.getParameter("search");
    
    // 错误的做法(容易受到SQL注入攻击)
    // String sql = "SELECT * FROM students WHERE name = '" + userInput + "'";
    
    // 正确的做法(使用预编译语句)
    String sql = "SELECT * FROM students WHERE name = ?";
    PreparedStatement stmt = conn.prepareStatement(sql);
    stmt.setString(1, userInput);
    ResultSet rs = stmt.executeQuery();
    
    // XSS防护示例
    String safeOutput = userInput.replace("&", "&amp;")
                                 .replace("<", "&lt;")
                                 .replace(">", "&gt;")
                                 .replace("\"", "&quot;")
                                 .replace("'", "&#x27;");
%>

5.2 性能优化

<%@ page import="java.sql.*, java.util.*, java.util.concurrent.*" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    // 使用缓存减少数据库查询
    // 假设有一个简单的缓存实现
    class CourseCache {
        private static final Map<String, Object> cache = new ConcurrentHashMap<>();
        private static final long CACHE_DURATION = 5 * 60 * 1000; // 5分钟
        
        public static Object get(String key) {
            CacheEntry entry = (CacheEntry) cache.get(key);
            if (entry != null && System.currentTimeMillis() - entry.timestamp < CACHE_DURATION) {
                return entry.data;
            }
            return null;
        }
        
        public static void put(String key, Object data) {
            cache.put(key, new CacheEntry(data, System.currentTimeMillis()));
        }
        
        static class CacheEntry {
            Object data;
            long timestamp;
            CacheEntry(Object data, long timestamp) {
                this.data = data;
                this.timestamp = timestamp;
            }
        }
    }
    
    // 使用缓存获取课程列表
    String cacheKey = "course_list";
    List<Map<String, Object>> courses = (List<Map<String, Object>>) CourseCache.get(cacheKey);
    
    if (courses == null) {
        // 从数据库获取
        courses = new ArrayList<>();
        Connection conn = DatabaseUtil.getConnection();
        String sql = "SELECT course_id, course_name, teacher FROM courses";
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery(sql);
        
        while (rs.next()) {
            Map<String, Object> course = new HashMap<>();
            course.put("course_id", rs.getString("course_id"));
            course.put("course_name", rs.getString("course_name"));
            course.put("teacher", rs.getString("teacher"));
            courses.add(course);
        }
        
        DatabaseUtil.close(conn, stmt, rs);
        
        // 存入缓存
        CourseCache.put(cacheKey, courses);
    }
    
    // 显示课程列表
    out.println("<h3>课程列表(来自缓存)</h3>");
    out.println("<ul>");
    for (Map<String, Object> course : courses) {
        out.println("<li>" + course.get("course_name") + " - " + course.get("teacher") + "</li>");
    }
    out.println("</ul>");
%>

5.3 代码组织与MVC模式

在实际项目中,建议采用MVC(Model-View-Controller)模式:

项目结构示例:
src/
├── com/education/
│   ├── model/          // 数据模型
│   │   ├── Student.java
│   │   ├── Course.java
│   │   └── Teacher.java
│   ├── dao/            // 数据访问对象
│   │   ├── StudentDAO.java
│   │   └── CourseDAO.java
│   ├── service/        // 业务逻辑
│   │   ├── StudentService.java
│   │   └── CourseService.java
│   └── controller/     // 控制器
│       ├── StudentController.java
│       └── CourseController.java
└── web/
    ├── WEB-INF/
    │   ├── web.xml
    │   └── classes/
    ├── jsp/            // 视图层
    │   ├── student/
    │   │   ├── list.jsp
    │   │   ├── detail.jsp
    │   │   └── edit.jsp
    │   └── course/
    │       ├── list.jsp
    │       └── detail.jsp
    ├── css/
    ├── js/
    └── uploads/

Model示例(Student.java):

package com.education.model;

public class Student {
    private String studentId;
    private String name;
    private String major;
    private String grade;
    
    // 构造函数、getter和setter
    public Student() {}
    
    public Student(String studentId, String name, String major, String grade) {
        this.studentId = studentId;
        this.name = name;
        this.major = major;
        this.grade = grade;
    }
    
    // getter和setter方法...
}

DAO示例(StudentDAO.java):

package com.education.dao;

import com.education.model.Student;
import com.education.util.DatabaseUtil;
import java.sql.*;
import java.util.*;

public class StudentDAO {
    public List<Student> getAllStudents() throws SQLException {
        List<Student> students = new ArrayList<>();
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        
        try {
            conn = DatabaseUtil.getConnection();
            stmt = conn.createStatement();
            String sql = "SELECT student_id, name, major, grade FROM students";
            rs = stmt.executeQuery(sql);
            
            while (rs.next()) {
                Student student = new Student(
                    rs.getString("student_id"),
                    rs.getString("name"),
                    rs.getString("major"),
                    rs.getString("grade")
                );
                students.add(student);
            }
        } finally {
            DatabaseUtil.close(conn, stmt, rs);
        }
        
        return students;
    }
    
    // 其他方法:getStudentById, insertStudent, updateStudent, deleteStudent等
}

Controller示例(StudentController.java):

package com.education.controller;

import com.education.dao.StudentDAO;
import com.education.model.Student;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;

public class StudentController extends HttpServlet {
    private StudentDAO studentDAO = new StudentDAO();
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        String action = request.getParameter("action");
        
        if (action == null) {
            action = "list";
        }
        
        try {
            switch (action) {
                case "list":
                    listStudents(request, response);
                    break;
                case "detail":
                    showStudentDetail(request, response);
                    break;
                default:
                    listStudents(request, response);
            }
        } catch (SQLException e) {
            throw new ServletException("数据库错误", e);
        }
    }
    
    private void listStudents(HttpServletRequest request, HttpServletResponse response) 
            throws SQLException, ServletException, IOException {
        
        List<Student> students = studentDAO.getAllStudents();
        request.setAttribute("students", students);
        RequestDispatcher dispatcher = request.getRequestDispatcher("/jsp/student/list.jsp");
        dispatcher.forward(request, response);
    }
    
    private void showStudentDetail(HttpServletRequest request, HttpServletResponse response) 
            throws SQLException, ServletException, IOException {
        
        String studentId = request.getParameter("id");
        Student student = studentDAO.getStudentById(studentId);
        request.setAttribute("student", student);
        RequestDispatcher dispatcher = request.getRequestDispatcher("/jsp/student/detail.jsp");
        dispatcher.forward(request, response);
    }
}

View示例(list.jsp):

<%@ page import="java.util.*, com.education.model.Student" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    List<Student> students = (List<Student>) request.getAttribute("students");
%>
<!DOCTYPE html>
<html>
<head>
    <title>学生列表</title>
</head>
<body>
    <h1>学生信息列表</h1>
    <table>
        <tr>
            <th>学号</th>
            <th>姓名</th>
            <th>专业</th>
            <th>年级</th>
            <th>操作</th>
        </tr>
        <%
            if (students != null) {
                for (Student student : students) {
        %>
        <tr>
            <td><%= student.getStudentId() %></td>
            <td><%= student.getName() %></td>
            <td><%= student.getMajor() %></td>
            <td><%= student.getGrade() %></td>
            <td>
                <a href="StudentController?action=detail&id=<%= student.getStudentId() %>">查看详情</a>
            </td>
        </tr>
        <%
                }
            }
        %>
    </table>
</body>
</html>

六、JSP在现代教育系统中的发展趋势

6.1 与现代前端框架的集成

虽然JSP主要用于后端,但可以与现代前端框架结合:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
    <title>现代教育系统</title>
    <!-- 引入Vue.js -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
    <!-- 引入Axios用于HTTP请求 -->
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <style>
        [v-cloak] { display: none; }
    </style>
</head>
<body>
    <div id="app" v-cloak>
        <h1>{{ title }}</h1>
        
        <!-- 搜索框 -->
        <div>
            <input type="text" v-model="searchKeyword" placeholder="搜索学生...">
            <button @click="searchStudents">搜索</button>
        </div>
        
        <!-- 学生列表 -->
        <table v-if="students.length > 0">
            <thead>
                <tr>
                    <th>学号</th>
                    <th>姓名</th>
                    <th>专业</th>
                    <th>年级</th>
                </tr>
            </thead>
            <tbody>
                <tr v-for="student in students" :key="student.studentId">
                    <td>{{ student.studentId }}</td>
                    <td>{{ student.name }}</td>
                    <td>{{ student.major }}</td>
                    <td>{{ student.grade }}</td>
                </tr>
            </tbody>
        </table>
        
        <p v-else>暂无数据</p>
        
        <!-- 分页 -->
        <div v-if="totalPages > 1">
            <button @click="changePage(currentPage - 1)" :disabled="currentPage === 1">上一页</button>
            <span v-for="page in totalPages" :key="page">
                <button @click="changePage(page)" :class="{ active: page === currentPage }">
                    {{ page }}
                </button>
            </span>
            <button @click="changePage(currentPage + 1)" :disabled="currentPage === totalPages">下一页</button>
        </div>
    </div>
    
    <script>
        new Vue({
            el: '#app',
            data: {
                title: '学生管理系统',
                students: [],
                searchKeyword: '',
                currentPage: 1,
                totalPages: 1,
                pageSize: 10
            },
            methods: {
                loadStudents() {
                    // 调用JSP API获取数据
                    axios.get('api/students.jsp', {
                        params: {
                            page: this.currentPage,
                            pageSize: this.pageSize,
                            keyword: this.searchKeyword
                        }
                    })
                    .then(response => {
                        this.students = response.data.students;
                        this.totalPages = response.data.totalPages;
                    })
                    .catch(error => {
                        console.error('加载数据失败:', error);
                    });
                },
                searchStudents() {
                    this.currentPage = 1;
                    this.loadStudents();
                },
                changePage(page) {
                    if (page >= 1 && page <= this.totalPages) {
                        this.currentPage = page;
                        this.loadStudents();
                    }
                }
            },
            mounted() {
                this.loadStudents();
            }
        });
    </script>
</body>
</html>

对应的JSP API(api/students.jsp):

<%@ page import="java.sql.*, java.util.*, com.google.gson.Gson" %>
<%@ page contentType="application/json;charset=UTF-8" %>
<%
    // 设置响应头
    response.setHeader("Access-Control-Allow-Origin", "*");
    response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
    response.setHeader("Access-Control-Allow-Headers", "Content-Type");
    
    // 获取参数
    int page = Integer.parseInt(request.getParameter("page"));
    int pageSize = Integer.parseInt(request.getParameter("pageSize"));
    String keyword = request.getParameter("keyword");
    
    // 计算偏移量
    int offset = (page - 1) * pageSize;
    
    try {
        Connection conn = DatabaseUtil.getConnection();
        
        // 构建查询
        String countSql = "SELECT COUNT(*) FROM students";
        String dataSql = "SELECT student_id, name, major, grade FROM students";
        
        if (keyword != null && !keyword.isEmpty()) {
            countSql += " WHERE name LIKE ?";
            dataSql += " WHERE name LIKE ? LIMIT ?, ?";
        } else {
            dataSql += " LIMIT ?, ?";
        }
        
        // 获取总记录数
        PreparedStatement countStmt = conn.prepareStatement(countSql);
        if (keyword != null && !keyword.isEmpty()) {
            countStmt.setString(1, "%" + keyword + "%");
        }
        ResultSet countRs = countStmt.executeQuery();
        countRs.next();
        int totalRecords = countRs.getInt(1);
        int totalPages = (int) Math.ceil((double) totalRecords / pageSize);
        
        // 获取数据
        PreparedStatement dataStmt = conn.prepareStatement(dataSql);
        if (keyword != null && !keyword.isEmpty()) {
            dataStmt.setString(1, "%" + keyword + "%");
            dataStmt.setInt(2, offset);
            dataStmt.setInt(3, pageSize);
        } else {
            dataStmt.setInt(1, offset);
            dataStmt.setInt(2, pageSize);
        }
        
        ResultSet dataRs = dataStmt.executeQuery();
        
        // 构建JSON响应
        List<Map<String, Object>> students = new ArrayList<>();
        while (dataRs.next()) {
            Map<String, Object> student = new HashMap<>();
            student.put("studentId", dataRs.getString("student_id"));
            student.put("name", dataRs.getString("name"));
            student.put("major", dataRs.getString("major"));
            student.put("grade", dataRs.getString("grade"));
            students.add(student);
        }
        
        Map<String, Object> response = new HashMap<>();
        response.put("students", students);
        response.put("totalPages", totalPages);
        response.put("currentPage", page);
        response.put("totalRecords", totalRecords);
        
        // 使用Gson库转换为JSON
        Gson gson = new Gson();
        out.print(gson.toJson(response));
        
        // 关闭资源
        DatabaseUtil.close(conn, countStmt, countRs);
        DatabaseUtil.close(conn, dataStmt, dataRs);
        
    } catch (Exception e) {
        Map<String, Object> error = new HashMap<>();
        error.put("error", e.getMessage());
        Gson gson = new Gson();
        out.print(gson.toJson(error));
    }
%>

6.2 微服务架构中的JSP

在现代微服务架构中,JSP可以作为API网关的一部分:

<%@ page import="java.net.*, java.io.*, com.google.gson.*" %>
<%@ page contentType="application/json;charset=UTF-8" %>
<%
    // API网关示例:转发请求到微服务
    String service = request.getParameter("service");
    String endpoint = request.getParameter("endpoint");
    
    if (service == null || endpoint == null) {
        out.print("{\"error\": \"缺少参数\"}");
        return;
    }
    
    // 根据服务名称路由到不同的微服务
    String serviceUrl = "";
    switch (service) {
        case "student":
            serviceUrl = "http://localhost:8081/student/" + endpoint;
            break;
        case "course":
            serviceUrl = "http://localhost:8082/course/" + endpoint;
            break;
        case "exam":
            serviceUrl = "http://localhost:8083/exam/" + endpoint;
            break;
        default:
            out.print("{\"error\": \"未知服务\"}");
            return;
    }
    
    // 转发请求
    try {
        URL url = new URL(serviceUrl);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        
        // 复制请求头
        String authHeader = request.getHeader("Authorization");
        if (authHeader != null) {
            conn.setRequestProperty("Authorization", authHeader);
        }
        
        // 读取响应
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(conn.getInputStream()));
        String line;
        StringBuilder response = new StringBuilder();
        
        while ((line = reader.readLine()) != null) {
            response.append(line);
        }
        reader.close();
        
        // 返回响应
        out.print(response.toString());
        
    } catch (Exception e) {
        out.print("{\"error\": \"" + e.getMessage() + "\"}");
    }
%>

七、实际案例分析:在线课程注册系统

7.1 系统架构设计

在线课程注册系统架构:
1. 前端层:JSP页面 + HTML/CSS/JavaScript
2. 控制层:Servlet处理请求
3. 业务层:JavaBean处理业务逻辑
4. 数据层:JDBC + MySQL数据库
5. 安全层:Session管理 + 权限控制

7.2 核心功能实现

7.2.1 学生注册与登录

<%@ page import="java.sql.*, java.security.MessageDigest, java.math.BigInteger" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    // 登录处理
    if ("POST".equalsIgnoreCase(request.getMethod())) {
        String studentId = request.getParameter("studentId");
        String password = request.getParameter("password");
        
        try {
            Connection conn = DatabaseUtil.getConnection();
            
            // 验证用户
            String sql = "SELECT student_id, name, password FROM students WHERE student_id = ?";
            PreparedStatement stmt = conn.prepareStatement(sql);
            stmt.setString(1, studentId);
            ResultSet rs = stmt.executeQuery();
            
            if (rs.next()) {
                String storedPassword = rs.getString("password");
                String hashedInput = hashPassword(password);
                
                if (storedPassword.equals(hashedInput)) {
                    // 登录成功,设置session
                    session.setAttribute("studentId", studentId);
                    session.setAttribute("name", rs.getString("name"));
                    session.setAttribute("role", "student");
                    
                    // 重定向到学生主页
                    response.sendRedirect("student_dashboard.jsp");
                    return;
                }
            }
            
            out.println("<h3>登录失败:用户名或密码错误</h3>");
            out.println("<a href='login.jsp'>返回登录</a>");
            
            DatabaseUtil.close(conn, stmt, rs);
            
        } catch (Exception e) {
            out.println("错误:" + e.getMessage());
        }
    } else {
        // 显示登录表单
%>
<!DOCTYPE html>
<html>
<head>
    <title>学生登录</title>
</head>
<body>
    <h1>学生登录</h1>
    <form action="login.jsp" method="post">
        <table>
            <tr>
                <td>学号:</td>
                <td><input type="text" name="studentId" required></td>
            </tr>
            <tr>
                <td>密码:</td>
                <td><input type="password" name="password" required></td>
            </tr>
            <tr>
                <td colspan="2">
                    <input type="submit" value="登录">
                </td>
            </tr>
        </table>
    </form>
    <p>没有账号?<a href="register.jsp">立即注册</a></p>
</body>
</html>
<%
    }
%>

7.2.2 课程选择与退选

<%@ page import="java.sql.*" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    // 检查登录状态
    String studentId = (String) session.getAttribute("studentId");
    if (studentId == null) {
        response.sendRedirect("login.jsp");
        return;
    }
    
    // 处理选课请求
    String action = request.getParameter("action");
    String courseId = request.getParameter("courseId");
    
    if (action != null && courseId != null) {
        try {
            Connection conn = DatabaseUtil.getConnection();
            
            if ("enroll".equals(action)) {
                // 选课
                // 检查是否已选
                String checkSql = "SELECT * FROM enrollment WHERE student_id = ? AND course_id = ?";
                PreparedStatement checkStmt = conn.prepareStatement(checkSql);
                checkStmt.setString(1, studentId);
                checkStmt.setString(2, courseId);
                ResultSet checkRs = checkStmt.executeQuery();
                
                if (checkRs.next()) {
                    out.println("<h3>您已经选过该课程</h3>");
                } else {
                    // 检查课程容量
                    String capacitySql = "SELECT current_enrollment, max_capacity FROM courses WHERE course_id = ?";
                    PreparedStatement capStmt = conn.prepareStatement(capacitySql);
                    capStmt.setString(1, courseId);
                    ResultSet capRs = capStmt.executeQuery();
                    
                    if (capRs.next()) {
                        int current = capRs.getInt("current_enrollment");
                        int max = capRs.getInt("max_capacity");
                        
                        if (current < max) {
                            // 插入选课记录
                            String enrollSql = "INSERT INTO enrollment (student_id, course_id, enroll_time) VALUES (?, ?, NOW())";
                            PreparedStatement enrollStmt = conn.prepareStatement(enrollSql);
                            enrollStmt.setString(1, studentId);
                            enrollStmt.setString(2, courseId);
                            enrollStmt.executeUpdate();
                            
                            // 更新课程当前人数
                            String updateSql = "UPDATE courses SET current_enrollment = current_enrollment + 1 WHERE course_id = ?";
                            PreparedStatement updateStmt = conn.prepareStatement(updateSql);
                            updateStmt.setString(1, courseId);
                            updateStmt.executeUpdate();
                            
                            out.println("<h3>选课成功!</h3>");
                            
                            DatabaseUtil.close(null, enrollStmt, null);
                            DatabaseUtil.close(null, updateStmt, null);
                        } else {
                            out.println("<h3>课程已满,无法选课</h3>");
                        }
                    }
                    
                    DatabaseUtil.close(null, capStmt, capRs);
                }
                
                DatabaseUtil.close(null, checkStmt, checkRs);
                
            } else if ("drop".equals(action)) {
                // 退课
                String dropSql = "DELETE FROM enrollment WHERE student_id = ? AND course_id = ?";
                PreparedStatement dropStmt = conn.prepareStatement(dropSql);
                dropStmt.setString(1, studentId);
                dropStmt.setString(2, courseId);
                int rows = dropStmt.executeUpdate();
                
                if (rows > 0) {
                    // 更新课程当前人数
                    String updateSql = "UPDATE courses SET current_enrollment = current_enrollment - 1 WHERE course_id = ?";
                    PreparedStatement updateStmt = conn.prepareStatement(updateSql);
                    updateStmt.setString(1, courseId);
                    updateStmt.executeUpdate();
                    
                    out.println("<h3>退课成功!</h3>");
                    
                    DatabaseUtil.close(null, updateStmt, null);
                } else {
                    out.println("<h3>退课失败,未找到选课记录</h3>");
                }
                
                DatabaseUtil.close(null, dropStmt, null);
            }
            
            DatabaseUtil.close(conn, null, null);
            
        } catch (Exception e) {
            out.println("错误:" + e.getMessage());
        }
        
        out.println("<a href='course_selection.jsp'>返回选课页面</a>");
        return;
    }
    
    // 显示可选课程列表
    try {
        Connection conn = DatabaseUtil.getConnection();
        
        // 获取已选课程
        String enrolledSql = "SELECT c.course_id, c.course_name, c.teacher, c.credit " +
                            "FROM courses c JOIN enrollment e ON c.course_id = e.course_id " +
                            "WHERE e.student_id = ?";
        PreparedStatement enrolledStmt = conn.prepareStatement(enrolledSql);
        enrolledStmt.setString(1, studentId);
        ResultSet enrolledRs = enrolledStmt.executeQuery();
        
        // 获取可选课程(未选且未满)
        String availableSql = "SELECT course_id, course_name, teacher, credit, current_enrollment, max_capacity " +
                             "FROM courses " +
                             "WHERE course_id NOT IN (SELECT course_id FROM enrollment WHERE student_id = ?) " +
                             "AND current_enrollment < max_capacity";
        PreparedStatement availableStmt = conn.prepareStatement(availableSql);
        availableStmt.setString(1, studentId);
        ResultSet availableRs = availableStmt.executeQuery();
%>
<!DOCTYPE html>
<html>
<head>
    <title>课程选择</title>
    <style>
        table { border-collapse: collapse; width: 100%; margin-bottom: 20px; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        th { background-color: #4CAF50; color: white; }
        .enrolled { background-color: #e8f5e8; }
        .available { background-color: #fff3cd; }
    </style>
</head>
<body>
    <h1>课程选择系统</h1>
    
    <h2>已选课程</h2>
    <table class="enrolled">
        <tr>
            <th>课程编号</th>
            <th>课程名称</th>
            <th>教师</th>
            <th>学分</th>
            <th>操作</th>
        </tr>
        <%
            while (enrolledRs.next()) {
        %>
        <tr>
            <td><%= enrolledRs.getString("course_id") %></td>
            <td><%= enrolledRs.getString("course_name") %></td>
            <td><%= enrolledRs.getString("teacher") %></td>
            <td><%= enrolledRs.getInt("credit") %></td>
            <td>
                <a href="course_selection.jsp?action=drop&courseId=<%= enrolledRs.getString("course_id") %>"
                   onclick="return confirm('确定要退选这门课程吗?')">退选</a>
            </td>
        </tr>
        <%
            }
        %>
    </table>
    
    <h2>可选课程</h2>
    <table class="available">
        <tr>
            <th>课程编号</th>
            <th>课程名称</th>
            <th>教师</th>
            <th>学分</th>
            <th>当前人数/容量</th>
            <th>操作</th>
        </tr>
        <%
            while (availableRs.next()) {
                int current = availableRs.getInt("current_enrollment");
                int max = availableRs.getInt("max_capacity");
        %>
        <tr>
            <td><%= availableRs.getString("course_id") %></td>
            <td><%= availableRs.getString("course_name") %></td>
            <td><%= availableRs.getString("teacher") %></td>
            <td><%= availableRs.getInt("credit") %></td>
            <td><%= current %>/<%= max %></td>
            <td>
                <a href="course_selection.jsp?action=enroll&courseId=<%= availableRs.getString("course_id") %>"
                   onclick="return confirm('确定要选这门课程吗?')">选课</a>
            </td>
        </tr>
        <%
            }
        %>
    </table>
    
    <p><a href="student_dashboard.jsp">返回学生主页</a></p>
</body>
</html>
<%
        DatabaseUtil.close(conn, enrolledStmt, enrolledRs);
        DatabaseUtil.close(conn, availableStmt, availableRs);
        
    } catch (Exception e) {
        out.println("错误:" + e.getMessage());
    }
%>

7.2.3 成绩查询与统计

<%@ page import="java.sql.*, java.text.DecimalFormat" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    // 检查登录状态
    String studentId = (String) session.getAttribute("studentId");
    if (studentId == null) {
        response.sendRedirect("login.jsp");
        return;
    }
    
    try {
        Connection conn = DatabaseUtil.getConnection();
        
        // 获取成绩信息
        String sql = "SELECT c.course_name, c.teacher, c.credit, r.score, r.exam_date " +
                    "FROM exam_results r " +
                    "JOIN courses c ON r.course_id = c.course_id " +
                    "WHERE r.student_id = ? " +
                    "ORDER BY r.exam_date DESC";
        
        PreparedStatement stmt = conn.prepareStatement(sql);
        stmt.setString(1, studentId);
        ResultSet rs = stmt.executeQuery();
        
        // 计算统计信息
        int totalCourses = 0;
        int totalCredits = 0;
        double totalScore = 0;
        double gpa = 0;
        
        DecimalFormat df = new DecimalFormat("#.##");
        
        // 先遍历一次计算统计
        ResultSet rsCopy = rs;
        while (rsCopy.next()) {
            totalCourses++;
            totalCredits += rsCopy.getInt("credit");
            totalScore += rsCopy.getInt("score");
        }
        
        if (totalCourses > 0) {
            gpa = totalScore / totalCourses;
        }
        
        // 重新执行查询用于显示
        rs = stmt.executeQuery();
%>
<!DOCTYPE html>
<html>
<head>
    <title>成绩查询</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        .stats { background-color: #f0f0f0; padding: 15px; margin-bottom: 20px; border-radius: 5px; }
        table { border-collapse: collapse; width: 100%; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        th { background-color: #4CAF50; color: white; }
        .score-high { color: green; font-weight: bold; }
        .score-medium { color: orange; }
        .score-low { color: red; }
    </style>
</head>
<body>
    <h1>成绩查询系统</h1>
    
    <div class="stats">
        <h2>成绩统计</h2>
        <p><strong>总修课程数:</strong> <%= totalCourses %> 门</p>
        <p><strong>总修学分:</strong> <%= totalCredits %> 学分</p>
        <p><strong>平均成绩:</strong> <%= df.format(gpa) %> 分</p>
        <p><strong>GPA:</strong> <%= calculateGPA(gpa) %></p>
    </div>
    
    <h2>成绩详情</h2>
    <table>
        <tr>
            <th>课程名称</th>
            <th>教师</th>
            <th>学分</th>
            <th>成绩</th>
            <th>考试日期</th>
            <th>等级</th>
        </tr>
        <%
            while (rs.next()) {
                String courseName = rs.getString("course_name");
                String teacher = rs.getString("teacher");
                int credit = rs.getInt("credit");
                int score = rs.getInt("score");
                String examDate = rs.getString("exam_date");
                
                String scoreClass = "score-medium";
                String grade = "C";
                
                if (score >= 90) {
                    scoreClass = "score-high";
                    grade = "A";
                } else if (score >= 80) {
                    grade = "B";
                } else if (score >= 70) {
                    grade = "C";
                } else if (score >= 60) {
                    grade = "D";
                } else {
                    scoreClass = "score-low";
                    grade = "F";
                }
        %>
        <tr>
            <td><%= courseName %></td>
            <td><%= teacher %></td>
            <td><%= credit %></td>
            <td class="<%= scoreClass %>"><%= score %></td>
            <td><%= examDate %></td>
            <td><%= grade %></td>
        </tr>
        <%
            }
        %>
    </table>
    
    <p><a href="student_dashboard.jsp">返回学生主页</a></p>
</body>
</html>
<%
        DatabaseUtil.close(conn, stmt, rs);
        
    } catch (Exception e) {
        out.println("错误:" + e.getMessage());
    }
%>

<%!
    // 辅助方法:计算GPA等级
    public String calculateGPA(double gpa) {
        if (gpa >= 90) return "4.0";
        else if (gpa >= 80) return "3.0";
        else if (gpa >= 70) return "2.0";
        else if (gpa >= 60) return "1.0";
        else return "0.0";
    }
%>

八、JSP在教育系统中的挑战与解决方案

8.1 性能瓶颈问题

问题:JSP页面中直接嵌入Java代码可能导致性能问题,特别是在高并发场景下。

解决方案:

  1. 使用连接池:避免频繁创建数据库连接
  2. 缓存机制:缓存常用数据
  3. 代码优化:避免在JSP中执行复杂业务逻辑
  4. 异步处理:使用AJAX减少页面刷新

8.2 安全性问题

问题:JSP页面容易受到SQL注入、XSS攻击等安全威胁。

解决方案:

  1. 使用预编译语句:防止SQL注入
  2. 输入验证:对用户输入进行严格验证
  3. 输出编码:防止XSS攻击
  4. 会话管理:使用安全的会话管理机制
  5. HTTPS:使用加密传输

8.3 代码维护问题

问题:JSP页面中混合HTML和Java代码,导致维护困难。

解决方案:

  1. 采用MVC模式:分离业务逻辑和视图
  2. 使用自定义标签库:减少Java代码
  3. 代码规范:制定统一的编码规范
  4. 模块化设计:将功能模块化

九、未来展望

9.1 与Spring Boot的集成

现代教育系统越来越多地采用Spring Boot框架,JSP可以作为视图层与Spring Boot集成:

// Spring Boot配置类
@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        resolver.setViewClass(JstlView.class);
        return resolver;
    }
    
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/resources/");
    }
}

9.2 云原生部署

JSP应用可以部署在云环境中,利用云服务的弹性伸缩能力:

# Dockerfile示例
FROM tomcat:9.0-jdk11

# 复制应用
COPY target/education-system.war /usr/local/tomcat/webapps/

# 复制配置文件
COPY src/main/resources/application.properties /usr/local/tomcat/conf/

# 暴露端口
EXPOSE 8080

# 启动Tomcat
CMD ["catalina.sh", "run"]

十、总结

JSP技术在教育系统的动态网页开发和数据交互中发挥着重要作用。通过本文的详细分析和示例代码,我们可以看到:

  1. JSP的优势:动态内容生成、与Java生态集成、MVC模式支持
  2. 实际应用:学生信息管理、课程选择、在线考试、成绩查询等
  3. 最佳实践:安全性、性能优化、代码组织
  4. 现代发展:与前端框架集成、微服务架构、云原生部署

尽管现代Web开发中出现了许多新技术,但JSP在教育系统中仍然具有重要价值,特别是在需要快速开发、与现有Java系统集成、以及处理复杂业务逻辑的场景中。通过合理的设计和优化,JSP可以构建出高效、安全、可维护的教育系统。

对于教育机构而言,选择JSP技术意味着可以利用成熟的Java生态系统,获得稳定的性能和良好的扩展性,同时降低开发和维护成本。随着技术的不断发展,JSP也在不断演进,与现代技术栈的融合将为其在教育系统中的应用开辟更广阔的前景。