SpringBoot -- 抱团学习社区系统项目实战

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
Elasticsearch Serverless通用抵扣包,测试体验金 200元
简介: SpringBoot -- 抱团学习社区系统项目实战

📑 项目简介

抱团学习社区系统 是一套前后端不分离的社区系统,基于目前主流 Java Web 技术栈(SpringBoot + MyBatis + MySQL + Redis + Kafka + Elasticsearch + Spring Security + ...)。包含帖子、评论、私信、系统通知、点赞、关注、搜索、用户设置、数据统计等功能模块。

📖 核心技术栈

后端:

  • Spring
  • Spring Boot 2.1.5 RELEASE
  • Spring MVC
  • Mybatis
  • 数据库:MySQL 5.7
  • 分布式缓存:Redis
  • 本地缓存:Caffeine
  • 消息队列:kafka 2.12-2.3.0
  • 搜索引擎:elasticsearch-6.4.3
  • 安全:Spring Security
  • 邮件服务:Spring Mail
  • 分布式定时任务:Spring Quartz
  • 日志:SLFJ(日志接口)+ Logback(日志实现)

前端:

  • Thymeleaf
  • Bootstrap 4.x
  • JQuery
  • Ajax

💻 开发环境

  • 操作系统:Windows 10
  • 构建工具:Apache Maven
  • 集成开发工具:Intellij IDEA
  • 应用服务器:Apache Tomcat
  • 接口测试工具:Postman
  • 压力测试工具:Apache JMeter
  • Java版本:Java 8

⭐ 界面展示

  • 帖子发布页

在这里插入图片描述

  • 帖子详情页

在这里插入图片描述

  • 私信详情页

在这里插入图片描述

  • 账号设置页

在这里插入图片描述

  • 搜索详情页

在这里插入图片描述

🎯 功能逻辑图

 单向绿色箭头:

 - 前端模板 -> Controller:表示这个前端模板中有一个超链接是由这个 Controller 处理的
 - Controller -> 前端模板:表示这个 Controller 会像该前端模板传递数据或者跳转

 双向绿色箭头:表示 Controller 和前端模板之间进行参数的相互传递或使用

 单向蓝色箭头: A -> B,表示 A 方法调用了 B 方法

 单向红色箭头:数据库或缓存操作

注册

  • 用户注册成功,将用户信息存入 MySQL,但此时该用户状态为未激活
  • 向用户发送激活邮件,用户点击链接则激活账号(Spring Mail)

在这里插入图片描述

登录 | 登出

登录认证模块跳过了 Spring Secuity 自带的认证机制。主要逻辑如下:

  • 进入登录界面,随机生成一个字符串来标识这个将要登录的用户,将这个字符串短暂的存入 Cookie(60 秒);
  • 动态生成验证码,并将验证码及标识该用户的字符串短暂存入 Redis(60 秒);
  • 为登录成功(验证用户名、密码、验证码)的用户随机生成登录凭证且设置状态为有效,并将登录凭证及其状态等信息永久存入 Redis,再在 Cookie 中存一份登录凭证;
  • 使用拦截器在所有的请求执行之前,从 Cookie 中获取登录凭证,只要 Redis 中该凭证有效并在有效期内,本次请求就会一直持有该用户信息(使用 ThreadLocal 持有用户信息,保证多台服务器上用户的登录状态同步);
  • 勾选记住我,则延长 Cookie 中登录凭证的有效时间;
  • 用户登出,将凭证状态设为无效,并更新 Redis 中该登录凭证的相关信息。

下图是登录模块的功能逻辑图,并没有使用 Spring Security 提供的认证逻辑(我觉得这个模块是最复杂的,这张图其实很多细节还没有画全)

分页显示所有的帖子

  • 支持按照 “发帖时间” 显示
  • 支持按照 “热度排行” 显示(Spring Quartz)
  • 将热帖列表和所有帖子的总数存入本地缓存 Caffeine(利用分布式定时任务 Spring Quartz 每隔一段时间就刷新计算帖子的热度/分数 — 见下文,而 Caffeine 里的数据更新不用我们操心,它天生就会自动的更新它拥有的数据,给它一个初始化方法就完事儿)

在这里插入图片描述

账号设置

  • 修改头像(异步请求)

    • 将用户选择的头像图片文件上传至七牛云服务器
  • 修改密码

此处只画出修改头像:

在这里插入图片描述

发布帖子(异步请求)

发布帖子(过滤敏感词),将其存入 MySQL

在这里插入图片描述

显示评论及相关信息

评论部分前端的名称显示有些缺陷,有兴趣的小伙伴欢迎提 PR 解决 ~

关于评论模块需要注意的就是评论表的设计,把握其中字段的含义,才能透彻了解这个功能的逻辑。

评论 Comment 的目标类型(帖子,评论) entityType 和 entityId 以及对哪个用户进行评论/回复 targetId 是由前端传递给 DiscussPostController 的

在这里插入图片描述

一个帖子的详情页需要封装的信息大概如下:

在这里插入图片描述

添加评论(事务管理)

发布对帖子的评论(过滤敏感词),将其存入 MySQL

在这里插入图片描述

私信列表和详情页

在这里插入图片描述

发送私信(异步请求)

在这里插入图片描述

点赞(异步请求)

将点赞相关信息存入 Redis 的数据结构 set 中。其中,key 命名为 like:entity:entityType:entityId,value 即点赞用户的 id。比如 key = like:entity:2:246 value = 11 表示用户 11 对实体类型 2 即评论进行了点赞,该评论的 id 是 246

某个用户的获赞数量对应的存储在 Redis 中的 key 是 like:user:userId,value 就是这个用户的获赞数量

<img width=" title="20210207165837.png">

我的获赞数量

在这里插入图片描述

关注(异步请求)

  • 若 A 关注了 B,则 A 是 B 的粉丝 Follower,B 是 A 的目标 Followee
  • 关注的目标可以是用户、帖子、题目等,在实现时将这些目标抽象为实体(目前只做了关注用户)

将某个用户关注的实体相关信息存储在 Redis 的数据结构 zset 中:key 是 followee:userId:entityType ,对应的 value 是 zset(entityId, now) ,以关注的时间进行排序。比如说 followee:111:3 对应的value (20, 2020-02-03-xxxx),表明用户 111 关注了一个类型为 3 的实体即人(用户),关注的这个实体 id 是 20,关注该实体的时间是 2020-02-03-xxxx

同样的,将某个实体拥有的粉丝相关信息也存储在 Redis 的数据结构 zset 中:key 是 follower:entityType:entityId,对应的 value 是 zset(userId, now),以关注的时间进行排序

在这里插入图片描述

关注列表

在这里插入图片描述

发送系统通知

显示系统通知

搜索

  • 发布事件

    • 发布帖子时,通过消息队列将帖子异步地提交到 Elasticsearch 服务器
    • 为帖子增加评论时,通过消息队列将帖子异步地提交到 Elasticsearch 服务器
  • 搜索服务

    • 从 Elasticsearch 服务器搜索帖子
    • 从 Elasticsearch 服务器删除帖子(当帖子从数据库中被删除时)
  • 显示搜索结果

类似的,置顶、加精也会触发发帖事件,就不再图里面画出来了。

置顶加精删除(异步请求)

在这里插入图片描述

网站数据统计

  • 独立访客 UV

    • 存入 Redis 的 HyperLogLog
    • 支持单日查询和区间日期查询
  • 日活跃用户 DAU

    • 存入 Redis 的 Bitmap
    • 支持单日查询和区间日期查询
  • 权限管理(Spring Security)

    • 只有管理员可以查看网站数据统计

帖子热度计算

每次发生点赞(给帖子点赞)、评论(给帖子评论)、加精的时候,就将这些帖子信息存入缓存 Redis 中,然后通过分布式的定时任务 Spring Quartz,每隔一段时间就从缓存中取出这些帖子进行计算分数。

帖子分数/热度计算公式:分数(热度) = 权重 + 发帖距离天数

// 计算权重
double w = (wonderful ? 75 : 0) + commentCount * 10 + likeCount * 2;
// 分数 = 权重 + 发帖距离天数
double score = Math.log10(Math.max(w, 1))
        + (post.getCreateTime().getTime() - epoch.getTime()) / (1000 * 3600 * 24);

相关实践学习
以电商场景为例搭建AI语义搜索应用
本实验旨在通过阿里云Elasticsearch结合阿里云搜索开发工作台AI模型服务,构建一个高效、精准的语义搜索系统,模拟电商场景,深入理解AI搜索技术原理并掌握其实现过程。
ElasticSearch 最新快速入门教程
本课程由千锋教育提供。全文搜索的需求非常大。而开源的解决办法Elasricsearch(Elastic)就是一个非常好的工具。目前是全文搜索引擎的首选。本系列教程由浅入深讲解了在CentOS7系统下如何搭建ElasticSearch,如何使用Kibana实现各种方式的搜索并详细分析了搜索的原理,最后讲解了在Java应用中如何集成ElasticSearch并实现搜索。 &nbsp;
相关文章
|
28天前
|
监控 安全 JavaScript
2025基于springboot的校车预定全流程管理系统
针对传统校车管理效率低、信息不透明等问题,本研究设计并实现了一套校车预定全流程管理系统。系统采用Spring Boot、Java、Vue和MySQL等技术,实现校车信息管理、在线预定、实时监控等功能,提升学校管理效率,保障学生出行安全,推动教育信息化发展。
|
28天前
|
JavaScript Java 关系型数据库
基于springboot的高校运动会系统
本系统基于Spring Boot、Vue与MySQL,实现高校运动会报名、赛程安排及成绩管理的全流程信息化,提升组织效率,杜绝信息错漏与冒名顶替,推动体育赛事智能化发展。
|
25天前
|
JavaScript 安全 Java
基于springboot的大学生兼职系统
本课题针对大学生兼职信息不对称、权益难保障等问题,研究基于Spring Boot、Vue、MySQL等技术的兼职系统,旨在构建安全、高效、功能完善的平台,提升大学生就业竞争力与兼职质量。
|
28天前
|
JavaScript Java 关系型数据库
基于springboot的美食城服务管理系统
本系统基于Spring Boot、Java、Vue和MySQL技术,构建集消费者服务、商家管理与后台监管于一体的美食城综合管理平台,提升运营效率与用户体验。
|
29天前
|
Java 关系型数据库 MySQL
基于springboot的网咖网吧管理系统
本文探讨了基于Java、MySQL和SpringBoot的网吧管理系统的设计与实现。随着信息化发展,传统管理方式难以满足需求,而该系统通过先进技术提升管理效率、保障数据安全、降低运营成本,具有重要意义。
|
1月前
|
JavaScript Java 关系型数据库
基于springboot的摄影师分享交流社区系统
本系统基于Spring Boot与Vue构建摄影师分享交流平台,旨在打造专业社区,支持作品展示、技术交流与合作互动。采用Java、MySQL等成熟技术,提升摄影爱好者创作水平,推动行业发展。
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
270 9
|
Java API Spring
Spring学习路径
Spring作为一个优秀的开源企业级框架有着一下特点 开源框架 简化企业级应用开发的流程 Spring是一个JavaSE/EE的一站式框架 优点在于 方便解耦 AOP的编程支持 声明式事务的支持 可以引入jUnit4,方便程序测试 对优秀开源框架的支持,方便集成 降低JavaEE API的使用难度.
2611 0
|
4月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
840 0