基于SSH框架的高校选课管理系统 - 源码深度解析

JavaScriptSSH框架HTMLCSSMySQLJSP+Servlet
2026-03-232 浏览

文章摘要

本项目是基于SSH(Struts2 + Spring + Hibernate)框架构建的高校选课管理系统,旨在解决传统人工或半自动化选课流程中效率低下、数据不一致、管理复杂等核心痛点。系统通过集成化的信息平台,实现了选课流程的标准化与自动化,显著提升了教务管理的工作效率与选课数据的准确性,为高校教务...

在高校教务管理领域,选课流程的效率和准确性一直是核心挑战。传统的人工登记或基于简单脚本的选课系统,常常面临数据不一致、选课冲突频发、系统高峰期响应迟缓等问题。为解决这些痛点,我们设计并实现了一套基于SSH(Struts2 + Spring + Hibernate)整合框架的“教务通”选课管理平台。该系统通过标准化的三层架构,将表现层、业务逻辑层和数据持久层清晰分离,实现了选课业务的自动化与集中化管理,显著提升了教务工作的处理效率和数据可靠性。

系统采用Struts2作为MVC框架,负责前端请求的拦截与分发,其强大的拦截器机制和OGNL表达式为数据传递和验证提供了便利。业务层由Spring框架托管,利用其控制反转(IoC)和面向切面编程(AOP)特性,实现了服务组件的高效管理和声明式事务控制,确保了如选课、退课等关键操作的事务原子性。数据持久层则基于Hibernate构建,通过对象关系映射(ORM)将Java对象与数据库表关联,简化了数据库操作,并利用HQL(Hibernate Query Language)和Criteria API应对复杂的查询场景,如课程容量实时校验、时间冲突检测等。

数据库架构设计与核心表分析

一个稳健的选课系统离不开精心设计的数据库模型。本系统数据库包含5张核心表,结构清晰,关系明确,有效支撑了复杂的业务逻辑。

1. 学生表(t_student

学生表是系统的基础数据表,不仅存储学生的基本信息,还通过外键关联定义了其所属的院系和专业,为后续的选课权限控制和数据统计奠定了基础。

CREATE TABLE `t_student` (
  `studentNumber` varchar(15) NOT NULL,
  `name` varchar(15) NOT NULL,
  `sex` varchar(2) NOT NULL,
  `phone` varchar(15) NOT NULL,
  `grade` varchar(15) NOT NULL,
  `major` int(11) NOT NULL,
  `academy` int(11) NOT NULL,
  `password` varchar(20) NOT NULL,
  `remark` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`studentNumber`),
  KEY `major` (`major`),
  KEY `academy` (`academy`),
  CONSTRAINT `t_student_ibfk_1` FOREIGN KEY (`major`) REFERENCES `t_major` (`id`),
  CONSTRAINT `t_student_ibfk_2` FOREIGN KEY (`academy`) REFERENCES `t_academy` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

设计亮点分析:

  • 主键设计: 使用具有业务含义的studentNumber(学号)作为主键,而非自增ID,这在查询学生信息时更为直接高效。
  • 关系规范化majoracademy字段并未直接存储名称,而是作为外键关联到专业表(t_major)和院系表(t_academy)。这种设计避免了数据冗余,保证了数据一致性。当专业或院系名称需要更新时,只需修改对应主表的一条记录即可。
  • 扩展性考虑: 预留了remark(备注)字段,为未来可能需要的额外信息提供了扩展空间。

2. 选课记录表(t_selectedcourse

此表是系统的核心业务表,记录了每一次选课操作的成功结果。它是连接学生与课程的桥梁,其设计直接关系到选课业务逻辑的正确性。

CREATE TABLE `t_selectedcourse` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `studentId` varchar(15) NOT NULL,
  `courseId` int(11) NOT NULL,
  `score` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `studentId` (`studentId`),
  KEY `courseId` (`courseId`),
  CONSTRAINT `t_selectedcourse_ibfk_1` FOREIGN KEY (`studentId`) REFERENCES `t_student` (`studentNumber`),
  CONSTRAINT `t_selectedcourse_ibfk_2` FOREIGN KEY (`courseId`) REFERENCES `t_course` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

设计亮点分析:

  • 代理主键: 使用与业务无关的自增id作为主键,这是一个最佳实践。它避免了使用(studentId, courseId)这类自然键作为主键可能带来的复杂性,特别是在需要关联其他表时更为灵活。
  • 成绩管理score字段允许为NULL,这精确地反映了业务现实:选课成功初期,成绩是未知的。只有当教师录入成绩后,该字段才被更新。这种设计避免了使用特殊值(如-1)来表示未评分状态,更加规范。
  • 唯一性约束: 虽然没有在DDL中显式创建唯一索引,但在应用层通过业务逻辑保证了(studentId, courseId)组合的唯一性,防止同一学生重复选择同一门课程。

核心功能实现与代码剖析

1. 学生选课功能

选课功能是系统最核心的交互之一,涉及复杂的业务规则校验,如课程容量、时间冲突、预修课程等。其后端处理逻辑集中在Spring管理的Service组件中。

学生选课界面

上图为学生进行选课操作的界面,系统会列出所有可选课程,并清晰展示课程容量、已选人数等关键信息。

CourseService.java (业务逻辑层)

@Service("courseService")
@Transactional
public class CourseService {
    
    @Autowired
    private CourseDAO courseDAO;
    @Autowired
    private SelectedCourseDAO selectedCourseDAO;

    /**
     * 执行选课操作,包含完整的业务规则校验
     * @param studentNumber 学号
     * @param courseId 课程ID
     * @return 操作结果信息
     */
    public String selectCourse(String studentNumber, Integer courseId) {
        // 1. 检查课程是否存在且可选
        Course course = courseDAO.get(Course.class, courseId);
        if (course == null) {
            return "课程不存在!";
        }
        if (course.getSelectedNum() >= course.getMaxNum()) {
            return "课程容量已满,选课失败!";
        }

        // 2. 检查是否已选过该课程
        String hql = "FROM SelectedCourse sc WHERE sc.studentId=? AND sc.courseId=?";
        List<SelectedCourse> list = selectedCourseDAO.find(hql, new Object[]{studentNumber, courseId});
        if (list != null && list.size() > 0) {
            return "您已经选择过该课程!";
        }

        // 3. 检查时间冲突(简化示例,实际需比较上课时间节次)
        // ... 时间冲突检测逻辑 ...

        // 4. 所有校验通过,执行选课
        SelectedCourse sc = new SelectedCourse();
        sc.setStudentId(studentNumber);
        sc.setCourseId(courseId);
        // 成绩初始为null
        sc.setScore(null);
        selectedCourseDAO.save(sc);

        // 5. 更新课程的已选人数
        course.setSelectedNum(course.getSelectedNum() + 1);
        courseDAO.update(course);

        return "选课成功!";
    }
}

该Service方法通过@Transactional注解被声明为一个事务。这意味着,只要在方法执行过程中抛出任何运行时异常,整个操作(包括插入选课记录和更新课程人数)都会回滚,从而保证了数据的一致性。

2. 选课信息查询与展示

学生需要便捷地查询自己已选的课程列表及相关信息。这通过Hibernate的HQL查询实现,并将数据传递到前端JSP页面进行渲染。

已选课程查询

SelectedCourseAction.java (表现层控制器)

public class SelectedCourseAction extends ActionSupport {
    
    private List<SelectedCourse> selectedCourseList;
    private String studentNumber; // 从Session中获取

    // Struts2 Action的默认执行方法
    public String execute() {
        // 构建HQL,联表查询以获取课程详情而非仅ID
        String hql = "SELECT new map(sc.id as id, c.name as courseName, c.teacher as teacher, "
                   + "c.credit as credit, sc.score as score) "
                   + "FROM SelectedCourse sc, Course c "
                   + "WHERE sc.courseId = c.id AND sc.studentId = ?";
        selectedCourseList = selectedCourseDAO.find(hql, new Object[]{studentNumber});
        return SUCCESS;
    }

    // Getter and Setter...
}

此Action使用了HQL的投影查询,通过new map语法构造了一个包含课程详细信息的Map对象列表,避免了在JSP页面上进行额外的数据库查询,提升了性能。

3. 课程管理功能

教务管理员拥有对课程信息的全生命周期管理权限,包括增、删、改、查。后端通过Hibernate的getHibernateTemplate()提供的基础CRUD方法进行操作。

课程管理后台

上图为管理员进行课程管理的界面,支持对课程信息的全面维护。

CourseDAO.java (数据访问对象)

@Repository("courseDAO")
public class CourseDAO extends BaseDAO<Course> {

    // 继承的BaseDAO已包含save, update, delete, get等方法
    // 此处可编写复杂的自定义查询

    /**
     * 根据课程名称模糊查询
     * @param name 课程名称关键词
     * @return 课程列表
     */
    public List<Course> findCourseByName(String name) {
        String hql = "FROM Course WHERE name LIKE ?";
        return this.getHibernateTemplate().find(hql, "%" + name + "%");
    }

    /**
     * 分页查询课程列表
     * @param page 当前页码
     * @param pageSize 每页记录数
     * @return 分页数据
     */
    public PageBean<Course> findCourseByPage(int page, int pageSize) {
        // 查询总记录数
        String countHql = "SELECT count(*) FROM Course";
        List<Long> list = this.getHibernateTemplate().find(countHql);
        Long totalCount = list.get(0);

        // 查询当前页数据
        String dataHql = "FROM Course";
        List<Course> dataList = this.getHibernateTemplate().execute(new HibernateCallback<List<Course>>() {
            @Override
            public List<Course> doInHibernate(Session session) throws HibernateException {
                Query query = session.createQuery(dataHql);
                query.setFirstResult((page - 1) * pageSize);
                query.setMaxResults(pageSize);
                return query.list();
            }
        });

        return new PageBean<>(page, pageSize, totalCount.intValue(), dataList);
    }
}

BaseDAO封装了Hibernate的通用操作,遵循DRY(Don't Repeat Yourself)原则,减少了代码重复。

4. 登录认证与权限控制

系统根据用户角色(学生/管理员)提供不同的功能视图。登录认证过程涉及密码验证和Session管理。

用户登录

LoginAction.java

public class LoginAction extends ActionSupport {
    private String username;
    private String password;
    private String userType; // "student" or "admin"

    public String execute() {
        if ("student".equals(userType)) {
            Student student = studentDAO.get(Student.class, username);
            if (student != null && password.equals(student.getPassword())) {
                // 登录成功,将用户信息存入Session
                ActionContext.getContext().getSession().put("currentUser", student);
                ActionContext.getContext().getSession().put("userType", "student");
                return "student_success";
            }
        } else if ("admin".equals(userType)) {
            // 管理员验证逻辑类似...
        }
        this.addActionError("用户名或密码错误!");
        return INPUT;
    }
    // ... Getter and Setter
}

通过将用户信息和类型存入Session,后续的拦截器或页面标签可以根据userType来控制功能的可见性与可访问性。

实体模型与ORM映射

Hibernate的核心在于将数据库表映射为Java实体类。以下以Course实体为例,展示其与t_course表的映射关系。

Course.java (实体类)

@Entity
@Table(name = "t_course")
public class Course {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id; // 课程ID

    @Column(name = "name", length = 50, nullable = false)
    private String name; // 课程名称

    @Column(name = "teacher", length = 20, nullable = false)
    private String teacher; // 任课教师

    @Column(name = "maxNum", nullable = false)
    private Integer maxNum; // 最大容量

    @Column(name = "selectedNum", nullable = false)
    private Integer selectedNum = 0; // 已选人数,默认0

    @Column(name = "credit", nullable = false)
    private Integer credit; // 学分

    @Column(name = "courseTime", length = 50)
    private String courseTime; // 上课时间

    // 无参构造器、全参构造器、Getter和Setter方法...
}

JPA注解(@Entity, @Table, @Id, @Column)清晰地定义了对象-关系的映射规则,使得对Course对象的操作可以直接转化为对t_course表的SQL操作。

功能展望与系统优化方向

尽管当前系统已稳定实现了核心选课功能,但在高性能、高并发和用户体验方面仍有持续的优化空间。

  1. 引入Redis缓存层: 对于课程列表、学生已选课程等读多写少的数据,可以引入Redis作为缓存。例如,在选课高峰期,将课程容量信息缓存至Redis,通过原子操作(如DECR)来快速判断和更新剩余名额,极大减轻数据库压力。

    // 伪代码示例
    @Service
    public class CourseServiceWithCache {
        @Autowired
        private RedisTemplate redisTemplate;
    
        public boolean selectCourseWithCache(String studentId, Integer courseId) {
            String key = "course:stock:" + courseId;
            Long remaining = redisTemplate.opsForValue().decrement(key);
            if (remaining >= 0) {
                // 缓存中扣减成功,再进行数据库持久化操作
                // ... 异步或同步写入数据库
                return true;
            } else {
                // 库存不足,回滚缓存
                redisTemplate.opsForValue().increment(key);
                return false;
            }
        }
    }
    
  2. 前后端分离架构重构: 将现有的JSP技术栈重构为前后端分离模式。后端SSH框架演变为纯RESTful API服务(可使用SpringBoot简化配置),前端采用Vue.js或React等现代化框架。这将使前端交互更加流畅,并支持移动端App的开发。

  3. 细粒度权限控制与审计日志: 引入Spring Security或Apache Shiro框架,实现基于角色的访问控制(RBAC)甚至基于权限点的更细粒度控制。同时,建立完整的操作日志系统,记录所有关键操作(如登录、选课、退课、成绩修改),便于问题追溯和安全审计。

  4. 选课策略引擎: 实现更复杂的选课规则,如权重抽签、分年级分批次选课、预修课程强制校验等。可以设计一个可配置的规则引擎,使教务人员无需修改代码即可调整选课策略,增强系统的灵活性和适应性。

  5. 系统监控与性能分析: 集成监控工具(如Spring Boot Actuator、Prometheus),对系统的QPS、响应时间、异常率等关键指标进行实时监控。同时,使用Druid等连接池的监控功能,分析SQL性能,对慢查询进行优化,保障系统长期稳定运行。

该系统通过经典的SSH框架整合,成功构建了一个结构清晰、功能完备的高校选课管理解决方案。其严谨的数据库设计、分层的代码架构以及事务性的业务处理,为高校教务信息化提供了坚实的技术基础。面向未来,通过引入缓存、微服务、前端框架等新技术,该系统具备持续演进为更强大、更智能的教务管理平台的巨大潜力。

本文关键词
SSH框架高校选课管理系统源码解析数据库设计选课业务逻辑

上下篇

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