智慧课堂app(一)Flutter+springboot 实现考勤码+gps考勤签到功能
Flutter+springboot实现考勤码+gps考勤签到功能
- 实现步骤和思路:
- 设计
- 发布考勤任务
- 签到考勤
- 环境准备
- 后端步骤:
- 1.教师发布考勤任务接口
- 2.rabbitmq收到教师发布考勤执行的步骤代码接口
- 3.考勤过期后,rabbitmq执行的代码
- 4.websocket推送,以及离线消息缓存,上线取出发送,删除缓存
- 5.学生考勤接口
- 前端flutter app
- 需要用到的插件
- 2. 发布成功,通过provide更新UI,把考勤记录记入本地换成,并且利用计时器倒计时
- websocket接收考勤消息推送和处理
- 1.websocket接收数据
- 2.websocket处理解析数据
- 3. 利用NotificationsUtil通知用户,并使用EventBus消息总线将处理好的数据推送到相关的UI界面
- 4. 要显示跟新的UI界面监听消息总线通道,取出收到的数据写入本地并通过provide刷新UI
- 效果预览图
- 总结
本人正在做一个智慧课堂辅助app的毕设作品,刚好有一个功能是考勤签到,正好实现了,分享一下经验。
主要实现有 1.app教师用户发布数字或gps考勤任务,gps考勤可以设置考勤地点和距离范围内有效,并且能设置考勤失效时间。后端将考勤任务通过websocket推送到该课程的所有学生,学生收到后在指定时间地点内输入考勤码完成签到,过期不签到的同学将被系统设置为旷课。利用redis做离线消息缓存七天,离线用户的将消息存储到redis中,用户上线后取出redis离线消息推送。
实现步骤和思路:
后端springboot:
1.教师通过restful风格接口创建考勤任务,生成数据库记录
2. 在该创建考勤接口中使用rabbitmq来执行三个步骤:
1.生成需要签到的学生名单记录到数据库,赋默认状态值-1,表示需要签到;2.将需要考勤的消息通过websocket推送给前端app,3.使用redis把教师创建的考勤任务记入,并设置过期时间为教师设置的有效时间。
3.在创建考勤接口最后一步使用rabbitmq的消息延迟队列去跟新数据库状态为-1(需要考勤)的记录修改为缺勤的状态,并把缺勤的记录通过websocket推送到学生前端。 消息延迟队列时间为考勤有效时间
4. 利用redis做离线消息缓存
前端flutter:
1.教师使用高德地图插件定位获取考勤位置,设置考勤距离和有效时间,通过http请求发送到后端;
3. 成功通过Timer计时器来显示剩余时间,并且使用provide状态管理来保持时间显示;
4. 考勤期间收到完成考勤的学生数据,使用provide插入本地并更新名单记录;
5. 考勤结束收到后端websocket推送的学生缺勤名单,provide更新数据;
学生:1.收到教师发布的考勤任务,前往考勤页面点击考勤,完成考勤更新UI,如果失败,也跟新UI界面
使用到的工具和框架有:
springboot
spring-data-jpa
mysql
redis
rabbitmq
rabbitmq消息延迟队列插件
设计
发布考勤任务
课堂创建者可以发布考勤任务让学生用户在指定的时间内完成考勤。发布的考勤主要分两种方式,第一种是数字考勤,学生只需要在指定的时间内通过考勤码完成考勤任务即可;第二种为GPS考勤,是在第一种考勤的方式上,设置指定考勤的地点范围,只有在指定的地点范围内完成考勤,才算成功,否则系统视为缺勤。该功能主要涉及的工具和技术有Reids非关系型数据库、RabbitMQ消息中间件、消息延时队列、Websocket。服务端具体的设计过程如下:
(1) 客户端通过请求Restful风格接口创建考勤任务,生成数据库记录;
(2) 在该创建考勤任务接口中利用RabbitMQ消息中间件来异步完成三个步骤:
①生成需要签到的学生名单(userId)批量写入到数据库,考勤状态(status)赋默认状态值-1,表示需要完成签到任务;
②将考勤消息通过websocket推送给需要完成考勤任务的所有用户App客户 端;
③把教师用户创建的考勤任务记录写入Redis,并设置过期时间为教师用户指 定的时间(expireTime)。
(3) 利用RabbitMQ的延时队列去修改学生考勤记录状态(status)为-1的记录统一修改为状态为0,表示学生缺勤,未能在指定时间内完成考勤任务,并用Websocket推送缺勤名单给考勤任务创建者;
(4) 需要完成考勤的学生用户在考勤有效时间内完成考勤,数据库学生考勤状态(status)为-1的修改为1,表示出勤, 并用Websocket推送缺勤名单给考勤任务创建者。
Flutter
App客户端Gps考勤使用到高德地图的定位接口,主要分为以下几个步骤:
(1)在Flutter的pubspec.yaml文件中引入高德地图插件:
amap_location_fluttify: 0.8.11+481e45c #高德地图
(2) 到高德地图开放平台(https://lbs.amap.com/)注册开发者,并创建应用;
(3) 在Android的AndroidManifest.xml文件下添加高德地图创建应用生成的Key
(4) 在调用高德地图接口插件前,调用以下代码,初始化接口:
WidgetsFlutterBinding.ensureInitialized();
Await AmapCore.init(‘21f35eb097c0cd048f7668194525ba7a’);
发布考勤任务功能的流程如图。
签到考勤
学生用户在收到教师用户发布的考勤任务后,将收到系统提示的考勤消息。在相应的课堂考勤列表中出现需要完成的考勤记录,如果发布的是数字考勤,通过教师告诉学生的考勤码完成签到,如果是GPS考勤,则需要手机定位后在输入考勤码签到。如果考勤任务时间过期,或者考勤用户的定位地点不在指定地点范围内将直接视为缺勤,无法再签到。具体实现流程如图所示。
环境准备
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency>
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>25.1-jre</version>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope>
</dependency>
后端步骤:
1.教师发布考勤任务接口
2.rabbitmq收到教师发布考勤执行的步骤代码接口
3.考勤过期后,rabbitmq执行的代码
4.websocket推送,以及离线消息缓存,上线取出发送,删除缓存
用户上线后,websocket取出redis离线消息推送,并且清除离线缓存的数据
@OnPen接口
5.学生考勤接口
///学生考勤
@RequestMapping(value = "AttendanceStudentCheck", method = {RequestMethod.GET, RequestMethod.POST})
public BaseResult AttendanceStudentCheck(@Valid @RequestBody AttendanceStudentDto attendanceStudentDto,HttpServletRequest request) {String key = RedisKeyUtil.Attendance.getAttendanceExpireKey(attendanceStudentDto.getAttendanceId());Attendance attendance = (Attendance) redisService.get(key);String studentId = (String) request.getAttribute("X-AUTH-ID");if (attendance == null) {//考勤失败,缺勤attendanceStudentService.updateStudentStatus(studentId, attendanceStudentDto, 3, 0);return BaseResult.ok(3);}boolean isSuccess = false;double d = 0;if (attendance.getAttendCode().equals(attendanceStudentDto.getAttendCode())) {if (attendanceStudentDto.getType() == 0) {//数字考勤//考勤成功isSuccess = true;} else {//gpsBigDecimal lat = attendance.getLatitude();BigDecimal lon = attendance.getLongitude();double distance = attendance.getDistance();attendanceStudentDto.getLatitude();attendanceStudentDto.getLongitude();d = DistanceUtil.earthDis(lat.doubleValue(), lon.doubleValue(),attendanceStudentDto.getLatitude().doubleValue(),attendanceStudentDto.getLongitude().doubleValue());System.out.println("distance: " + d);if (d <= distance) {isSuccess = true;}}}if (isSuccess) {AttendanceStudent attendanceStudent =attendanceStudentService.updateStudentStatus(studentId, attendanceStudentDto, 0, d);Map<String, Object> map = new HashMap<>();map.put("method", "teacher/createAttendance");map.put("publisherId", attendance.getPublisherId());try {redisRabbitProvider.websocketSend(attendanceStudent, map);} catch (IOException e) {e.printStackTrace();}return BaseResult.ok(0);} else {return BaseResult.ok(-1);}}
前端flutter app
需要用到的插件
dio: ^3.0.8provide: ^1.0.2 #状态管理shared_preferences: ^0.5.1flutter_local_notifications: ^1.1.5+1 #permission_handler: ^4.2.0+hotfix.3 #权限库amap_location_fluttify: 0.8.6+356f11c #高德地图flutter_event_bus: ^0.0.2
主要思路
教师通过dio 发送http请求创建考勤任务,
经过封装的发布考勤接口,
2. 发布成功,通过provide更新UI,把考勤记录记入本地换成,并且利用计时器倒计时
自定义的provide+计时器工具类
class TimeExpire{int expire=0;double minutes = 0;int second = 0;}///倒计时器
class ExpireTimerProvide with ChangeNotifier{Map<int, Timer> timerMap = Map();Map<int, TimeExpire> timeExpire=Map();///void init(){timerMap.clear();timeExpire.clear();}//开始计时方法startCountdownTimer(Duration d, int id) {int counterTime = d.inSeconds;print('进来 ${counterTime}');TimeExpire expireT=TimeExpire();expireT.expire=counterTime;expireT.minutes= counterTime / 60;expireT.second = counterTime % 60;timeExpire.putIfAbsent(id, ()=>expireT);var oneMinuute = Duration(seconds: 1);var callback = (Timer timer) async {// print(timer.tick);if (timeExpire[id].expire < 1) {timerMap[id].cancel();if (timerMap.containsKey(id)) {timerMap.remove(id);}print('remove :${timerMap}');} else {int temp=timeExpire[id].expire;timeExpire[id].expire =temp- 1;timeExpire[id].minutes = temp / 60;timeExpire[id].second = temp % 60;}notifyListeners();};timerMap.putIfAbsent(id, ()=>Timer.periodic(oneMinuute, callback));}}
显示计时UI代码
websocket接收考勤消息推送和处理
1.websocket接收数据
2.websocket处理解析数据
3. 利用NotificationsUtil通知用户,并使用EventBus消息总线将处理好的数据推送到相关的UI界面
推送总线消息
Application.eventBus.publish(要推送的数据);
4. 要显示跟新的UI界面监听消息总线通道,取出收到的数据写入本地并通过provide刷新UI
完整代码已经上传到github项目,做为项目的某部分,项目将继续完善
github:coureapp源码
效果预览图
总结
最终圆满完成考勤功能,推送消息没有问题。本人做后端的,不擅长前端,UI做的太丑了,求手下留情!
智慧课堂app(一)Flutter+springboot 实现考勤码+gps考勤签到功能相关推荐
- 智慧农场app定制开发是否需要源码交付
随着移动互联网的发展,越来越多的人开始使用智慧农场app进行农业生产活动.对于开发者来说,开发一款智慧农场app需要考虑很多因素. 1:智慧农场app定制开发需要源码交付吗 智慧农场app定制开发需要 ...
- 职教云计算机网络基础题库,智慧职教云课堂APP计算机组装与维护章节测试答案...
智慧职教云课堂APP计算机组装与维护章节测试答案 更多相关问题 早餐摄入的能量应占全天总能量的25%,午餐占50%,晚餐占25%.() 边远地区和交通不便地区的企业库存现金可多于5天,但最多不能超过( ...
- Flutter智慧城市App
前言 下面将是我使用Flutter对智慧城市APP的实现过程,尽管过程有点繁琐,但这终究只是我的一片记录学习过程的文章,如果有错误的地方,望在评论区留言,给广大的朋友们指条明路- 要求 任务 1:引导 ...
- 搜题计算机组装与维修教程,智慧职教云课堂APP计算机组装与维护(长沙环境保护职业技术学院)答案大全...
智慧职教云课堂APP计算机组装与维护(长沙环境保护职业技术学院)答案大全 更多相关问题 下列关于实验现象的描写正确的是()A.红磷在氧气中燃烧,产生大量白雾B.硫在空气中燃烧--蓝紫色火焰,生成有 关 ...
- 智慧工地无线覆盖重点产品人员定位和移动考勤
智慧工地无线覆盖重点产品[人员定位]-产品功能 智慧工地无线覆盖重点产品人员定位和移动考勤 智慧工地无线覆盖重点产品:移动考勤 产品简介:移动考勤以移动互联网应用模式,基于综合定位,为建筑施工企业员工 ...
- 【互联网+“创新创业大赛”】智慧课堂项目计划书
文章目录 项目简介 项目背景 课堂教育发展痛点与现状分析 教育硬件设备的普及率有限 教育软件平台标准不一 教学内容制作的水平参差不齐 产品技术和服务 硬件设备 软件应用 智能化服务 市场分析 市场规模 ...
- 计算机毕业设计ssm面向智慧课堂的教学过程管理系统evi14系统+程序+源码+lw+远程部署
计算机毕业设计ssm面向智慧课堂的教学过程管理系统evi14系统+程序+源码+lw+远程部署 计算机毕业设计ssm面向智慧课堂的教学过程管理系统evi14系统+程序+源码+lw+远程部署 本源码技术栈 ...
- 【附源码】计算机毕业设计SSM面向智慧课堂的教学过程管理系统
项目运行 环境配置: Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclis ...
- 【附源码】Python计算机毕业设计面向智慧课堂的教学过程管理系统
项目运行 环境配置: Pychram社区版+ python3.7.7 + Mysql5.7 + HBuilderX+list pip+Navicat11+Django+nodejs. 项目技术: dj ...
最新文章
- 自己实现一个最简单的数据库
- DelphiX教程系列 4 - 滚动背景 part 1
- angular 动态取到的html片段 在页面的展示
- Android Intent基本使用
- 网络体系结构(OSI模型和TCP/IP协议 功能)
- simplified build configuration
- Java多线程学习十七:读锁应该插队吗?什么是读写锁的升降级?
- 如何在Timeline中使用Cinemachine?
- 拖拽动态生成网页-VvvebJs
- 汽车+辐射测试软件,汽车EMC辐射发射的一些所见所闻和思考
- swoft使用redis
- Atitit 非结构化数据管理法 目录 1. 什么是非结构化数据?	1 2. 对非结构化数据也即对全文数据的搜索主要有两种方法:	2 2.1. 顺序扫描法(Serial Scanning):	2 2
- 基于SpringCloud Alibaba实现的论坛
- css中引入下载字体的方法
- 微信小程序实现图片上传
- java从本地下载pdf文件_java下载PDF文件
- Stellarium 0.19.0 发布,开源 3D 天象模拟软件
- java ckfinder_java 使用ckfinder
- Elasticsearch:如何在聚合时选择所需要的 bucket 并进行可视化
- Typora常用快捷键(详细)
热门文章
- 手掌是人体健康的晴雨表
- python抢火车票成功率_用Python抢火车票
- 公司发的月饼出虫了~~~~
- flutter应用安卓商店合规化处理
- 基于java-web的公园景区导游网站系统jsp版本---计算机毕业设计
- 【制作多媒体演示文稿软件】Focusky教程 | 六个高效演示文稿综合制作技巧
- h710阵列卡支持最大硬盘_DELL服务器RAID磁盘阵列级别迁移 (RLM)(以H710P阵列卡为例)...
- 关于使用UIWebView加载HTTPS站点出现NSURLErrorDomain code=-1202
- 计算机专业英语+贾任,网络环境下的高职英语教学_网络与高职英语教学的整合_贾泽军...
- 电工的恶魔果实-布线-PCB系列教程1-13