1. 项目概述
作为一名经历过多次高校信息化系统开发的老手,我深知传统考勤管理中的痛点:教师上课点名耗时、手工记录易错、数据统计困难。这个基于SpringBoot+Vue的大学生考勤系统,正是为解决这些实际问题而设计的全栈解决方案。
系统采用前后端分离架构,后端使用SpringBoot提供RESTful API接口,前端基于Vue.js构建响应式界面,数据库选用MySQL 8.0。特别适合作为Java Web方向的毕业设计项目,因为:
- 技术栈主流且完整(涵盖Spring Security、JWT、ECharts等)
- 业务场景贴近实际需求(高校确实需要这类系统)
- 复杂度适中但足够体现技术水平(包含权限管理、数据可视化等难点)
提示:我在实际部署时发现,MySQL 8.0默认使用caching_sha2_password认证插件,如果客户端驱动较旧会出现连接问题。建议在application.yml中明确指定useSSL=false和allowPublicKeyRetrieval=true参数。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统架构设计
2.1 技术栈选型解析
后端技术组合:
- SpringBoot 2.7.x:快速构建微服务,内嵌Tomcat简化部署
- Spring Security + JWT:实现无状态的认证授权体系
- MyBatis-Plus:比原生MyBatis更便捷的ORM框架
- Hutool:国产工具库,处理加密、日期等常见操作
- Lombok:通过注解减少样板代码
前端技术组合:
- Vue 3.x:组合式API比Options API更灵活
- Element Plus:适合中后台项目的UI组件库
- Axios:处理HTTP请求,配合拦截器实现JWT自动刷新
- ECharts 5.0:展示考勤统计的折线图、柱状图
数据库设计要点:
- 所有表字段使用下划线命名法(如user_id)
- 密码字段使用BCrypt加密存储(Spring Security默认算法)
- 建立外键关系但不在数据库层面强制约束(如attendance.student_id关联user.user_id)
2.2 核心数据模型
用户表(user)的设计考虑了扩展性:
sql复制CREATE TABLE `user` (
`user_id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '学号/工号',
`password_hash` varchar(255) NOT NULL COMMENT 'BCrypt加密',
`real_name` varchar(50) DEFAULT NULL,
`role_type` tinyint NOT NULL COMMENT '1学生 2教师 3管理员',
`class_id` bigint DEFAULT NULL COMMENT '学生所在班级',
`register_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`user_id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
考勤记录表(attendance)包含状态机设计:
java复制public enum AttendanceStatus {
PRESENT(1, "出勤"),
ABSENT(2, "缺勤"),
LATE(3, "迟到"),
LEAVE(4, "请假");
private final int code;
private final String desc;
// 省略getter和constructor
}
3. 关键功能实现
3.1 JWT认证流程
- 登录接口返回双Token:
java复制public LoginResult login(String username, String password) {
// 验证账号密码...
return LoginResult.builder()
.accessToken(JwtUtil.generateAccessToken(user))
.refreshToken(JwtUtil.generateRefreshToken(user))
.build();
}
- 前端Token刷新机制:
javascript复制// axios响应拦截器
instance.interceptors.response.use(response => {
return response
}, error => {
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true
return refreshToken().then(res => {
store.commit('updateToken', res.data.accessToken)
originalRequest.headers.Authorization = 'Bearer ' + res.data.accessToken
return instance(originalRequest)
})
}
return Promise.reject(error)
})
3.2 考勤数据可视化
使用ECharts实现教师端的统计视图:
vue复制<template>
<div ref="chart" style="width: 600px; height:400px;"></div>
</template>
<script setup>
import * as echarts from 'echarts'
import { onMounted, ref } from 'vue'
const chart = ref(null)
onMounted(async () => {
const res = await getAttendanceStats()
const myChart = echarts.init(chart.value)
myChart.setOption({
tooltip: { trigger: 'axis' },
legend: { data: ['出勤率', '迟到率'] },
xAxis: { type: 'category', data: res.data.dates },
yAxis: { type: 'value' },
series: [
{ name: '出勤率', type: 'line', data: res.data.presentRates },
{ name: '迟到率', type: 'bar', data: res.data.lateRates }
]
})
})
</script>
4. 部署与运维实践
4.1 多环境配置
使用Spring Profiles区分环境:
yaml复制# application-dev.yml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/attendance_dev?useSSL=false
username: dev_user
password: dev123
# application-prod.yml
spring:
datasource:
url: jdbc:mysql://prod-db:3306/attendance_prod?useSSL=false
username: ${DB_USER}
password: ${DB_PASS}
4.2 前端打包优化
配置vue.config.js实现:
javascript复制module.exports = {
chainWebpack: config => {
config.plugin('html').tap(args => {
args[0].title = '大学生考勤系统'
return args
})
config.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
echarts: {
name: 'chunk-echarts',
test: /[\\/]node_modules[\\/]echarts[\\/]/,
priority: 30
}
}
})
}
}
5. 开发经验与避坑指南
-
时间处理陷阱:
- 前端传参使用ISO8601格式("2023-08-15T14:30:00")
- MySQL时区设置为Asia/Shanghai
- Java代码中明确指定TimeZone:
java复制@PostConstruct void init() { TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai")); }
-
跨域解决方案:
后端配置允许前端地址跨域:java复制@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://localhost:8081") .allowedMethods("*") .allowCredentials(true) .maxAge(3600); } } -
MyBatis-Plus分页失效:
需要配置分页拦截器:java复制@Configuration public class MyBatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return interceptor; } }
这个项目我在实际部署时遇到一个典型问题:当并发考勤提交时出现重复记录。最终通过数据库唯一索引解决:
sql复制ALTER TABLE attendance
ADD UNIQUE INDEX uk_student_course_time (student_id, course_id, DATE(check_time));
对于毕业设计答辩,建议重点准备以下技术点的阐述:
- 如何保证JWT的安全性(过期时间、刷新机制)
- 前后端分离项目的会话管理方案
- ECharts动态数据加载的实现原理
- 权限系统的RBAC模型设计
