팀프로젝트일기/SKKUNION

SKKUNION - User Entity 및 Repository 설계

Recfli 2023. 9. 23. 23:59

Entity 설계

Postman에 올려주신 메서드 요청을 보니까, 모든 컬럼 값을 정리해보니 Entity를 아래처럼 설계하면 될 것 같더라고요. 그래서 UserEntity라는 Entity를 다음과 같이 생성했습니다.

 

 아래 주석으로 각각의 어노테이션의 의미와 제가 왜 Id라는 컬럼을 만들었는지 DB에는 어떻게 연결되는지 나와있어요! - JPA에서 getter, setter, constructor는 생성이 필수입니다. 사실 setter는 열면 안된다고 하는데, 저도 아직은 이유를 정확하게 경험해본 적이 없어서 일단 개발 편의상 열어놓을게요.

 

@Data
@Builder
@Entity
@AllArgsConstructor // constructor 생성
@NoArgsConstructor // getter, setter 생성
public class UserEntity {

    // 혹시나 나중에 수정할지도 몰라서 전혀 관련이 없는 DB 자체 내부 설정값을 PK로 두겠습니다.
    // 다른 Table에서도 id를 사용할 예정이니까. 얘만 이름을 따로 설정할게요.
    @Id @GeneratedValue
    @Column(name = "USER_ID")
    private Long Id;

    private String userEmail; // DB 내부 user_Email로 변경

    private String userPassword; // DB 내부 user_password로 변경

    private String userName; // DB 내부 user_name으로 변경

    private String userPhoneNumber; // DB 내부 user_phone_number로 변경

}

 

이제 application.properties를 다음 아래처럼 변경하시면 됩니다. 저희는 gradle을 사용하기 때문에 아래처럼 연결하시면 되는데, 중요한 거 몇 개만 설명드릴게요.

 

이전과 다르게 아래에 여러 개가 생겼습니다. 각각의 의미는 아래와 같습니다.

 

1. "spring.jpa.database-platform"은 jpa에서 사용할 언어를 무엇으로 지정하느냐인데 저희는 MySQL이니 해당으로 설정했고요. 

 

2. "spring.jpa.show-sql"은 jpa에서 자동적으로 만들어지는 쿼리를 볼 수 있는 옵션입니다. SQL문을 직접 볼 수 있어요. 이건 이거 설명하고 아래에 캡처본을 올리겠습니다.

 

3. "spring.jpa.hibernate.ddl-auto", 이게 제일 중요합니다. 이거 나중에 어느정도 프로젝트 완성됐는데 잘못 쓰시면 DB가 완전 깨끗해지는 결과를 얻을 수 있어요.

 

지금은 초기 단계라 "create"로 옵션을 해놨는데 이 옵션의 의미는 지금 저희가 skkunion을 Database로 설정해놨잖아요? 거기에 있는 모든 테이블을 Drop하고 main - entity 폴더 내부에 있는 모든 @Entity 어노테이션이 달린 걸 찾아서 그것만 자동적으로 Table로 올려줍니다. 당연히 모든 데이터 싹 다 날라가고요.

 

 나중에 테스트용 더미 데이터 싹 넣어놨는데 그거 저장 안해두시고 이 모드로 하면 전부 날라가니까. 나중에 테스트용 더미 데이터를 만드시면 인텔리제이에서 넣지 말고 꼭!!! 반드시!!! MySQL 내부 쿼리문으로 직접 작성하시던, 따로 DB에 넣을 Java 파일만을 따로 남기시건 기록으로 남겨주세요. 

 

어느정도 안정화되면 "none"으로 작성하시면 Table 계속 유지됩니다.

 

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/skkunion?serverTimezone=UTC&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=1234

spring.jpa.database=mysql
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.jpa.open-in-view=false
spring.jpa.show-sql=true
spring.jpa.generate-ddl=true

spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.format_sql=true

logging.level.web=DEBUG
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.BasicBinder=TRACE

 

이제 Application.java 파일에 들어가셔서 실행을 누르시면 아래 처럼 이미지가 뜨신 걸 확인할 수 있어요.

 

 진짜 제대로 된건지 의심이 가면, DB도 들어가보시면 됩니다.  MySQL에서 들어가보니 제가 원하는 Table이 정상적으로 생성이 되었네요. 이제 여기서 조회, 삭제, 변경, 저장을 만들어봅시다.

 

 

Repository 패키지에 이제 LoginRepository를 생성하면 되는데 아래면 충분합니다. Entity이름, pk 타입만 JpaRepository에 넣고 interface 클래스로 생성하면 돼요. Interface로 생성 안하시면 오류 생겨요!

 

여러 컬럼을 하고 싶거나 데이터 조회를 일부만 하고 싶거나 조건을 달고 싶으면 첫번째 글로 가셔서 해당 글에 있는 spring 공식문서 링크에 들어가셔서 옵션을 살펴보시고 필요한 메서드는 직접 만들어서 사용하시면 됩니다. 아래에 예시하나 메서드만 만들었어요.

@Repository 
public interface LoginRepository extends JpaRepository<User, Long> {
	// 유저의 이메일 정보로 찾는 함수, 기본은 Long이라서 찾아오려면 이거로 해야함.
    public UserEntity findByUserEmail(String UserEmail);
}

 

 이전에 만드신 좋은 게 있지만 제 생각에 다른 Entity까지 자동생성시키려면 실제로 클라이언트가 요청하는 JSON 형태로는 아래처럼 들어올 것 같아서 signUp2라는 이름으로 새로 포스트맨 내부에 POST 요청을 만들었습니다. 

 

 

해당 JSON요청은 이제 SignUpDto가 관리를 하게 하기 위해서 다음과 같이 SignUpDto를 dto 패키지 내부에 만들어주세요. 불편하시더라도 나중에 따로따로 정의하면 찾기 힘드니까 제 생각엔 Data 타입 따로 정리하는게 디버깅이 훨신 편할 것 같습니다.

 

@Data
@AllArgsConstructor
@NoArgsConstructor
public class SignUpDto {
    private String userEmail;
    private String userPassword;
    private String userName;
    private String userPhoneNumber;
}

 

 잘 됐는지 확인하려면, 서버 쪽에서도 응답용 Response를 만들어야해서 signUp이 제대로 됐는지는 우선 자바에서 Exception으로 갔는지 아닌지 확인하기 위한 result, Exception이 여러 개일 경우 어떤 Exception인지 확인하는데 사용하는 message칸, Data칸까지해서 아무래도 제가 계속한다면 다음처럼 계속 설계하는 게 나쁘지 않다고 봐요.

 

 Exception을 따로 만들어서 해당 Exception 로그를 남기는 방법도 있는데 그것보단 이게 편할 것 같습니다. 어차피 응답은 자동으로 200, 400, 500번 대가 오니까요. 200번 대가 와도 DATABASE에 들어가는 것까지는 성공을 했지만 JPA내부 로직에서 예외로 놓은 곳에 딱 걸려서 catch문으로 넘어가버리는 경우 JPA log에는 Database 에러라고 떠서 제 생각엔 이렇게 해야지 디버깅이 쉬울 것 같아요.

 

@Data
@AllArgsConstructor(staticName="set")
public class ResponseDto<D> {

    private boolean result; // 서버에서는 정상이라고 200번이 떴는데, 서버 내부에선 오류인 경우 파악용
    private String message; // Exception 대신 사용할 에러 위치 찾는 용
    private D data; // 서버에서 처리한 Data를 그대로 응답해주는 용

    // 성공했을 때 정의하는 메서드
    public static <D> ResponseDto<D> setSuccess(String message, D data){
        return ResponseDto.set(true, message, data);
    }

    // 실패했을 때 정의하는 메서드
    public static <D> ResponseDto<D> setFailed(String message){
        return ResponseDto.set(false, message, null);
    }
}