一:系统概述:
通过对学校日常教学管理中的课程、选课、学生、班级、教师、成绩等相关内容进行分析,完成具有教师管理、学生管理、成绩管理(含学籍分)、课程管理、选课管理、班级管理等相关功能的小型数据库管理应用系统。
二:基本需求 :
1.基本需求:
- 一个学生属于一个班级,一个班级有多个学生;
- 一个学生可以选修多门课程,一门课程可以由多个学生选修;
- 一门课程可以由多个教师讲授,一个教师可以讲授多门课程;
- 每次的选课需要事先进行排课,学生按给出的排课安排进行选择,比如:一门课程可以由多个教师讲授,但该次选课只安排2个教师讲授,每个教师讲授该门课程限定20人;
- 每次的选课安排有生效时间,生效后学生才能选课;
- 每次的选课安排有选课到期时间限制,达到时间限制后不能再选;
- 每次的选课安排有成绩录入到期时间限制,达到时间限制后不能再修改成绩;
- 学生按选课安排进行选课,选课时不分班级,同一门课程只能选择某个教师讲授的该课程;某教师讲授的某课程选满后学生不可以再选;
- 学生选课后,在选课到期时间之前可以“退选”已选择的课程进行重新“选课”;
- 教师按所授课程的选课学生来进行教学和成绩录入,一旦某学生选修某老师的某门课程录入和修改了成绩,均应同时计算该学生的学籍分并保存;
- 学生的学籍分 =(选修课程成绩*课程学分)之和/(选修的全部课程学分)之和;
- 教师录入成绩时,无论是编程工具代码实现还是数据库端实现都需要实现批量录入一次保存;达到录入成绩到期时间后不能再修改学生成绩。
- 输出各类名册和统计报表,做好数据库备份和恢复。使用编程工具编码实现的建议所有的报表数据用存储过程实现数据获取,降低网络传输量,利用集合运算的优势提升查询速度,提高数据独立性。
2.其他需求
- 完成学生、班级、课程、教师等基础数据的维护(增删改查)和数据准备。其中学生基本信息的获取要求使用视图,因为学生表上的学籍分在常规增删改查时不需要显示和查看,应该使用自己的外模式。
- 完成选课安排的维护(增删改查),注意生效时间、选课到期时间、成绩录入到期时间的设定,注意每个教师讲授的每门课程的选课人数设定。选课人数限制利用触发器、冗余列实时动态更新选课人数,到达限定人数再选抛出异常。
- 完成学生选课的维护(增删改查),以及“退选”功能,注意“选课”和“退选”都只能在有效时间内进行操作。
- 按课程教学班级查询/输出学生课程成绩登记册;按班级查询/输出学生课程成绩登记册;
- 学生可以查询自己选修的某门课程的成绩或全部课程的成绩以及获得的学籍分。
- 按班级、按课程计算平均成绩、最高成绩、最低成绩、及格率并输出。
- 统计某学生、某学期的所有课程的平均成绩。
- 按学生所属班级输出学生名单(含学籍分)。
- 至少设计3类角色:教师、学生、教务来分别操作不同的系统功能
- 完成数据备份与恢复功能,要求可以备份数据到指定的文件夹、文件和从指定的文件夹、文件恢复数据到数据库。
- 运维需求变更案例:学校原本采用学籍分来决定学生是否能获取学位证书,学校更换了校长,认为绩点分更科学合理。请在不改变原来代码的基础上做加法,在数据库端实现先进先出法。提示:可以新增冗余列、冗余表保存每个学生的实时绩点分,新增或修改触发器代码、修改视图、存储过程代码来实现。比如按学生所属班级输出学生名单(含学籍分)因为输入和输出没有改变,只需要修改原来的存储过程代码“学籍分”列的数据为“绩点分”的数据即可,几乎不用修改任何前端和后端代码,最多只需修改报表“学籍分”列的名称为“绩点分”,无需重新编译和发布后端代码。
学生的平均学分绩点GPA = (每门课程的学分*对应课程的绩点) / 总学分
课程成绩绩点表如表2-1所示。
表2-1 课程成绩绩点表
编码 | 成绩下限 | 成绩上限 | 绩点 |
1 | 0 | 59.99 | 0 |
2 | 60 | 69.99 | 1 |
3 | 70 | 79.99 | 2 |
4 | 80 | 89.99 | 3 |
5 | 90 | 100 | 4 |
三:概念结构设计
1.实体描述
该学生成绩管理系统的抽象实体有六个
学生实体属性:学生号,姓名,性别,用户编号,班级号;
教师实体属性:教师号,姓名,性别,用户编号;
课程实体属性:课程号,课程名,学分,选课开始时间,选课结束时间,成绩录用截止时间,选课最大人数;
教务人员实体属性:教务号,姓名,性别,用户编号;
用户实体属性:用户编号,用户账号,用户密码,用户类型;
班级实体:班级号,班级名,班级人数
2.ER图设计
四:逻辑结构设计
1.ER图转换为关系模型
教师与课程为多对多关系,排课与学生为一对多关系
因此设立以下关系模型:
教师(教师号,姓名,性别,用户id)
课程(课程号,课程名,学分,选课开始时间,选课结束时间,成绩录用截止时间,选课最大人数)
排课表(排课号,教师号,课程号)
学生(学生号,姓名,性别,用户id,班级)
选课表(选课编号,学生号,排课号,成绩,已选人数)
2.表结构设计
4.2.1. 学生表 (student)
4.2.2. 课程表 (course)
4.2.3. 教师表 (teacher)
4.2.4. 选课表(student_course)
4.2.5. 排课表(teacher_course)
4.2.6. 教务人员表(admin)
4.2.7. 用户表(user)
五:前端页面设计:
1.登录页面
5.1.1. 相关代码
<div class="container">
<header>
<h1>
<img src="/images/透明底Logo.png" alt="">
</h1>
<div>学生成绩管理系统</div>
</header>
<form action="/admin/main" method="post">
<div class="form-group">
<label for="">用户名</label>
<input type="text" name="userName">
</div>
<div class="form-group">
<label for="">密码</label>
<input type="password" name="userPwd">
</div>
<div class="form-group">
<label for="">身份</label>
<input type="radio" id="student" name="userType" value="student">
<label for="student">学生</label>
<input type="radio" id="teacher" name="userType" value="teacher">
<label for="teacher">教师</label>
<input type="radio" id="admin" name="userType" value="admin">
<label for="admin">教务人员</label>
</div>
<input type="submit" value="Login">
<!-- <button>Login</button> -->
</form>
</div>
5.1.2. 效果展示:
5.1.3. 交互逻辑
//查询数据库
db.query('select * from user where userName = ? and userPwd = ? and userType = ?',[userName,userPwd,userType],function(err,userdata){
if(err){
throw err;
}else if(userdata.length > 0){
console.log(userdata);
// res.render('main');
if(userdata[0].userType == 'student'){
db.query('SELECT * FROM student WHERE userid = ?',[userdata[0].userid],function(err,studentdata){
if(err){
throw err;
}else {
console.log(studentdata);
req.session.user = {
userid: userdata[0].userid,
userName: userdata[0].userName,
userType: userdata[0].userType,
personName: studentdata[0].name,
personNo: studentdata[0].sno,
personGender: studentdata[0].gender
};
res.render('main');
}
})
}else if(userdata[0].userType == 'teacher'){
db.query('SELECT * FROM teacher WHERE userid = ?',[userdata[0].userid],function(err,teacherdata){
if(err){
throw err;
}else {
// console.log(studentdata);
req.session.user = {
userid: userdata[0].userid,
userName: userdata[0].userName,
userType: userdata[0].userType,
personName: teacherdata[0].name,
personNo: teacherdata[0].tno,
personGender: teacherdata[0].gender
};
res.render('main');
}
})
}else {
db.query('SELECT * FROM admin WHERE userid = ?',[userdata[0].userid],function(err,admindata){
if(err){
throw err;
}else {
// console.log(studentdata);
req.session.user = {
userid: userdata[0].userid,
userName: userdata[0].userName,
userType: userdata[0].userType,
personName: admindata[0].name,
personNo: admindata[0].ano,
personGender: admindata[0].gender
};
res.render('main');
}
})
}
}else{
res.render('tip',{message:'用户名或密码或用户类型有误'})
// res.write('<head><meta charset="utf-8"/head>');
// res.end('用户名或密码或用户类型有误');
}
})
2.后台管理页面
5.2.1. 相关代码
main.ejs
<div class="container">
<div class="left-panel">
<iframe src="/left" name="left"></iframe>
</div>
<div class="right-panel">
<iframe src="/right" name="right"></iframe>
</div>
</div>
left.ejs
<div class="nav-left">
<h3>
<img src="/images/透明底Logo.png" alt="">
</h3>
<ul>
<!-- 一级导航 -->
<li>
<div class="menu active">
<img src="/images/后台管理UI素材/切图/icon_shouye.png" alt="">
<span>首页</span>
<img src="/images/后台管理UI素材/切图/icon_down.png" class="down" alt="">
</div>
<ul>
<li class="menu">
<img src="/images/后台管理UI素材/切图/icon_kecheng.png" alt="">
<a href="/user" target="right">个人页面</a>
</li>
<li class="menu">
<img src="/images/后台管理UI素材/切图/icon_class.png" alt="">
<a href="/studentCourse" target="right">学生选课</a>
</li>
<li class="menu">
<img src="/images/后台管理UI素材/切图/icon_banner.png" alt="">
<a href="/teacherCourse" target="right">排课安排</a>
</li>
</ul>
</li>
<!-- 一级导航 -->
<li>
省略,相关信息参考上面li
</li>
</ul>
<div class="out">
<a href="/admin" target="_parent">退出登录</a>
</div>
</div>
right.ejs
<div class="main">
<!-- <img src="/images/sha.gif"> -->
<img src="/images/Sayori_sun.jpg" alt="">
<h1>欢迎进入学生成绩管理系统</h1>
</div>
5.2.2. 效果展示
六:前端与数据库连接
1.数据库连接
在文件根目录下建立sql.js
var mysql = require('mysql2');//导入包
var db = mysql.createConnection({
host:'localhost',
user:'root',
password:'123456',
database:'cms'
});
db.connect();//连接
module.exports = db;
2.数据库数据渲染
以student数据为例,首先在routes文件夹下创建student.js
var express = require('express');
var router = express.Router();
let db = require('../sql.js');
/* GET home page. */
router.get('/', function(req, res, next) {
let pageNum = req.query.page;
const user = req.session.user;
if(user){
db.query('SELECT * FROM student',function(err,data){
let pager = {};
//当前第几页,默认1
pager.pageCurrent = pageNum || 1;
//总的记录数
pager.maxNum = data.length;
//每页显示多少条记录
pager.pageSize = 5;
//一个多次页
pager.pageCount = parseInt(Math.ceil(pager.maxNum/pager.pageSize));
//修改传递的数量
let dataList = data.slice((pager.pageCurrent-1)*pager.pageSize,(pager.pageCurrent-1)*pager.pageSize + pager.pageSize);
if(err){
throw err;
}else{
db.query('SELECT DISTINCT s.class FROM student s ORDER BY s.class',function(err,Class){
if(err){
throw err;
}else{
//'student'为渲染的页面,即student.ejs,后面为要渲染的数据
//其中student:dataList用户渲染学生信息数据
//Class渲染班级数据,方便按班级查询学生信息
//pager为页面码数,用户渲染页面页数
//user为用户信息,方便根据用户信息授予不同的权限
res.render('student',{student:dataList,pager,Class,user});
}
})
}
})
}else{
res.redirect('/');
}
});
module.exports = router;
注意: 要在app.js中配置相关路由信息
let student = require('./routes/student');
app.use('/student',student);
以下是student.ejs中学生数据的相关渲染过程
<table class="table">
<thead>
<tr>
<th>学号</th>
<th>姓名</th>
<th>班级</th>
<th>性别</th>
<th>用户id</th>
<% if(user.userType == 'admin'){ %>
<th>操作</th>
<% } %>
</tr>
</thead>
<tbody>
<% student.forEach(function(item) { %>
<tr>
<td><%= item.sno %></td>
<td><%= item.name %></td>
<td><%= item.class %></td>
<td><%= item.gender %></td>
<td><%= item.userid %> </td>
<td>
<% if(user.userType == 'admin'){ %>
<img src="/images/后台管理UI素材/切图/btn_chakan.png" class="edit update" data-sno="<%= item.sno %>" data-name="<%= item.name %>" data-class="<%= item.class %>">
<img src="/images/后台管理UI素材/切图/btn_shanchu.png" alt="del" class="delete-item" data-sno="<%= item.sno %>">
<% } %>
</td>
</tr>
<% }) %>
</tbody>
</table>
3.效果展示
关于其他数据的渲染以及增删改查基本都是按照上面照葫芦画瓢 ,
更多详细操作可查看博主源码
七:总结
1 课程设计中遇到的主要问题和解决方法
本次数据库大作业采用我采用Node.js+express框架+mysql数据库来完成前端页面的渲染以及与数据之间的交互。由于第一次进行前端页面与数据库的连接,因此在本次课程设计的过程中,遇到最多的问题就是数据渲染到前端页面。最后通过搞清楚数据传递和渲染原理后解决,搞清楚原理,后面的操作也很简单。
2 课程设计中存在的不足,需进一步改进的设想
该系统原本想实现用户注册功能以及用户更详细的信息的渲染,但由于时间有限,以及本次对数据库的掌握程度不高,没有实现该功能,在开始课程设计时,刚开始对表结构设计不是很好,导致后面修改很麻烦。同时,该系统原本该使用到存储过程的操作全都用视图来代替了。设置了太多视图,导致部分操作很繁琐,以及在书写路由下的代码时代码没有进行封装,导致代码冗余。
注:第一次发表博客,如有错误或不足之处,欢迎指出