Sunshine
node_modules 下的所有包为使用npm安装的
public/bower_components 下所有包为使用 bower 包管理器安装
public文件夹下的creave.js、creave.less、mixins.less、variables.less、creave.css文件取自html主题creave并根据自己的需要做了 很大程度的修改
代码框架由Yaoman生成
登录模态框来自 bootsnipp.com 并做了大量修改使其和主题兼容
导入xml使用的代码是基于github开源项目修改的
开发环境:Koajs+MySql+Redis(NoSql)+Bootstrap
运行环境:Nodejs+MySql+Redis-server
E-R图
实现了课程要求中的全部功能。还实现了作业倒计时的贴心功 能以防止同学们忘记交作业错过DDL。
界面基于 bootstrap 制作,配色由自己调成,有很多动画效果,可以让用户的交作业体验获得提升。
简洁体现在使用了很多带有提示功能的搜索框,将很多功能集 成在一起,操作起来更方便,如效果图1所示。使用typeaheadjs制 作的搜索提示框被用在以下位置:
学生通过搜索框选课
教师通过搜索框开课
管理员通过一个搜索框管理学生、教师和课程的信息
使用了很多多彩的tag来告诉用户当前作业的状态,如效果图1 所示。
效果图 1
在每一条路由前都有检查当前用户权限的中间件(Middleware),比如:
学生想通过修改 url 访问他没有选的课程就会禁止其访问并且显示相关错误信息(如效果图 2 所示)
学生想通过自己发送 post 请求来提交已经过期的作业也不会得逞
教师想批改其他教师的课程作业等都不会成功
效果图 2
大多数的检查在前端和后端同时存在,这样可以保证:
在用户误操作的时候可以通过前端检测来友善的提醒用户这是非法操作
在用户试图强行绕过前端检测时,在后端也会有检测,防止非法事件发生
当然也有一些例外,比如教师给学生打分时只会在前端检查分数是否在 0 到分数上限之间(如效果图 3 所示),因为我认为教师没有必要去专门绕过前端检测去给学生打分。因此省掉了后端检测来节约资源。
效果图 3
事实上数据库层面的安全性检查用的比较少,唯一用到之处是查看教师有没有修改某一门课程内容的权限。用到比较少是因为数据库的 trigger 似乎会对每一行都检查一遍,不知道数据库系统的查
询优化做的怎样,因此没有过多使用。
数据库层面防止注入其实是有银弹的,只要使用参数化调用即可。为了防止数据库注入,我主要尝试采用了两种办法:
拼接字符串,使用 escape 函数转义防止注入
更进一步,可以将查询语句打包成存储过程,同样使用 escape函数把字符串类参数转义
但是无论采用怎样的写法,都要保证非字符串类参数为正确的类型(如数字类参数要保证其不能是字符串)。
使用复杂存储过程来查询而不是在后端写逻辑的好处首先是可以加快系统的响应速度:
可以减少访问数据库的次数
虽然查询过程复杂,但是数据库系统会帮助我们优化,而且这种优化是基于数据库系统内部存储状态的优化,是后端无法做到的
其次,这样把后端和数据库分开使得代码更加结构化,更加利于开发。就我本人为例,在开发学生接口时使用拼接字符串的方法,码代码愉悦程度远低于使用存储过程:
每次发现查询过程有误时只要修改存储过程就好,不需要重新启动 nodejs
可以在不同地方重复调用存储过程
海量数据的生成是使用 Fakerjs+JavaScript 脚本来生成的,这种逼真度极高的数据生成为调试提供了很大的方便,可以暴露出很多通过手动添加少量信息表现不出来的错误。在调试时可以通过访问/generateFakeData 来生成数据。
KoaJs 是下一代的 nodejs 框架,相比于 Express 可以免除繁琐的回调函数的嵌套,而是通过 generator 这种语法糖来实现,更加的简洁优雅。但是这并不意味着在 KoaJs 框架下开发不需要掌握异步的相关概念——只有掌握其工作的真正原理,才能在出现错误时知道怎么应对。KoaJs 面临的一个问题是相关的生态还没有建立起来,因此对于初学者来说并不友好,很多的中间件都没有文档,只有自己看源代码,自己尝试才可以掌握用法。
为了让用户的登陆状态保留一段时间,我使用了 session,在 koa 中有几种不同的 session 中间件,我选择 koa-generic-session 的原因首先是文档比较全,其次相比于 cookie session 更加强大,因为后者只在 cookie 中记录相关信息,因此容量很小,不易于扩展。
为了使用 generic-session,我使用了 redis 来存储相关信息,redis是最常用的 NoSQL,原生只是 generic-session,因此使用 redis 来存储 session。
在作业提交系统中提交附件是一件再平常不过的事情,附件怎么上传,如何存储,都是我们要解决的问题。在数据库课程中我了解到 MySQL 中有 BLOB 这个类型是专门用来存储大型附件的,但是经过实践发现这个东西很难用——在 insert 进入数据库之前竟然需要修改附件的拥有者为 mysql;并且经过询问王珂同学得知附件一般不会放到数据库中——放到数据库中会带来不容易迁移数据库的问题,并且也可能会增大查询代价。而一般的解决方案是为附件重命名为随机字符串,并且把原文件名和重命名后的文件名存入数据库。这样的安全性其实已经很高,因为随机字符串可是并不容易试对,而这样做比加入数据库方便很多。如果还嫌安全性不够高可以定时全部重命名,而事实上微信就是这么做的。
具体来说,我采用 koa-multer 这个中间件来处理有附件的表单。
shelljs 主要用来调用系统命令,如调用 mysqldump 来导出,使用 cd 命令切换文件夹等。
swig 为前端模板,在各种框架中都有相应概念,不再赘述。
typeahead 是前端中的搜索提示框插件,配合 ajax 可以达到不断查询数据库实时返回结果的效果。
测试不够充分,可能会存在潜在 bug
对于上传大型附件没有进度条
人机交互可能做得还不够好,在给同学试用时同学有时不能自己找到一些功能
仍待发现…
其中黄色为主键,除主键和外键外属性均可以为 NULL,为获得更详细的表信息,可以查看附件中的 LiLearning_EER_Diagram.mwb文件。
user
teacher
student
admin
course
course_has_student
homework
homework_student_submit
homework_attachment
submit_attachment
欢迎界面
单机右上方登陆(说明图 2)或者注册(说明图 3)会弹出模态框。如果输入用户名登陆,则系统会自动根据用户名去数据库中查找来判断用户的身份;如果注册则按照要求只能注册学生账号,教师账号要向管理员申请。
说明图 2
说明图 3
登陆或注册后会跳到相应身份的主页上。
学生
学生主页(如说明图 4)是作业倒计时的功能,提醒学生哪些作业没有做。左边栏显示的是学生已经选的课程。
说明图 4
通过左边栏来搜索尚未加入的课程(如说明图 5),按回车加入。
说明图 5
点击任意左边栏课程查看作业列表,作业列表中有不同的 tag 来表示作业的状态(未提交、已提交、已返还、已过期)(如说明图6)。
说明图 6
点击卡片有下角相应按钮可以提交作业(支持上传附件)(如说明图 7)或者查看作业(如说明图 8),过期的作业无法提交。
说明图 7
说明图 8
教师
教师主页(如说明图 10)显示所有教师没有批完的作业,左边栏显示的是教师所开设的课程。
说明图 10
单击左边栏课程之后会显示该门课程的所有作业,以及作业批改的情况,还有添加新作业的界面(如效果图 11)
说明图 11
点击某一门作业上的“去批改”或者“查看详情”按钮查看要交该作业的同学(即选了这门课的同学),和同学们提交的情况。(如效果图 12)
说明图 12
之后点击同学卡片的右下角的“批改”或者“查看详情”可以看同学提交作业的内容,下载提交的附件(如果有)。(如效果图 13)
说明图 13
如果想要修改作业的要求、截止时间、总分等信息,可以点击效果图 12 中的“修改作业要求”。之后出现修改作业要求的界面。(如效果图 14)点击修改之后作业要求即更新。
说明图 14
如果想要新增作业可以在效果图 11 中填写相关信息,并且点击“新增作业”可以跳到新增作业的页面。(如效果图 15)
说明图 15
如果想要添加新课程可以在左边输入框输入新的课程 ID,如果ID 冲突则会显示提示信息(如效果图 16),否则进入添加课程的页面(如效果图 17)。
说明图 16
说明图 17
点击上方导航栏中的导出统计信息,可以设置每次作业分数的比例并且得到选课同学的总分。(如效果图 18,效果图 19)
说明图 18
说明图 19
管理员
通过管理员主页上的多功能实时提示的搜索框可以添加管理教师信息,管理学生信息,管理课程信息。(如效果图 20,21,22,23)
说明图 20
说明图 21
说明图 22
说明图 23
单击上方导航栏的导入导出可以导入导出数据。(如效果图 24)
说明图 24