1. 项目背景与核心需求
山西大同大学学生公寓管理系统是一个典型的校园信息化建设项目,旨在解决传统纸质化宿舍管理中的效率低下、数据孤岛等问题。我在实际开发中发现,高校宿舍管理通常面临三大痛点:
- 人工分配宿舍耗时耗力,每年新生入学时管理员需要处理上千份住宿申请
- 水电费收缴依赖线下登记,经常出现漏记错记的情况
- 访客管理缺乏数字化记录,安全隐患难以追溯
这个系统采用前后端分离架构,前端使用Vue 3组合式API开发,后端基于Spring Boot 2.7.x构建,数据持久层选用MyBatis-Plus 3.5.x。这种技术栈组合在2023年高校信息化项目中已成为主流选择,主要优势在于:
- Vue的响应式特性非常适合处理频繁变动的宿舍调换数据
- Spring Boot的自动配置简化了复杂的权限管理体系开发
- MyBatis-Plus的Lambda查询大大减少了基础CRUD代码量
2. 系统架构设计详解
2.1 技术选型决策过程
在技术验证阶段,我们对比了多种方案:
前端框架选型:
- Vue vs React:最终选择Vue是因为其更平缓的学习曲线,方便学校后续自主维护
- UI库对比:Element Plus vs Ant Design Vue,选择Element Plus因其表单组件更符合管理系统需求
后端技术决策:
- 放弃JPA选择MyBatis-Plus,因为需要复杂SQL处理宿舍分配算法
- 使用Hutool工具包处理Excel导入导出,比Apache POI更简洁
数据库设计:
- MySQL 8.0版本,利用其窗口函数优化统计报表查询
- 专门为宿舍楼栋表添加空间索引,支持按地理位置查询
2.2 核心功能模块实现
2.2.1 智能宿舍分配算法
// 基于专业、班级的分配策略实现 public class DormAllocator { public List<Student> autoAllocate(List<Student> students) { return students.stream() .collect(Collectors.groupingBy(s -> s.getMajor() + "_" + s.getClassId())) .values().stream() .flatMap(group -> { // 每个专业班级按性别分组 Map<Boolean, List<Student>> byGender = group.stream() .collect(Collectors.partitioningBy(Student::isMale)); return Stream.concat( allocateByGender(byGender.get(true)), allocateByGender(byGender.get(false)) ); }).collect(Collectors.toList()); } }关键点:算法需要处理边缘情况,如同性别人数不足填满整个宿舍时,采用"填空+新开"的混合策略
2.2.2 水电费计算模块
-- 按月统计宿舍水电费的视图 CREATE VIEW dorm_utility_view AS SELECT d.dorm_id, SUM(CASE WHEN u.type = 'water' THEN u.amount ELSE 0 END) AS water_usage, SUM(CASE WHEN u.type = 'electric' THEN u.amount ELSE 0 END) AS electric_usage, (water_rate * SUM(CASE WHEN u.type = 'water' THEN u.amount ELSE 0 END) + electric_rate * SUM(CASE WHEN u.type = 'electric' THEN u.amount ELSE 0 END)) AS total_fee FROM dorm d JOIN utility_record u ON d.dorm_id = u.dorm_id GROUP BY d.dorm_id;3. 开发中的典型问题与解决方案
3.1 并发分配冲突处理
当多个管理员同时操作宿舍分配时,出现了床位重复分配的问题。我们最终采用两种方案结合:
- 数据库层面:在bed表添加version字段实现乐观锁
- 应用层面:使用Redisson分布式锁控制分配入口
@Transactional public AllocationResult allocateBed(Long studentId, Long dormId) { RLock lock = redissonClient.getLock("alloc:" + dormId); try { lock.lock(10, TimeUnit.SECONDS); // 检查床位状态 Bed targetBed = bedMapper.selectOne(new LambdaQueryWrapper<Bed>() .eq(Bed::getDormId, dormId) .eq(Bed::getStatus, 0) .last("FOR UPDATE")); if(targetBed != null) { // 更新状态 targetBed.setStatus(1); targetBed.setStudentId(studentId); bedMapper.updateById(targetBed); return AllocationResult.success(targetBed.getBedNo()); } return AllocationResult.fail("无可用床位"); } finally { lock.unlock(); } }3.2 大数据量导出优化
在生成整栋楼的住宿名单Excel时,最初方案导致OOM。改进方案:
- 使用Apache POI的SXSSFWorkbook实现流式导出
- 添加分页查询,每次处理500条记录
- 前端采用WebSocket推送导出进度
public void exportDormStudents(Long buildingId, HttpServletResponse response) { SXSSFWorkbook workbook = new SXSSFWorkbook(100); // 保留100行在内存中 // 分页查询 int pageSize = 500; int pageNo = 1; while(true) { Page<Student> page = studentService.page(new Page<>(pageNo, pageSize), new LambdaQueryWrapper<Student>() .eq(Student::getBuildingId, buildingId)); if(page.getRecords().isEmpty()) break; // 写入当前页数据 writePageData(workbook, page.getRecords()); pageNo++; } // 写入响应流 workbook.write(response.getOutputStream()); workbook.dispose(); }4. 系统安全与权限设计
4.1 基于RBAC的权限模型
系统设计了五级角色:
- 超级管理员(校方IT)
- 公寓管理员
- 楼栋管理员
- 辅导员
- 学生
使用Spring Security结合JWT实现鉴权,关键配置:
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/api/admin/**").hasRole("ADMIN") .antMatchers("/api/building/**").access("@rbacService.checkBuildingAccess(authentication,#request)") .anyRequest().authenticated() .and() .addFilter(new JwtAuthenticationFilter(authenticationManager())) .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); return http.build(); } }4.2 敏感数据保护措施
- 学生身份证号等字段使用AES加密存储
- 日志系统自动脱敏敏感信息
- 数据库审计日志记录所有数据变更
5. 部署与性能优化
5.1 生产环境配置
服务器配置:
- 前端:Nginx容器(2C4G)
- 后端:Spring Boot应用(4C8G)×2实例
- 数据库:MySQL主从架构(8C16G)
关键JVM参数:
-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:InitiatingHeapOccupancyPercent=45 -Xms4g -Xmx4g5.2 缓存策略设计
使用多级缓存提升查询性能:
- 本地缓存(Caffeine):缓存静态数据如楼栋信息
- Redis缓存:
- 热点数据:宿舍剩余床位数
- 分布式锁:宿舍分配过程
- MySQL查询缓存:配置表等低频修改数据
@Cacheable(value = "dorm", key = "#dormId") public DormInfo getDormInfo(Long dormId) { return dormMapper.selectByIdWithDetails(dormId); } @CacheEvict(value = "dorm", key = "#dormId") public void updateDorm(Dorm dorm) { dormMapper.updateById(dorm); }6. 项目总结与扩展思考
在实际开发过程中,有几个经验值得特别分享:
数据一致性保障:宿舍调换涉及多个表更新,我们最终采用TCC模式实现分布式事务,补偿机制设计是关键
移动端适配:后期新增微信小程序入口,发现需要重构部分API以适应移动端场景,建议初期就考虑多端兼容
监控系统集成:接入Prometheus监控后发现,宿舍查询接口的99线偶尔飙高,最终通过添加复合索引解决
系统未来可扩展方向:
- 物联网集成:对接智能电表实现自动抄表
- 人脸识别:结合门禁系统实现刷脸进出
- 数据分析:建立学生行为分析模型辅助管理决策