# Echo
**Repository Path**: coderEasy/Echo
## Basic Information
- **Project Name**: Echo
- **Description**: 🦄 开源社区系统:基于 SpringBoot + MyBatis + MySQL + Redis + Kafka + Elasticsearch + Spring Security + ... 并提供详细的开发文档和配套教程。包含帖子、评论、私信、系统通知、点赞、关注、搜索、用户设置、数据统计等模块。
- **Primary Language**: Java
- **License**: MIT
- **Default Branch**: master
- **Homepage**: http://1.15.127.74/
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 995
- **Created**: 2021-03-15
- **Last Updated**: 2021-03-15
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Echo — 开源社区系统
---
## 🌌 部署架构
我每个都只部署了一台,以下是理想的部署架构:
## 🎯 功能逻辑图
画了一些不是那么严谨的图帮助各位小伙伴理清思绪。
> 单向绿色箭头:
>
> - 前端模板 -> 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 就是这个用户的获赞数量
### 我的获赞数量
### 关注(异步请求)
- 若 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,每隔一段时间就从缓存中取出这些帖子进行计算分数。
帖子分数/热度计算公式:分数(热度) = 权重 + 发帖距离天数
```java
// 计算权重
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);
```

## 📖 配套教程
想要自己从零开始实现这个项目或者深入理解的小伙伴,可以扫描下方二维码关注公众号『**飞天小牛肉**』回复 `Echo` 获取配套教程,订阅话题 [Echo 学习教程](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzI0NDc3ODE5OQ==&action=getalbum&album_id=1744497649518493697&scene=173&from_msgid=2247485209&from_itemidx=3&count=3&uin=&key=&devicetype=Windows+10+x64&version=63010043&lang=zh_CN&ascene=1&session_us=gh_089c9f6e334b&fontgear=2) 第一时间获取更新。本套教程不仅会详细解释本项目涉及的各大技术点,还会汇总相关的常见面试题,目前尚在更新中。
并推荐我的开源教程类项目 [『 CS-Wiki 』](https://gitee.com/veal98/CS-Wiki),Gitee 推荐项目,目前已 0.9k star: 致力打造完善的 Java 后端知识体系,不仅仅帮助各位小伙伴快速且系统的准备面试(秋招/社招),更指引学习的方向。
### 序章
- [必读:Echo 项目的 README](https://mp.weixin.qq.com/s/iiukwRNW1-my1q6UjYl4iw)
- [Echo 项目结构分析](https://mp.weixin.qq.com/s/dZqSB0EN5-rmGQeG3Lx2jA)
- [Echo 数据库表是如何设计的](https://mp.weixin.qq.com/s/DG549DzLy3NhXwpsOWaXYA)
- [Echo 技术选型分析](https://mp.weixin.qq.com/s/tTBzyMklFtBfkyvuh8W0Nw)
### 部署篇
- [Echo 在 Windows 环境下的部署](https://mp.weixin.qq.com/s/ZgYGqLB5_rfCXNrW9jqgtQ)
- [Echo 在 Linux 服务器上的部署](https://mp.weixin.qq.com/s/q9X5sJv7mtPaSApZB0PxPA)
### 架构篇
### 技术要点篇
### 常见面试题
## 📞 联系我
有什么问题也可以添加我的微信,记得备注来意:格式 (学校或公司 - 姓名或昵称 - 来意)
## 🙋 微信交流群
下方扫码加入 Echo 微信交流群,实时跟进项目进度、分享您的想法、讨论您遇到的问题:
## 👏 鸣谢
博主水平有限,本项目参考[牛客网](https://www.nowcoder.com/) — Java 高级工程师课程,感谢老师和平台。
另外,若发现 Bug 或好的想法可以积极与我联系或提 PR / issue,采纳后您将出现在下方列表中。感谢以下小伙伴对本项目做出的贡献,排名按照时间先后:
- [freedom_dh](https://gitee.com/dh_free)
> 🔗 友情链接(若您想要出现在这里,可以上方扫描微信二维码联系我):
>
> - [CS-Wiki](https://gitee.com/veal98/CS-Wiki):致力打造完善的 Java 后端知识体系,不仅仅帮助各位小伙伴快速且系统的准备面试,更指引学习的方向
> - [Furion](https://gitee.com/dotnetchina/Furion):让 .NET 开发更简单,更通用,更流行