基于JSP+Servlet的宿舍人员事务管理系统 - 源码深度解析

JavaScriptHTMLCSSJSP+Servlet
2026-02-114 浏览

文章摘要

本系统基于JSP与Servlet技术构建,旨在为高校或企业宿舍管理部门提供一套集中化的人员与日常事务管理解决方案。其核心业务价值在于彻底改变了传统依赖纸质登记或零散Excel表格的管理模式,解决了信息更新滞后、数据统计困难、事务处理流程不清晰等核心痛点。系统通过数字化手段,将宿舍分配、人员入住/迁出...

在现代高校后勤管理体系中,宿舍管理作为与学生日常生活最紧密相关的环节,其效率和规范性直接影响着校园生活的质量。传统依赖纸质登记、Excel表格分散管理的方式已经无法满足大规模、动态化的管理需求。为了解决信息更新滞后、数据统计困难、事务处理流程不清晰等核心痛点,我们设计并实现了一套基于JSP+Servlet技术的宿舍管理数字化平台——"智慧宿管通"。

该系统采用经典的MVC架构模式,将业务逻辑、数据展示和用户交互清晰分离。Servlet作为控制器负责接收和处理所有HTTP请求,JSP页面负责动态渲染视图,而JavaBean实体类则封装了核心业务数据和数据库操作。这种分层设计不仅提高了代码的可维护性,也为后续功能扩展奠定了坚实基础。

系统架构与技术栈深度解析

"智慧宿管通"的技术选型充分考虑了高校实际应用场景的特点。前端采用HTML+CSS+JavaScript构建响应式界面,确保在不同设备上都能获得良好的用户体验。后端基于Java EE标准的Servlet技术,配合JSP实现动态内容生成。数据库选用MySQL,通过JDBC进行高效的数据持久化操作。

在架构设计上,系统严格遵循MVC模式:

  • 模型层(Model):由JavaBean实体类组成,如Student、Dormitory、Absent等,每个实体类都对应数据库中的一张表,封装了数据的属性和基本操作方法
  • 视图层(View):使用JSP页面结合JSTL标签库和EL表达式,实现数据的动态展示,避免了在页面中嵌入过多Java代码
  • 控制层(Controller):通过Servlet接收用户请求,调用相应的业务逻辑处理,并决定跳转到哪个JSP页面

这种架构的优势在于职责分离明确,便于团队协作开发和后期维护。例如,当需要修改界面样式时,只需调整JSP页面而无需改动业务逻辑代码;当业务规则变化时,也只需修改对应的Servlet而不会影响前端展示。

数据库设计亮点与优化策略

数据库作为系统的核心支撑,其设计质量直接关系到系统的性能和稳定性。通过对宿舍管理业务的深入分析,我们设计了7张核心数据表,以下是几个关键表的设计解析:

宿舍信息表(dormitory)的设计智慧

CREATE TABLE `dormitory` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `building_id` int(11) DEFAULT NULL COMMENT '楼宇ID',
  `name` varchar(20) DEFAULT NULL COMMENT '宿舍名称',
  `type` int(11) DEFAULT NULL COMMENT '宿舍类型',
  `available` int(11) DEFAULT NULL COMMENT '可用床位数量',
  `telephone` varchar(20) DEFAULT NULL COMMENT '宿舍电话',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='宿舍信息表'

该表设计有几个值得关注的优化点:

  1. 索引策略:主键采用自增ID,确保插入性能的同时便于数据关联。building_id字段虽然没有显式创建索引,但在实际查询中经常作为条件,建议添加索引优化查询性能
  2. 数据类型选择:available字段使用int类型而非布尔值,可以精确记录剩余床位数量,支持更灵活的业务逻辑
  3. 可扩展性考虑:type字段预留了宿舍类型分类,可以支持如"标准间"、"套间"等不同类型的扩展

学生信息表(student)的关系设计

CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `number` varchar(11) DEFAULT NULL COMMENT '学号',
  `name` varchar(20) DEFAULT NULL COMMENT '姓名',
  `gender` varchar(20) DEFAULT NULL COMMENT '性别',
  `dormitory_id` int(11) DEFAULT NULL COMMENT '宿舍ID',
  `state` varchar(20) DEFAULT NULL COMMENT '学生状态',
  `create_date` varchar(20) DEFAULT NULL COMMENT '创建日期',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=67 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='学生信息表'

学生表的设计体现了业务逻辑的完整性:

  • 状态管理:state字段记录了学生在宿状态(如"在住"、"已迁出"、"休学"等),支持复杂的状态流转
  • 关联设计:dormitory_id与宿舍表关联,建立了学生与宿舍的多对一关系
  • 业务标识:number字段作为学号,是业务的唯一标识符,建议添加唯一索引确保数据一致性

缺勤记录表(absent)的业务建模

CREATE TABLE `absent` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `building_id` int(11) DEFAULT NULL COMMENT '楼宇ID',
  `dormitory_id` int(11) DEFAULT NULL COMMENT '宿舍ID',
  `student_id` int(11) DEFAULT NULL COMMENT '学生ID',
  `dormitory_admin_id` int(11) DEFAULT NULL COMMENT '宿舍管理员ID',
  `create_date` varchar(20) DEFAULT NULL COMMENT '创建日期',
  `reason` varchar(20) DEFAULT NULL COMMENT '缺勤原因',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='缺勤记录表'

缺勤表的设计展现了复杂业务关系的处理能力,通过多个外键关联实现了完整的业务链条追溯。

核心功能实现与代码解析

宿舍分配管理功能

宿舍分配是系统的核心功能之一,实现了自动化床位分配和手动调换的灵活结合。系统通过实时统计各宿舍可用床位数量,为新生分配提供智能推荐。

宿舍管理界面

后端Servlet处理分配逻辑的核心代码:

@WebServlet("/dormitory/assign")
public class DormitoryAssignServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        String studentId = request.getParameter("studentId");
        String dormitoryId = request.getParameter("dormitoryId");
        
        try {
            // 检查宿舍是否还有空床位
            DormitoryDAO dormDAO = new DormitoryDAO();
            Dormitory dorm = dormDAO.findById(Integer.parseInt(dormitoryId));
            
            if (dorm.getAvailable() <= 0) {
                request.setAttribute("error", "该宿舍已满员,无法分配");
                request.getRequestDispatcher("/dormitory/assign.jsp").forward(request, response);
                return;
            }
            
            // 更新学生宿舍信息
            StudentDAO studentDAO = new StudentDAO();
            Student student = studentDAO.findById(Integer.parseInt(studentId));
            student.setDormitoryId(Integer.parseInt(dormitoryId));
            student.setState("在住");
            studentDAO.update(student);
            
            // 更新宿舍可用床位数量
            dorm.setAvailable(dorm.getAvailable() - 1);
            dormDAO.update(dorm);
            
            response.sendRedirect("/dormitory/assign_success.jsp");
            
        } catch (Exception e) {
            e.printStackTrace();
            request.setAttribute("error", "分配过程中发生错误");
            request.getRequestDispatcher("/dormitory/assign.jsp").forward(request, response);
        }
    }
}

前端JSP页面通过EL表达式动态展示宿舍信息:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<table class="table table-bordered">
    <thead>
        <tr>
            <th>宿舍编号</th>
            <th>楼宇</th>
            <th>类型</th>
            <th>可用床位</th>
            <th>操作</th>
        </tr>
    </thead>
    <tbody>
        <c:forEach var="dorm" items="${dormitoryList}">
            <tr>
                <td>${dorm.name}</td>
                <td>${dorm.buildingName}</td>
                <td>
                    <c:choose>
                        <c:when test="${dorm.type == 1}">四人间</c:when>
                        <c:when test="${dorm.type == 2}">六人间</c:when>
                        <c:otherwise>其他</c:otherwise>
                    </c:choose>
                </td>
                <td>${dorm.available}</td>
                <td>
                    <c:if test="${dorm.available > 0}">
                        <button class="btn btn-primary assign-btn" 
                                data-dorm-id="${dorm.id}">分配</button>
                    </c:if>
                </td>
            </tr>
        </c:forEach>
    </tbody>
</table>

学生迁出管理功能

学生迁出功能处理毕业生离校、转宿等业务场景,确保床位资源的及时释放和状态更新。

学生迁出记录管理

迁出业务逻辑的完整实现:

public class MoveOutService {
    /**
     * 处理学生迁出业务
     */
    public boolean processMoveOut(MoveOutRecord record) {
        Connection conn = null;
        try {
            conn = DatabaseUtil.getConnection();
            conn.setAutoCommit(false); // 开启事务
            
            // 1. 插入迁出记录
            MoveOutDAO moveOutDAO = new MoveOutDAO(conn);
            moveOutDAO.insert(record);
            
            // 2. 更新学生状态
            StudentDAO studentDAO = new StudentDAO(conn);
            Student student = studentDAO.findById(record.getStudentId());
            student.setState("已迁出");
            student.setDormitoryId(null); // 清空宿舍关联
            studentDAO.update(student);
            
            // 3. 更新宿舍可用床位
            DormitoryDAO dormDAO = new DormitoryDAO(conn);
            Dormitory dorm = dormDAO.findById(record.getDormitoryId());
            dorm.setAvailable(dorm.getAvailable() + 1);
            dormDAO.update(dorm);
            
            conn.commit(); // 提交事务
            return true;
            
        } catch (SQLException e) {
            if (conn != null) {
                try {
                    conn.rollback(); // 回滚事务
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            e.printStackTrace();
            return false;
        } finally {
            DatabaseUtil.closeConnection(conn);
        }
    }
}

缺勤记录管理功能

缺勤管理模块支持宿管员记录学生夜不归宿等情况,便于学校掌握学生动态。

查看缺勤记录

缺勤实体类的完整定义展示了复杂业务对象的建模:

package com.southwind.entity;

public class Absent {
    private Integer id;
    private Integer buildingId;
    private String buildingName;
    private Integer dormitoryId;
    private String dormitoryName;
    private Integer studentId;
    private String studentName;
    private Integer dormitoryAdminId;
    private String dormitoryAdminName;
    private String createDate;
    private String reason;

    // 构造方法
    public Absent(Integer id, String buildingName, String dormitoryName, 
                 String studentName, String dormitoryAdminName, 
                 String createDate, String reason) {
        this.id = id;
        this.buildingName = buildingName;
        this.dormitoryName = dormitoryName;
        this.studentName = studentName;
        this.dormitoryAdminName = dormitoryAdminName;
        this.createDate = createDate;
        this.reason = reason;
    }

    public Absent(Integer buildingId, Integer dormitoryId, Integer studentId, 
                 Integer dormitoryAdminId, String createDate, String reason) {
        this.buildingId = buildingId;
        this.dormitoryId = dormitoryId;
        this.studentId = studentId;
        this.dormitoryAdminId = dormitoryAdminId;
        this.createDate = createDate;
        this.reason = reason;
    }

    // Getter和Setter方法
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getBuildingId() {
        return buildingId;
    }

    public void setBuildingId(Integer buildingId) {
        this.buildingId = buildingId;
    }

    public String getBuildingName() {
        return buildingName;
    }

    public void setBuildingName(String buildingName) {
        this.buildingName = buildingName;
    }

    // 其他getter/setter方法...
    
    @Override
    public String toString() {
        return "Absent{" +
                "id=" + id +
                ", buildingName='" + buildingName + '\'' +
                ", dormitoryName='" + dormitoryName + '\'' +
                ", studentName='" + studentName + '\'' +
                ", createDate='" + createDate + '\'' +
                ", reason='" + reason + '\'' +
                '}';
    }
}

缺勤数据访问层的实现:

public class AbsentDAO {
    /**
     * 查询缺勤记录(带关联信息)
     */
    public List<Absent> findWithDetails(String startDate, String endDate) {
        List<Absent> list = new ArrayList<>();
        String sql = "SELECT a.id, b.name as building_name, d.name as dormitory_name, " +
                    "s.name as student_name, da.name as admin_name, " +
                    "a.create_date, a.reason " +
                    "FROM absent a " +
                    "LEFT JOIN building b ON a.building_id = b.id " +
                    "LEFT JOIN dormitory d ON a.dormitory_id = d.id " +
                    "LEFT JOIN student s ON a.student_id = s.id " +
                    "LEFT JOIN dormitory_admin da ON a.dormitory_admin_id = da.id " +
                    "WHERE a.create_date BETWEEN ? AND ? " +
                    "ORDER BY a.create_date DESC";
        
        try (Connection conn = DatabaseUtil.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            
            pstmt.setString(1, startDate);
            pstmt.setString(2, endDate);
            
            ResultSet rs = pstmt.executeQuery();
            while (rs.next()) {
                Absent absent = new Absent(
                    rs.getInt("id"),
                    rs.getString("building_name"),
                    rs.getString("dormitory_name"),
                    rs.getString("student_name"),
                    rs.getString("admin_name"),
                    rs.getString("create_date"),
                    rs.getString("reason")
                );
                list.add(absent);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return list;
    }
}

系统登录与权限控制

系统支持多角色登录,不同角色拥有不同的操作权限。

管理员登录

登录验证的Servlet实现:

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String role = request.getParameter("role");
        
        try {
            boolean loginSuccess = false;
            String redirectUrl = "";
            
            if ("admin".equals(role)) {
                // 管理员登录验证
                DormitoryAdminDAO adminDAO = new DormitoryAdminDAO();
                DormitoryAdmin admin = adminDAO.findByUsername(username);
                if (admin != null && admin.getPassword().equals(password)) {
                    loginSuccess = true;
                    request.getSession().setAttribute("admin", admin);
                    redirectUrl = "/admin/main.jsp";
                }
            } else if ("system".equals(role)) {
                // 系统管理员登录验证
                SystemAdminDAO sysAdminDAO = new SystemAdminDAO();
                SystemAdmin sysAdmin = sysAdminDAO.findByUsername(username);
                if (sysAdmin != null && sysAdmin.getPassword().equals(password)) {
                    loginSuccess = true;
                    request.getSession().setAttribute("systemAdmin", sysAdmin);
                    redirectUrl = "/system/main.jsp";
                }
            }
            
            if (loginSuccess) {
                response.sendRedirect(redirectUrl);
            } else {
                request.setAttribute("error", "用户名或密码错误");
                request.getRequestDispatcher("/login.jsp").forward(request, response);
            }
            
        } catch (Exception e) {
            e.printStackTrace();
            request.setAttribute("error", "登录过程发生错误");
            request.getRequestDispatcher("/login.jsp").forward(request, response);
        }
    }
}

实体模型设计的精妙之处

系统的实体类设计体现了面向对象编程的核心思想。以Absent类为例,它不仅包含了基本的属性定义,还通过多个构造方法支持不同的业务场景:

  1. 数据展示优化:除了基本的ID字段,还包含了buildingName、dormitoryName等展示字段,避免了在JSP页面中进行复杂的关联查询
  2. 业务逻辑封装:通过不同的构造方法,支持从不同数据源创建对象实例
  3. 数据完整性:每个字段都提供了完整的getter和setter方法,确保数据的封装性和安全性

这种设计模式使得业务逻辑更加清晰,代码的可读性和可维护性都得到了显著提升。

功能展望与系统优化方向

基于当前系统架构,未来可以从以下几个方向进行深度优化和功能扩展:

1. 引入Redis缓存提升性能

当前系统每次查询都需要直接访问数据库,在高并发场景下可能存在性能瓶颈。可以引入Redis作为缓存层,将热点数据如宿舍空余床位、学生基本信息等缓存起来。

// 伪代码示例:缓存优化的实现思路
public class DormitoryServiceWithCache {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    public Dormitory findById(Integer id) {
        String cacheKey = "dormitory:" + id;
        Dormitory dorm = (Dormitory) redisTemplate.opsForValue().get(cacheKey);
        
        if (dorm == null) {
            dorm = dormitoryDAO.findById(id);
            if (dorm != null) {
                redisTemplate.opsForValue().set(cacheKey, dorm, Duration.ofMinutes(30));
            }
        }
        return dorm;
    }
}

2. 增加消息队列异步处理

本文关键词
JSPServlet宿舍管理系统源码解析MVC架构

上下篇

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