[Project] User DTO 개발
현재 글은 User Entity_(Reputation) 개발 글의 뒷 내용을 이어갑니다.
👨💻 User CRUD 개발과정 순서
-
Repository :데이터베이스에 접근하여 데이터를 다루는 기능을 담당하는 Repository를 먼저 구현.
JpaRepository를 추가함으로써 USER CRUD 기능을 쉽게 사용하게 함.email로 user찾기 / username으로 user찾기 / id값에 해당하는 user찾기 메서드 추가.
Entity :
데이터베이스의 테이블과 매핑되는 객체로, 테이블의 컬럼들과 매핑되는 필드를 가지고있음.
UserReputation
- DTO :
데이터를 전송하기 위한 객체로, Entity와 비슷하지만 HTTP 요청과 응답에서 사용하는 데이터를 가지고 있음.
- Service :
비즈니스 로직을 처리하는 컴포넌트로, Repository를 사용하여 데이터를 조작하고, 비즈니스 로직에 맞게 데이터를 가공한다.
- Controller :
HTTP 요청을 처리하는 컴포넌트로, 클라이언트로부터 요청을 받아 Servcie에게 전달하고, Service가 처리한 결과를 다시 클라이언트에게 반환한다.
- Mapper :
Entity와 DTO 간의 변환을 담당하는 컴포넌트로, Entity를 DTO로 변환하거나, DTO를 Entity로 변환하는 등의 작업을 함
📃 DTO 작성방법
DTO(Data Transfer Object)를 작성할 때 고려해야 할 몇 가지 사항이 있습니다.
- DTO는 순수한 데이터 객체이며, 로직을 가지고 있지 않아야 합니다. 이는 DTO가 데이터를 전송하는데에만 사용되며, 데이터를 가공하는 역할을 하지 않기 때문입니다.
- DTO에는 Getter와 Setter 메서드만 포함되어야 합니다. 이 메서드들은 DTO 객체의 필드 값을 설정하고 가져오는 데 사용됩니다.
- DTO는 가급적 불변 객체(Immutable Object)로 작성하는 것이 좋습니다. 이렇게 하면 객체가 변경되지 않기 때문에 코드의 안정성이 높아집니다.
- DTO의 필드는 가능한 간단하게 유지해야 합니다. 이는 데이터 전송 시에 불필요한 데이터가 전송되는 것을 막고, DTO의 용도가 명확하게 드러나도록 돕습니다.
- DTO는 보통 Entity 클래스와 매우 유사하게 작성됩니다. 이는 DTO가 Entity 객체를 대신해 데이터 전송 시 사용되기 때문입니다.
- DTO는 클라이언트와 서버 간의 데이터 전송에 사용되므로, 전송할 필드를 선택하는 것이 중요합니다. 불필요한 데이터를 전송하면 불필요한 대역폭을 사용하게 되므로, 필요한 필드만 선택하여 전송해야 합니다.
위의 사항들을 고려하여 DTO를 작성하면, 보다 효율적인 데이터 전송을 할 수 있습니다.
❓ DTO에는 어떠한 내용들이 작성되어야 할까?
DTO에는 일반적으로 데이터를 전송하기 위해 필요한 필드들이 작성됩니다. 필드는 데이터 전송 시에 클라이언트와 서버 간의 인터페이스를 형성하며, 클라이언트에서 요청하는 데이터와 서버에서 응답하는 데이터에 모두 적용됩니다. 이를 통해 클라이언트와 서버 간의 데이터 전송을 원활하게 할 수 있습니다.
일반적으로 DTO에 작성되는 필드는 다음과 같습니다.
기본 데이터 타입(Primitive Data Type): DTO는 일반적으로 간단한 데이터를 전송하는 데 사용되므로, 기본 데이터 타입(Int, Long, Float, Double, Boolean 등)을 사용하여 필드를 작성하는 것이 일반적입니다.객체(Object): DTO에는 객체 필드도 포함될 수 있습니다. 이 경우에는 객체의 필드들 중에서 데이터 전송에 필요한 필드만 선택하여 DTO에 포함시키는 것이 좋습니다.리스트(List): DTO에는 리스트 필드도 포함될 수 있습니다. 이 경우에는 리스트에 포함된 각 항목에 대한 정보를 DTO로 전송할 필요가 있을 때 사용됩니다.열거형(Enum): DTO에는 열거형 필드도 포함될 수 있습니다. 이 경우에는 열거형의 상수값을 전송하면 됩니다.날짜(Date): DTO에는 날짜 필드도 포함될 수 있습니다. 이 경우에는 보통 Date, LocalDate, LocalDateTime 등의 날짜 타입을 사용합니다.문자열(String): DTO에는 문자열 필드도 포함될 수 있습니다. 이 경우에는 보통 String 타입을 사용합니다.
이외에도, 데이터 전송에 필요한 필드들을 추가하여 DTO를 작성할 수 있습니다. 단, DTO는 순수한 데이터 객체이므로, 로직을 작성하지 않아야 합니다.
😎 그러면 내가 구상하고 있는 DTO 내용.
- UserDTO : 사용자 정보를 전송하기 위한 DTO입니다. 사용자 ID, 이름, 이메일 등의 정보
- QuestionDTO : 질문 정보를 전송하기 위한 DTO입니다. 질문 ID, 제목, 내용, 태그 등의 정보
- AnswerDTO : 답변 정보를 전송하기 위한 DTO입니다. 답변 ID, 내용 등의 정보
- CommentDTO : 댓글 정보를 전송하기 위한 DTO입니다. 댓글 ID, 내용 등의 정보
- VoteDTO : 투표 정보를 전송하기 위한 DTO입니다. 투표 ID, 투표 유형(VoteType), 투표한 사용자 ID 등의 정보
- TagDTO : 태그 정보를 전송하기 위한 DTO입니다. 태그 ID, 이름 등의 정보
- BadgeDTO : 배지 정보를 전송하기 위한 DTO입니다. 배지 ID, 이름, 설명 등의 정보
- NotificationDTO : 알림 정보를 전송하기 위한 DTO입니다. 알림 ID, 내용, 알림 받는 사용자 ID 등의 정보
이중에서 기획한 요구사항을 자르면
1, 2, 3, 4, 6 정도가 될것같다.
⭐ User DTO(LoginDto) 코드
@Getter
@Setter
@NoArgsConstructor
public class LoginDto {
private String username;
private String password;
}
❓ LoginDto의 역할
로그인 기능을 구현할 때 LoginDTO는 다음과 같은 역할을 한다.
- 클라이언트에서 서버로 로그인 정보를 전송하는 역할 LoginDTO는 로그인 요청 시 클라이언트에서 서버로 전송되는 데이터를 담기 위한 객체입니다. 클라이언트에서는 사용자의 ID와 비밀번호 등의 정보를 LoginDTO에 담아 서버로 전송합니다.
- 서버에서 로그인 정보를 검증하는 역할 서버는 클라이언트로부터 전송된 LoginDTO에 포함된 사용자의 ID와 비밀번호를 검증합니다. 이를 통해 해당 사용자가 인증됐는지 여부를 판단하고, 인증에 성공하면 로그인 세션을 생성하고 클라이언트에 응답을 보냅니다.
- 로그인 세션을 유지하는 역할 로그인에 성공하면 서버는 로그인 세션을 생성하고 클라이언트에게 세션 ID를 반환합니다. 이후 클라이언트는 세션 ID를 사용하여 로그인 상태를 유지하며, 서버는 해당 세션 ID를 통해 클라이언트가 로그인한 사용자임을 인증합니다.
따라서 LoginDTO는 로그인 기능을 구현하기 위해 필요한 중요한 요소 중 하나입니다.
❓ LoginDto에서의 @Getter / @Setter 역할
LoginDTO 클래스에서는 getter와 setter 메서드가 각각 username과 password 필드의 값을 설정하고 반환하는 역할을 합니다.
간단한 예시를 들면, 클라이언트에서 사용자의 ID와 비밀번호 정보를 입력받은 후, 이를 LoginDTO 객체에 저장합니다. 그리고 이후에 로그인 기능을 수행하기 위해 해당 객체의 username과 password 필드 값을 서버로 전송합니다. 이때 getter 메서드를 사용하여 해당 필드 값을 조회하여 전송할 수 있습니다.
또한, 서버에서는 LoginDTO 객체를 받아 로그인을 처리하는데, 이때 setter 메서드를 사용하여 해당 객체의 필드 값을 설정하고 처리할 수 있습니다.
즉, LoginDTO 클래스에서는 사용자의 로그인 정보를 저장하고 전송하기 위한 객체이며, getter와 setter 메서드는 이를 가능하게 하는 역할을 합니다.
❓ @NoArgsConstructor 어노테이션의 역할
@NoArgsConstructor 어노테이션은 인자 없는 생성자를 자동으로 생성해주는 Lombok의 기능입니다.
DTO 클래스에서는 주로 데이터를 전송하고 저장하기 위한 객체를 사용합니다. 이 경우, 인자 없는 생성자가 필요한 경우가 많습니다. 예를 들어, LoginDTO 클래스에서는 username과 password 필드를 가지고 있습니다. 로그인 기능에서는 클라이언트에서 전송된 사용자 정보를 LoginDTO 객체에 담아 서버로 전송하는데, 이때 인자 없는 생성자가 필요합니다.
하지만, Java에서는 클래스에 생성자를 선언하지 않으면 컴파일러가 인자 없는 기본 생성자를 자동으로 생성합니다. 이 경우, 클래스 내에 다른 생성자가 선언되어 있지 않다면 인자 없는 기본 생성자가 자동으로 생성되므로 @NoArgsConstructor 애노테이션을 사용하지 않아도 되지만, 코드의 가독성을 높이고자 @NoArgsConstructor 어노테이션을 사용하기도 합니다.
또한, 다른 Lombok 어노테이션과 함께 사용하면 더욱 간편하게 코드를 작성할 수 있습니다. 예를 들어, @Data 애노테이션을 사용하면 @NoArgsConstructor, @Getter, @Setter, @EqualsAndHashCode 등의 기능을 모두 포함하는 코드를 간편하게 작성할 수 있습니다.
🔑정리
Data 어노테이션을 사용해도 괜찮지만 @NoArgsConstructor를 안써도 Java에서 컴파일러가 기본 생성자를 자동 생성하지만, 코드의 가독성을 높이고자 작성함.
⭐ User DTO(UserDto) 코드
@Getter
@Setter
@AllArgsConstructor
public class UserDto {
@Getter
@AllArgsConstructor
public static class Post{
private String displayName;
@NotBlank(message = "비밀번호는 필수 입력 항목입니다. ")
private String password;
@Email
@NotBlank(message = "이메일은 필수 입력 항목입니다.")
private String email;
}
@Getter
@AllArgsConstructor
public static class Patch{
private Long userId; // null을 가질 수 있는 wrapper class로 감싸기.
private String displayName;
// public void setUserId(long userId) {this.userId = userId;}
// @AllArgsConstructor을 통해서 userId필드에 대한 생성자가 자동 생성되고 있으니 제거해도 되지않을까?
// 만들려는 이유는 userId필드에 대한 생성자를 만들려고하는것임.
}
@Getter
@AllArgsConstructor
public static class Response{
private long userId;
private String email;
private String displayName;
private String profileImage;
private Reputation reputation;
public int getReputation() {return reputation.getAmount();}
}
}
❓ UserDto에는 어떠한 내용이 작성되어야 할까?
UserDto에는 User 엔티티의 데이터를 전달하기 위한 필드와 메서드가 작성되어야 합니다. 주로 다음과 같은 내용들이 포함됩니다.
- User 엔티티의 필드들과 일치하는 필드들
- 필요한 경우, 연관 엔티티의 데이터를 전달하기 위한 필드들
- Getter, Setter 메서드들
이외에도, API 요청/응답에 필요한 필드들을 추가로 작성할 수 있습니다. 예를 들어, 로그인 요청 API의 경우에는 이메일과 비밀번호를 입력받는 필드를 추가로 작성할 수 있습니다. 또한, API 요청/응답에 따라 필요한 데이터가 다를 수 있으므로, 상황에 맞게 필드와 메서드를 추가/수정해주어야 한다.
민이는 Post / Patch / Response 의 내용을 추가할 생각이다.
❓ Response 에는 get이 쓰이고, Patch에는 set이 안쓰이는 이유가 뭐지?
원래대로라면 set메서드를 쓰지 않아도 됩니다.
@AllArgsConstructor 어노테이션은 해당 클래스의 모든 필드를 파라미터로 받는 생성자를 자동으로 생성해줍니다. 그렇기 때문에 별도로 set 메서드를 만들어줄 필요가 없습니다.
다만, 만약 생성자에 포함되지 않은 필드가 있다면, 그 필드에 대해서는 따로 set 메서드를 만들어줘야 합니다. 이때, 해당 필드가 null 값을 가질 수 있는 경우, 해당 필드를 wrapper 클래스로 감싸서 set 메서드를 만들어주는 것이 좋습니다. 이렇게 하면, null 값을 가질 수 있는 필드에 대해서도 안전하게 값을 할당할 수 있습니다.
예를 들어, 위의 코드에서 Patch 클래스의 userId 필드는 Long 타입으로 선언되어 있습니다. 이는 null 값을 가질 수 있는 wrapper 클래스입니다. 따라서, 이 필드에 대한 set 메서드를 만들 때도 Long 타입을 파라미터로 받도록 만들어주는 것이 좋습니다. 이렇게 하면, 해당 필드에 null 값을 할당할 수 있게 됩니다.
🌟 TIL
-
@DATA 어노테이션이란?
@Data는 Lombok에서 제공하는 애노테이션 중 하나로, 클래스 내의 필드들에 대해 Getter, Setter, ToString, EqualsAndHashCode, RequiredArgsConstructor 등의 메서드를 자동으로 생성해주는 기능을 제공합니다.
보통 DTO, VO 등의 객체를 정의할 때, 클래스 내에 필드를 선언하고 각각의 Getter, Setter 메서드를 만들어주어야 하는데, 이를 @Data 애노테이션을 사용하면 자동으로 생성해줍니다. 따라서 개발자는 필드의 정의만 해주면 됩니다.
@Data 애노테이션은 다른 Lombok 애노테이션과 함께 사용하면 더욱 편리합니다. 예를 들어, @NoArgsConstructor와 함께 사용하면 기본 생성자를 자동으로 생성해주고, @AllArgsConstructor와 함께 사용하면 모든 필드를 인자로 받는 생성자를 자동으로 생성해줍니다. 또한, @ToString 애노테이션과 함께 사용하면 toString() 메서드를 자동으로 생성해주고, @EqualsAndHashCode 애노테이션과 함께 사용하면 equals()와 hashCode() 메서드를 자동으로 생성해줍니다.
@Data 애노테이션을 사용하면 개발자가 직접 Getter, Setter, toString(), equals(), hashCode() 등을 작성하지 않아도 되므로, 코드의 간결성과 가독성을 높일 수 있습니다.
댓글남기기