User Entity
유저 엔티티에서 필요한 필드는 무엇일까? 해당 프로젝트에서 중요한 유저 기능은 자체 로그인과 소셜 로그인일 것이다. 따라서 기본적인 유저의 정보(이메일, 비밀번호, 닉네임 등)가 필요하다. 또한 어떤 소셜 서비스를 사용하는지 나타내는 소셜 아이디, 소셜 타입 정도를 추가하면 될 것 같다.
- 유저 아이디
- 이메일
- 비밀번호
- 이름
- 소셜 타입
- 소셜 아이디
🛠️ 채번 전략
그동안 JPA에서 채번 방식으로 Auto Increment 전략을 사용해 PK 값을 지정했다. 여러 전략이 있지만 구현이 간단하고 1부터 시작하여 자동 증가하기 때문에 별 생각 없이 자동 생성 전략을 채택한 것이다. 하지만 여기엔 몇 가지 문제점이 있는데, 해당 글에선 다루지 않고 따로 작성하도록 하겠다. 이외에도 다음과 같은 채번 전략들이 있다. 그중에서도 나는 TSID를 사용하기로 했다.
- Auto Increment
- Sequence
- UUID
- ULID
- TSID
- Snowflake
TSID를 사용하기 위해선 build.gradle에 아래 의존성을 추가해주어야 한다. 물론 Tsid Creator를 통해 생성하는 방법도 존재한다. 따라서 필요한 의존성을 찾아 추가해주면 된다.
implementation 'io.hypersistence:hypersistence-utils-hibernate-60:3.5.1'
그러면 엔티티 클래스에서 @Tsid 어노테이션 만으로도 간단하게 TSID를 사용할 수 있다. 참고로 TSID는 Long 타입이고 타임 스탬프 기반이라 시간순 정렬도 가능하다.
🛠️ 소셜 타입, 소셜 아이디
소셜 타입은 Enum으로 관리한다. 현재 우리 프로젝트에선 일반, 카카오, 구글 유저가 존재하기 때문에 각각 추가해주면 된다.
public enum SocialType {
GENERAL,
KAKAO,
GOOGLE,
}
일반 유저 자체 로그인을 사용하기 때문에 소셜 아이디가 필요 없다. 따라서 일반 유저인 경우 null, 나머진 각각 고유한 소셜 아이디가 저장된다. 반면 소셜 로그인 유저는 이메일과 비밀번호가 빈 값일 것이다.
🛠️ 엔티티 클래스
@Entity
@Getter
@Table(name = "users")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User extends BaseTimeEntity {
@Id @Tsid
@Column(name = "user_id")
private Long id;
@Column(name = "email", unique = true)
private String email;
@Column(name = "password")
private String password;
@Column(name = "name")
private String name;
@Enumerated(EnumType.STRING)
@Column(name = "social_type")
private SocialType type;
@Column(name = "social_id")
private String socialId;
@Builder
public User(String email, String password, String name, SocialType type, String socialId) {
this.email = email;
this.password = password;
this.name = name;
this.type = type;
this.socialId = socialId;
}
}
애플리케이션 실행 후 데이터베이스를 확인하면 테이블이 잘 정의된 것을 볼 수 있다.

User Repository, Service, Controller
🛠️ UserRepository
public interface UserRepository extends JpaRepository<User, Long> {
boolean existsByEmail(final String email);
Optional<User> findByEmail(final String email);
Optional<User> findByName(final String name);
Optional<User> findBySocialTypeAndSocialId(final SocialType socialType, final String socialId);
}
[시리즈 보러가기]
Spring Boilerplate 시리즈 (1) - 프로젝트 개요 및 요구 사항 분석
Spring Boilerplate 시리즈 (2) - 프로젝트 세팅
Spring Boilerplate 시리즈 (3) - 유저 도메인 추가