1. 项目背景与意义
随着高校信息化建设的不断深入,大学城内的师生、社团、商家和后勤部门之间产生了大量碎片化信息,如讲座通知、社团活动、失物招领、二手交易、校园公告等。传统的信息发布方式主要依赖公告栏、QQ群、微信群和邮件,存在信息分散、时效性差、检索困难、推送不精准等问题。
本课题设计并实现一个基于SpringBoot的大学城信息推送平台,旨在将分散的校园信息统一汇聚,并按照用户兴趣、身份和地理位置进行精准推送。该平台的意义主要体现在以下几个方面:
- 提升信息触达效率:通过订阅与推送机制,将重要通知及时送达目标用户,减少信息遗漏。
- 整合校园资源:将社团、商家、后勤等多方信息源统一管理,形成校园信息生态。
- 支撑个性化服务:基于用户画像和浏览行为,实现分类订阅与智能推荐。
- 锻炼工程实践能力:完整覆盖需求分析、系统设计、数据库建模、接口开发、前后端联调等软件工程全流程。
2. 技术栈选型
本系统采用前后端分离架构,后端以SpringBoot为核心框架,前端使用Vue.js构建单页应用,数据库选用MySQL,缓存与消息推送分别借助Redis和WebSocket实现。具体技术栈如下表所示:
| 层次 | 技术选型 | 说明 |
|---|---|---|
| 后端框架 | SpringBoot 2.7 | 快速构建RESTful API,集成Spring Security与MyBatis-Plus |
| 前端框架 | Vue.js 3 + Element Plus | 组件化开发,提供后台管理与用户端界面 |
| 数据库 | MySQL 8.0 | 存储用户、信息、分类、订阅关系等核心业务数据 |
| 缓存 | Redis | 缓存热点信息、用户会话与推送任务状态 |
| 实时推送 | WebSocket | 实现站内实时消息通知 |
| 权限认证 | Spring Security + JWT | 基于Token的无状态身份认证与角色授权 |
| 构建工具 | Maven | 依赖管理与项目构建 |
3. 系统需求分析
3.1 功能需求
系统面向三类角色:普通用户、信息发布者和系统管理员。普通用户可以浏览信息、订阅分类、收藏内容并接收推送;信息发布者可以创建、编辑和下线自己的信息;系统管理员负责用户管理、分类管理、内容审核和推送任务配置。
核心功能模块包括:
- 用户模块:注册、登录、个人信息维护、兴趣标签设置。
- 信息模块:信息发布、编辑、审核、上下架、分类检索与关键词搜索。
- 订阅推送模块:用户按分类订阅,系统根据订阅关系和用户活跃度生成推送任务。
- 消息通知模块:站内信、WebSocket实时提醒、已读未读管理。
- 管理后台:数据统计、用户管理、内容审核、推送日志查询。
3.2 非功能需求
- 性能:支持500人以上并发访问,普通接口响应时间不超过2秒。
- 安全:密码加密存储,接口鉴权,防止SQL注入与XSS攻击。
- 可维护性:采用分层架构与统一响应格式,便于后续扩展。
- 可用性:关键操作具备异常处理与日志记录,保证系统稳定运行。
4. 系统总体设计
4.1 架构设计
系统采用B/S架构,分为表现层、业务逻辑层和数据访问层。表现层由Vue.js构建,通过Axios调用后端RESTful接口;业务逻辑层由SpringBoot的Controller、Service、Mapper三层组成;数据访问层使用MyBatis-Plus操作MySQL,Redis用于缓存热点数据。
flowchart TD A[Vue前端] -->|HTTP/JSON| B[Controller层] B --> C[Service业务层] C --> D[Mapper数据访问层] D --> E[(MySQL数据库)] C --> F[(Redis缓存)] B --> G[WebSocket推送] G --> A4.2 数据库设计
系统核心数据表包括用户表、信息表、分类表、订阅关系表、推送记录表和收藏表。各表之间通过外键关联,主要表结构如下:
| 表名 | 主要字段 | 说明 |
|---|---|---|
| user | id, username, password, role, tags | 用户基本信息与角色 |
| category | id, name, description | 信息分类 |
| info | id, title, content, category_id, publisher_id, status, create_time | 推送信息主体 |
| subscription | id, user_id, category_id | 用户与分类的订阅关系 |
| push_record | id, info_id, user_id, push_time, is_read | 推送记录与已读状态 |
| favorite | id, user_id, info_id, create_time | 用户收藏信息 |
5. 核心功能实现
5.1 用户认证与JWT鉴权
用户登录成功后,后端生成JWT令牌并返回给前端。前端在后续请求中携带该令牌,Spring Security过滤器负责校验令牌并解析用户身份。密码使用BCrypt加密存储,确保安全性。
@Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Autowired private PasswordEncoder passwordEncoder; @Autowired private JwtUtil jwtUtil; @Override public String login(String username, String password) { User user = userMapper.selectByUsername(username); if (user == null || !passwordEncoder.matches(password, user.getPassword())) { throw new BusinessException("用户名或密码错误"); } return jwtUtil.generateToken(user.getId(), user.getRole()); } }5.2 信息发布与审核
信息发布者提交信息后,信息状态默认为待审核。管理员审核通过后,信息状态变为已发布,并触发推送任务。核心代码如下:
@Service public class InfoServiceImpl implements InfoService { @Autowired private InfoMapper infoMapper; @Autowired private PushService pushService; @Override @Transactional public void publish(Info info) { info.setStatus(InfoStatus.PENDING); info.setCreateTime(LocalDateTime.now()); infoMapper.insert(info); } @Override @Transactional public void approve(Long infoId) { Info info = infoMapper.selectById(infoId); if (info == null) { throw new BusinessException("信息不存在"); } info.setStatus(InfoStatus.PUBLISHED); infoMapper.updateById(info); // 审核通过后触发推送 pushService.pushToSubscribers(info); } }5.3 分类订阅与推送
用户可以选择感兴趣的分类进行订阅。当某分类下发布新信息时,系统查询该分类的所有订阅用户,生成推送记录,并通过WebSocket向在线用户发送实时通知。
@Service public class PushServiceImpl implements PushService { @Autowired private SubscriptionMapper subscriptionMapper; @Autowired private PushRecordMapper pushRecordMapper; @Autowired private WebSocketServer webSocketServer; @Override @Transactional public void pushToSubscribers(Info info) { List<Long> userIds = subscriptionMapper.selectUserIdsByCategoryId(info.getCategoryId()); for (Long userId : userIds) { PushRecord record = new PushRecord(); record.setInfoId(info.getId()); record.setUserId(userId); record.setPushTime(LocalDateTime.now()); record.setIsRead(false); pushRecordMapper.insert(record); // 实时推送 webSocketServer.sendMessageToUser(userId, "您订阅的分类有新消息:" + info.getTitle()); } } }5.4 WebSocket实时通知
WebSocket服务端维护用户会话映射,当推送任务生成时,向目标用户的在线连接发送消息。前端收到消息后弹出提醒并刷新未读数量。
@Component public class WebSocketServer { private static final Map<Long, Session> SESSION_MAP = new ConcurrentHashMap<>(); @OnOpen public void onOpen(Session session, @PathParam("userId") Long userId) { SESSION_MAP.put(userId, session); } @OnClose public void onClose(@PathParam("userId") Long userId) { SESSION_MAP.remove(userId); } public void sendMessageToUser(Long userId, String message) { Session session = SESSION_MAP.get(userId); if (session != null && session.isOpen()) { try { session.getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); } } } }5.5 信息检索与分页
信息列表支持按分类、关键词和发布时间进行筛选,使用MyBatis-Plus的分页插件实现高效分页查询。
@Service public class InfoQueryServiceImpl implements InfoQueryService { @Autowired private InfoMapper infoMapper; @Override public PageResult<InfoVO> query(InfoQuery query) { Page<Info> page = new Page<>(query.getPageNum(), query.getPageSize()); LambdaQueryWrapper<Info> wrapper = new LambdaQueryWrapper<>(); if (StringUtils.hasText(query.getKeyword())) { wrapper.like(Info::getTitle, query.getKeyword()) .or().like(Info::getContent, query.getKeyword()); } if (query.getCategoryId() != null) { wrapper.eq(Info::getCategoryId, query.getCategoryId()); } wrapper.eq(Info::getStatus, InfoStatus.PUBLISHED); wrapper.orderByDesc(Info::getCreateTime); Page<Info> result = infoMapper.selectPage(page, wrapper); return PageResult.of(result.getRecords(), result.getTotal()); } }6. 系统测试与总结
系统完成后,对用户登录、信息发布、分类订阅、推送通知、检索分页等核心功能进行了功能测试和接口测试,测试结果表明各模块运行正常,接口响应时间满足设计要求。
本课题设计并实现了一个功能完整、架构清晰的大学城信息推送平台,覆盖了信息汇聚、分类订阅、精准推送和实时通知等核心场景。后续可以从智能推荐算法、消息队列削峰、移动端适配等方向继续优化,进一步提升系统的实用性和扩展性。