基于SSM框架的实践活动信息管理系统 - 源码深度解析

JavaJavaScriptMavenHTMLCSSSSM框架MySQL
2026-02-0813 浏览

文章摘要

本项目是一款基于SSM(Spring+SpringMVC+MyBatis)框架构建的实践活动信息管理系统,旨在解决高校、企业或社团在组织与管理实践活动过程中普遍存在的信息分散、流程繁琐、数据统计困难等核心痛点。系统通过数字化的信息整合与流程管控,将活动发布、报名审核、过程记录、成果评定等环节进行一体...

在高校教育管理领域,实践活动管理一直是个复杂而关键的环节。传统的纸质记录和分散的Excel表格管理方式,不仅效率低下,还容易导致数据不一致和统计困难。针对这一痛点,我们设计开发了一套基于SSM框架的实践活动管理平台,实现了从活动发布、报名审核到成果评定的全流程数字化管理。

系统架构与技术栈

该平台采用经典的SSM(Spring + SpringMVC + MyBatis)三层架构,结合Maven进行项目依赖管理,前端使用JSP渲染页面,数据库选用MySQL 5.7版本。

技术栈配置示例:

<!-- pom.xml 核心依赖配置 -->
<dependencies>
    <!-- Spring核心依赖 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.18</version>
    </dependency>
    
    <!-- MyBatis整合Spring -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.7</version>
    </dependency>
    
    <!-- MySQL驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.28</version>
    </dependency>
    
    <!-- JSP支持 -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
</dependencies>

Spring框架作为IoC容器,管理着所有的业务Bean对象,通过注解驱动的方式实现依赖注入。SpringMVC负责Web请求的分发和处理,采用基于注解的控制器设计,使代码更加简洁明了。MyBatis作为持久层框架,通过XML映射文件实现对象关系映射,提供了灵活的SQL编写能力。

数据库设计亮点

用户权限分离设计

系统采用基于角色的访问控制模型,通过t_user表统一管理所有用户的登录凭证,而具体的角色信息(学生、教师)则分别存储在t_studentt_teacher表中,通过外键关联实现数据的一致性。

-- 用户表核心字段设计
CREATE TABLE `t_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `u_username` varchar(255) DEFAULT NULL COMMENT '用户名',
  `u_password` varchar(255) DEFAULT NULL COMMENT '密码',
  `u_type` varchar(255) DEFAULT NULL COMMENT '类型(student/teacher/admin)',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_username` (`u_username`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;

这种设计实现了用户信息的统一认证和角色信息的分离存储,既保证了系统安全,又提供了良好的扩展性。当需要新增角色类型时,只需创建对应的扩展表并维护外键关系即可。

实践活动关联模型

t_shijiancanyu表作为核心的业务关联表,巧妙地将学生、实践活动和评分体系联系在一起:

-- 实践参与表结构优化
CREATE TABLE `t_shijiancanyu` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `t_pf1` decimal(5,2) DEFAULT NULL COMMENT '评分1(优化为数值类型)',
  `t_pf2` decimal(5,2) DEFAULT NULL,
  `t_pf3` decimal(5,2) DEFAULT NULL,
  `t_pjf` decimal(5,2) GENERATED ALWAYS AS ((t_pf1 + t_pf2 + t_pf3)/3) COMMENT '平均分(计算列)',
  `shijian_id` int(11) NOT NULL,
  `student_id` int(11) NOT NULL,
  `participate_status` tinyint(1) DEFAULT '0' COMMENT '参与状态(0-报名中,1-已参与,2-已完结)',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_student_shijian` (`student_id`,`shijian_id`),
  KEY `idx_shijian_status` (`shijian_id`,`participate_status`),
  CONSTRAINT `fk_shijian` FOREIGN KEY (`shijian_id`) REFERENCES `t_shijian` (`id`),
  CONSTRAINT `fk_student` FOREIGN KEY (`student_id`) REFERENCES `t_student` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

数据库关系图

这种设计支持一个学生参与多个实践活动,一个实践活动有多个学生参与的多对多关系。通过计算列自动维护平均分,确保了数据的准确性和一致性。

核心功能实现

1. 实践活动报名管理

系统实现了完整的实践活动报名流程,包括活动发布、学生报名、教师审核等功能。

控制器实现代码:

@Controller
@RequestMapping("/Shijiancanyu")
public class ShijiancanyuController {
    
    @Autowired
    private ShijiancanyuMapper shijiancanyuMapper;
    
    @Autowired
    private ShijianMapper shijianMapper;
    
    @Autowired
    private StudentMapper studentMapper;

    /**
     * 初始化报名页面,加载可选实践活动和学生列表
     */
    @RequestMapping("/initUtil.do")
    public String initUtil(HttpServletRequest request, Model model) {
        // 获取所有可报名的实践活动
        List<Shijian> activeShijians = shijianMapper.getActiveShijians();
        model.addAttribute("listShijian", activeShijians);
        
        // 获取所有学生信息(用于管理员操作)
        List<Student> allStudents = studentMapper.getObjectList(null, null);
        model.addAttribute("listStudent", allStudents);
        
        return "Shijiancanyu/saveOrUpdate";
    }

    /**
     * 学生报名实践活动
     */
    @RequestMapping("/applyShijian.do")
    @ResponseBody
    public Map<String, Object> applyShijian(@RequestParam Integer shijianId, 
                                          HttpSession session) {
        Map<String, Object> result = new HashMap<>();
        try {
            // 从session中获取当前登录学生信息
            Student currentStudent = (Student) session.getAttribute("currentStudent");
            
            if (currentStudent == null) {
                result.put("success", false);
                result.put("message", "请先登录");
                return result;
            }
            
            // 检查是否已报名
            Shijiancanyu existing = shijiancanyuMapper
                .checkExistingApplication(shijianId, currentStudent.getId());
            if (existing != null) {
                result.put("success", false);
                result.put("message", "您已报名该实践活动");
                return result;
            }
            
            // 创建新的报名记录
            Shijiancanyu application = new Shijiancanyu();
            application.setShijianId(shijianId);
            application.setStudentId(currentStudent.getId());
            application.setParticipateStatus(0); // 报名中
            
            shijiancanyuMapper.insertObject(application);
            result.put("success", true);
            result.put("message", "报名成功,等待审核");
            
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "报名失败:" + e.getMessage());
        }
        return result;
    }
}

实践活动报名界面

2. 分页查询与数据检索

系统实现了高效的分页查询机制,支持按字段搜索和分页显示:

/**
 * 分页查询实践参与记录
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
@RequestMapping("/getAllUtil.do")
public String getAllUtil(HttpServletRequest request, Model model) {
    // 获取查询条件
    String field = request.getParameter("field");
    String fieldValue = request.getParameter("fieldValue");
    
    // 处理中文编码
    try {
        if (fieldValue != null) {
            fieldValue = new String(fieldValue.getBytes("UTF-8"), "utf-8");
        }
    } catch (Exception e) {
        // 编码处理异常
    }
    
    // 分页参数处理
    String pageNo = request.getParameter("pageModel.currentPageNo");
    int currentPageNo = 1;
    try {
        currentPageNo = Integer.parseInt(pageNo);
    } catch (Exception e) {
        // 使用默认页码
    }
    
    // 执行查询
    List<Shijiancanyu> list = shijiancanyuMapper.getObjectList(field, fieldValue);
    
    // 构建分页模型
    PageModel pageModel = new PageModel();
    pageModel = pageModel.getUtilByController(list, currentPageNo);
    
    // 返回结果
    model.addAttribute("pageModel", pageModel);
    model.addAttribute("fieldValue", fieldValue);
    model.addAttribute("field", field);
    
    return "Shijiancanyu/find";
}

/**
 * 自定义分页工具类
 */
public class PageModel {
    private int currentPageNo = 1; // 当前页码
    private int totalCount; // 总记录数
    private int pageSize = 10; // 页面大小
    private List<?> list; // 当前页数据
    
    public PageModel getUtilByController(List list, int currentPageNo) {
        PageModel pageModel = new PageModel();
        pageModel.setTotalCount(list.size());
        pageModel.setCurrentPageNo(currentPageNo);
        
        // 计算分页数据
        int fromIndex = (currentPageNo - 1) * pageSize;
        int toIndex = Math.min(fromIndex + pageSize, list.size());
        
        if (fromIndex <= toIndex) {
            pageModel.setList(list.subList(fromIndex, toIndex));
        } else {
            pageModel.setList(new ArrayList<>());
        }
        
        return pageModel;
    }
    
    // getter和setter方法
    public int getCurrentPageNo() { return currentPageNo; }
    public void setCurrentPageNo(int currentPageNo) { this.currentPageNo = currentPageNo; }
    public int getTotalCount() { return totalCount; }
    public void setTotalCount(int totalCount) { this.totalCount = totalCount; }
    public int getPageSize() { return pageSize; }
    public void setPageSize(int pageSize) { this.pageSize = pageSize; }
    public List<?> getList() { return list; }
    public void setList(List<?> list) { this.list = list; }
}

3. 批量操作与事务管理

系统提供了批量删除等管理功能,确保数据操作的原子性:

/**
 * 批量删除实践参与记录
 */
@RequestMapping("/deleteManyUtil.do")                    
public String deleteManyUtil(HttpServletRequest request, User util, Model model) {
    String ids[] = request.getParameterValues("id");
    
    if (ids != null && ids.length > 0) {
        try {
            for (String id : ids) {
                if (id != null && !id.trim().equals("")) {
                    shijiancanyuMapper.deleteObject(Integer.parseInt(id));
                }
            }
        } catch (Exception e) {
            // 记录日志并处理异常
            logger.error("批量删除失败", e);
        }
    }
    
    return this.getAllUtil(request, model);
}

/**
 * 评分更新服务,使用Spring事务管理
 */
@Service
@Transactional
public class ScoreService {
    
    @Autowired
    private ShijiancanyuMapper shijiancanyuMapper;
    
    /**
     * 更新学生实践评分
     */
    public boolean updateStudentScores(Integer participationId, 
                                     BigDecimal score1, 
                                     BigDecimal score2, 
                                     BigDecimal score3) {
        try {
            Shijiancanyu participation = shijiancanyuMapper.selectObject(participationId);
            if (participation == null) {
                return false;
            }
            
            // 更新单项评分
            participation.setTPf1(score1);
            participation.setTPf2(score2);
            participation.setTPf3(score3);
            
            // 计算平均分
            BigDecimal avgScore = score1.add(score2).add(score3)
                                      .divide(new BigDecimal(3), 2, RoundingMode.HALF_UP);
            participation.setTPjf(avgScore);
            
            // 更新状态为已评分
            participation.setParticipateStatus(2);
            
            shijiancanyuMapper.updateObject(participation);
            return true;
            
        } catch (Exception e) {
            // 事务会自动回滚
            throw new RuntimeException("评分更新失败", e);
        }
    }
}

评分管理界面

4. 数据模型设计

系统的实体类设计充分体现了面向对象的思想:

/**
 * 实践参与实体类
 */
public class Shijiancanyu {
    private Integer id;
    private BigDecimal tPf1; // 评分1
    private BigDecimal tPf2; // 评分2
    private BigDecimal tPf3; // 评分3
    private BigDecimal tPjf; // 平均分
    private String tBz;     // 备注
    private Integer shijianId; // 实践ID
    private Integer studentId; // 学生ID
    private Integer participateStatus; // 参与状态
    
    // 关联对象
    private Shijian shijian;
    private Student student;
    
    // getter和setter方法
    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }
    
    public BigDecimal getTPf1() { return tPf1; }
    public void setTPf1(BigDecimal tPf1) { this.tPf1 = tPf1; }
    
    // ... 其他getter/setter方法
    
    /**
     * 计算平均分
     */
    public void calculateAverage() {
        if (tPf1 != null && tPf2 != null && tPf3 != null) {
            this.tPjf = tPf1.add(tPf2).add(tPf3)
                           .divide(new BigDecimal(3), 2, RoundingMode.HALF_UP);
        }
    }
}

/**
 * 学生信息实体类
 */
public class Student {
    private Integer id;
    private String TXuehao; // 学号
    private String TName;   // 姓名
    private String TBanji;  // 班级
    private String TNianji; // 年级
    private String TLianxi; // 联系方式
    private String TBz;     // 备注
    private Integer userId; // 用户ID
    
    private User user; // 关联用户信息
    
    // getter和setter方法
}

功能展望与优化方向

1. 引入Redis缓存优化

当前系统的查询性能可以通过引入Redis缓存来大幅提升:

@Service
public class ShijianCacheService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    private static final String CACHE_KEY = "shijian:active:list";
    private static final long CACHE_EXPIRE = 3600; // 1小时
    
    /**
     * 获取缓存中的实践活动列表
     */
    @SuppressWarnings("unchecked")
    public List<Shijian> getActiveShijiansFromCache() {
        try {
            Object cached = redisTemplate.opsForValue().get(CACHE_KEY);
            if (cached != null) {
                return (List<Shijian>) cached;
            }
        } catch (Exception e) {
            // 缓存异常,降级到数据库查询
        }
        return null;
    }
    
    /**
     * 更新缓存
     */
    public void cacheActiveShijians(List<Shijian> shijians) {
        try {
            redisTemplate.opsForValue().set(CACHE_KEY, shijians, 
                CACHE_EXPIRE, TimeUnit.SECONDS);
        } catch (Exception e) {
            // 记录日志,但不影响主流程
        }
    }
}

2. 微服务架构改造

将单体应用拆分为微服务架构:

# docker-compose.yml 微服务部署配置
version: '3.8'
services:
  user-service:
    image: practice-platform/user-service:latest
    ports:
      - "8081:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - DB_URL=jdbc:mysql://mysql:3306/practice_user
    
  activity-service:
    image: practice-platform/activity-service:latest
    ports:
      - "8082:8080"
    depends_on:
      - user-service
      - redis
    
  gateway-service:
    image: practice-platform/gateway-service:latest
    ports:
      - "80:80"
    depends_on:
      - user-service
      - activity-service

3. 移动端适配与PWA支持

通过响应式设计和PWA技术提升移动端体验:

<!-- 响应式布局示例 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<div class="container-fluid">
    <div class="row">
        <div class="col-12 col-md-8">
            <!-- 移动端优先的实践活动列表 -->
            <div class="activity-card" v-for="activity in activities" :key="activity.id">
                <h5>{{ activity.name }}</h5>
                <p class="text-muted">{{ activity.date }} | {{ activity.location }}</p>
                <button class="btn btn-primary btn-sm" 
                        @click="applyActivity(activity.id)"
                        :disabled="activity.applied">
                    {{ activity.applied ? '已报名' : '立即报名' }}
                </button>
            </div>
        </div>
    </div>
</div>

4. 实时通知系统

集成WebSocket实现实时消息推送:

@ServerEndpoint("/notifications")
@Component
public class NotificationEndpoint {
    
    private static Set<Session> sessions = Collections.synchronizedSet(new HashSet<>());
    
    @OnOpen
    public void
本文关键词
SSM框架实践活动管理高校教育管理系统架构数据库设计

上下篇

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