ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Spring Boot+小程序GPS定位考勤系统:从源码到部署全解析

2026/9/28 6:28:11 拓冰建站 浏览量
Spring Boot+小程序GPS定位考勤系统:从源码到部署全解析 简介一套基于 Spring Boot 与小程序前端的本科毕业设计——上课考勤系统完整源码包面向计算机相关专业学生、毕业设计选题者以及希望快速上手前后端分离开发的入门工程师。系统覆盖后台管理、小程序前端 GPS 签到、定位打卡、迟到统计等功能模块并附有 docx 格式的系统操作文档可用于毕业设计答辩准备和后续二次开发。资源共 488 个文件压缩包体约 4.3MB主要包含 js、wxml、wxss 等小程序前端文件java、xml、yml、properties 等后端源码与配置以及 png 图片、sql 数据库脚本和系统操作文档目录结构细致便于按模块检索和学习。目前已有 944 人学习下载尤其适合作为课程设计、毕业设计的完整参考。系统设计曾获优秀毕业设计其中 GPS 定位签到与迟到统计模块贴近真实考勤场景能帮助读者从数据库设计、接口开发到小程序端交互对照实践完整走通 Spring Boot 小程序的项目流程。1. 拿到这套 Java 小程序考勤系统代码先别急着双击运行一份标注了“优秀毕业设计”的 Java 小程序上课考勤系统源代码从解压到跑通中间隔着三步看数据库脚本、配环境、理解签到链路。这不是一套“下载就能用”的工具而是一份完整的课程设计答案——后端基于 Spring Boot 快速开发框架小程序端负责 GPS 定位打卡后台管理覆盖课程配置、学生维护和迟到统计。对正在做 Java 毕业设计、或者想快速搭一套带位置校验的业务系统的从业者来说它最大的价值不是帮你省一个月的开发时间而是让你看清“定位签到”这个功能从哪下手。我用一晚上的时间把它从零跑到真机把启动步骤、参数坑和核心逻辑全拆在下面。2. 系统架构与签到定位原理Spring Boot 后台、小程序前端与 GPS 距离计算2.1 三个端的分工小程序、后台管理、MySQL 数据层这套考勤系统从工程目录来看属于典型的前后端分离结构小程序端是学生拿手机打卡的入口后台管理端跑在浏览器里数据统一落在 MySQL。三个端各管一段边界很清晰。小程序端做的事只有一个——拿定位、发起签到。具体来说学生进入小程序后看到当前课程点击签到按钮时前端调用wx.getLocation获取当前经纬度连同用户身份和课程 ID 一起提交给后端接口。它不负责判断“有没有迟到”更不负责算“距离够不够”这些全部抛给后台。后台管理端则是另一套界面面向教师或教务人员。这里能看到课程列表、学生名单、签到记录也能配置“这门课几点开始、允许迟到几分钟、签到半径设多少米”。之所以强调这套系统用了快速开发框架是因为这些增删改查页面绝大多数是框架自动生成的菜单、权限、字典、日志这些毕设必写的“基础设施”不用自己从头造轮子。MySQL 负责把数据关系串起来学生表、课程表、考勤记录表是最核心的三张表。考勤记录表里会存学生的经纬度、签到时间、签到状态正常/迟到/异常后台所有统计都从这张表上做聚合查询。三端的关系用一个链条概括就是小程序产生签到事件后端消费事件并落库后台管理从库里取数展示。理解这层分工对第二步“启动项目”很有用——很多人拿到代码先找Application.java然后点运行跑起来后又发现前端连不上后端、后端查不到数据就是因为没先在脑子里把这套链路画出来。2.2 定位签到是怎么算“在不在教室”的整个系统里技术含量最高的点就是这个 GPS 签到。它的原理并不复杂只用到了两个距离判断第一小程序提交的经纬度坐标系是gcj02国测局坐标。这是微信wx.getLocation默认返回的坐标系属于火星座标系不能直接当作真实经纬度去画地图但用来算相对距离没有问题。第二后端拿到学生坐标后要和这门课预先设置好的“签到点”坐标算球面距离然后和配置的签到半径比较。距离小于等于半径判定签到成功大于半径就算人在教室门口也照样记成异常。算球面距离的常见做法是 Haversine 公式。我把这个公式写成一个工具方法放到后端的工具类里就能直接复用public static double distance(double lat1, double lng1, double lat2, double lng2) { double radLat1 Math.toRadians(lat1); double radLat2 Math.toRadians(lat2); double a radLat1 - radLat2; double b Math.toRadians(lng1) - Math.toRadians(lng2); double s 2 * Math.asin(Math.sqrt( Math.pow(Math.sin(a / 2), 2) Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2) )); return s * 6371.0 * 1000; // 单位米 }这段代码里6371.0是地球半径单位是公里乘 1000 后返回米。如果你把签到半径配置成 200 米那传入的两个坐标点距离在 200 米以内就放行。实际部署时我会把结果再保留一位小数用BigDecimal格式化避免浮点数直接比较时出现边界误差。有一个细节容易忽略签到半径不要写死在后端代码里尽量做成课程的配置字段。我见过不少毕设源码把半径常量硬编码成 100 米结果换到操场点名就全军覆没。这套系统既然走的是课程维度把半径挂到课程表上一个字段就解决。2.3 快速开发框架给毕设省下来的工作量如果这套系统完全从零手写 Spring Boot你要做的事会多出很多——用户登录、验证码、菜单权限、操作日志、数据字典哪一样都和考勤业务无关但哪一样又都是毕设论文里会被评审老师翻出来问的东西。快速开发框架的价值就在这里登录认证是现成的用户表和角色表一关联权限就生效菜单是配置驱动的加一个菜单项就能在后台管理页面看到新功能入口操作日志和 SQL 日志默认开启演示的时候能直接截一张日志记录图放进论文。我一般拿到这类框架项目习惯先去看数据库脚本里有没有sys_user、sys_menu、sys_role这种前缀的表——只要看到它们心里就有数了业务代码只需要关注考勤自己那部分。这也是为什么很多学校评“优秀毕业设计”时使用快速开发框架的项目更容易出彩——不是因为它技术含量高而是因为它的“完成度”看起来很高。评审老师看到的不只是签到功能本身还有完整的管理后台、权限体系和操作留痕这些都是容易被加分的地方。但这套系统真正区别于“换皮商城”类毕设的地方是它的业务闭环是完整的学生签到 → 后端校验距离 → 落库 → 后台统计迟到。所以后面几章我会按这个闭环一步步讲。3. 本地启动流程JDK 1.8 MySQL 5.7 环境下的导入与运行3.1 启动前检查JDK、MySQL、微信开发者工具三件套这套系统对环境的要求很明确项目正文里写着jdk1.8和mysql5.7这两条必须严格照做。先说 JDK——我见过太多人本地装的是 Java 11 甚至 Java 17导入 Spring Boot 老项目后一启动就报UnsupportedClassVersionError或者反射异常这不是代码问题是编译和运行环境不一致。建议你把 JDK 1.8 单独装在一个目录比如D:\Java\jdk1.8.0_202然后在JAVA_HOME里指过去尽量不要动你日常开发用的高版本 JDK两个版本共存更稳妥。然后是 MySQL。项目要求 5.7这个版本要注意的是连接方式。MySQL 8.0 开始默认的认证插件改成了caching_sha2_password而很多老项目的驱动和连接池配置还是按 5.7 的mysql_native_password写的。如果你手头只有 MySQL 8.0启动大概率会卡在数据库认证这一步。最省心的方案是直接装 5.7或者用启动脚本里自带的 Dockerfile 起一个 5.7 的容器命令如下docker build -t mykq-mysql . docker run -d --name mykq-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD123456 mykq-mysqlDocker 方式的好处是不污染本机环境缺点是新手处理容器和宿主机之间的网络、端口映射容易绕晕所以我更建议本地直接装 MySQL 5.7装完用命令行mysql -uroot -p验证一下能连上再继续。第三个环境是微信开发者工具。小程序端代码不能用普通浏览器跑必须装微信官方的开发者工具。装完之后先不用急着导入项目后面 3.3 节统一处理。3.2 导入 mykq.sql字符集与排序规则这次别再选错数据库是这套系统的地基mykq.sql就是地基图纸。项目正文里专门强调了两件事导入时选择编码为utf8排序规则默认utf8_general_ci。这行提示看着不起眼实际踩坑率极高——用 Navicat 导入的时候如果数据库默认字符集是utf8mb4表大概率能建出来但后面查询中文数据会出现“问号”或者排序异常。我建议新建数据库时显式指定字符集而不是依赖工具的默认值CREATE DATABASE IF NOT EXISTS mykq DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;建完库之后再导入脚本。命令行导入最直接Windows 下打开 cmd 切到 SQL 文件所在目录执行mysql -uroot -p --default-character-setutf8 mykq mykq.sql这里--default-character-setutf8一定要加上它保证的是 SQL 文件里的中文字面量在传输过程中不会被转义乱掉。如果你用 Navicat注意选择数据库后右键“运行 SQL 文件”文件编码处手动选 UTF-8不要让它自动检测。导入完成之后别急着下一步先验证表结构。跑一句 SQL 看一下SHOW TABLES;正常情况下你能看到用户表、课程表、学生表、考勤记录表还应该有一批sys_开头的框架表。如果sys_user或者等价的管理员表不在列表里说明 SQL 脚本可能只导入了一部分回看上一个命令有没有报错。3.3 后端启动与小程序端联调数据库就绪后后端启动有两种方式。项目根目录里有个winStart.batWindows 下双击就能跑脚本内部做的是mvnw.cmd spring-boot:run这类启动动作。它的好处是不用你先装 Maven——项目自带了 Maven Wrappermvnw.cmd会拿着maven-wrapper.jar按项目里锁定的 Maven 版本自动下载并按需使用这对没配过 Maven 环境变量的同学非常友好。第一次运行会下载依赖耗时取决于网络耐心等就好。启动成功后控制台会出现 Spring Boot 的启动日志关键信息是一个 Tomcat 端口号常见的是8080具体端口以你的application.yml配置为准。看到Started ... in x.xxx seconds字样说明后端已经在跑了。小程序端的导入稍微有一点讲究。打开微信开发者工具选择“导入项目”目录指向源码里的小程序前端目录AppID 可以先选“测试号”。项目导入后第一件要做的事是检查后端的请求地址——小程序代码里会有一个封装request的公共 JS 文件里面通常会有baseUrl或者host常量把它改成http://localhost:8080或者你电脑的局域网 IP。这一步经常出问题的地方在于安全校验。默认情况下微信开发者工具会校验 request 的合法域名而开发阶段你的后端是http://localhost既不是 HTTPS 也不在域名白名单里所以要在开发者工具的“详情→本地设置”里勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”。不勾这个前端请求一发出去就会被工具拦下来。联调成功的标志是小程序里能看到课程列表点击签到后地图上出现定位点后台管理端刷出对应考勤记录。到这里整套系统才真正算跑通。4. 核心业务的数据流转GPS 签到、迟到统计与后台管理的协作逻辑4.1 一次签到的完整链路小程序定位 → 后端校验 → 写入考勤表把一次成功签到的完整链路拆开看其实是五个步骤串联。前端先调wx.getLocation拿坐标这一步在真机上会唤起授权弹窗拿到坐标后前端再调后端签到接口把studentId、courseId、latitude、longitude和当前时间一起传过去后端接口收到请求先查课程配置里的签到点和签到半径然后用上一章的距离公式算出学生位置和签到点的距离距离在范围内就组装一条考勤记录写入数据库状态设为“正常”。接口的伪代码逻辑大致如下public Result signIn(SignRequest request) { Course course courseMapper.selectById(request.getCourseId()); double distance GpsUtils.distance( request.getLatitude(), request.getLongitude(), course.getLatitude(), course.getLongitude()); Attendance record new Attendance(); record.setStudentId(request.getStudentId()); record.setCourseId(course.getId()); record.setSignTime(new Date()); if (distance course.getRadius()) { record.setStatus(NORMAL); attendanceMapper.insert(record); return Result.ok(签到成功); } else { record.setStatus(ABNORMAL); attendanceMapper.insert(record); return Result.error(不在签到范围内当前位置距离签到点约 (int) distance 米); } }这段代码有两个值得注意的参数设计。第一个是course.getRadius()签到半径从课程表读取而不是写死这是我在真实项目里强烈建议保留的做法——不同教室的物理环境差别很大阶梯教室和户外操场需要的半径完全不同。第二个是“不在范围内也落库”很多初学者会直接拒绝写入但实际更合理的做法是把这次异常签到存下来保留学生的位置和时间后台管理端才能看到“谁尝试过签到但没进范围”的记录。4.2 迟到统计的判定逻辑与课程时间配置迟到统计是这套系统的另一个核心卖点。它本质上是一道时间判断题课程配置里有两个时间字段——“上课时间”和“宽限分钟数”。学生签到时后端拿到当前时间先判断是不是早于上课时间是就是正常签到晚于上课时间再看有没有超过宽限期没超过算正常超过了就改成“迟到”。这个逻辑的巧妙之处在于它把“迟到”的判定从简单的“晚于上课时间”细化到了“晚到但可接受”的区间让统计结果更符合实际教学场景。配置一般在课程管理页面完成课程表里会有start_time、late_minutes这种字段。对应的判定代码可以用下面这个简化版表达LocalTime now LocalTime.now(); LocalTime startTime course.getStartTime(); LocalTime deadline startTime.plusMinutes(course.getLateMinutes()); if (now.isBefore(startTime) || now.isBefore(deadline)) { record.setStatus(NORMAL); } else { record.setStatus(LATE); }这里要提示一个容易忽略的数据类型细节时间比较直接用LocalTime不要用字符串。老代码里常见的问题是课程开始时间存成了08:30这种字符串后端比较时用compareTo结果由于格式不统一出现“08:5”和“08:30”这类脏数据。项目里的表设计如果不是datetime而是字符串建议你拿到代码后第一件事就检查这个字段的取值格式。迟到统计的结果最终要落到后台管理页面上。常见做法是后台提供一个按课程、按日期范围查询考勤记录的列表列表里直接展示每条记录的签到状态再用一个聚合查询算出某门课某天的迟到人数和签到率。只要考勤记录表里的status字段区分得够细这些统计都是几条 SQL 的事不需要额外引入复杂的统计组件。4.3 后台管理的角色权限与数据展示考勤系统的后台管理端是快速开发框架主要发挥作用的地方。管理端的功能大体分成三块第一块是基础数据维护。学生信息、课程信息的增删改查这些都是框架自带 CRUD 页面数据库表结构对上页面就能用。课程管理页里除了课程名称、上课时间还要预留签到半径和签到点的经纬度字段。有些项目会把签到点做成地图选点前端引入地图组件后点一个位置自动回填经纬度比手动输入坐标体验好很多。第二块是考勤记录查询。后台提供一个带筛选条件的列表页常见条件有课程、日期、状态正常/迟到/异常。这个列表要支持导出方便老师月底把考勤记录交给教务。部分源码会在列表页右上角直接放一个“导出 Excel”按钮如果没有这正好是你可以自己去扩展的小功能点。第三块是权限控制。框架自带的用户-角色-菜单模型决定了谁能看到哪些菜单。毕设演示时一般用管理员账号登录能看到全部功能如果你要把系统做成多角色演示比如“教师”角色只看得到自己教的课程那需要给课程表加上“授课教师”关联字段。后台管理和小程序端之间还有一个容易忽略的数据同步问题管理端配置了新的签到点或改了上课时间小程序端再次进入课程页时必须拉到的是最新配置。这类问题通常靠小程序端的下拉刷新或者重新进入页面时onShow里重新请求接口解决。我在调试时遇到过“后台改了半径小程序始终按老半径判断”的情况最后发现是小程序本地缓存了课程信息——建议签到相关的课程配置不要做前端缓存每次都从接口拉。5. 避坑与常见问题排查启动失败、定位不准、签名报错的五个现场5.1 问题排查的正确顺序不管代码出什么幺蛾子我建议你按“环境 → 数据库 → 接口 → 前端”的顺序排查。环境指的是 JDK 版本、MySQL 版本、端口占用数据库指的是字符集、表结构完整性、连接配置接口指的是后端日志里的报错堆栈最后才是前端的问题。绝大多数毕设项目跑不起来问题都出在前两层而不是代码写法本身。后面四条坑是我在拆这个项目时实际遇到过的现场每一条按“现象 → 原因 → 解决”展开直接照做就行。5.2 五个高频坑的完整记录坑一导入 mykq.sql 后中文全部变成问号现象用 Navicat 导入 SQL 之后打开课程表发现课程名称显示 “???”数据量没少文字全部乱掉。原因导入时数据库连接没有指定字符集。Navicat 默认按 UTF-8 传输但如果数据库创建时的默认字符集是latin1表继承了库的字符集中文写入时就丢了。另一个更隐蔽的原因是 SQL 文件本身在 Windows 下被双击打开并修改过编码从 UTF-8 被另存成了 ANSI。解决严格按 3.2 节来先建库指定utf8和utf8_general_ci再导入。如果已经导乱了先把库删掉重建不要手动去改表字符集重复导入很容易留下脏数据。坑二后端启动时报数据库连接错误一长串Access denied现象Spring Boot 启动日志跑到HikariPool初始化那一块就抛异常提示用户被拒绝访问密码错误或者无法连接端口和 IP 都没问题。原因八成是application.yml里的数据库账号密码和本地 MySQL 不一致。下载源码自带的配置用的是作者本机密码比如root/123456而你本地 MySQL 密码不是这个。更麻烦的情况是 MySQL 5.7 的root账号用了auth_socket插件本地命令行能连JDBC 连不上。解决先打开配置文件确认连接串把spring.datasource.url、username、password改成你本地真实的值。改完再重启如果还报Access denied就用管理员身份进 MySQL执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码; FLUSH PRIVILEGES;这条命令把认证插件换回老版本驱动认识的mysql_native_password一次搞定。坑三小程序里点击签到一直转圈后台没有任何请求日志现象小程序端点击签到按钮后一直 loading后端控制台没有任何请求进入。开发者工具里打开调试面板能看到request请求的报错常见提示是不在合法域名列表。原因开发者工具默认开启域名校验http://localhost或者局域网 IP 不在白名单。这是微信对小程序的硬性限制不是代码问题。解决在开发者工具的“详情 → 本地设置”里勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”。如果你需要真机预览手机和电脑连同一个局域网后端地址改成电脑的局域网 IP同时手机微信里打开调试模式。坑四真机上定位结果和实际位置偏差几百公里现象开发者工具里签到一切正常换成手机真机预览后定位到的坐标在学校所在的省、但具体位置完全不对签到系统直接判定不在范围内。原因开发者工具默认的模拟定位是深圳也就是腾讯总部所在地。如果课程签到点配的是本地坐标模拟定位当然没意义。真机上出现大偏差则要看是不是wx.getLocation的type参数写成了wgs84——这个坐标系是 GPS 原始坐标在中国大陆地图上使用会整体偏移。解决开发者工具里在“详情 → 本地设置”中手动修改模拟定位把它调到课程签到点的经纬度。真机调试则确认代码里type用的是gcj02wx.getLocation({ type: gcj02, success: (res) { this.setData({ latitude: res.latitude, longitude: res.longitude }); } });坑五后端改完代码重启后端口被占用现象spring-boot:run启动时报Port 8080 was already in use或者启动到一半失败。原因上一次启动的后端进程没有被正确杀掉。如果你用 IDE 启动过项目进程可能还存活在后台winStart.bat这种启动脚本关闭窗口时也不一定能把 Java 子进程带走。解决Windows 下打开任务管理器找到 Java 相关的进程直接结束或者命令行执行netstat -ano | findstr 8080 taskkill /PID 你的进程号 /F建议每次重启前养成先清端口的习惯尤其是反复调试的阶段。6. 进阶改造把考勤数据导出成 Excel 报表并补齐答辩演示细节这套系统跑通之后最值得做的第一个改造是给考勤记录加上 Excel 导出功能。老师在期末看考勤几乎不会对着后台管理页面慢慢翻能直接导出报表是一个很加分的功能点。项目本身没有这个能力的话用 Apache POI 写一个导出接口并不复杂。思路是后台考勤列表页加一个“导出”按钮调用一个独立的导出接口后端把查询结果写入.xlsx文件通过HttpServletResponse直接写回浏览器触发下载。核心代码用 POI 实现按课程名和日期分组输出XSSFWorkbook workbook new XSSFWorkbook(); XSSFSheet sheet workbook.createSheet(考勤统计); ListAttendanceVO list attendanceMapper.selectByCourse(courseId); int rowNum 0; for (AttendanceVO item : list) { Row row sheet.createRow(rowNum); row.createCell(0).setCellValue(item.getStudentName()); row.createCell(1).setCellValue(item.getCourseName()); row.createCell(2).setCellValue(item.getSignTime()); row.createCell(3).setCellValue(item.getStatus()); } response.setContentType(application/vnd.openxmlformats-officedocument.spreadsheetml.sheet); response.setHeader(Content-Disposition, attachment; filenameattendance.xlsx); workbook.write(response.getOutputStream()); workbook.close();这段代码是导出功能的骨架。注意setContentType必须用对应的 MIME 类型否则浏览器下载下来的文件没有后缀名文件名最好带上日期用String.format(attendance_%s.xlsx, LocalDate.now())拼一下避免多人导出时文件重名覆盖。答辩演示的时候还有两个小的细节值得注意。第一个是演示数据不能太干净数据库里最好有连续几天的考勤记录包含几条迟到、一条签到点外的异常记录这样演示迟到统计和异常查询时才有素材。第二个是提前准备好一个专门用来演示的“签到点”配置在开发者工具里手动把模拟位置设到签到点 50 米以内演示时点签到按钮路径最短也最稳。我自己的习惯是拿到任何一套新源码第一件事永远是打开 SQL 脚本把表关系和数据字典过一遍而不是先点启动。这套考勤系统让我印象最深的就是 3.2 节那个字符集提示如果没有它我大概率会在乱码上面耗掉一个小时。从那以后我每次导入数据库脚本都会强制自己先建库、再指定字符集、最后导数据一步都不跳。这个习惯帮我避开过不少藏在数据库初始化里的坑希望帮到你。本文还有配套的精品资源点击获取