1. 项目背景与核心需求
在大学计算机专业的毕业设计中,开发一个基于SpringBoot的二维码课堂签到系统是个非常实用的选题。这个系统主要解决传统纸质签到效率低、容易代签的问题,同时为教师提供便捷的考勤管理工具。
我在实际教学中发现,传统签到方式存在几个痛点:一是点名耗时,50人的班级可能需要10分钟;二是代签现象普遍,教师难以辨别;三是考勤数据统计繁琐。而二维码签到系统能实现:
- 即时生成动态二维码,防止截图转发
- 自动记录签到时间和位置信息
- 一键导出考勤报表
- 支持异常签到情况标注
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术选型与架构设计
2.1 核心技术栈
这个系统采用经典的SpringBoot+MyBatis技术组合:
- SpringBoot 2.7.5:简化配置,快速搭建Web应用
- MyBatis-Plus 3.5.1:增强的ORM框架,减少SQL编写
- Redis 6.2:缓存二维码数据,提高并发性能
- MySQL 8.0:存储用户和考勤数据
- ZXing 3.4.1:二维码生成与识别库
提示:建议使用SpringBoot 2.x稳定版而非3.x,因为部分学校实验室环境可能还在使用JDK8。
2.2 系统架构
系统采用三层架构设计:
- 表现层:Thymeleaf模板引擎+少量jQuery
- 业务层:Spring MVC处理请求,自定义业务逻辑
- 数据层:MyBatis操作MySQL,Redis缓存热点数据
关键类设计:
java复制// 二维码生成服务
@Service
public class QrCodeService {
private final RedisTemplate<String, String> redisTemplate;
public String generateQrCode(String courseId) {
String randomCode = UUID.randomUUID().toString();
redisTemplate.opsForValue().set("QR:"+courseId, randomCode, 5, TimeUnit.MINUTES);
return QRCodeGenerator.generate(randomCode);
}
}
// 签到记录实体
@Data
@TableName("attendance_record")
public class AttendanceRecord {
private Long id;
private Long studentId;
private Long courseId;
private LocalDateTime signTime;
private String location;
private Integer status; // 0正常 1迟到 2早退
}
3. 核心功能实现细节
3.1 动态二维码生成
关键实现点在于防止二维码被截图转发:
- 每次生成带随机码的二维码
- 随机码5分钟有效期(通过Redis TTL控制)
- 前端每60秒自动刷新二维码
java复制// 二维码生成工具类
public class QRCodeGenerator {
public static String generate(String content) throws WriterException {
QRCodeWriter writer = new QRCodeWriter();
BitMatrix matrix = writer.encode(content, BarcodeFormat.QR_CODE, 300, 300);
ByteArrayOutputStream os = new ByteArrayOutputStream();
MatrixToImageWriter.writeToStream(matrix, "PNG", os);
return "data:image/png;base64," +
Base64.getEncoder().encodeToString(os.toByteArray());
}
}
3.2 签到业务流程
完整签到流程包括:
- 教师端发起签到,生成动态二维码
- 学生扫描二维码,提交学号信息
- 系统验证二维码有效性
- 记录签到信息(含GPS定位)
- 返回签到结果
mermaid复制sequenceDiagram
participant Teacher
participant System
participant Student
Teacher->>System: 发起签到请求
System->>Teacher: 返回动态二维码
Student->>System: 扫描二维码提交学号
System->>System: 验证二维码有效性
System->>Student: 返回签到结果
3.3 考勤数据分析
系统提供多维度的考勤统计:
- 按课程统计出勤率
- 按学生统计缺勤次数
- 异常签到(异地签到、时间异常)标记
sql复制-- 周出勤率统计SQL示例
SELECT
student_id,
COUNT(CASE WHEN status = 0 THEN 1 END) AS normal_count,
COUNT(*) AS total_count,
ROUND(COUNT(CASE WHEN status = 0 THEN 1 END)*100.0/COUNT(*),2) AS rate
FROM attendance_record
WHERE course_id = #{courseId}
AND sign_time BETWEEN #{startDate} AND #{endDate}
GROUP BY student_id
4. 开发中的关键问题与解决方案
4.1 并发签到问题
当多个学生同时扫码时可能出现的问题:
- 二维码重复使用
- 数据库插入冲突
解决方案:
- 使用Redis分布式锁控制并发
- 数据库添加唯一索引(student_id, course_id, date)
java复制public boolean signIn(Long studentId, String qrCode) {
String lockKey = "LOCK:" + studentId;
try {
// 获取分布式锁
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
if (Boolean.TRUE.equals(locked)) {
// 验证二维码逻辑...
return true;
}
return false;
} finally {
redisTemplate.delete(lockKey);
}
}
4.2 定位信息处理
获取学生签到位置的两个方案:
- 微信JS-SDK获取地理位置(需公众号权限)
- HTML5 Geolocation API(精度较低)
实际采用混合方案:
javascript复制// 前端定位代码示例
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
position => {
const {latitude, longitude} = position.coords;
submitSignIn(latitude, longitude);
},
error => {
// 失败时使用IP定位
fetch('/api/location/by-ip')
.then(res => res.json())
.then(data => submitSignIn(data.lat, data.lng));
}
);
}
}
5. 毕业设计扩展建议
5.1 功能扩展方向
- 人脸识别签到:结合OpenCV实现活体检测
- 微信小程序端:方便学生使用
- 异常签到预警:基于历史数据智能分析
- 请假审批流程:线上请假与考勤联动
5.2 论文撰写要点
在毕业设计论文中建议包含:
- 系统需求分析(用例图、流程图)
- 二维码安全机制设计
- 性能测试方案(JMeter压测报告)
- 与传统签到方式的对比分析
注意:论文中的系统架构图建议使用PlantUML绘制,比Visio更专业。
6. 部署与运维实践
6.1 生产环境部署
推荐部署方案:
- 开发环境:IDEA内嵌Tomcat
- 测试环境:Docker Compose(MySQL+Redis+应用)
- 生产环境:Nginx反向代理 + 多实例负载均衡
关键Nginx配置:
nginx复制upstream sign_system {
server 127.0.0.1:8080 weight=1;
server 127.0.0.1:8081 weight=1;
}
server {
listen 80;
server_name sign.yourschool.edu.cn;
location / {
proxy_pass http://sign_system;
proxy_set_header Host $host;
}
}
6.2 监控与日志
建议添加的监控项:
- 二维码生成频率监控
- 签到成功率监控
- 系统响应时间监控
使用Spring Boot Actuator暴露监控端点:
properties复制# application.properties
management.endpoints.web.exposure.include=health,metrics,prometheus
management.metrics.tags.application=sign-system
7. 项目源码结构说明
核心代码目录结构:
code复制src/
├── main/
│ ├── java/
│ │ └── edu/
│ │ └── yourschool/
│ │ ├── config/ # 配置类
│ │ ├── controller/ # 控制器
│ │ ├── service/ # 业务逻辑
│ │ ├── mapper/ # MyBatis接口
│ │ ├── entity/ # 数据库实体
│ │ └── util/ # 工具类
│ └── resources/
│ ├── static/ # 静态资源
│ ├── templates/ # 模板文件
│ └── application.yml # 配置文件
└── test/ # 测试代码
关键配置文件示例:
yaml复制# application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/sign_system?useSSL=false
username: root
password: yourpassword
redis:
host: localhost
port: 6379
8. 常见问题排查指南
8.1 二维码生成失败
可能原因及解决方案:
- ZXing依赖冲突:检查是否有多个版本的zxing-core
xml复制<dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.4.1</version> </dependency> - Redis连接超时:检查Redis服务是否启动,网络是否通畅
8.2 定位信息不准
优化方案:
- 增加WiFi指纹定位
- 使用第三方定位服务(如高德API)
- 设置合理的位置误差范围(如100米内视为有效)
8.3 系统性能优化
实测有效的优化手段:
- 二维码图片缓存(Redis)
- 考勤统计结果预计算
- 数据库添加适当索引
sql复制CREATE INDEX idx_attendance ON attendance_record(course_id, sign_time);
9. 毕业设计答辩准备建议
9.1 演示重点
建议在答辩中重点演示:
- 动态二维码生成与刷新过程
- 并发签到测试(可使用JMeter模拟)
- 考勤数据可视化报表
- 异常签到检测功能
9.2 可能提问
准备以下问题的回答:
- 如何防止二维码被截图冒用?
- 系统最大支持多少并发签到?
- 定位不准时如何处理?
- 与市面商业产品的区别是什么?
我在实际开发中发现,使用Lombok的@Builder注解可以大幅简化实体类的构建,但在继承场景下需要特别处理:
java复制@Data
@SuperBuilder
@NoArgsConstructor
public class BaseEntity {
private Long id;
private LocalDateTime createTime;
}
@Data
@EqualsAndHashCode(callSuper = true)
@SuperBuilder
@NoArgsConstructor
public class User extends BaseEntity {
private String username;
}
