毕业才刚刚两个多月而已,现在想想大学生活是那么的遥不可及,感觉已经过了好久好久,社会了两个月才明白学校的好啊。。。额,扯远了,自从毕业开始就想找个时间写下毕设的记录总结,结果找了好久好久到今天才开始动笔。
我的毕业设计题目是:教学辅助系统的设计与实现,,是不是很俗。。。至于为啥是这个题目呢,完全是被导师坑了。。。。。
1、需求分析拿到这个题目想着这个可能被做了无数次了,就像着哪里能够做出点创新,,最后强行创新出了一个个性化组题(根据学生水平出题)和徽章激励(达到某个要求给予一个徽章)。最后就产生了如下需求,系统有学生端和管理端:
学生端:
个人资料设置
徽章激励机制
查看课程信息,下载课程资料
知识点检测及针对性训练
在线作业,考试
在线答疑,向老师或者学生提问
管理端:
课程管理,用户管理(需要管理员权限)
课程信息管理
课程公告管理
题库管理,支持单选,多选,填空,编程题,支持题目编组
发布作业,包括个性组题和手动组题
发布考试,包括随机出题和手动出题
自动判题,支持编程题判重
在线答疑,给学生解答
统计分析,包含测试统计和课程统计
洋洋洒洒需求列了一大堆,后面才发现是给自己挖坑,,答辩老师一看这类的题目就不感兴趣了,不论你做的咋样(况且我的演讲能力真的很一般),最后累死累活写了一大堆功能也没太高的分,,不过倒是让我的系统设计能力和代码能力有了不少的提高。
2、架构选择大三的时候了解到Node.js这个比较“奇葩"的异步语言,再加上在公司实习了三个月也是用的node开发,对node已经比较熟悉了,于是就用它做了后台,前端用最近比较火的vue.js做单页应用。当时还想着负载均衡啥的,就没有用传统的session,cookie机制,转而用jwt做的基于token的身份认证,同时后台接口也是类Restful风格的(因为纯正的Rest接口太难设计了)。
总的来说后台用了以下技术和框架:
总的来说后台用了以下技术和框架:
语言:Node.js
web框架:kOA
前后台传输协议:jwt
缓存:redis
数据库:mysql
编程题判题核心:青岛大学OJ判题核心
代码判重:SIM
前台技术如下:
框架:Vue.js
UI框架:Element-UI
图表组件:G2
3、系统基础框架搭建本系统是前后端分离的,下面分别介绍前后端的实现基础。
1、后台一个web后台最重要的无非那么几个部分:路由;权限验证;数据持久化。
a、路由KOA作为一个web框架其实它本身并没有提供路由功能,需要配合使用koa-router来实现路由,koa-router以类似下面这样的风格来进行路由:
KOA作为一个web框架其实它本身并没有提供路由功能,需要配合使用koa-router来实现路由,koa-router以类似下面这样的风格来进行路由:
const app = require("koa"); const router = require("koa-router"); router.get("/hello",koa=>{ koa.response="hello"; }); app.use(router.routes())显然这样在项目中是很不方便的,如果每个路由都要手动进行挂载,很难将每个文件中的路由都挂载到一个router中。因此在参考网上的实现后,我写了一个方法在启动时自动扫描某个文件夹下所有的路由文件并挂载到router中,代码如下:
const fs = require('fs'); const path = require('path'); const koaBody = require('koa-body'); const config = require('../config/config.js'); function addMapping(router, filePath) { let mapping = require(filePath); for (let url in mapping) { if (url.startsWith('GET ')) { let temp = url.substring(4); router.get(temp, mapping[url]); console.log(`----GET:${temp}`); } else if (url.startsWith('POST ')) { let temp = url.substring(5); router.post(temp, mapping[url]); console.log(`----POST:${temp}`); } else if (url.startsWith('PUT ')) { let temp = url.substring(4); router.put(temp, mapping[url]); console.log(`----PUT:${temp}`) } else if (url.startsWith('DELETE ')) { let temp = url.substring(7); router.delete(temp, mapping[url]); console.log(`----DELETE: ${temp}`); } else { console.log(`xxxxx无效路径:${url}`); } } } function addControllers(router, filePath) { let files = fs.readdirSync(filePath); files.forEach(element => { let temp = path.join(filePath, element); let state = fs.statSync(temp); if (state.isDirectory()) { addControllers(router, temp); } else { if (!temp.endsWith('Helper.js')) { console.log('\n--开始处理: ' + element + "路由"); addMapping(router, temp); } } }); } function engine(router, folder) { addControllers(router, folder); return router.routes(); } module.exports = engine;然后在index.js中use此方法:
const RouterMW = require("./middleware/controllerEngine.js"); app.use(RouterMW(router,path.join(config.rootPath, 'api')));