ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

微信小程序课堂签到源码:SSM+MySQL实现四种签到方式

微信小程序课堂签到源码:SSM+MySQL实现四种签到方式 简介这份资源是课堂签到微信小程序的完整源码与项目文档后台采用SSM框架结合MySQL开发面向计算机、数学、电子信息等专业的学生可用于课程设计、期末大作业或毕业设计参考。项目实现了限时签到、密码签到、手势签到和位置签到四种模式覆盖了从微信小程序前端到Java后端接口的完整链路适合具备一定Java与前端基础、希望深入理解签到业务逻辑与SSM整合的开发者学习借鉴。压缩包共367个文件约18.3MB包含40个Java源文件、28个XML配置、33个JAR依赖包以及小程序端的27个JS、22个WXML、23个WXSS和25个JSON文件另有SQL脚本、JSP页面与项目说明文档目录结构清晰便于按模块查阅。目前已有32人学习下载。读者可从中获取完整的签到系统实现方案包括数据库建表脚本、后端控制器与实体类、小程序页面交互逻辑以及限时、密码、手势、位置四类签到的具体代码实现适合作为二次开发与功能扩展的参考基础。1. 课堂签到小程序从 SSM 后台到四种签到方式一套能跑通的源码怎么落地课堂签到这件事做过教学系统的人都知道它有多“玄学”。老师要的是三秒内点完名学生要的是别在教室门口排队扫码而开发者要面对的是限时签到怎么防代签、密码签到怎么防泄露、手势签到怎么防偷看、位置签到怎么防虚拟定位。这套基于微信小程序 SSM 框架 MySQL 的课堂签到源码把四种签到方式做成了可切换的模块后台用 Java 写业务逻辑前端用小程序原生组件渲染数据全部落在 MySQL 里。它适合两类人一是正在找 Java 课程设计案例源码的学生二是想快速搭一套课堂考勤系统的开发者。源码和项目文档都在但能不能跑起来、跑起来之后怎么改才是真正要解决的问题。2. 环境搭建JDK、Tomcat、MySQL 和微信开发者工具怎么配才不打架2.1 后台运行环境的最小依赖清单SSM 框架的本质是 Spring SpringMVC MyBatis 三件套它对环境的要求并不苛刻但版本错配是新手翻车的重灾区。我一般会锁定一套经过验证的组合JDK 1.8不要用 JDK 11 以上Spring 4.x 的反射机制在高版本 JDK 上会报InaccessibleObjectException、Tomcat 8.5Tomcat 9 对 Servlet 4.0 的支持有细微差异部分老标签库会失效、MySQL 5.7MySQL 8.0 的驱动类名和时区配置都变了源码里的jdbc.properties大概率没改、Maven 3.6。组件推荐版本不推荐版本原因JDK1.811/17Spring 4.x 反射兼容性Tomcat8.59.xServlet 版本差异MySQL5.78.0驱动类名和时区配置Maven3.63.9部分老插件不兼容MySQL 安装配置教程网上很多但有一个坑必须提前说源码里的数据库连接串通常写的是jdbc:mysql://localhost:3306/checkin?useUnicodetruecharacterEncodingutf-8如果你装的是 MySQL 8.0驱动类要从com.mysql.jdbc.Driver改成com.mysql.cj.jdbc.Driver连接串还要加serverTimezoneAsia/Shanghai否则启动就报时区错误。2.2 导入源码后必须改的四个配置文件拿到源码包后不要急着点运行。先找到src/main/resources目录里面有四个文件需要按你的环境改# jdbc.properties —— 数据库连接 jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/checkin?useUnicodetruecharacterEncodingutf-8 jdbc.usernameroot jdbc.password你的密码!-- applicationContext.xml —— 扫描包路径 -- context:component-scan base-packagecom.checkin.controller/ context:component-scan base-packagecom.checkin.service/!-- spring-mvc.xml —— 视图解析器和静态资源 -- bean classorg.springframework.web.servlet.view.InternalResourceViewResolver property nameprefix value/WEB-INF/jsp// property namesuffix value.jsp/ /bean mvc:resources mapping/static/** location/static//# wechat.properties —— 小程序 AppID 和 Secret appid你的小程序AppID secret你的小程序Secret这四个文件改完数据库建好、表结构导入 SQL 文件Tomcat 挂上去启动后台基本就能跑。如果启动报ClassNotFoundException八成是 Maven 依赖没下全执行mvn clean install -DskipTests重新拉一遍。2.3 微信开发者工具侧的三处关键设置小程序端在微信开发者工具里打开后有三处必须改。第一处是app.js里的globalData.serverUrl改成你本机的 IP 加端口比如http://192.168.1.100:8080不要写localhost因为开发者工具的请求是从模拟器发出的localhost指向的是模拟器自己。第二处是project.config.json里的appid换成你自己的测试号或正式 AppID。第三处是开发者工具的“详情 → 本地设置”勾选“不校验合法域名”否则所有请求都会被拦截。提示如果你在真机上调试手机和电脑必须在同一个局域网且电脑防火墙要放行 8080 端口。Windows 防火墙默认会拦这个坑我踩过不止一次。3. 四种签到方式的实现限时、密码、手势、位置各自怎么落库3.1 签到主表设计一张表怎么装下四种签到类型四种签到方式看起来差异很大但落到数据库层面核心字段是共用的。我一般会设计一张sign_in_task表存签到任务一张sign_in_record表存签到记录。CREATE TABLE sign_in_task ( id INT NOT NULL AUTO_INCREMENT, teacher_id INT NOT NULL COMMENT 发起签到的教师ID, course_id INT NOT NULL COMMENT 课程ID, type TINYINT NOT NULL COMMENT 1限时 2密码 3手势 4位置, password VARCHAR(32) DEFAULT NULL COMMENT 密码签到时的密码, gesture_path VARCHAR(128) DEFAULT NULL COMMENT 手势路径序列化字符串, latitude DECIMAL(10,7) DEFAULT NULL COMMENT 位置签到纬度, longitude DECIMAL(10,7) DEFAULT NULL COMMENT 位置签到经度, radius INT DEFAULT 100 COMMENT 位置签到有效半径(米), start_time DATETIME NOT NULL, end_time DATETIME NOT NULL, status TINYINT DEFAULT 1 COMMENT 1进行中 0已结束, PRIMARY KEY (id), KEY idx_course (course_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;CREATE TABLE sign_in_record ( id INT NOT NULL AUTO_INCREMENT, task_id INT NOT NULL, student_id INT NOT NULL, sign_time DATETIME DEFAULT CURRENT_TIMESTAMP, distance DECIMAL(8,2) DEFAULT NULL COMMENT 位置签到时距签到点的距离, status TINYINT DEFAULT 1 COMMENT 1成功 0失败, PRIMARY KEY (id), UNIQUE KEY uk_task_student (task_id, student_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;sign_in_task表用type字段区分四种签到password、gesture_path、latitude/longitude/radius分别对应密码、手势、位置三种签到的参数。sign_in_record表的uk_task_student唯一索引是关键它从数据库层面防止同一个学生对同一个任务重复签到比在代码里查一遍再插入可靠得多。3.2 限时签到时间窗口校验和防代签的取舍限时签到的逻辑最简单但防代签是最难的。源码里的做法是教师发起签到时设定start_time和end_time学生在这个窗口内点击签到按钮后台校验当前时间是否在窗口内。// SignInServiceImpl.java public Result signByTime(Integer taskId, Integer studentId) { SignInTask task taskMapper.selectById(taskId); if (task null || task.getType() ! 1) { return Result.error(签到任务不存在); } Date now new Date(); if (now.before(task.getStartTime()) || now.after(task.getEndTime())) { return Result.error(不在签到时间范围内); } // 唯一索引兜底重复插入会抛异常 try { SignInRecord record new SignInRecord(); record.setTaskId(taskId); record.setStudentId(studentId); record.setSignTime(now); recordMapper.insert(record); } catch (DuplicateKeyException e) { return Result.error(请勿重复签到); } return Result.success(签到成功); }这段代码的逻辑说明先查任务是否存在且类型匹配再校验时间窗口最后靠数据库唯一索引防重。参数方面start_time和end_time的间隔建议不要超过 5 分钟时间越长代签风险越大。如果要做更严格的防代签可以叠加位置校验但那就是位置签到的范畴了。限时签到有一个容易被忽略的坑服务器时间和手机时间不一致。学生手机显示还在窗口内但服务器已经过了end_time签到就会失败。解决办法是在小程序端用服务器返回的时间做倒计时而不是用本地时间。3.3 密码签到和手势签到两种“知识型”签到的实现差异密码签到的逻辑是教师设置一个 4 到 6 位的数字密码学生在小程序里输入密码后台比对sign_in_task.password字段。手势签到则是教师在小程序端绘制一个手势路径路径被序列化成字符串存入gesture_path学生绘制相同路径才能签到。// 密码签到 public Result signByPassword(Integer taskId, Integer studentId, String inputPassword) { SignInTask task taskMapper.selectById(taskId); if (task null || task.getType() ! 2) { return Result.error(签到任务不存在); } if (!task.getPassword().equals(inputPassword)) { return Result.error(密码错误); } // 后续插入记录逻辑同上 return insertRecord(taskId, studentId); }// 手势签到路径比对 public Result signByGesture(Integer taskId, Integer studentId, String gesturePath) { SignInTask task taskMapper.selectById(taskId); if (task null || task.getType() ! 3) { return Result.error(签到任务不存在); } // gesturePath 格式如 0-1-2-5-8表示经过的九宫格点位 if (!task.getGesturePath().equals(gesturePath)) { return Result.error(手势错误); } return insertRecord(taskId, studentId); }密码签到的参数建议密码长度 4 到 6 位纯数字避免字母和特殊字符因为学生在手机上输入字母很麻烦。手势签到的路径序列化格式源码里用的是九宫格点位编号用短横线连接比如0-1-2-5-8。这里有一个血泪经验手势路径不要允许太简单的比如0-1-2这种一条直线同学之间看一眼就记住了。我一般会在前端加一个校验要求至少经过 4 个点且不能是直线。密码和手势这两种方式有一个共同的弱点密码会泄露手势会被偷看。所以它们适合小班教学或者对考勤要求不严格的场景。如果要做大班考勤位置签到才是主力。3.4 位置签到经纬度距离计算和虚拟定位的对抗位置签到的核心是计算学生当前位置与教师设定的签到点之间的距离如果小于radius字段设定的半径就允许签到。距离计算用 Haversine 公式// 计算两个经纬度之间的距离米 private static final double EARTH_RADIUS 6371000; public static double getDistance(double lat1, double lng1, double lat2, double lng2) { double radLat1 Math.toRadians(lat1); double radLat2 Math.toRadians(lat2); double deltaLat radLat1 - radLat2; double deltaLng Math.toRadians(lng1) - Math.toRadians(lng2); double a Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) Math.cos(radLat1) * Math.cos(radLat2) * Math.sin(deltaLng / 2) * Math.sin(deltaLng / 2); double c 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return EARTH_RADIUS * c; }参数说明EARTH_RADIUS取 6371000 米是地球平均半径这个精度对课堂签到足够了。radius字段建议设 100 到 200 米太小了 GPS 漂移会导致签不上太大了学生可以在教学楼外面签。我一般设 150 米兼顾容错和防作弊。虚拟定位是位置签到最大的敌人。学生用虚拟定位软件把手机位置改到教室后台拿到的是假经纬度。对抗手段有几个一是校验sign_in_record.distance字段如果距离为 0 或者异常小标记为可疑二是结合 Wi-Fi 指纹但小程序拿不到 Wi-Fi 信息三是用微信的wx.getLocation的type参数设为gcj02这个坐标系在国内有偏移校正虚拟定位软件改出来的坐标往往对不上。源码里用的是第一种简单但有效。注意wx.getLocation需要在app.json里声明permission字段否则真机上调用会直接失败。这个配置在开发者工具里不报错但真机必现很多人在这里翻车。4. 避坑与排查源码跑不起来时先看这五个地方4.1 启动报 404URL 映射和视图解析器的双重检查现象Tomcat 启动成功但访问任何接口都返回 404。原因通常是 SpringMVC 的组件扫描没扫到 Controller 包或者RequestMapping的路径和请求路径对不上。解决先看spring-mvc.xml里的component-scan是否包含了 Controller 所在包再看 Controller 类上有没有Controller注解最后确认web.xml里DispatcherServlet的url-pattern是/而不是/*。/*会拦截所有请求包括静态资源导致 JSP 和 JS 文件也 404。4.2 数据库连接池报错驱动版本和连接串的匹配问题现象启动时报Cannot create PoolableConnectionFactory或Unknown system variable query_cache_size。原因MySQL 8.0 的驱动和 5.7 的驱动类名不同且 8.0 移除了query_cache_size变量。解决如果是 MySQL 8.0驱动类改成com.mysql.cj.jdbc.Driver连接串加serverTimezoneAsia/ShanghaiuseSSLfalse。如果是 5.7检查jdbc.properties里的驱动类是不是com.mysql.jdbc.Driver。另外Maven 的pom.xml里 MySQL 驱动的版本也要和数据库版本匹配5.7 用5.1.478.0 用8.0.20以上。4.3 小程序请求失败域名校验和 IP 配置的连环坑现象开发者工具里请求正常真机上请求全部失败。原因微信小程序真机环境要求所有请求的域名必须在后台配置白名单且必须是 HTTPS。开发阶段可以用 IP 加端口但要在开发者工具里勾选“不校验合法域名”并且真机调试时手机和电脑在同一局域网。解决如果只是本地调试用开发者工具的“预览”模式不要用“真机调试”模式预览模式会继承“不校验合法域名”的设置。如果要真机调试把电脑的 IP 固定下来不要用 DHCP 自动分配否则第二天 IP 变了又要改配置。4.4 位置签到距离计算偏差大坐标系没统一现象学生明明在教室但距离计算出来是几百米甚至几公里。原因微信wx.getLocation默认返回wgs84坐标系而国内地图服务用的是gcj02两者之间有几百米的偏移。解决调用wx.getLocation时把type参数设为gcj02教师端设定签到点时也用gcj02坐标。如果教师端是从地图选点获取的坐标确认地图 SDK 返回的是gcj02还是wgs84不统一的话距离计算永远对不上。4.5 重复签到没拦住唯一索引和事务的配合现象学生快速点击签到按钮插入了两条记录。原因代码里先查再插两个请求同时查到“没有记录”然后都执行插入。解决在sign_in_record表上建(task_id, student_id)唯一索引插入时捕获DuplicateKeyException。这是最可靠的防重方式比在代码里加锁简单得多。如果业务要求更严格可以在 Service 层加Transactional注解但唯一索引仍然是最后一道防线。5. 从能跑到好用签到数据导出和异常签到的二次校验源码跑通只是第一步真正投入教学使用后教师最需要的是两件事导出签到数据做平时分统计以及识别异常签到做二次校验。先说数据导出。SSM 框架里用 POI 导出 Excel 是最常见的做法但有一个细节容易被忽略签到记录表里存的是student_id导出的表格里教师要看到的是学号和姓名。所以 SQL 查询要关联学生表SELECT s.student_no, s.name, r.sign_time, r.distance, r.status FROM sign_in_record r JOIN student s ON r.student_id s.id WHERE r.task_id #{taskId} ORDER BY r.sign_time ASC;导出时用XSSFWorkbook创建.xlsx文件表头写“学号、姓名、签到时间、距离(米)、状态”distance字段只有位置签到才有值其他类型签到时为NULL导出时显示为空即可。这个表格直接可以贴到平时分统计表里用。再说异常签到的二次校验。位置签到里distance字段小于 10 米的记录值得怀疑因为 GPS 精度通常在 10 到 50 米之间距离为 0 或个位数说明坐标可能被篡改。我一般会在后台加一个“异常签到”筛选按钮把distance 10或者sign_time与start_time间隔小于 3 秒的记录标红。教师看到标红记录后可以手动确认是否有效。这个功能不复杂但很实用相当于给签到数据加了一层后悔药。还有一个进阶技巧把签到记录和课程表关联自动计算每个学生的出勤率。出勤率 有效签到次数 / 总签到任务数。这个计算可以在 SQL 里用COUNT和GROUP BY完成也可以在前端用 JavaScript 算。我习惯在后台算好前端只负责展示因为后台算一次可以缓存前端每次刷新都要重算。最后说一个我自己的习惯每次改完签到逻辑不要只在开发者工具里测一定要用真机走一遍完整流程——教师发起签到、学生签到、后台查记录、导出 Excel。开发者工具的模拟定位和真机 GPS 差异很大位置签到尤其明显。这个习惯帮我拦住了至少三次“开发者工具正常但真机翻车”的问题。希望帮到你。本文还有配套的精品资源点击获取
返回列表