Вступление
Добро пожаловать в часть 2 создания клона Reddit с использованием Spring Boot и React.
В части 1 мы инициализировали наш проект и добавили все необходимые зависимости. В этой статье мы рассмотрим создание всех сущностей и репозиториев, которые нам понадобятся для завершения нашего бэкенда!
Важные ссылки
- Внутренний источник: https://github.com/MaxiCB/vox-nobis/tree/master/backend
- Источник интерфейса: https://github.com/MaxiCB/vox-nobis/tree/master/client
- Прямой URL-АДРЕС: в процессе
Часть 1. Создание сущностей Домена 📝
Давайте рассмотрим все различные доменные сущности, которые будут иметь наше приложение. Внутри com.your-name.backend создайте новый пакет под названием модели и добавьте следующие классы.
Примечание: Мы установили Lombok в качестве зависимости в части 1. Мы будем использовать различные аннотации Ломбока на протяжении всего процесса разработки. Чтобы получить доступ к этим аннотациям, вам необходимо включить обработку аннотаций в вашей среде разработки. Для получения дополнительных инструкций по этому вопросу вы можете ознакомиться с руководством по настройке Ломбока здесь – Для получения дополнительных инструкций по этому вопросу вы можете ознакомиться с руководством по настройке Ломбока здесь –
Примечание: В некоторых случаях вам может потребоваться добавить следующую зависимость к вашему pom.xml файл для проверки поля
org.springframework.boot spring-boot-starter-validation
- Пользователь: Иметь уникальный идентификатор пользователя, имя пользователя, пароль, адрес электронной почты, дату создания, статус учетной записи
package com.maxicb.backend.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import java.time.Instant;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "users")
@Entity
public class User {
@Id
@SequenceGenerator(name = "USER_GEN", sequenceName = "SEQ_USER", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_GEN")
private Long userId;
@NotBlank(message = "Username is required")
private String username;
@NotBlank(message = "Password is required")
private String password;
@Email
@NotBlank(message = "Email is required")
private String email;
private Instant creationDate;
private boolean accountStatus;
}
- Сообщение: Иметь уникальный идентификатор, имя сообщения, URL, описание, количество голосов, пользователя, дату создания, субреддит
package com.maxicb.backend.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.lang.Nullable;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.time.Instant;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class Post {
@Id
@SequenceGenerator(name = "POST_GEN", sequenceName = "SEQ_POST", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "POST_GEN")
private Long postId;
@NotBlank(message = "Post Title is required")
private String postTitle;
@Nullable
private String url;
@Nullable
@Lob
private String description;
private Integer voteCount;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "userId", referencedColumnName = "userId")
private User user;
private Instant creationDate;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "id", referencedColumnName = "id")
private Subreddit subreddit;
}
- Субреддит: Иметь уникальный идентификатор, имя, описание, сообщения, дату создания, пользователи
package com.maxicb.backend.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.time.Instant;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class Subreddit {
@Id
@SequenceGenerator(name = "SUB_GEN", sequenceName = "SEQ_SUB", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SUB_GEN")
private Long id;
@NotBlank(message = "Subreddit name is required")
private String name;
@NotBlank(message = "Subreddit description is required")
private String description;
@OneToMany(fetch = FetchType.LAZY)
private List posts;
private Instant creationDate;
@ManyToOne(fetch = FetchType.LAZY)
private User user;
}
- Голосовать: Иметь уникальный идентификатор, сообщение, пользователя
package com.maxicb.backend.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class Vote {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long voteId;
private VoteType voteType;
@NotNull
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "postId", referencedColumnName = "postId")
private Post post;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "userId", referencedColumnName = "userId")
private User user;
}
- Комментарий: Иметь уникальный идентификатор, текст, сообщение, дату создания, пользователя
package com.maxicb.backend.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import javax.validation.constraints.NotEmpty;
import java.time.Instant;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@NotEmpty
private String text;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "postId", referencedColumnName = "postId")
private Post post;
private Instant creationDate;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "userId", referencedColumnName = "userId")
private User user;
}
- ПЕРЕЧИСЛЕНИЕ типов голосов: Повышающий голос, Понижающий голос
public enum VoteType {
UPVOTE(1), DOWNVOTE(-1);
VoteType(int direction) {}
}
- Проверка учетной записи Токен: Иметь уникальный идентификатор, токен, пользователя, срок действия
package com.maxicb.backend.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.Instant;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Table(name = "token")
@Entity
public class AccountVerificationToken {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String token;
@OneToOne(fetch = FetchType.LAZY)
private User user;
private Instant expirationDate;
}
- Уведомление по электронной почте: тема, получатель, тело
package com.maxicb.backend.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class NotificationEmail {
private String subject;
private String recepient;
private String body;
}
Часть 2. Создание репозиториев 👩
Теперь нам нужно охватить репозитории, которые будут отвечать за хранение сущностей в базе данных. Внутри com.you-name.backend создайте новый пакет под названием репозиторий и добавьте следующие интерфейсы.
- Хранилище пользователей:
package com.maxicb.backend.repository;
import com.maxicb.backend.model.User;
import org.springframework.data.repository.CrudRepository;
import java.util.Optional;
public interface UserRepository extends CrudRepository {
Optional findByUsername(String username);
}
- Хранилище сообщений:
package com.maxicb.backend.repository;
import com.maxicb.backend.model.Post;
import com.maxicb.backend.model.Subreddit;
import com.maxicb.backend.model.User;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
public interface PostRepository extends CrudRepository {
List findAllBySubreddit(Subreddit subreddit);
List findByUser(User user);
}
- Репозиторий субреддитов:
package com.maxicb.backend.repository; import com.maxicb.backend.model.Subreddit; import org.springframework.data.repository.CrudRepository; import java.util.Optional; public interface SubredditRepository extends CrudRepository{ Optional findByName(String subredditName); }
- Хранилище голосов:
package com.maxicb.backend.repository;
import com.maxicb.backend.model.Post;
import com.maxicb.backend.model.User;
import com.maxicb.backend.model.Vote;
import org.springframework.data.repository.CrudRepository;
import java.util.Optional;
public interface VoteRepository extends CrudRepository {
Optional findTopByPostAndUserOrderByVoteIdDesc(Post post, User currentUser);
}
- Хранилище комментариев:
package com.maxicb.backend.repository;
import com.maxicb.backend.model.Comment;
import com.maxicb.backend.model.Post;
import com.maxicb.backend.model.User;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
public interface CommentRepository extends CrudRepository {
List findByPost(Post post);
List findAllByUser(User user);
}
- Хранилище токенов:
package com.maxicb.backend.repository; import com.maxicb.backend.model.AccountVerificationToken; import org.springframework.data.repository.CrudRepository; import java.util.Optional; public interface TokenRepository extends CrudRepository{ Optional findByToken(String token); }
Вывод 🔍
- Чтобы убедиться, что все настроено правильно, вы можете запустить приложение и убедиться, что в консоли нет ошибок. В нижней части консоли вы должны увидеть вывод, аналогичный приведенному ниже
- В этой статье мы создали сущности и репозитории, необходимые в нашем бэкэнде Spring Boot. Закладывая основу для всей логики, которая последует за этим.
Следующий
Часть 3 Реализация регистрации, отправки электронной почты и активации/верификации учетной записи.
Оригинал: “https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-2-446l”