1. 项目背景与核心需求
在高校信息化建设进程中,学生考勤管理一直是教学管理的重要环节。传统纸质签到方式存在代签、统计效率低等问题,而基于微信小程序的签到系统具有以下优势:
- 无需安装独立APP,通过微信即可使用
- 利用微信原生能力(定位、摄像头等)实现防作弊
- 实时数据同步,教师可即时查看考勤情况
- 与学校现有SSM框架系统无缝对接
这个项目的核心功能模块包括:
- 学生端:签到、请假申请、考勤记录查询
- 教师端:课程管理、考勤统计、异常处理
- 管理端:系统配置、数据导出、报表生成
实际开发中发现,微信小程序的用户授权机制与网页端有显著差异,特别是获取用户身份信息时需要特别注意合规性,避免违反平台规则。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计
2.1 前端技术选型
采用微信小程序原生框架+WUX组件库的组合方案:
javascript复制// 典型页面结构示例
Page({
data: {
courseList: [],
currentLocation: null
},
onLoad() {
this.getLocation()
this.loadCourses()
},
getLocation() {
wx.getLocation({
type: 'gcj02',
success: (res) => {
this.setData({currentLocation: res})
}
})
}
})
选择原生框架而非uniapp等跨平台方案的原因:
- 性能更优,特别是地图、相机等原生功能调用
- 避免跨平台兼容性问题
- 直接使用微信提供的API和组件
2.2 后端技术栈
采用经典的SSM(Spring+SpringMVC+MyBatis)架构:
- Spring 5.2.6:IoC容器和事务管理
- SpringMVC:RESTful API设计
- MyBatis 3.5.6:数据持久层
- MySQL 8.0:关系型数据库
- Redis 6.0:缓存和会话管理
数据库主要表结构设计:
- 学生表(student):学号、姓名、班级等
- 课程表(course):课程ID、名称、时间地点等
- 考勤记录(attendance):关联学生和课程,含时间、位置等
3. 核心功能实现细节
3.1 地理位置签到防作弊
实现原理:
- 学生端获取当前GPS坐标(wx.getLocation)
- 与课程预设坐标比对(Haversine公式计算距离)
- 只有距离在100米内才允许签到
关键代码:
java复制// 距离计算工具类
public class LocationUtils {
private static final double EARTH_RADIUS = 6378137;
public static double getDistance(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 * EARTH_RADIUS;
}
}
3.2 人脸识别辅助验证
为防止代签,系统集成百度AI人脸识别:
- 首次使用采集学生人脸特征
- 签到时进行活体检测和人脸比对
- 相似度阈值设置为85%以上通过
配置示例:
xml复制<!-- Spring配置人脸识别服务 -->
<bean id="faceService" class="com.xxx.service.FaceServiceImpl">
<property name="appId" value="${baidu.face.appId}"/>
<property name="apiKey" value="${baidu.face.apiKey}"/>
<property name="secretKey" value="${baidu.face.secretKey}"/>
</bean>
4. 系统集成与部署
4.1 微信小程序配置
必须完成的微信平台配置:
- 服务器域名白名单(request合法域名)
- 业务域名配置(web-view使用)
- 消息推送配置(模板消息)
- 安全域名设置(图片等资源域名)
小程序app.json典型配置:
json复制{
"pages": [
"pages/index/index",
"pages/signin/signin",
"pages/record/record"
],
"permission": {
"scope.userLocation": {
"desc": "用于获取当前位置完成签到"
}
}
}
4.2 SSM后端部署要点
-
Tomcat配置优化:
- 连接池大小调整
- 静态资源缓存设置
- GZIP压缩启用
-
数据库分表策略:
- 按学期分表存储考勤记录
- 使用MyBatis拦截器实现动态表名
-
定时任务设计:
- 每日凌晨统计前一天考勤
- 每周生成课程考勤报表
5. 开发中的典型问题与解决方案
5.1 微信授权问题
常见场景:用户拒绝授权地理位置后如何引导重新授权
解决方案:
javascript复制// 检查授权状态
wx.getSetting({
success(res) {
if (!res.authSetting['scope.userLocation']) {
wx.showModal({
title: '需要位置授权',
content: '请允许获取位置信息以完成签到',
success(res) {
if (res.confirm) {
wx.openSetting() // 引导用户打开设置
}
}
})
}
}
})
5.2 高并发签到处理
当多个班级同时签到时可能出现的问题:
- 数据库插入冲突
- 缓存雪崩
- 接口响应变慢
优化方案:
- 使用Redis队列缓冲签到请求
- 数据库批量插入代替单条插入
- 增加CDN节点分散静态资源压力
Spring配置示例:
java复制@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}
}
6. 扩展功能与优化方向
6.1 数据可视化分析
基于ECharts实现考勤数据可视化:
- 班级出勤率趋势图
- 学生个人考勤日历
- 异常签到热力图
实现要点:
javascript复制// 小程序端使用ec-canvas组件
<ec-canvas id="mychart-dom-bar"
canvas-id="mychart-bar"
ec="{{ ec }}"></ec-canvas>
Page({
data: {
ec: {
lazyLoad: true
}
},
onLoad() {
this.ecComponent = this.selectComponent('#mychart-dom-bar')
this.initChart()
},
initChart() {
this.ecComponent.init((canvas, width, height) => {
const chart = echarts.init(canvas, null, {
width: width,
height: height
})
chart.setOption({...})
return chart
})
}
})
6.2 离线签到功能
针对网络不稳定场景的设计:
- 本地缓存签到数据(wx.setStorage)
- 定时尝试同步(wx.onNetworkStatusChange监听)
- 冲突解决策略(时间戳比对)
核心逻辑:
javascript复制// 离线签到处理
function offlineSign(courseId) {
const timestamp = Date.now()
const record = {
courseId,
timestamp,
status: 'pending'
}
wx.setStorageSync('offline_sign', record)
// 定时尝试同步
const timer = setInterval(() => {
if (wx.getNetworkType().isConnected) {
uploadOfflineRecord()
clearInterval(timer)
}
}, 5000)
}
在实际部署中发现,iOS和Android平台在后台网络恢复时的行为不一致,需要分别处理重连逻辑。特别是在教学楼等网络信号不稳定的区域,完善的离线机制可以显著提升用户体验。
