声明:本文为本人原创,本应用已取得软件著作权(全部权利),本项目及其衍生品在当年获得多项省部级国家级荣誉,本文系多年前个人独立项目开发项目文档,近期完善而成的博文,掘金发布本文仅供签约作者评选使用。
第一章 需求分析
1.1开发背景
2020年是极其特殊的一年,全国疫情多地区爆发,所有高校学生一直居家上课没有返校,老师和学生互动有着很大的困难,老师为了调动学生的学习积极性很是头痛,我的开发团队意识到了这一点,我们致力于开发一款多功能集成的抽题移动端APP,用实时更新的积分排行榜来不断刺激学生们保持每日学习的好习惯与攀比排名的正反馈,本产品通过采用Flask+H5+MUI+MongoDB的新颖开发方式构建前后端完全分离模式,我们的APP是以多样式答题为主,集成多个实用学习功能为辅的多功能集成类移动端APP。
1.2 竞品分析
目前,因为疫情的原因刺激推动一些辅助教学的各类新应用的不断出现,但是目前市面上的雨课堂等系统仅仅是起到了老师留一次作业学生被迫完成一次作业的负反馈,并不能调动学生的主动学习积极性。而我们的APP采用了每日学习签到,每日多样式答题,每日无限制练习等功能,尤其是友好的可视化实时更新的个人积分排行榜和班级排行榜,能够有效的刺激学生保持每日签到,每日答题赚积分冲榜的友好正反馈。
名称 | 师生互动 | 动态可视化排名 | 多样式班级化答题 | 多功能集成 |
---|---|---|---|---|
题小满(本app) | √ | √ | √ | √ |
雨课堂 | √ | × | √ | × |
猿题库 | × | √ | × | × |
学习强国 | × | × | × | √ |
作业帮 | × | × | × | × |
表1.2多类答题类应用对比
第二章 概要设计
随着小程序技术的快速流行与发展,WebAPP也随之发展起来了,基于项目需求我们前端采用MUI框架与部分VUE框架混合开发,结合后端的Flask框架与MongoDB数据库,大大的提升了应用的可延展性、亲和性、稳定性等特点。
图2.1系统设计图
我们将需求分析结果分解为六大模块:用户管理模块、抽题模块、积分模块、天下事模块、学习功能集合模块、后台管理模块。其中学生身份账号没有访问后台管理模块权限,老师身份账号解锁所有功能模块权限。
图2.2功能模块设计图
第三章 详细设计
3.1界面设计
3.1.1 登录注册页面
主页面登录注册系统设计如下,用户打开题小满需要先进行登录/注册操作,点击登录/注册按钮账号密码以post方法想服务端发出请求,后端执行MongoDB查询/添加语句,后返回结果给前端,前端处理响应值跳转/重新输入。
图3.1登录和注册功能效果图
3.1.2 首页设计
首页设计如下,分为四个部分组成:轮转图、功能区、答题专区、练习专区。其中功能区集成了多个小模块的入口,对深度使用本APP学习的用户非常友好。并且采用了子父页面继承,前端携带参数跳转与前后端深度交互结合等技术,最大限度的发挥了MUI框架的优点,大大的提升了APP运行的流畅度与稳定性。
图3.2首页设计效果图
3.1.3 抽题模块设计
抽题模块分为答题部分和练习部分,每个部分下设单元专项,选择专项,填空专项。用户点击目标专项会随机抽取五道(选择或者填空),每个用户每天只能计入前三次的选择成绩的最高分和前三次填空的成绩最高分存入积分(选择专项和填空专项次数完全分离互不影响),大于三次不计分。
图3.3单元专项,选择专项,填空专项效果图
抽题模块的数据库设计如下:
序号 | 字段 | 类型 | 允许空 | 字段说明 |
---|---|---|---|---|
1 | id | Int32 | F | 主键 |
2 | choice | String | F | 题目答案 |
3 | title | String | F | 题目描述 |
4 | xuanxiang | Array | F | 题目选项 |
5 | jiexi | String | F | 题目解析 |
6 | unit | String | F | 所属单元 |
表3.3.1选择题数据库(questions)关系模型与文档模型
序号 | 字段 | 类型 | 允许空 | 字段说明 |
---|---|---|---|---|
1 | id | String | F | 主键 |
2 | answer | String | F | 题目答案 |
3 | title | String | F | 题目描述 |
4 | jiexi | String | T | 题目解析 |
5 | unit | String | F | 所属单元 |
表3.3.3填空题数据库(fillbound)关系模型与文档模型
lua
db.questions.insert({"id":"1","choice":"2","title":"x","xuanxiang": [
"x",
"x",
"x",
"x"
],"jiexi":"x","unit":"1",})
lua
db.fillbound.insert({
"id":"1"
,"answer":"指针"
,"title":"题小满"
,"jiexi":"X"
,"unit":"1",})
3.1.4 个人中心模块和天下事模块设计
个人中心模块设计如下:个人中心模块分为俩个部分,第一部分为个人基本信息展示,包括用户的昵称(学号)、账号(学号)、段位、积分。第二部分设计了一些功能比如立即刷新个人信息按钮、修改信息、后台入口,退出登录等等功能。
天下事模块设计如下:通过获取到某网站URL响应,对JSON数据处理之后遍历显示到题小满,满足了学生在使用题小满的时候,还可以了解到每日热闻和点击进入该文章阅读。
图3.4个人中心和天下事模块效果图
3.1.5 学习功能集合模块设计
学习功能模块聚集了10个学习功能,包涵丰富的功能,对使用题小满的用户带来了极大的便利性和友好性。这些功能包括:师资力量、知网、签到、日历、排行榜、休闲娱乐、翻译、天气等等。下面我列举几个较为重要的功能设计:
首先是签到功能,关于签到功能的设计,A用户在新的一天点击签到,通过mui.post向后端发起请求,后端获取到当前登录账号用户名,执行查询语句sign_day字段判断今天是否已经签到,执行相应的积分操作,返回响应给前端。
图3.4 签到功能展示
接下来是动态排行榜功能:
动态排行榜包括(个人积分榜、班级排行榜、游戏挑战排行榜),用户点击排行榜按钮向后端发起请求,后端执行db.mongo.find({}).sort([("jifeng", -1)])等一系列语句,返回JSON数据给前端。用户点击个人积分榜、班级排行榜、游戏挑战排行榜,分别会显示对应的排行榜,有很大的用户友好性与稳定性。
图3.5 排行榜功能展示
3.2数据库设计
由于我们开发的项目采用Flask+MUI的框架,且基于主要面向人群的考虑,我们采用的数据库并非传统的SQL sever、MySQL等数据库,而是极其轻便易使用的MongoDB,MongoDB是一个新的和普遍使用的数据库。它是一个基于文档的非关系数据库提供程序。在数据库特性上,MongoDB具有反范式化的功能特性,用关系型数据库中的范式来看,违反了第一范式(1NF,属性不能拆分)。
3.3 部分关键算法展示
用户在登录时,通过mui.post方法向后端发起请求,后端获取到表单数据先过滤判断是否为注入攻击,后执行数据库查找操作。其中效验成功后将对应的username写入session,执行跳转操作。
python
find=db.mongo.find_one(user_info) #find为找到与没找到返回bool
name = request.form.get("username")
if find: #登录状态
session['username'] = request.form['username']
return jsonify({"code": 0,"msg":"登录成功","name":request.form.get("username"),"_id":_id,"status": 200})
对于积分处理模块的处理较为复杂,我们需要先根据到当前登录状态的username找到目标文档。使用datetime包获取到当天日期。
python
res={"username":session['username']} #以username为主键,找到数据库里对应的那行
find=db.mongo.find_one(res)
muqianjifen=find['jifeng']
now = datetime.date.today()
jifeng=request.form.get('jifeng')
由于time字段为Document类型其结构为:
这里写了一个遍历深度访问判断,对上文所示的结构图进行遍历判断time.time1~time.time3分别对应某一用户当天最多3次有效记录。if(str(now)!=str(find['time'][flag+str(i)][0])),对其进行遍历判断,如果time.timeX存储不是当天日期,执行本次答题有效赋值jifeng(String)操作。
flag1的作用则是为下文判断,该用户当日是否完成3次答题。
python
flag='time'
falg=0
flag1=0
for i in range(1,4):
falg=falg+1
if(str(now)!=str(find['time'][flag+str(i)][0])):
flag1=1
find['time'][flag+str(i)][0]=str(now)
find['time'][flag+str(i)][1]=str(jifeng)
break
else:
continue
if(flag1==0):
return jsonify({"stayus":200,"mag":"今天选择专项已经上限了,本次不计入分数!"})
当flag1为1时说明,该次答题积分有效,进入判断执行阶段。当falg为3代表本次答题有效且为当天最后一次有效成绩。该用户现积分为=积分-max(当日第一次答题成绩,当日第二次答题成绩)+本次答题成绩。
python
if(falg==3 and flag1==1):
if(int(find['time']['time3'][1])>int(find['time']['time2'][1])and int(find['time']['time3'][1])>int(find['time']['time1'][1])): muqianjifen=int(muqianjifen)-max(int(find['time']['time2'][1]),int(find['time']['time1'][1]))+int(find['time']['time3'][1])
db.mongo.update_one(
{'username':find['username']},
{'$set':{"jifeng":int(muqianjifen)}
}
)
return jsonify({"stayus":200,"mag":"成功计入分数,"+"今天已经完成选择专项任务了哦。"})
当falg<3时:分为第一次答题和第二次答题俩种情况,当falg为1时,该用户现积分为=积分+本次答题成绩,当falg为2时,如果本次答题成绩大于time.time1(jifeng),该用户现积分为=积分-当日第一次答题成绩+本次答题成绩。否则不执行赋值操作。
python
if(falg==1):
muqianjifen=int(muqianjifen)+int(find['time']['time1'][1])
if(falg==2):
if(int(find['time']['time2'][1])>int(find['time']['time1'][1])):
muqianjifen=int(muqianjifen)-int(find['time']['time1'][1])+int(find['time']['time2'][1])
db.mongo.update_one(
{'username':find['username']},
{'$set':{"jifeng":int(muqianjifen)}})
return jsonify({"stayus":200,"mag":"成功计入分数,"+"今天已经完成"+str(falg)+"次选择专项答题了。"})
对于随机抽题模块分为三种类型,这里举例专项抽题的关键算法。前端点击对应的单元入口,unit变量会随着表单传递过来,后端根据unit的值,先对数据库进行筛选操作,获取到目标题库。
python
collection = db.questions
objective_unit = { "unit": unit }
resultww = collection.find(objective_unit)
这里的mubiao_list存储遍历目标对象,mubiao_list_id存储每一条符合unit的ID值,
采用random.shuffle() 随机打乱序列,后采用切片操作得到前五道题的ID值,最后构建题目列表,返回值。
python
mubiao_list=[]
mubiao_list_id=[]
for aa in resultww:
mubiao_list.append(aa)
mubiao_list_id.append(aa['id'])
random.shuffle(mubiao_list_id)
questionList=mubiao_list_id[:5]
titleList = [] # 构建题目列表
for i in range(5):
titleList.append(collection.find_one({'id': str(questionList[i])}))
return titleList
JSONEncoder类:采用JSONEncoder类来实现objectID转换为str类型数据。
python
class JSONEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, ObjectId):
return str(o)
return json.JSONEncoder.default(self, o)
最后将返回的objectID调用JSONEncoder类转换为str,后使用json.dumps()函数转化为json对象返回给前端。
python
# 每日答题_单元
@app.route("/questionBack",methods=['POST','GET'])
def questionBack():
unit = ''
unit = request.form.get('unit') # 单元测试
titleList = questionGet(unit)
return json.dumps(titleList,cls=JSONEncoder)
第四章 测试报告
4.1 测试目的
1.功能测试(包含界面测试):保证应用主要功能正常,满足功能需求;
2.兼容性测试:保证应用在各种型号手机中可以正常工作
3.安全性测试:保证应用的权限分配安全有效
本次测试的应用模块主要有:
-
登录模块
-
答题模块
-
积分排名界面
-
教师后台界面
4.2 测试环境与配置
使用WeTest进行线上真机测试,我们开了俩次20台测试[Android]/[HarmonyOS]设备进行兼容抗压测试。
测试设备品牌包括了市面上常见的手机厂商。
4.3 测试用例
题小满标准标准兼容测试(Android)报告:
部分机型数据:
设备品牌 | 设备别名 | 设备型号 | 安装耗时(秒) | 启动耗时(秒) | FPS(帧/秒) |
---|---|---|---|---|---|
HUAWEI | 华为nova 5 Pro | SEA-AL10 | 1.40 | 0.19 | 23.49 |
OPPO | OPPO R9s Plus | OPPO R9s Plus | 5.88 | 0.82 | 21.35 |
Xiaomi | 小米6 | MI 6 | 2.17 | 0.48 | 19.42 |
vivo | VIVO X27 | V1838A | 1.95 | 0.73 | 29.70 |
HUAWEI | 荣耀8X | JSN-AL00a | 3.89 | 0.38 | 29.34 |
功能、模块名称**** | 用例数**** | 已通过用例数**** | 未通过用例数**** | 备注**** |
---|---|---|---|---|
登陆界面**** | 10 | 10 | 0 | 登录模块包含:注册与登录界面 |
答题模块**** | 10 | 10 | 0 | 答题模块包含:填空题界面与选择题界面;答题模块限制了用户只能答题三次,超出的积分无法获取 |
积分排名界面**** | 10 | 10 | 0 | 可以获取用户积分对其进行排序 |
教师后台界面**** | 10 | 10 | 0 | 教师后台可以向数据库输入题目 |
表4.3.1测试用例及相关信息表
4.4 缺陷的统计与分析
4.4.1缺陷汇总
设备别名 | 结果 | 问题类别 | 问题描述 |
---|---|---|---|
荣耀20 | 未通过 | Crash | libc : Fatalsignal5 (SIGTRAP) |
按严重程度分 | 已修复BUG数 | 未修复/暂缓bug明细 | 当前严重程度bug总数 |
---|---|---|---|
严重、高 | 2个 | 无法维持用户登录,每次登录需手动登录! | 3个 |
一般 | 0个 | 0个 | 0个 |
低 | 0个 | 0个 | 0个 |
汇总 | 2个 | 1个 | 3个 |
表4.1.1缺陷汇总表
4.4.2 缺陷修复明细及结果
答题界面积分无法限制用户答题三次:我们在数据库中设置Object类型数据库,对每天的答题进行存储
答题界面积分获得混乱:逻辑性错误,在后端我们加上了,对每次结果进行特判
以上便是我们修复的bug明细及结果
4.4.3测试分析总结:
本次测试功能覆盖率为:100%,获得的总缺陷数为3,已改正缺陷数为2
测试兼容随机机型40个,兼容通过率百分之百。
第五章 安装及使用
5.1安装环境要求
系统:Android 7.0+ 存储空间:100MB 需要网络连接
5.2安装过程
以oppo手机为例:首先获取安装包
图5.2.1 安装界面
安装结束后便可从首页点击进入应用
图5.2.2应用安装完成
5.3使用流程
进入应用以后,首先会出现加载界面
图5.3.1应用加载界面 等待加载完成后便来到登录界面,若用户是第一次使用应用,需注册才能进入应用
图5.3.2登录及注册界面
登录完成后来到应用首页,在首页有多种功能入口,点击相应功能进入
图5.3.3首页界面
点击章节检测可选择相应单元进行答题,点击填空专项可答填空题,每天答题只有前三次计入积分。
图5.3.4答题界面
答题完成后,获得积分将记录在个人中心中,可在个人中心查看自己当前排名及积分,可点击排行榜查看当前所有人的排名。
图5.3.5个人中心及积分排名
当用户身份是老师时,可点击后台对题目进行添加操作,可分别添加选择题与填空题。
图5.3.6后台添加题目
第六章 项目总结
在项目构思的前期,由于当时团队对于Java开发技术栈并不熟练,技术选型阶段我们将后端框架定为Flask,MUI做前端框架,数据库选用MongoDB。
由于我们的技术选型组合(Flask+MUI+Mongodb+H5)较为冷门,网络上几乎没有这样的参考资料,虽然困难重重但是我们团队以官网文档做为基础不断学习,不断突破优化这些技术栈的结合伴随的bug,现阶段本APP已经有着良好的性能和优越的流畅度。同时我们的团队本着开源精神,也在gitee上开源了我们的APP项目,同时也引起了广大技术网友的关注与讨论。 对于项目协调方面,我们根据各自的优势合理分配相应的开发任务,最大程度的发挥了团队开发的优势,实现了1+1+1>3 的效果。 为了高效的实现开发任务,我们团队采用: ①,为了解决开发难以统一的问题,我们采用gitee协同开发,提高了开发效率,高效解决了冲突处理等等问题。 ②,项目初期直接将MongoDB数据库部署到服务器,团队成员开发直连云数据库,极大的提高了开发效率。 升级演进方面,我们采用独立模块化开发,每个人负责不同的模块开发,之后相互测试对方的模块,交流优化心得,不断优化各种模块。 推广方面,因为现在的居家上课状态,老师同学们很需要题小满的出现,我们团队在项目后期积极联系相关老师和社团同学,已经在本专业范围内推广,并且不断优化不断迭代,在近期也将面向全校推广,以至于全国高校进行推广。
参考文献
[1] 基于Python Flask的论文盲审系统的设计与开发[J]. 朱枫帆,汤军. 造纸装备及材料. 2020(04)
[2] 基于B/S架构的软件项目开发[J]. 赵巧玲. 计算机光盘软件与应用. 2014(24)
[3] 移动阅读APP功能需求研究[D]. 王俊芳.武汉大学 2017