Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Вы можете использовать сопровождающие учебные материалы для самостоятельной установки и запуска
📚 Описание проекта
Эхо представляет собой систему открытого доступа сообщества, основанную на современной технологии Java Web (SpringBoot + MyBatis + MySQL + Redis + Kafka + Elasticsearch + Spring Security + ...). Она предоставляет подробные руководства по разработке и сопутствующие учебные материалы. Включает в себя модули таких как темы, комментарии, личные сообщения, системные уведомления, лайки, подписки, поиск, настройки пользователя, статистика данных и другие.
Страница публикации поста (поддерживает Markdown):
Страница деталей поста (рендеринг Markdown):
Страница деталей поста:
Личная страница пользователя:
Страница личных сообщений друзей:
Страница деталей личных сообщений:
Страница системных уведомлений:
Страница деталей уведомлений:
Страница настроек аккаунта:
Страница статистики данных:
Страница деталей поиска:
🎨 Список функций
Регистрация
Войти | Выйти
Динамическое создание CAPTCHA
Запомнить меня
Настройка аккаунта
Изменение аватара
Изменение пароля
Фильтрация нежелательных слов
Префиксное дерево
Модуль публикаций
Создание публикации (фильтрация нежелательных слов)
Страница со всеми публикациями
Поддерживает отображение по времени публикации
Поддерживает отображение по рейтингу популярности (Spring Quartz)
Просмотр деталей публикации
Управление правами доступа (Spring Security + Thymeleaf Security)
Незарегистрированные пользователи не могут создавать публикации
Модератор может видеть кнопки "вверху списка" и "выделено" и выполнять соответствующие действия
Администратор может видеть кнопку "удалить" и выполнять соответствующие действия
Обычный пользователь не может видеть кнопки "вверху списка", "выделено" и "удалить", а также выполнять соответствующие действия
Модуль комментариев
Опубликовать комментарий к публикации (фильтрация нежелательных слов)
Страница с комментариями
Опубликовать ответ на комментарий (фильтрация нежелательных слов)
Управление правами доступа (Spring Security)
Незарегистрированные пользователи не могут использовать функцию комментариев
Модуль личных сообщений - Отправка личного сообщения (фильтрация нежелательных слов)
Список сообщений
Поиск списка текущих диалогов пользователя
Каждый диалог показывает последнее сообщение
Поддерживает страницацию
Детали сообщения
Поиск всех сообщений в конкретном диалоге
При просмотре деталей сообщения, оно помечается как прочитанное
Поддерживает страницацию
Управление правами доступа (Spring Security)
Незарегистрированные пользователи не могут использовать функцию личных сообщений
Общее обработывание ошибок 404 / 500 метод
Обработка обычных запросов
Обработка асинхронных запросов
Универсальная запись логов
Модуль лайков
Поддерживает лайки для публикаций, комментариев/ответов
Первый лайк, второй отменяет лайк
Главная страница отображает количество лайков для публикаций
Страница деталей отображает количество лайков для публикаций и комментариев/ответов
Страница деталей показывает состояние лайка текущего пользователя (если лайкнуто, то отмечено как "лайкнуто")
Статистика количества полученных лайков
Управление правами доступа (Spring Security)
Незарегистрированные пользователи не могут использовать функцию лайков
Модуль подписок
Функция подписки
Функция отмены подписки
Статистика количества подписок и подписчиков - Список моих подписок (поиск людей, на которых пользователь подписан), поддерживает страницацию
Список моих подписчиков (поиск пользователей, которые подписаны на данного пользователя), поддерживает страницацию
Управление правами доступа (Spring Security)
Незарегистрированные пользователи не имеют доступа к функции подписок
Модуль системных уведомлений
Список уведомлений
Отображает уведомления трёх типов: комментарии, лайки, подписки
Детали уведомления
При переходе в детали определённого типа системного уведомления, состояние всех непрочитанных системных уведомлений на данной странице будет установлено как прочитанные
Количество непрочитанных уведомлений
Отдельное отображение количества непрочитанных уведомлений каждого типа системных уведомлений
Отображение общего количества непрочитанных системных уведомлений
Навигационная панель отображает общее количество непрочитанных сообщений (непрочитанные личные сообщения + непрочитанные системные уведомления)
Управление правами доступа (Spring Security)
Пользователи, не прошедшие аутентификацию, не имеют доступа к функциональности системных уведомлений
Модуль поиска
Статистика данных сайта (только для администраторов)
Уникальные посетители UV - Поддерживает запрос за один день и запрос за диапазон дат
Дневной активный пользователь (DAU)
Поддерживает запрос за один день и запрос за диапазон дат
Управление правами доступа (Spring Security)
Только администраторы могут просматривать статистику данных сайта
Оптимизация производительности сайта
При каждом запросе информация пользователя проверяется через интерцептор с использованием учетных данных входа. Частота обращений очень высока. Поэтому информация пользователя после успешного входа хранится в кэше Redis некоторое время; при запросе информации пользователя данные берутся из кэша; если в кэше нет информации о данном пользователе, она заносится в кэш; при изменении информации пользователя соответствующий кэш очищается
Введение локального кэширования Caffeine, кэширование списка популярных тем и общего количества тем, повышение скорости ответа (можно использовать двухуровневую схему кэширования)
🌱 Локальная установкаДля тестирования проекта на локальной машине заранее подготовьте следующие компоненты:
Java 8
MySQL 5.7
Redis
Kafka 2.13-2.7.0
Elasticsearch 6.4.3
Необходимо изменить информацию в конфигурационных файлах под свои локальные данные, так как без этого запустить проект невозможно. Также все конфиденциальные данные заменены на xxxxxxx.
Информация, которую следует изменить при локальном запуске:
application-develop.properties:
MySQL
Spring Mail (необходимо включить SMTP-сервер)
Kafka: consumer.group-id (значение можно найти в файле consumer.properties, который находится в пакете установки Kafka; после изменения потребуется перезапуск Kafka)
Elasticsearch: cluster-name (значение можно найти в файле elasticsearch.yml, который находится в пакете установки Elasticsearch; после изменения потребуется перезапуск Elasticsearch)
Qiniu Cloud (необходимо создать пространство объектного хранилища Qiniu Cloud для хранения загруженных изображений)
logback-spring-develop.xml:
LOG_PATH: путь к логам
При каждом запуске требуется запуск следующих сервисов:
MySQL
Redis
Elasticsearch
Kafka
Кроме того, необходимо создать базу данных greatecommunity и последовательно выполнить SQL-скрипты из папки sql для создания таблиц базы данных:
🌌 Архитектура развертывания
На каждый компонент установлен один экземпляр. Ниже представлена идеальная архитектура развертывания:
🎯 Схема функциональной логики
Ниже приведены схемы, которые помогут понять логику работы системы.
Одиночные зелёные стрелки:
Шаблон фронта -> контроллер: указывает на то, что в шаблоне есть ссылка, которая обрабатывается данным контроллером
Контроллер -> шаблон фронта: указывает на то, что контроллер передает данные или переходит к данному шаблону
Двунаправленные зелёные стрелки: указывают на взаимодействие между контроллером и шаблоном фронта
Одиночные голубые стрелки: A -> B, указывают на вызов метода B методом A
Одиночные красные стрелки: операции с базой данных или кэширование
Регистрация
При успешной регистрации пользователя его информация сохраняется в MySQL, но статус аккаунта остаётся неактивным
Отправка активационного письма пользователю, которое позволяет активировать аккаунт при переходе по ссылке (Spring Mail)
Войти | Выйти
Механизм аутентификации пропускает встроенную систему аутентификации Spring Security. Основная логика работы следующая:- При входе на страницу авторизации генерируется случайная строка, которая используется для идентификации пользователя. Эта строка временно хранится в cookie (60 секунд);
Генерируется динамический код проверки, который вместе с идентификатором пользователя временно сохраняется в Redis (60 секунд);
Для успешной авторизации (проверка имени пользователя, пароля и кода проверки) генерируется случайный токен доступа, который устанавливается как действительный. Этот токен и связанные данные сохраняются навсегда в Redis, а также временно сохраняются в cookie;
Используется интерцептор, чтобы перед выполнением каждого запроса получить токен доступа из cookie. Если токен действителен и находится в периоде действия в Redis, то этот запрос будет иметь информацию о пользователе (информация о пользователе хранится с использованием ThreadLocal для обеспечения синхронизации состояния авторизации между несколькими серверами);
Выбор "Запомнить меня" продлевает срок действия токена доступа в cookie;
При выходе пользователя состояние токена устанавливается как недействительное, и обновляются связанные данные в Redis.Ниже представлена схема функциональной логики модуля авторизации, который не использует встроенные механизмы аутентификации Spring Security (по моему мнению, это самый сложный модуль, и эта схема ещё не полностью отражает все детали).
Отображение всех тем постранично
Поддерживает отображение по времени публикации
Поддерживает отображение по рейтингу популярности (Spring Quartz)
Список популярных тем и общее количество тем сохраняются в локальном кэше Caffeine (используются распределённые задачи планировщика Spring Quartz для регулярного обновления рейтинга/баллов тем — подробнее ниже, а данные в Caffeine автоматически обновляются при каждом обращении)
Настройка аккаунта
Изменение аватара (асинхронный запрос)
Выбранный пользователем файл аватара загружается на сервер Qiniu Cloud
Изменение пароля
На данном этапе показана только схема изменения аватара:
Создание новой темы (асинхронный запрос)
При создании новой темы (фильтрация запрещённых слов) она сохраняется в базе данных MySQL
Отображение комментариев и связанных данных> В названии раздела с комментариями в фронтэнде есть некоторые недочеты; если кто-то заинтересован, приветствуем ваш Pull Request для решения этой проблемы.
Что следует учесть при работе с модулем комментариев — это проектирование таблицы комментариев, понимание значений полей помогает глубже освоить логику этого функционала.
Комментарий Comment имеет тип цели (пост, комментарий) entityType и ID цели entityId, а также ID пользователя, которому адресован комментарий/ответ targetId, передаются фронтендом в контроллер DiscussPostController.
Для страницы деталей одного поста требуется примерно следующее:
Добавление комментария (управление транзакциями)
Публикация комментария к посту (фильтрация отрицательных слов), его хранение в MySQL.
Список и детальная информация сообщений
Отправка сообщения (асинхронный запрос)
Лайк (асинхронный запрос)
Информация о лайках сохраняется в структуре данных типа set в Redis. Ключ называется like:entity:entityType:entityId, значение представляет собой ID пользователя, который поставил лайк. Например, ключ like:entity:2:246 и значение 11 указывают на то, что пользователь 11 поставил лайк на комментарий с ID 246.Общее количество лайков для конкретного пользователя хранится в Redis под ключом like:user:userId, где значение представляет собой общее количество лайков данного пользователя.
Мои лайки
Подписка (асинхронный запрос)
Если A подписался на B, то A является фолловером (Follower), а B — объектом подписки (Followee).
Объектом подписки может быть пользователь, пост, задача и т.д.; при реализации эти объекты абстрагируются как сущности (в настоящее время возможна только подписка на пользователей).
Информация о подписках пользователя сохраняется в структуре данных типа zset в Redis: ключ followee:userId:entityType, значение zset(entityId, now), сортировка по времени подписки. Например, ключ followee:111:3 со значением (20, 2020-02-03-xxxx) указывает на то, что пользователь 111 подписался на пользователя с ID 20, время подписки — 2020-02-03-xxxx. Аналогично, информация о подписчиках, принадлежащих определенной сущности, также хранится в структуре данных Redis zset:
Ключ: follower:entityType:entityId
Значение: zset(userId, now)
Сортировка выполняется по времени подписки.
Список подписок
Отправка системных уведомлений
Отображение системных уведомлений
Поиск
Опубликование событий
При публикации поста сообщение отправляется через очередь сообщений на сервер Elasticsearch
При добавлении комментария к посту сообщение отправляется через очередь сообщений на сервер Elasticsearch
Поиск сервис
Поиск постов на сервере Elasticsearch
Удаление постов с сервера Elasticsearch при удалении их из базы данных
Отображение результатов поиска
Аналогично, закрепление поста и его пометка как "выдающегося" также вызывают события публикации, что больше не показывается на диаграмме.
Закрепление, пометка как выдающееся и удаление (асинхронные запросы)
Статистика сайта
Уникальные посетители UV
Хранятся в Redis с использованием HyperLogLog
Поддерживают однодневные и диапазонные запросы
Дневной активный пользователь DAU
Хранятся в Redis с использованием Bitmap
Поддерживают однодневные и диапазонные запросы
Управление правами доступа (Spring Security)
Только администратор может просматривать статистику сайта
Вычисление популярности постовПри каждом лайке (лайк поста), комментарии (комментарий к посту) и пометке поста как "выдающегося", информация о таких постах сохраняется в кэше Redis, а затем распределенные задачи планировщика Spring Quartz каждые несколько минут извлекают эти посты из кэша для расчета их рейтинга.
Формула для расчета рейтинга поста: рейтинг (популярность) = вес + количество дней до создания поста
// Расчет весаdoublew=(wonderful?75:0)+commentCount*10+likeCount*2;// Рейтинг = вес + количество дней до создания постаdoublescore=Math.log10(Math.max(w,1))+(post.getCreateTime().getTime()-epoch.getTime())/(1000*3600*24);
Мы предоставим вам отзыв в течение 2 рабочих дней через внутреннее сообщение!
Заполните причину отчета внимательно и по возможности подробно опишите ее.
Выберите тип отчета
Отмена
Отправить
Обжалование ошибочного суждения
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )