排课、选课系统——JSP与数据库设计

缘起是,在数据库实践课程上我们选择做“兴趣班排课系统”,并做页面设计。

开发工具:

        NetBeans 14(Tomcat8.5,JDK11)

        MySQL 5.7.19

目录

一:实现功能

二:项目运行的前置条件(配置)

三:高复用与核心代码

四:表结构与表的建立

五:登录、注册功能

六:机构管理员功能实现

七:教师相关操作实现

八:学生相关操作实现

九:教务员相关操作实现

十:总结

十一:项目文件结构与提取



一:实现功能

1.登录、注册功能

2.机构管理员相关操作(机构管理员是兴趣班的最高权限者)

        (1)教师信息管理(添加教师信息、修改教师信息)

        (2)教务员信息管理(添加教师信息、修改教师信息)

        (3)退费管理(对学生申请的退课退费申请进行处理)        

        (4)个人中心(查询与修改)

3.教师相关操作

        (1)显示教师的课(教务员排课后发布的课,发布后不可在页面进行退课)

        (2)教师空闲时间(教师空闲时间表一学期换,教师在此设置自己的空闲时间方便教务员排课)

        (3)个人中心(查询与修改)

4.学生相关操作

        (1)课程查询(先选科目类别,再进行选课,已选的课不能重复选课,已选择的课要申请退课才能退课)

        (2)我的课表(需要选择学期;如果想退课,可以点击课程进行申请)

        (3)申请退课(在申请课程后,申请信息会出现现在这里,还有机构管理员的处理结果)

        (4)个人中心(查询与修改) 

5.教务员相关操作

        (1)学生信息管理(查询与修改)

        (2)教室信息管理(查询与修改,方便排课)

        (3)排课(下拉选择学期,点击对应的节次进入排课和修改,排好后点击“发布!”)

        (4)教室信息查询(只能查询不能修改,方便排课)

        (5)个人中心(查询与修改)

二:项目运行的前置条件(配置)

1.配置Tomcat,参考:

NetBeans配置Tomcat-CSDN博客

2.mysql安装与使用和Navicat工具激活

(1)mysql安装与使用

        在官网安装即可,但是需要注意,在jdbc连接mysql时需要下载mysql的connector/J包,如果下的版本不一致可能造成不适配的情况。

        我这里的mysql是5.7.19,连接包是mysql-connector-j-8.2.0.jar

Netbeans + MySQL-CSDN博客

(2)Navicat Premium工具(MySQL可视化工具)

        这里要先说明一下,有条件支持正版!

        

三:高复用与核心代码

1.数据库层次:

        (1)jsp界面头部的导入工具包

<%@page import="java.sql.ResultSet"%>
<%@page import="java.sql.PreparedStatement"%>
<%@page import="java.sql.DriverManager"%>
<%@page import="java.sql.Connection"%>

        (2)连接数据库与之操作:

Class.forName("com.mysql.jdbc.Driver");  //加载驱动
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/homework", "root", "alfo123456");//这里是本地连接,数据库名是homework,账号是root,密码是alfo123456
String sql = "SELECT * FROM `USER` WHERE LoginID=? AND PASSWORD=?";//这里写sql语句,对于要赋值的变量用“?”代替
PreparedStatement ps = conn.prepareStatement(sql);//PreparedStatement是Java中的一个接口,用于执行预编译的SQL语句,这里创建一个它的实例,名叫ps
ps.setString(1, id);//给前面sql语句要赋值的变量赋值,如果是int是ps.setInt(1,XXX);
ps.setString(2, password);
ResultSet rs = ps.executeQuery();//执行查询语句并把结果赋值给rs,ResultSet是Java的一个接口,用于表示执行数据库操作的结果集。需要注意如果是增删改查操作是ps.executeUpdate();

int user_id = 0;
String user_name = "";
if(rs.next()){    //这里请做rs.next()操作,因为rs指针本来指向空,rs.next()相当于把rs指针右移一位,不然会报错!同理的如果查询结果为多行值,可以用while(rs.next())......数据结构用Java的集合列表ArrayList
    user_id = rs.getInt("UserID");
    user_name = rs.getString("UserName");
}
    

2.HTML高复用模块:

(1)课表模板

<table class="the_table" id="the_table">
                <div style="display:flex; justify-content: center; align-items: center;">
                <tr class="week_tr">
                    <td></td> <!-- 空白单元格 -->
                    <% for (int i = 0; i < weeks.length; i++) {%>
                    <td><%= weeks[i]%></td> <!-- 显示周次 -->
                    <% } %>
                </tr>
                <% for (int i = 1; i < times.length + 1; i++) {%>
                <!--改用数据库的section,这里调整的比较多-->
                <tr>
                    <td class="section_no"><%= times[i - 1]%></td> <!-- 显示节次 -->
                    <% for (int j = 1; j < weeks.length + 1; j++) {
                            //这里添加自己代码
                    %>
                    <td id="cell_<%= (i)%>_ <%= (j)%>" class="<%= cellClass%>"><%= cellText%></td>
                    <% } %>
                </tr>
                <% }%>
            </div>
</table>
//这里实现的功能是渲染一个课表,table等结构的样式可以在<style>添加。
//这里有周和节次两个数组,分别存放库中一周有几天和一天有几个节次。weeks.length=7,times.length=6,对应周一到周日,早上第一节课到晚上最后一节课

实现效果如下(我这里自己代码是进行数据库该教师课程的查询)

(2)“修改”和“添加”信息的提交表单的次级页面

<div id="classroomModal" class="modal">
        <div class="modal-content">
            <div class="form_title">修改教室信息</div>

            <form action="change_classroom_form.jsp" method="post" class="the_form">
                <!-- 这里放置你的表单内容 -->
                <input type="hidden" id="classroom_id" name="classroom_id">
                //这里设置类型为hidden,说明只传内容,不显示
                <div class="details">
                    <label for="classroom_name">教室名称:</label>
                    <input type="text" id="classroom_name" name="classroom_name">
                </div>
                <br>
                <div class="details">
                    <label for="classroom_location">教室位置:</label>
                    <input type="text" id="classroom_location" name="classroom_location">
                </div>
                <br>
                <div class="details">
                    <label for="locked_time">占用时间:</label>
                    <input type="text" id="locked_time" name="locked_time">
                </div>
                <br> 
                <div class="details">
                    <label for="locked_task_name">占用事项:</label>
                    <input type="text" id="locked_task_name" name="locked_task_name">
                </div>
                <br> 

                <input type="submit" value="提交">
                <input type="button" value="取消" onclick="closeClassroomModal()">
            </form>
        </div>
</div>
//通过点击事件触发(js处理)后,可以打开这个次级页面(设置宽高),同时传递信息,提交后把信息传递到目标jsp文件进行处理(这里是change_classroom_form.jsp),取消后调用函数(这里是closeClassroomModal())关闭

实现效果如下

这里顺便吧用到的js代码带上

 //classroom_manage's functions
function closeClassroomModal() {
    document.getElementById('classroomModal').style.display = 'none';
}
function openClassroomModal(classroom_id, classroom_name, classroom_location, locked_time, locked_task_name) {
    //这里要指定前面打开的模块id:classroomModal
    document.getElementById('classroomModal').style.display = 'block';
    //这里传参数,做到点击“修改”就有信息而不是重新输入(比如名字已经出现在了输入框)
    document.getElementById('classroom_id').value = classroom_id;
    document.getElementById('classroom_name').value = classroom_name; 
    document.getElementById('classroom_location').value = classroom_location;
    document.getElementById('locked_time').value = locked_time;
    document.getElementById('locked_task_name').value = locked_task_name;
//                console.log("click it once!");//用于调试
}

3.Java代码复用

(1)渲染内容(本质还是html了这里)

// Print the results in a table
out.print("<table class='table_info' border='1'>");
out.print("<tr><th>教室编号</th><th>教室名称</th><th>教室位置</th><th>占用时间</th><th>占用事项</th><th>更改</th></tr>");
for (int i = 0; i < classroom_id.size(); i++) {
    out.print("<tr class='tr_info'>");
    out.print("<td id='name-" + i + "'>" + classroom_id.get(i) + "</td>");
    out.print("<td id='sex-" + i + "'>" + classroom_name.get(i) + "</td>");
    out.print("<td id='age-" + i + "'>" + classroom_location.get(i) + "</td>");
    out.print("<td id='phone-" + i + "'>" + locked_time.get(i) + "</td>");
    out.print("<td id='phone-" + i + "'>" + locked_task_name.get(i) + "</td>");
    out.print("<td><button href='javascript:void(0)' "
            + "onclick=\"openClassroomModal('" + classroom_id.get(i) + "','" + classroom_name.get(i) + "','" + classroom_location.get(i) + "','" + locked_time.get(i) + "','" + locked_task_name.get(i) + "')\">"
            + "修改</button></td>"
    );//此处Javascript.void(0)不执行任何操作,只说明执行后面的JavaScript代码
    out.print("</tr>");
}
out.print("</table>");
//实现的其实就是对要查询的数据进行遍历输出
//点击“修改”后,调用js函数进行修改

实现效果:(这里渲染库里的教室信息,变量值前面已经获取)

(2)在进行数据库请求的时候,要做防止乱码的操作:

4.JS代码复用(这里主要是函数)

提要:如果有的方法用不了,尤其是异步传参等,请在文件的<head>下添加以下代码

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

(1)点击事件后的页面跳转:

function showIt(term) {
        console.log(term);
        if (confirm("是否确认公布?")) {
            var xhttp = new XMLHttpRequest();
            xhttp.onreadystatechange = function () {
                if (this.readyState === 4 && this.status === 200) {
                    // 刷新页面以更新数据(不跳转)
                    location.reload();
                }
            };
            xhttp.open("GET", "showIT.jsp?term=" + term, true);  // 替换为你的showIT.jsp的路径
            xhttp.send();
         } else {
            // 如果取消则关闭弹出框
            // 需要注意的是,在 `confirm` 弹出框中点击取消会自动关闭弹出框,你不需要写额外的代码来关闭它
         }
    }
//这个函数在点击“公布!”后触发,会弹出窗口提示“是否确认公布?”
//如果结果是true,会跳转页面到showIT.jsp页面(这个页面把学期为term的课程是否发布属性设为1),同时吧term作为参数传过去
//如果是传两个参数:xhttp.open("GET", "showIT.jsp?term="+ term + "&var2_name=" +var2, true);
//如果希望跳转而不是刷新页面:应该是这样:window.location.href = "showIT.jsp?term=" + term + "&var2_name=" + var2;

(2)打开次级页面(常用于提交表单)

function closeClassroomModal() {
    document.getElementById('classroomModal').style.display = 'none';
}
function openClassroomModal(classroom_id, classroom_name, classroom_location, locked_time, locked_task_name) {
    document.getElementById('classroomModal').style.display = 'block';
    document.getElementById('classroom_id').value = classroom_id;
    document.getElementById('classroom_name').value = classroom_name; 
    document.getElementById('classroom_location').value = classroom_location;
    document.getElementById('locked_time').value = locked_time;
    document.getElementById('locked_task_name').value = locked_task_name;
//                console.log("click it once!");
}
//这里在上面已经解释过了,如果希望该开始没有显示内容只保留第一行就行了

(3)选择学期并渲染表格(比如选择第一学期,则表格同步刷新为第一学期的课)

function changeSemester(semester) {
    // 发送请求或执行其他逻辑来获取对应学期的课程数据
    var semesterSelect = document.getElementById("semesterSelect");
    console.log(semesterSelect);
    var semester = semesterSelect.value;
    console.log("this is a line!");
    console.log(semester);
    $.ajax({
        url: "course_plan.jsp",    //请求来自该页面
        type: "GET",
        data: {
             semester: semester
        },
        success: function (response) {
             var selectedSemester = semesterSelect.value;
             refreshTable(selectedSemester);    //获取成功则同步渲染表格
        }
    });
}
function refreshTable(semester) {
    $.ajax({
         url: "course_table.jsp",    //这里是渲染课程的表格的jsp页面
         method: "GET",
         data: {
              semester: semester
         },
         success: function (response) {
              $("#the_table").html(response);    //把course_table.jsp文件当成一个整体
         },
         error: function () {
              // 处理错误情况
         }
   });
 }

四:表结构与表的建立

1.表结构设计如下:

此处需要注意:

(1)主键需要是单列的,可以提高连接和查询的效率(使用逻辑主键解决,即使它无意义)

(2)在设计表名字时,要做到直观(见字如面);同时如果与库中原有的表名相同,则要避免或在使用的时候用“  `  ”引起来(ESC的下面按键)

(3)避免使用外键(使用逻辑外键,在库内不使用,但都认为它是外键,

  KEY `idx_user_id` (`user_id`),而不是

FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)

2.表结构代码:

CREATE DATABASE homework

CREATE TABLE USER(
	UserID INT NOT NULL AUTO_INCREMENT,
	UserName VARCHAR(10) NOT NULL,
	UserSex ENUM('男','女') DEFAULT '男' NOT NULL,
	UserAge INT NOT NULL,
	UserPhone VARCHAR(11) NOT NULL,
    LoginID VARCHAR(20) NOT NULL,
    `Password` VARCHAR(20) NOT NULL,
	Identity ENUM('学生','教师','教务员','机构管理员') NOT NULL,
	PRIMARY KEY(UserID)
)

CREATE TABLE TEACHER(
 TeacherID INT NOT NULL AUTO_INCREMENT, 
 TeacherName VARCHAR(10) NOT NULL, 
 TeacherAge INT NOT NULL, 
 TeacherSex ENUM('男','女') DEFAULT '男' NOT NULL, 
 TeacherPhone VARCHAR(11) NOT NULL, 
 PRIMARY KEY(TeacherID) 
) ENGINE = INNODB DEFAULT CHARSET=UTF8;

CREATE TABLE `SUBJECT`(
	SubjectID INT NOT NULL AUTO_INCREMENT,
	TeacherID INT NOT NULL,
	SubjectType VARCHAR(10) NOT NULL,
	SubjectName VARCHAR(10) NOT NULL,
	PRIMARY KEY(SubjectID),
	KEY IdxTeacherID (TeacherID)
	) ENGINE = INNODB DEFAULT CHARSET=UTF8; 

CREATE TABLE LEISURE(
	ID INT NOT NULL AUTO_INCREMENT,
	SectionNo VARCHAR(4) NOT NULL,
	TeacherID INT NOT NULL,
	PRIMARY KEY(ID),
	KEY IdxSectionNO(SectionNo),
	KEY IdxTeacherID(TeacherID)
)	ENGINE = INNODB DEFAULT CHARSET=UTF8;

CREATE TABLE SECTION(
	SectionNo VARCHAR(4) NOT NULL,
	WeekNo VARCHAR(2) NOT NULL,
	TimePeriod VARCHAR(10) NOT NULL,
	PRIMARY KEY(SectionNo)
)	ENGINE = INNODB DEFAULT CHARSET=UTF8;

CREATE TABLE COURSE(
	CourseID INT NOT NULL AUTO_INCREMENT,
	SubjectID INT  NOT NULL,
	ClassroomID INT NOT NULL,
	TeacherID INT NOT NULL,
	SectionNo VARCHAR(4) NOT NULL,
	Term VARCHAR(6) NOT NULL,
    Status TINYINT(1) DEFAULT 0,
    IsShow TINYINT(1) DEFAULT 0,
	PRIMARY KEY(CourseID),
	KEY IdxSubjectID(SubjectID),
	KEY IdxClassroomID(ClassroomID),
	KEY IdxTeacherID(TeacherID),
	KEY IdxSectionNo(SectionNo)
) ENGINE = INNODB DEFAULT CHARSET=UTF8;

CREATE TABLE CLASSROOM(
	ClassroomID INT NOT NULL AUTO_INCREMENT,
	ClassroomName VARCHAR(20) NOT NULL,
	ClassroomLocation VARCHAR(30) NOT NULL,
	PRIMARY KEY(ClassroomID)
) ENGINE = INNODB DEFAULT CHARSET=UTF8;

CREATE TABLE CLASSROOMARRANGE(
	ID INT NOT NULL AUTO_INCREMENT,
	ClassroomID INT NOT NULL,
	LockedTime DATETIME DEFAULT CURRENT_TIMESTAMP,
	LockedTaskName VARCHAR(50) NOT NULL,
	PRIMARY KEY(ID),
	KEY IdxClassroomID(ClassroomID)
) ENGINE = INNODB DEFAULT CHARSET = UTF8;

CREATE TABLE STUDENT(
	StudentID INT NOT NULL AUTO_INCREMENT,
	StudentName VARCHAR(10) NOT NULL,
	StudentSex ENUM('男','女') DEFAULT '男' NOT NULL,
	StudentAge INT NOT NULL,
	StudentPhone VARCHAR(11) NOT NULL,
	PRIMARY KEY(StudentID)
) ENGINE = INNODB DEFAULT CHARSET=UTF8;

CREATE TABLE SIGNUP(
	ID INT NOT NULL AUTO_INCREMENT,
	CourseID INT NOT NULL,
	StudentID INT NOT NULL,
	SignUpTime DATETIME DEFAULT CURRENT_TIMESTAMP(),
	PayOrNot TINYINT(1) DEFAULT 0,
	PRIMARY KEY(ID),
	KEY IdxCourseID(CourseID),
	KEY IdxStudentID(StudentID)
) ENGINE = INNODB DEFAULT CHARSET=UTF8;

CREATE TABLE RETURNAPPLY(
	ApplyID INT NOT NULL AUTO_INCREMENT,
	SignUpID INT NOT NULL,
	ApprovalStatus TINYINT(1) DEFAULT 0,
    ApprovalResult VARCHAR(3) DEFAULT '未审批',
	PRIMARY KEY(ApplyID),
	KEY IdxSignUpID(SignUpID)
) ENGINE = INNODB DEFAULT CHARSET=UTF8;

这里笔者找的是最早的版本并进行了一些修改,不保证一定对,各位可以一条一条执行,同时修改为自己想要的类型

建成之后应该是这样的

五:登录、注册功能

(1)登录:这里本质就是一个表单操作和数据库查询操作

此处需要注意Tomcat的入口文件默认是index.jsp文件(改的话需要在conf文件修改),我这里直接把登录界面命名为index.jsp(不然运行项目会出现404)

核心代码:

<div id="a">
    <h1>登录界面</h1>
    <!--此处的check.jsp需要重写,分权限-->
    <form action="" method="post">
        账号:<input type="text" name="id"/>
        <br>
        密码:<input type="password"name="password"/>
        <br>
        <input type="submit" value="login"/>
        没有账号?<a href ="Register.jsp">注册账号</a>
    </form>
</div>

还有就是如果账号不为空时进行身份判别,跳转不同页面,同时传递user_id(方便后期数据处理)

if (identity.equals("学生")) {
    //传传传传参
    session.setAttribute("UserID", user_id);    //名字可能改,传id
    session.setAttribute("UserName", user_name);
    response.sendRedirect("./Student-Web/Student.jsp");    //跳转页面
} else if (identity.equals("教师")) {
    session.setAttribute("UserID", user_id);    
    session.setAttribute("UserName", user_name); 
    response.sendRedirect("./Teacher-Web/Teacher.jsp");
} else if (identity.equals("教务员")) {
    session.setAttribute("UserID", user_id);   
    session.setAttribute("UserName", user_name); 
    response.sendRedirect("./TeachAdmin-Web/TeachAdmin.jsp");
} else {
    session.setAttribute("UserID", user_id);   
    session.setAttribute("UserName", user_name);
    response.sendRedirect("./OrgAdmin-Web/OrgAdmin.jsp");
}

页面效果:

(2)注册界面:本质也是一个表单

此处需要注意注册默认的身份。我这个项目分四个身份:“机构管理员”、“教务员”、“教师”、“学生”。

我的设计是这样的:“机构管理员”是最高权限者,“学生”是最低,注册默认是“学生”。

“机构管理员”可以注册和管理“教师”、“教务员”信息;“教务员”可以注册和管理“学生信息”,但只能查看“教师”信息。

“教师”和“学生”只能修改和管理自己信息

核心代码:

//先验证是否已存在
String sql = "SELECT * FROM `USER` "
        + "WHERE LoginID=?";
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setString(1, login_id);
        ResultSet rs = ps.executeQuery();
        if (rs.next()) {//如果不为空
        out.println("
<script>alert('账号已存在');</script>");
        } else { //
//插入user表
        sql = "INSERT INTO `user` "
        + "(LoginID, Password, UserName, UserPhone, Identity) VALUES "
        + "(?, ?, ?, ?, ?)";
// PreparedStatement ps = conn.prepareStatement(sql);
        ps = conn.prepareStatement(sql);
        ps.setString(1, login_id);
        ps.setString(2, password);
        ps.setString(3, user_name);
        ps.setString(4, user_phone);
        ps.setString(5, "学生");
        ps.executeUpdate();

//插入学生表
        sql = "INSERT INTO STUDENT "
        + "(StudentName, StudentPhone) "
        + "VALUES (?,?)";
        ps = conn.prepareStatement(sql);
        ps.setString(1, user_name);
        ps.setString(2, user_phone);
        ps.executeUpdate();
        out.println("用户名为:" + login_id + "<br>");

        out.println("用户密码为:" + password + "<br>");

        out.println("姓名为:" + user_name + "<br>");

        out.println("电话号码为:" + user_phone + "<br>");
        %>
        恭喜您注册成功!<br>
<!--                您的账号为:<%=login_id%><br>
        您的密码为:<%=password%><br>-->
        请妥善保管好您的密码!<br>
<% }

效果:

六:机构管理员功能实现

1.主页面设计:

(1)左侧栏:

//左侧选择框,这里确保下面几个jsp文件都在
<div id="sidebar">
    <ul>
        <li><a href="#id=teacher" onclick="loadContent('TeacherManage.jsp')">教师信息管理</a></li>
        <li><a href="#id=teach_admin" onclick="loadContent('TeachAdminManage.jsp')">教务员信息管理</a></li>
        <li><a href="#id=return_apply" onclick="loadContent('ReturnApplyManage.jsp')">退费管理</a></li>
        <li><a href="#id=my_info" onclick="loadContent('MyInfo.jsp')">个人中心</a></li>
        <!-- 添加更多菜单项 -->
    </ul>
</div>

//在进入机构管理员页面的默认跳转页面
<div id="content">
    <!-- 默认显示的主题内容 -->
    <jsp:include page="TeacherManage.jsp" />
</div>

2.教师信息管理 和 教务员信息管理

(1)右上角的“添加教师信息”按钮

//上侧按钮
<button href='javascript:void(0)' onclick="addTeacher()"
            style="display: flex; margin-left: 1060px; height: 35px; margin-bottom: 10px; font-size: 20px">添加教师信息</button>


//在addTeacher()方法除法后,要调出的显示框,同时包含了提交信息
//这里提交后会把信息提交给add_teacher_form.jsp文件
<div id="addModal" class="modal">
    <div class="modal-content">
        <!--<span class="close" onclick="closeModal()">&times;</span>关闭-->
        <div class="form_title">添加教师信息</div>

        <form action="add_teacher_form.jsp" method="post" class="the_form">
            <!-- 这里放置你的表单内容 -->

            <div class="details">
                <label for="teacher_name">姓名:</label>
                <input type="text" name="teacher_name">
            </div>
            <br>
            <div class="details">
                <label for="teacher_sex">性别:</label>
                <input type="text" name="teacher_sex">
            </div>
            <br>
            <div class="details">
                <label for="teacher_age">年龄:</label>
                <input type="text" name="teacher_age">
            </div>
            <br>
            <div class="details">
                <label for="teacher_phone">电话:</label>
                <input type="text" name="teacher_phone">
            </div>
            <br>
            <div class="details">
                <label for="teacher_subject">所教科目:</label>
                <input type="text" name="teacher_subject" placeholder="(多个科目用  、 分割)">
            </div>
            <br>
            <div class="details">
                <label for="teacher_phone">科目类别</label>
                <input type="text" name="teacher_subject_type">
            </div>
            <br>
            <div class="details">
                <label>登录账号:</label>
                <input type="text" name="login_id">
            </div>
            <br>
            <div class="details">
                <label>登录密码:</label>
                <input type="text" name="password">
            </div>


            <input type="submit" value="提交">
            <input type="button" value="取消" onclick="closeAddModal()">
        </form>
    </div>
</div>

用到的方法:

function closeAddModal() {
    document.getElementById('addModal').style.display = 'none';
}

//添加教师按钮
function addTeacher() {
    document.getElementById('addModal').style.display = 'block';
}
//在add_teacher_form.jsp文件中
//这里要注意教师牵涉三个表:“TEACHER”、“`USER`”、“`SUBJECT`”
//在插入学科表时,可能一个教师教多个学科,所以要对字符串进行处理,切分,分别插入
<%
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        
        
        String teacher_name = request.getParameter("teacher_name");
        String teacher_sex = request.getParameter("teacher_sex");
        int teacher_age = Integer.parseInt(request.getParameter("teacher_age"));
        String teacher_phone = request.getParameter("teacher_phone");
        String teacher_subject_name = request.getParameter("teacher_subject");
        String subject_type = request.getParameter("teacher_subject_type");
        String teach_admin_login_id = request.getParameter("login_id");
        String teach_admin_password = request.getParameter("password");

        //连接数据库
        Class.forName("com.mysql.jdbc.Driver");  //加载驱动
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/homework?useUnicode=true&characterEncoding=UTF-8", "root", "Lfy666666");

        //插入`USER`表
        String sql = "INSERT INTO `USER` (UserName,UserSex,UserAge,UserPhone,Identity,LoginID,Password) "
        + "VALUES (?,?,?,?,'教师',?,?)";
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setString(1, teacher_name);
        ps.setString(2, teacher_sex);
        ps.setInt(3, teacher_age);
        ps.setString(4, teacher_phone);
        ps.setString(5, teach_admin_login_id);
        ps.setString(6, teach_admin_password);
        ps.executeUpdate();

        //插入TEACHER表
        sql = "INSERT INTO TEACHER (TeacherName,TeacherSex,TeacherAge,TeacherPhone) "
        + "VALUES (?,?,?,?)";
        ps = conn.prepareStatement(sql);
        ps.setString(1, teacher_name);
        ps.setString(2, teacher_sex);
        ps.setInt(3, teacher_age);
        ps.setString(4, teacher_phone);
        ps.executeUpdate();

        //插入学科表
        sql = "SELECT TeacherID FROM TEACHER WHERE TeacherName=?";
        ps = conn.prepareStatement(sql);
        ps.setString(1, teacher_name);
        ResultSet rs = ps.executeQuery();

        int teacher_id = 0;
        if (rs.next()) {
        teacher_id = rs.getInt("TeacherID");
        }
        String[] teacher_subject_names = teacher_subject_name.split("、");
        for (int i = 0; i < teacher_subject_names.length; i++) {
        sql = "INSERT INTO SUBJECT (TeacherID,SubjectType,SubjectName) "
        + "VALUES (?,?,?)";
        ps = conn.prepareStatement(sql);
        ps.setInt(1, teacher_id);
        ps.setString(2, subject_type);
        ps.setString(3, teacher_subject_names[i]);
        ps.executeUpdate();
        }

        conn.close();
        response.sendRedirect("OrgAdmin.jsp#id=teacher"); // 或者其他你想要重定向到的页面
%>

(2)修改教师功能

首先明白教师信息是这样渲染的

out.print("<table class='table_info' border='1'>");
out.print("<tr><th>姓名</th><th>性别</th><th>年龄</th><th>电话</th><th>所教科目</th><th>更改</th></tr>");
for (int i = 0; i < teacher_id.size(); i++) {
        out.print("<tr class='tr_info'>");
        out.print("<td id='name-" + i + "'>" + teacher_name.get(i) + "</td>");
        out.print("<td id='sex-" + i + "'>" + teacher_sex.get(i) + "</td>");
        out.print("<td id='age-" + i + "'>" + teacher_age.get(i) + "</td>");
        out.print("<td id='phone-" + i + "'>" + teacher_phone.get(i) + "</td>");
        out.print("<td>" + teacher_subject_name.get(i) + "</td>");
        out.print("<td><button href='javascript:void(0)' "
        + "onclick=\"openModal('" + teacher_id.get(i) + "','" + teacher_name.get(i) + "','" + teacher_sex.get(i) + "','" + teacher_age.get(i) + "','" + teacher_phone.get(i) + "','" + teacher_subject_name.get(i) + "','" + teacher_subject_type.get(i) + "')\">"
        + "修改</button></td>"
        );//此处Javascript.void(0)不执行任何操作,只说明执行后面的JavaScript代码
        out.print("</tr>");
}
out.print("</table>");
function openModal(the_teacher_id, the_teacher_name, the_teacher_sex, the_teacher_age, the_teacher_phone, the_teacher_subject, teacher_subject_type) {
    document.getElementById('myModal').style.display = 'block';
    document.getElementById('first_teacher_name_input').value = the_teacher_name;
    document.getElementById('teacher_id_input').value = the_teacher_id; // 将the_teacher_id传递给模态框中的表单input元素
    document.getElementById('teacher_name_input').value = the_teacher_name;
    document.getElementById('teacher_sex_input').value = the_teacher_sex;
    document.getElementById('teacher_age_input').value = the_teacher_age;
    document.getElementById('teacher_phone_input').value = the_teacher_phone;
    document.getElementById('teacher_subject_input').value = the_teacher_subject;
    document.getElementById('teacher_type_input').value = teacher_subject_type;
}

// 关闭模态框
function closeModal() {
    document.getElementById('myModal').style.display = 'none';

弹出的框:

<div id="myModal" class="modal">
    <div class="modal-content">
        <!--<span class="close" onclick="closeModal()">&times;</span>关闭-->
        <div class="form_title">修改教师信息</div>

        <form action="change_teacher_form.jsp" method="post" class="the_form">
            <!-- 这里放置你的表单内容 -->
            <input type="hidden" id="teacher_id_input" name="teacher_id">
            <!-- 这里需要特别注意,教师要保存原姓名,不然`USER`和TEACHER无法同步-->
            <input type="hidden" id="first_teacher_name_input" name="first_teacher_name">
            <div class="details">
                <label for="teacher_name">姓名:</label>
                <input type="text" id="teacher_name_input" name="teacher_name">
            </div>
            <br>
            <div class="details">
                <label for="teacher_sex">性别:</label>
                <input type="text" id="teacher_sex_input" name="teacher_sex">
            </div>
            <br>
            <div class="details">
                <label for="teacher_age">年龄:</label>
                <input type="text" id="teacher_age_input" name="teacher_age">
            </div>
            <br>
            <div class="details">
                <label for="teacher_phone">电话:</label>
                <input type="text" id="teacher_phone_input" name="teacher_phone">
            </div>
            <br> 
            <div class="details">
                <label for="teacher_subject">所教科目:</label>
                <input type="text" id="teacher_subject_input" name="teacher_subject">
            </div>
            <br>
            <input type="hidden" id="teacher_type_input" name="teacher_type" >
            <input type="submit" value="提交">
            <input type="button" value="取消" onclick="closeModal()">
        </form>
    </div>
</div>

这里提交后到change_teacher_form.jsp页面对数据进行处理,需要更新`USER`表和TEACHER表。

这里注意,如果只传了改变之后的TeacherName,虽然能根据TeacherID更改TEACHER表,但`USER`表无法更改,因为名字已经对不上了(这里把最初名字传进去解决)

教务员管理于此相同,不再赘述

效果:

3.退费管理:

核心代码

这里用的是列表(可变长度)不是数组啊各位

out.print("<table class='table_info' border='1'>");
out.print("<tr><th>姓名</th><th>性别</th><th>年龄</th><th>电话</th><th>报名科目</th><th>报名时间</th><th>是否同意</th></tr>");
for (int i = 0; i < apply_student_name.size(); i++) {
    System.out.println("姓名:" + apply_student_name.get(i));
    System.out.println("性别:" + apply_student_sex.get(i));
    System.out.println("年龄:" + apply_student_age.get(i));
    System.out.println("电话:" + apply_student_phone.get(i));
    System.out.println("报名科目:" + apply_student_subject.get(i));
    System.out.println("报名时间:" + apply_student_time.get(i));

    out.print("<tr class='tr_info'>");
    out.print("<td id='name-" + i + "'>" + apply_student_name.get(i) + "</td>");
    out.print("<td id='sex-" + i + "'>" + apply_student_sex.get(i) + "</td>");
    out.print("<td id='age-" + i + "'>" + apply_student_age.get(i) + "</td>");
    out.print("<td id='phone-" + i + "'>" + apply_student_phone.get(i) + "</td>");
    out.print("<td id='phone-" + i + "'>" + apply_student_subject.get(i) + "</td>");
    out.print("<td>" + apply_student_time.get(i) + "</td>");
    if (result.get(i).equals("未审批")) {
        out.print("<td><button href='javascript:void(0)' "
        + "onclick=\"agree('" + apply_id.get(i) + "','同意')\">"
        + "同意</button>"
        + "<button href='javascript:void(0)' "
        + "onclick=\"agree('" + apply_id.get(i) + "','不同意')\">"
        + "不同意</button></td>"
    );//此处Javascript.void(0)不执行任何操作,只说明执行后面的JavaScript代码
    } else {
        System.out.println(result.get(i));
        out.print("<td id='phone-" + i + "'>" + result.get(i) + "</td>");
    }

    out.print("</tr>");
}
out.print("</table>");

效果:

4.个人中心

这里更是没有什么难点

七:教师相关操作实现

左侧栏、入口文件、个人中心不再解释,非常容易

1.我的课表

(1)首先可以通过下拉选项框选择学期。

课程是在发布之后可以查看的(学生选课页面同理)

//这里实现的是下拉框,在changeSemester()方法中把学期传到相应位置
<div style="display:flex; justify-content: center; align-items: center;">
    <select id="semesterSelect" name="semesterSelect" onchange="changeSemester(this.value)" style="font-size: 25px;">
        <option value="202301">2023-2024学年第1学期</option>
        <option value="202302">2023-2024学年第2学期</option>
        <option value="202401">2024-2025学年第1学期</option>
        <option value="202402">2024-2025学年第2学期</option>
    </select>
</div>
<jsp:include page="./my_class_table.jsp" />
function changeSemester(semester) {
    // 发送请求或执行其他逻辑来获取对应学期的课程数据
    var semesterSelect = document.getElementById("semesterSelect");
    console.log(semesterSelect);
    var semester = semesterSelect.value;
    console.log("this is a line!");
    console.log(semester);

    $.ajax({
        url: "my_class.jsp",    //这是数据的来源文件
        type: "GET",
        data: {
            semester: semester
        },
        success: function (response) {
            var selectedSemester = semesterSelect.value;
            refreshTable(selectedSemester);
        }
    });
}
function refreshTable(semester) {
    $.ajax({
        url: "my_class_table.jsp",    //这是数据的目标文件
        method: "GET",
        data: {
            semester: semester
        },
        success: function (response) {
            $("#the_table").html(response);    //将my_class_table.jsp整个渲染
        },
        error: function () {
            // 处理错误情况
        }
    });
}

效果:

(2)在my_class_table.jsp文件渲染相应学期的课程

这里要在教务员进行选课并且发布之后才会渲染

核心代码

<table class="the_table" id="the_table">
    <div style="display:flex; justify-content: center; align-items: center;">
        <tr class="week_tr">
            <td></td> <!-- 空白单元格 -->
            <% for (int i = 0; i < weeks.length; i++) {%>
            <td><%= weeks[i]%></td> <!-- 显示周次 -->
            <% } %>
        </tr>
        //这里留了一个优化空间,就是数组的长度是固定的,如果库中的节次不等于tiems的长度怎么办?——用ArrayList
        <% for (int i = 1; i < times.length + 1; i++) {%>
        <!--改用数据库的section,这里调整的比较多-->
        <tr>
            <td class="section_no"><%= times[i - 1]%></td> <!-- 显示节次 -->
            <% for (int j = 1; j < weeks.length + 1; j++) {
                    // 查询数据库,看这个时间段和星期几是否空闲
                    String section_no = String.format("%02d%02d", j, i);

                    PreparedStatement psAvailability = conn.prepareStatement(
                            "SELECT TeacherName, SubjectName, ClassroomName "
                            + "FROM COURSE, TEACHER, `SUBJECT`, CLASSROOM "
                            + "WHERE COURSE.TeacherID=TEACHER.TeacherID AND "
                            + "COURSE.SubjectID=`SUBJECT`.SubjectID AND "
                            + "COURSE.ClassroomID=CLASSROOM.ClassroomID AND "
                            + "COURSE.SectionNo=? AND "
                            + "Term=? AND "
                            + "TEACHER.TeacherID=? AND "
                            + "COURSE.IsShow=1 AND "
                            + "Status=1");
                    psAvailability.setString(1, section_no);
                    psAvailability.setString(2, term);
                    psAvailability.setInt(3, teacher_id);
                    ResultSet rsAvailability = psAvailability.executeQuery();
                    // 如果查询结果有记录,那么表示这个时间段和星期几是空闲的
                    String Tname_Sname = "";
                    boolean isAvailable = false;
                    while (rsAvailability.next()) {
                        isAvailable = true;
                        Tname_Sname = Tname_Sname + rsAvailability.getString("TeacherName") +"<br>";
                        Tname_Sname = Tname_Sname + rsAvailability.getString("SubjectName") + "课<br>";
                        Tname_Sname = Tname_Sname + rsAvailability.getString("ClassroomName")+"<br>"  ;
                    }
                    rsAvailability.close();
                    psAvailability.close();
                    // 根据查询结果,动态设置单元格的状态和文字
                    String cellClass = isAvailable ? "available" : "unavailable";
                    String cellText = isAvailable ? Tname_Sname : "无课";
                    //                            System.out.println("term:"+term);
%>
            <td id="cell_<%= (i)%>_ <%= (j)%>" class="<%= cellClass%>"><%= cellText%></td>
            <% } %>
        </tr>
        <% }%>
    </div>
</table>

效果:

2.空闲时间页面

这里的空闲时间表一学期一扔,所以可以删去学期选择问题(所以只需要获得教师ID和节次信息就可以了)(节次信息由行列的i,j拼接得到)

核心代码

<table class="the_table" id="the_table">
            <div style="display:flex; justify-content: center; align-items: center;">
                <tr class="week_tr">
                    <td></td> <!-- 空白单元格 -->
                    <% for (int i = 0; i < weeks.length; i++) {%>
                    <td><%= weeks[i]%></td> <!-- 显示周次 -->
                    <% } %>
                </tr>
                <% for (int i = 1; i < times.length + 1; i++) {%>
                <!--改用数据库的section,这里调整的比较多-->
                <tr>
                    <td class="section_no"><%= times[i - 1]%></td> <!-- 显示节次 -->
                    <% for (int j = 1; j < weeks.length + 1; j++) {
                            // 查询数据库,看这个时间段和星期几是否空闲
                            String section_no = String.format("%02d%02d", j, i);

                            PreparedStatement psAvailability = conn.prepareStatement(
                                    "SELECT * FROM LEISURE WHERE SectionNo=? AND TeacherID=?");
                            psAvailability.setString(1, section_no);
                            psAvailability.setInt(2, teacher_id);
                            ResultSet rsAvailability = psAvailability.executeQuery();
                            // 如果查询结果有记录,那么表示这个时间段和星期几是空闲的
                            boolean isAvailable = rsAvailability.next();
                            rsAvailability.close();
                            psAvailability.close();
                            // 根据查询结果,动态设置单元格的状态和文字
                            String cellClass = isAvailable ? "available" : "unavailable";
                            String cellText = isAvailable ? "空闲" : "非空闲";
                    %>
                    <td id="cell_<%= i%>_<%= j%>" class="<%= cellClass%>" onclick="toggleAvailability(<%= i%>, <%= j%>, <%= teacher_id%>)"><%= cellText%></td>
                    <% } %>
                </tr>
                <% }%>
            </div>
        </table>
function toggleAvailability(section, week, teacher_id) {
    var cell = document.getElementById("cell_" + section + "_" + week);
    if (cell.innerHTML === "非空闲") {
        cell.innerHTML = "空闲";
        cell.className = "available";

        // 这里发送一个请求到服务器,更新数据库
        var sectionStr = String(section).padStart(2, "0");
        var weekStr = String(week).padStart(2, "0");
        var section_no = weekStr + sectionStr;
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function () {
            if (this.readyState === 4 && this.status === 200) {
                // 刷新页面以更新数据
                location.reload();
            }
        };
        xhttp.open("GET", "change.jsp?section_no=" + section_no + "&teacher_id=" + teacher_id, true);  // 替换为你的agree.jsp的路径
        xhttp.send();
    } else {
        cell.innerHTML = "非空闲";
        cell.className = "unavailable";
        // 这里发送一个请求到服务器,更新数据库
        var sectionStr = String(section).padStart(2, "0");
        var weekStr = String(week).padStart(2, "0");
        var section_no = weekStr + sectionStr;
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function () {
            if (this.readyState === 4 && this.status === 200) {
                // 刷新页面以更新数据
                location.reload();
            }
        };
        xhttp.open("GET", "change.jsp?section_no=" + section_no + "&teacher_id=" + teacher_id, true);  // 替换为你的agree.jsp的路径
        xhttp.send();
    }
}

八:学生相关操作实现

左侧栏、入口文件、个人中心、下拉选择学期不再解释

1.课程查询:

让学生先选择想选的科目类别

<div class="subject-type">
    <a href="course_list.jsp?subject_type=<%= subjectType%>">
        <img src="subject_type_images/<%= subjectType%>.jpg" alt="<%= subjectType%>">
        <span><%= subjectType%></span>
    </a>
</div>

<!-- 这里科目类别的图片与科目类别的名字相同,放在同级文件夹之下 -->

效果:

点进去可以进行选择(这里同理是在教务员排课并发布后可以查看)

这里在“开课时间”要进行一个字符串处理:

//样例:202301,0101|||||||2023~2024上半年周一8:00~9:30
if (year.equals("2023")) {
    insert.append("2023~2024");
} else if (year.equals("2024")) {
    insert.append("2024~2025");
}
if (para.equals("01")) {
    insert.append("上半年");
} else if (para.equals("02")) {
    insert.append("下半年");
}
if (week.equals("01")) {
    insert.append("周一");
} else if (week.equals("02")) {
    insert.append("周二");
} else if (week.equals("03")) {
    insert.append("周三");
} else if (week.equals("04")) {
    insert.append("周四");
} else if (week.equals("05")) {
    insert.append("周五");
} else if (week.equals("06")) {
    insert.append("周六");
} else {
    insert.append("周日");
}
if (section.equals("01")) {
    insert.append("8:00~9:30");
} else if (section.equals("02")) {
    insert.append("9:45~11:15");
} else if (section.equals("03")) {
    insert.append("13:00~14:30");
} else if (section.equals("04")) {
    insert.append("14:45~16:15");
} else if (section.equals("05")) {
    insert.append("18:00~19:30");
} else {
    insert.append("19:45~21:15");
}
subject_time.add(insert.toString());
classroom_name.add(rsCourses.getString("ClassroomName"));

点击选课后,除法函数进行处理

out.print("<td><button href='javascript:void(0)' "
    + " onclick=\"selectCourse('" + course_id.get(i) + "','" + student_id + "')\">"
        + "选课</button></td>"
);//此处Javascript.void(0)不执行任何操作,只说明执行后面的JavaScript代码
function selectCourse(course_id, student_id) {
    // 在控制台输出 "yes", course_id 和 student_id
//                console.log("yes");
//                console.log(course_id);
//                console.log(student_id);

    // 弹出弹出框,主体为“是否确认选课?”
    if (confirm("是否确认选课?")) {
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function () {
            if (this.readyState === 4 && this.status === 200) {
                // 刷新页面以更新数据
                location.reload();
            }
        };
        xhttp.open("GET", "select.jsp?course_id=" + course_id + "&student_id=" + student_id, true);  // 替换为你的agree.jsp的路径
        xhttp.send();

    } else {
        // 如果取消则关闭弹出框
        // 需要注意的是,在 `confirm` 弹出框中点击取消会自动关闭弹出框,你不需要写额外的代码来关闭它
    }
}

之后把信息插入到报名表中

效果:

2.我的课表

这里和教师的课表页面很像,不过加入了退课功能,这里如果出现多节课在一个时间段被选会先退下面一节的(因为变量是覆盖的,这里并没有对它进行处理)

boolean isAvailable = false;
while (rsAvailability.next()) {
    isAvailable = true;
    sign_id = rsAvailability.getInt("SignID");
    Tname_Sname = Tname_Sname + rsAvailability.getString("TeacherName") + "<br>";
    Tname_Sname = Tname_Sname + rsAvailability.getString("SubjectName") + "课<br>";
    Tname_Sname = Tname_Sname + rsAvailability.getString("ClassroomName") + "<br>";
}
//这里只对教师名和课进行了处理,没对报名号进行处理,所以退课是覆盖,多节课先退后面选的
<td id="cell_<%=i%>_<%=j%>" class="<%= cellClass%>" <% if (isAvailable) {%> onclick="confirmWithdraw('<%=sign_id%>')" <% }%>>
    <%= cellText%>
</td>
function confirmWithdraw(sign_id) {
    // console.log("sign_id:"+sign_id);
    if (confirm("是否确认退课?")) {
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function () {
        if (this.readyState === 4 && this.status === 200) {
            // 刷新页面以更新数据
            location.reload();
    }
    };
    xhttp.open("GET", "return.jsp?sign_id=" + sign_id, true); // 替换为你的agree.jsp的路径
    xhttp.send();

    } else {
        // 如果取消则关闭弹出框
        // 需要注意的是,在 `confirm` 弹出框中点击取消会自动关闭弹出框,你不需要写额外的代码来关闭它
    }
}

效果:

 3.申请退课不在多说,与机构管理员同步,等候机构管理员处理

九:教务员相关操作实现

教务员的学生信息管理 与 机构管理员管理的教师信息管理几乎一样,不在多说

教务员的教室信息管理 与 机构管理员管理的教务员信息管理几乎一样,不在多说

教师信息查看和个人中心也不再赘述,非常简单

1.这里着重说一下排课功能:

(1)下拉列表选择学期,与学生查看自己课表一致

教务员点击某个课时后,可以进行排课(学期信息和节次信息会传进去)

在排课页面会显示已经排的课程,如果教务员向取消排课,那么可以点击按钮,把库中COURSE的Status设置为0(其他人在查询时Status=1&IsShow=1才能查询到,而教务员只要Status=1就可以查询到)

// Print the results in a table
out.print("<table class='table_info' border='1'>");
out.print("<tr>
    <th>课程类别</th>
    <th>课程名称</th>
    <th>教师姓名</th>
    <th>开课时间</th>
    <th>上课地点</th>
    <th>调整</th>
</tr>");
for (int i = 0; i < subject_name.size(); i++) { 
    // System.out.println("课程类别:" + subject_type.get(i)); 
    //System.out.println("课程名称:" + subject_name.get(i)); 
    // System.out.println("教师姓名:" + teacher_name.get(i)); 
    //System.out.println("开课时间:" + subject_time.get(i)); 
    // System.out.println("上课地点:" + classroom_name.get(i)); 
    if(status.get(i)==1) { //输出已经排的 out.print("<tr class='tr_info'>");
        out.print("<td id='-" + i + "'>" + subject_type.get(i) + "</td>");
        out.print("<td id='-" + i + "'>" + subject_name.get(i) + "</td>");
        out.print("<td id='-" + i + "'>" + teacher_name.get(i) + "</td>");
        out.print("<td id='-" + i + "'>" + Insert + "</td>");
        out.print("<td id='-" + i + "'>" + classroom_name.get(i) + "</td>");
        out.print("<td><button href='javascript:void(0)' "
                                + " onclick=\"planCourse('" + course_id.get(i) + "')\">"
                + "取消选课</button></td>");//此处Javascript.void(0)不执行任何操作,只说明执行后面的JavaScript代码

        out.print("</tr>");
    }

}

点击退课后,会把库中COURSE的Status设置为0

(2)添加课程:

点击“添加选课信息”后,教务员可以在次级页面上下拉选择能用的教室和空闲的教师

这里的SQL语句可能有点难度(教室查询用到了NOT IN操作,教师与课程查询用到了外连接+嵌套查询)(这里教师和课程的查询难度大,是因为把教师与课程的查询写在了一块,一次查询得到全部信息,还有就是表的冗余过低)

同时的,在下拉列表调用rsXXX.next(),可能也是本项目实现难度最大的一点

<div id="addCourseModal" class="modal">
    <div class="modal-content">
        <!--<span class="close" onclick="closeModal()">&times;</span>关闭-->
        <div class="form_title">添加课程信息</div>

        <form action="add_course_form.jsp" method="post" class="the_form">
            <!-- 这里放置你的表单内容 -->

            <!--//term和section_no已经有了-->
            <input type="hidden" id="section_no" name="section_no" value="<%=section_no%>">
            <input type="hidden" id="term" name="term" value="<%=term%>">

            <%                    // 连接数据库并查询符合条件的教室、教师和科目
                PreparedStatement psClassroom = null;
                PreparedStatement psTeacher = null; //包含教师和所教科目
                ResultSet rsClassroom = null;
                ResultSet rsTeacher = null;

                try {
                    // 查询教室
                    psClassroom = conn.prepareStatement("SELECT CLASSROOM.ClassroomID, CLASSROOM.ClassroomName "
                            + "FROM CLASSROOM "
                            + "WHERE CLASSROOM.ClassroomID "
                            + "NOT IN (SELECT CLASSROOM.ClassroomID "
                            + "FROM CLASSROOM LEFT JOIN COURSE ON CLASSROOM.ClassroomID = COURSE.ClassroomID "
                            + "WHERE SectionNo = ? AND Term = ? AND "
                            + "Status=1)");

                    psClassroom.setString(1, section_no);
                    psClassroom.setString(2, term);
                    rsClassroom = psClassroom.executeQuery();
                    //测试用例 5    122

                    // 查询教师和学科
                    psTeacher = conn.prepareStatement("SELECT t.TID, t.TName, `SUBJECT`.SubjectID AS SID, SubjectType,SubjectName "
                            + "FROM `SUBJECT`,(SELECT T.TeacherID AS TID,TeacherName AS TName FROM COURSE "
                            + "RIGHT JOIN (SELECT TEACHER.TeacherID,TEACHER.TeacherName "
                            + "FROM TEACHER,LEISURE WHERE TEACHER.TeacherID=LEISURE.TeacherID "
                            + "AND LEISURE.SectionNo=?) AS T "
                            + "ON T.TeacherID=COURSE.TeacherID WHERE "
                            + "(SectionNo!=? OR Term!=?) OR SectionNo IS NULL OR Status=0) AS t "
                            + "WHERE t.TID=`SUBJECT`.TeacherID");

                    psTeacher.setString(1, section_no);
                    psTeacher.setString(2, section_no);
                    psTeacher.setString(3, term);
                    rsTeacher = psTeacher.executeQuery();
                    //测试用例:3	蒋程程	4	健身	瑜伽
//                                    3	蒋程程	6	数学	算数
                } catch (Exception e) {
                    e.printStackTrace();
                }
            %>



            <div style="display: flex; height: 200px">
                <!-- 教室下拉列表 -->
                <div style="width: 150px; height: 20px;">
                    <div>
                        选择教室
                    </div>
                    <!-- 教室下拉列表 -->
                    <select name="classroom">
                        <% if (!rsClassroom.next()) { %>
                        <option value="" disabled selected>没有空闲教室</option>
                        <% } else {
                            do {
                        %>
                        <option value="<%= rsClassroom.getString("ClassroomID")%>">
                            <%= rsClassroom.getString("ClassroomName")%>
                        </option>
                        <% } while (rsClassroom.next());
                            } %>
                    </select>
                </div>

                <!-- 教师学科下拉列表 -->
                <div>
                    <div>
                        选择教师和课程
                    </div>
                    <!-- 教师学科列表 -->
                    <select name="teacher">
                        <% if (!rsTeacher.next()) { %>
                        <option value="" disabled selected>没有空闲老师</option>
                        <% } else {
                            do {
                        %>
                        <option value="<%= rsTeacher.getString("SID") + "-" + rsTeacher.getString("TID")%>">
                            <%= rsTeacher.getString("TName")%> - <%= rsTeacher.getString("SubjectName")%>
                        </option>
                        <% } while (rsTeacher.next());
                            } %>
                    </select>
                </div>
            </div>


            <%
                // 关闭数据库连接和释放资源
                try {
                    if (rsClassroom != null) {
                        rsClassroom.close();
                    }
                    if (rsTeacher != null) {
                        rsTeacher.close();
                    }

                    if (psClassroom != null) {
                        psClassroom.close();
                    }
                    if (psTeacher != null) {
                        psTeacher.close();
                    }

                    if (conn != null) {
                        conn.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            %>


            <input type="submit" value="提交">
            <input type="button" value="取消" onclick="closeAddCourseModal()">
        </form>
    </div>
</div>

最后把得到的教师和教室信息在add_course_form.jsp页面进行处理

(这里首先查询该课程是否在COURSE表中,因为可能教务员选之后把Status设为了0,如果不存在插入,如果存在UPDATE COURSE SET Status=1 WHERE……)

效果:

(3)最后,点击“公布!”,把term=所选学期的IsShow设置为1,让学生和教师能够查询到

到此结束

十:总结

1.我们应用的是逻辑外键和逻辑主码,那么查询快的同时就会面临一些其它问题。

比如在修改教师信息的时候,要同步`USER`表和TEACHER表。

我们修改信息传进去的默认是输入的信息也就是改后的姓名,如果我们采取获取两个表的主码那么会相当麻烦,可以采用把教师原姓名传进去解决

2.在做页面设计的时候。要以需求驱动,先确定要展示什么内容,然后再去思考这个sql怎么写(先写sql是盲目的)

我们在设计登录界面的时候,我想到两种方式:(选择的是前者,考虑到查询时连接的表小一点)

(1)加一个用户表,加上身份属性,识别属性并跳转相应页面

(2)一个表,添加权限设置

3.我在写SQL的时候,复杂的总是出错,所以SQL要一点一点写,可以连接一个表就加它与前面表的关系,尤其是复杂连接时(同时可以写一点运行一点看看有没有达到效果)

同理的,大家思考一下这个怎么写:

SELECT t.TID, t.TName, `SUBJECT`.SubjectID AS SID, SubjectType,SubjectName 
FROM `SUBJECT`,(SELECT T.TeacherID AS TID,TeacherName AS TName 
FROM COURSE RIGHT JOIN (SELECT TEACHER.TeacherID,TEACHER.TeacherName 
FROM TEACHER,LEISURE WHERE TEACHER.TeacherID=LEISURE.TeacherID 
AND LEISURE.SectionNo='0101') AS T ON T.TeacherID=COURSE.TeacherID 
WHERE (SectionNo!='0101' OR Term!='202301') OR SectionNo IS NULL OR Status=0) AS t 
WHERE t.TID=`SUBJECT`.TeacherID

4.合理冗余还是好的,可以有效减缓上面的问题

5.表的节次传参问题 0101这样的(最重要的在表结构设计,越合理做着越快)

我在做课表的时候,第一次做的是这样:

但是这样写就写死了,更改程序麻烦,要考虑功能的可扩展性:

修改为:(这里其实更好的是改为ArrayList<String>,这里我承认我偷懒了因为我当时没发现后来发现不想改了……)

6.要考虑到多值处理问题,比如学生选了两节课,他点击退课那是两节课都退吗,还是退下面的一节(考虑代码实现方式)(这里上面解释过了,是先删除后选的课)

这个项目主要目的是对于数据库设计与应用和实际体验,只有在实际开发中个中体会到设计思想的精妙和数据库结构设计的重要

前段时间浅浅了解了一下设计模式和面向对象设计,这次考虑到开发时间短和经验不足可能在ddl前交不了作业,所以这次只简单使用了面向对象的建模方法,不过如此多的代码复用和复杂的项目结构还是让我体会到了它们的魅力所在。

我认为开发前最重要的是把数据库结构设计好,我这次除了COURSE表以外其他表结构基本没有变动,后期开发也只是在课表的行列对应库里面的SECTION节次表时进行了返工重做。同样的,这次项目的问题也有不少,比如我的很多表的属性都没有进行限定,对于插入异常处理很少等。

十一:项目文件结构与提取

1.项目文件结构

2.文件提取:

链接:https://pan.baidu.com/s/1HXEpjzjK1jvH7bhSft1Jbw 
提取码:56mj

      

        

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值