基于SSM框架的高校宿舍管理系统 - 源码深度解析

JavaJavaScriptMavenHTMLCSSSSM框架MySQL
2026-03-013 浏览

文章摘要

本项目是基于SSM(Spring + Spring MVC + MyBatis)框架开发的高校宿舍管理系统,旨在解决高校后勤管理中宿舍分配、信息维护、学生入住办理等环节长期依赖人工操作、数据分散、效率低下的核心痛点。系统通过数字化整合,将宿舍资源、学生信息、维修申报等业务流程集中在线处理,显著提升了...

在高校后勤管理体系中,宿舍管理长期面临着数据分散、流程繁琐、效率低下的挑战。传统依赖纸质档案和人工协调的方式,在新生入学、宿舍调换、日常运维等高峰期往往不堪重负,易出现分配冲突、信息更新滞后、维修响应缓慢等问题。数字化转型升级成为提升管理效能、优化学生居住体验的必然选择。

本项目正是针对这一痛点,设计并实现了一套集宿舍资源管理、学生入住办理、维修申报、信息查询于一体的综合管理平台。系统采用业界成熟的SSM框架组合进行构建,旨在通过技术手段将线下业务流程标准化、线上化,为高校后勤部门、宿舍管理员及在校学生提供全流程、可追溯的数字化解决方案。

技术架构与选型

系统采用经典的三层架构模式,清晰分离表示层、业务逻辑层和数据持久层,确保系统具备良好的可维护性、可扩展性和松耦合特性。

后端技术栈

  • Spring Framework:作为项目的核心控制容器,负责管理所有Bean的生命周期,并通过依赖注入机制实现各组件间的解耦。其声明式事务管理功能为宿舍分配、调换等关键操作提供了数据一致性保障。
  • Spring MVC:承担Web请求的调度职责。通过基于注解的控制器设计,简化了请求映射、参数绑定和视图解析的过程。集成自定义拦截器,实现了统一的用户身份认证与权限校验逻辑。
  • MyBatis:作为数据持久层框架,通过XML映射文件将Java对象与数据库表进行灵活映射。其强大的动态SQL能力,有效支持了系统中多条件、分页查询等复杂数据操作需求。

前端与数据层

  • 前端界面采用JSP动态页面技术,结合jQuery库处理页面交互逻辑,并使用Bootstrap前端框架构建响应式、风格统一的用户界面,确保在不同设备上均有良好的操作体验。
  • 数据库选用MySQL,利用其稳定性和事务支持特性存储系统所有业务数据。项目通过Maven进行依赖管理和构建,确保了第三方库版本的一致性和项目构建的自动化。

核心数据库设计剖析

一个稳健的数据库设计是系统高效运行的基石。本系统共设计18张数据表,以下选取几个核心表进行深入分析。

1. 宿舍楼与宿舍信息表 (dormitory_building, dormitory_room)

宿舍资源的管理是系统的核心。设计上采用两级结构,先定义宿舍楼,再定义具体的宿舍房间。

CREATE TABLE `dormitory_building` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `building_no` varchar(20) NOT NULL COMMENT '楼栋编号',
  `building_name` varchar(50) DEFAULT NULL COMMENT '楼栋名称',
  `total_floors` int(11) DEFAULT NULL COMMENT '总层数',
  `manager_id` int(11) DEFAULT NULL COMMENT '负责管理员ID',
  `description` text COMMENT '描述信息',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_building_no` (`building_no`),
  KEY `idx_manager` (`manager_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='宿舍楼栋表';

CREATE TABLE `dormitory_room` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `room_no` varchar(20) NOT NULL COMMENT '房间号',
  `building_id` int(11) NOT NULL COMMENT '所属楼栋ID',
  `floor` int(11) NOT NULL COMMENT '所在楼层',
  `bed_count` int(11) NOT NULL DEFAULT '4' COMMENT '床位数量',
  `occupied_bed_count` int(11) NOT NULL DEFAULT '0' COMMENT '已入住床位数量',
  `room_type` varchar(10) DEFAULT 'STANDARD' COMMENT '房间类型',
  `status` varchar(20) DEFAULT 'AVAILABLE' COMMENT '房间状态',
  `telephone` varchar(20) DEFAULT NULL COMMENT '房间电话',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_building_room` (`building_id`, `room_no`),
  KEY `idx_building` (`building_id`),
  KEY `idx_status` (`status`),
  CONSTRAINT `fk_room_building` FOREIGN KEY (`building_id`) REFERENCES `dormitory_building` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='宿舍房间表';

设计亮点

  • 数据完整性:通过外键约束 FOREIGN KEY 确保每个房间都必须归属于一个已存在的楼栋,删除楼栋时ON DELETE CASCADE会自动级联删除其下所有房间,避免脏数据。
  • 业务逻辑前置bed_countoccupied_bed_count字段的设计,使得快速判断房间是否已满(occupied_bed_count < bed_count)无需关联查询床位表,提升了查询效率。
  • 状态管理status字段用于标识房间是否可用、维修中或已满员,便于进行条件筛选和业务控制。

2. 学生住宿信息表 (student_accommodation)

此表是连接学生与宿舍床位的关键枢纽,记录了学生的入住历史。

CREATE TABLE `student_accommodation` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `student_id` int(11) NOT NULL COMMENT '学生ID',
  `bed_id` int(11) NOT NULL COMMENT '床位ID',
  `check_in_date` date NOT NULL COMMENT '入住日期',
  `expected_check_out_date` date DEFAULT NULL COMMENT '预计退宿日期',
  `actual_check_out_date` date DEFAULT NULL COMMENT '实际退宿日期',
  `accommodation_status` varchar(20) NOT NULL DEFAULT 'CHECKED_IN' COMMENT '住宿状态',
  `operator_id` int(11) DEFAULT NULL COMMENT '操作员ID',
  `remarks` text COMMENT '备注',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_student_active` (`student_id`, `accommodation_status`),
  KEY `idx_bed` (`bed_id`),
  KEY `idx_check_in_date` (`check_in_date`),
  CONSTRAINT `fk_accommodation_student` FOREIGN KEY (`student_id`) REFERENCES `student_info` (`id`),
  CONSTRAINT `fk_accommodation_bed` FOREIGN KEY (`bed_id`) REFERENCES `dormitory_bed` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生住宿信息表';

设计亮点

  • 唯一性约束UNIQUE KEY uk_student_active (student_id, accommodation_status) 是关键设计。它允许一个学生有多条历史住宿记录,但只能有一条状态为“已入住”的活跃记录,从数据库层面防止了学生被重复分配床位。
  • 状态与时间跟踪:通过accommodation_status和三个日期字段,可以清晰追踪学生从入住到退宿的完整生命周期,便于生成统计报表和办理流程控制。

核心功能模块实现解析

1. 学生宿舍分配与入住办理

新生入学或老生调换宿舍时,宿舍分配是核心流程。系统提供了自动分配和手动分配两种模式。

后端控制器 (DormAllocationController.java) 处理分配请求:

@Controller
@RequestMapping("/admin/allocation")
public class DormAllocationController {

    @Autowired
    private DormAllocationService allocationService;

    /**
     * 批量自动分配宿舍
     * @param batchReq 包含专业、班级、性别等分配条件
     * @return 分配结果
     */
    @PostMapping("/batchAuto")
    @ResponseBody
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<ApiResult> batchAutoAllocation(@RequestBody BatchAllocationRequest batchReq) {
        try {
            // 参数校验
            if (batchReq.getDepartmentId() == null || batchReq.getStudentCount() <= 0) {
                return ResponseEntity.badRequest().body(ApiResult.error("参数错误"));
            }

            // 调用服务层进行分配逻辑
            AllocationResult result = allocationService.executeBatchAutoAllocation(batchReq);
            return ResponseEntity.ok(ApiResult.success("分配成功", result));
        } catch (NoAvailableRoomException e) {
            return ResponseEntity.status(HttpStatus.CONFLICT).body(ApiResult.error(e.getMessage()));
        } catch (Exception e) {
            log.error("批量分配异常", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ApiResult.error("系统内部错误"));
        }
    }
}

服务层 (DormAllocationServiceImpl.java) 包含核心分配算法:

@Service
@Transactional
public class DormAllocationServiceImpl implements DormAllocationService {

    @Override
    public AllocationResult executeBatchAutoAllocation(BatchAllocationRequest request) throws NoAvailableRoomException {
        // 1. 根据条件(如性别、专业)筛选出可用的宿舍房间列表
        List<DormitoryRoom> availableRooms = dormitoryRoomMapper.selectAvailableRoomsByCriteria(request);
        if (availableRooms.isEmpty()) {
            throw new NoAvailableRoomException("当前没有符合条件的可用宿舍");
        }

        // 2. 按房间类型、楼层等规则排序,确定分配优先级
        availableRooms.sort((r1, r2) -> {
            // 优先分配剩余床位多的房间,使住宿相对集中
            int availableBed1 = r1.getBedCount() - r1.getOccupiedBedCount();
            int availableBed2 = r2.getBedCount() - r2.getOccupiedBedCount();
            return Integer.compare(availableBed2, availableBed1);
        });

        AllocationResult result = new AllocationResult();
        int remainingStudents = request.getStudentCount();
        List<AllocationDetail> details = new ArrayList<>();

        // 3. 循环分配,直到所有学生都被分配或房间用完
        for (DormitoryRoom room : availableRooms) {
            if (remainingStudents <= 0) break;

            int bedsToAssign = Math.min(remainingStudents, room.getAvailableBedCount());
            List<DormitoryBed> beds = dormitoryBedMapper.selectEmptyBedsByRoomId(room.getId(), bedsToAssign);

            for (DormitoryBed bed : beds) {
                // 4. 为每个床位创建预分配记录(此时学生ID可能暂未绑定)
                AllocationDetail detail = createPreAllocation(bed, request);
                details.add(detail);
                remainingStudents--;
            }
            // 5. 更新房间已入住床位数量
            dormitoryRoomMapper.increaseOccupiedCount(room.getId(), beds.size());
        }

        if (remainingStudents > 0) {
            throw new NoAvailableRoomException("宿舍资源不足,尚有 " + remainingStudents + " 名学生未分配");
        }

        result.setAllocationDetails(details);
        result.setTotalAllocated(request.getStudentCount() - remainingStudents);
        return result;
    }

    private AllocationDetail createPreAllocation(DormitoryBed bed, BatchAllocationRequest request) {
        StudentDormAllocation allocation = new StudentDormAllocation();
        allocation.setBedId(bed.getId());
        allocation.setAllocationStatus("PRE_ALLOCATED");
        allocation.setAllocationDate(new Date());
        allocation.setAcademicYear(request.getAcademicYear());
        allocation.setOperatorId(request.getOperatorId());
        studentDormAllocationMapper.insert(allocation);

        AllocationDetail detail = new AllocationDetail();
        detail.setAllocationId(allocation.getId());
        detail.setBuildingNo(bed.getDormitoryRoom().getDormitoryBuilding().getBuildingNo());
        detail.setRoomNo(bed.getDormitoryRoom().getRoomNo());
        detail.setBedNo(bed.getBedNo());
        return detail;
    }
}

批量宿舍分配界面 管理员在批量分配界面,可设定专业、班级、性别等条件,系统自动筛选并分配可用宿舍。

2. 宿舍报修流程管理

学生可在线提交维修申请,宿舍管理员进行审核、派单和完成确认,形成闭环管理。

报修实体与Mapper接口

// 报修单实体类
public class RepairOrder {
    private Long id;
    private Long studentId;       // 报修学生
    private Long dormitoryId;     // 报修宿舍
    private String repairItem;    // 报修项目
    private String description;   // 问题描述
    private String imageUrls;     // 图片URL,多个以逗号分隔
    private String status;        // 状态:PENDING, ASSIGNED, PROCESSING, COMPLETED, CANCELLED
    private Long assigneeId;      // 指派给的后勤人员
    private Date expectedRepairTime; // 期望维修时间
    private Date createTime;
    private Date updateTime;
    // ... getters and setters
}

// Mapper接口中的动态SQL查询
public interface RepairOrderMapper {
    List<RepairOrder> selectByCondition(@Param("dormitoryId") Long dormitoryId, 
                                        @Param("status") String status,
                                        @Param("startDate") Date startDate,
                                        @Param("endDate") Date endDate);
}

对应的MyBatis映射文件 (RepairOrderMapper.xml) 展示了动态SQL的应用:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dormitory.mapper.RepairOrderMapper">

    <sql id="Base_Column_List">
        id, student_id, dormitory_id, repair_item, description, image_urls, status, 
        assignee_id, expected_repair_time, create_time, update_time
    </sql>

    <select id="selectByCondition" resultType="com.dormitory.entity.RepairOrder">
        SELECT <include refid="Base_Column_List" />
        FROM repair_order
        WHERE 1=1
        <if test="dormitoryId != null">
            AND dormitory_id = #{dormitoryId}
        </if>
        <if test="status != null and status != ''">
            AND status = #{status}
        </if>
        <if test="startDate != null">
            AND create_time >= #{startDate}
        </if>
        <if test="endDate != null">
            AND create_time &lt;= #{endDate}
        </if>
        ORDER BY 
            CASE status 
                WHEN 'PENDING' THEN 1
                WHEN 'ASSIGNED' THEN 2
                WHEN 'PROCESSING' THEN 3
                ELSE 4
            END,
            create_time DESC
    </select>

    <!-- 更新报修单状态 -->
    <update id="updateStatus">
        UPDATE repair_order
        SET status = #{status},
            update_time = NOW()
        <if test="assigneeId != null">
            , assignee_id = #{assigneeId}
        </if>
        WHERE id = #{id}
    </update>
</mapper>

学生报修界面 学生登录系统后,可在线提交维修申请,填写报修项目和问题描述,并可上传现场图片。

3. 多角色权限控制与界面定制

系统基于Spring Security实现了基于角色的访问控制,不同角色登录后看到的功能菜单和操作权限完全不同。

Spring Security配置类

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/student/**").hasAnyRole("STUDENT", "ADMIN")
            .antMatchers("/dorm-admin/**").hasAnyRole("DORM_ADMIN", "ADMIN")
            .antMatchers("/admin/**").hasRole("ADMIN")
            .antMatchers("/css/**", "/js/**", "/images/**", "/login", "/auth/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
                .loginPage("/login")
                .loginProcessingUrl("/auth/login")
                .defaultSuccessUrl("/dashboard", true)
                .failureUrl("/login?error=true")
            .and()
            .logout()
                .logoutUrl("/auth/logout")
                .logoutSuccessUrl("/login")
            .and()
            .sessionManagement()
                .maximumSessions(1)
                .expiredUrl("/login?expired=true");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }
}

自定义用户详情服务

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userMapper.selectByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在: " + username);
        }

        // 从数据库查询用户角色权限
        List<SimpleGrantedAuthority> authorities = userMapper.selectUserRoles(user.getId())
                .stream()
                .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
                .collect(Collectors.toList());

        return new org.springframework.security.core.userdetails.User(
                user.getUsername(), 
                user.getPassword(), 
                user.getStatus() == 1, // 是否启用
                true, true, true,      // 账户未过期、凭证未过期、未锁定
                authorities);
    }
}

前端菜单动态渲染(JSP + JSTL)

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<div class="sidebar">
    <ul class="nav nav-pills flex-column">
本文关键词
SSM框架高校宿舍管理源码解析系统架构数据库设计

上下篇

上一篇
没有更多文章
下一篇
没有更多文章