DTO가 언제 Entity로❓
처음 제 생각은 DB 에 들어가기 전에 3번(Repository) 이후Entity로 변했을 것이라고 생각했습니다.
그러나, Spring Boot 애플리케이션에서 Service 계층에서 연산 로직을 수행한 후 2번(Service) 이후에 변환해야 합니다.
Repository 직전에 DTO(Data Transfer Object)를 Entity로 변환하는 것이 좋은 이유는 다음과 같습니다:
- 책임 분리 (Separation of Concerns):
- Service 계층은 비즈니스 로직을 처리하는 곳이며, Repository 계층은 데이터 접근을 담당합니다. DTO는 외부와의 데이터 교환을 담당하고, Entity는 데이터베이스와의 상호작용을 담당합니다. 따라서, Service 계층에서 연산 로직을 수행한 후 DTO를 Entity로 변환하여 Repository로 전달함으로써 각 계층의 역할을 명확히 분리할 수 있습니다.
- 유연성 (Flexibility):
- DTO와 Entity를 분리하면 데이터베이스 스키마와 관계없이 DTO를 변경할 수 있어 더 유연한 설계가 가능합니다. 예를 들어, API의 요구사항에 따라 DTO를 자유롭게 변경하더라도 Entity에는 영향을 주지 않으므로 유지보수가 용이합니다.
- 보안 및 데이터 무결성 (Security and Data Integrity):
- 외부에서 들어오는 데이터를 그대로 Entity로 변환하면 보안 취약점이 발생할 수 있습니다. DTO를 통해 유효성 검사를 수행하고 필요한 변환 작업을 통해 데이터의 무결성을 보장할 수 있습니다. Service 계층에서 DTO를 Entity로 변환하면 데이터 검증 로직을 추가하여 보안성을 높일 수 있습니다.
- 테스트 용이성 (Testability):
- Service 계층에서 DTO를 Entity로 변환하면 각각의 계층을 독립적으로 테스트할 수 있습니다. DTO와 Entity 변환 로직을 Service 계층에 포함시켜, 이 부분을 집중적으로 테스트할 수 있고, 이를 통해 비즈니스 로직과 데이터 접근 로직의 테스트를 분리할 수 있습니다.
- 재사용성 (Reusability):
- 여러 서비스에서 동일한 DTO를 사용할 수 있으며, DTO를 Entity로 변환하는 로직을 일관되게 관리할 수 있습니다. 이를 통해 코드의 재사용성을 높이고 중복을 줄일 수 있습니다.
- 클린 코드 (Clean Code):
- DTO를 Entity로 변환하는 로직을 Service 계층에 위치시킴으로써 코드가 더 명확해지고, 각 계층의 역할이 명확해집니다. 이는 코드의 가독성과 유지보수성을 높이는 데 기여합니다.
@Valid란?
Spring Boot에서 @Valid는 데이터 유효성 검사를 위한 어노테이션입니다. 이를 사용하면 객체의 속성들이 특정 기준을 만족하는지 검사할 수 있습니다. @Valid는 Java Bean Validation API (JSR-380, Bean Validation 2.0)의 일부로, 주로 javax.validation 패키지와 함께 사용됩니다.
종류
@NotNull | 필드가 null이 아니어야 함 | @NotNull private String name; |
@NotBlank | 문자열이 null, 빈 문자열, 공백 문자열이 아니어야 함 | @NotBlank private String address; |
@NotEmpty | 문자열, 컬렉션, 맵 또는 배열이 null이거나 비어 있으면 안 됨 | @NotEmpty private List<String> items; |
@Size | 문자열, 컬렉션, 맵 또는 배열의 크기가 지정된 범위 내에 있어야 함 | @Size(min = 2, max = 14) private String username; |
@Min | 숫자가 지정된 최소값 이상이어야 함 | @Min(18) private int age; |
@Max | 숫자가 지정된 최대값 이하이어야 함 | @Max(100) private int score; |
@Positive | 숫자가 양수이어야 함 | @Positive private int quantity; |
@PositiveOrZero | 숫자가 양수이거나 0이어야 함 | @PositiveOrZero private int balance; |
@Negative | 숫자가 음수이어야 함 | @Negative private int temperature; |
@NegativeOrZero | 숫자가 음수이거나 0이어야 함 | @NegativeOrZero private int debt; |
@Past | 날짜가 과거이어야 함 | @Past private LocalDate birthDate; |
@PastOrPresent | 날짜가 과거이거나 현재이어야 함 | @PastOrPresent private LocalDate lastUpdate; |
@Future | 날짜가 미래이어야 함 | @Future private LocalDate appointmentDate; |
@FutureOrPresent | 날짜가 미래이거나 현재이어야 함 | @FutureOrPresent private LocalDate startDate; |
@Pattern | 문자열이 지정된 정규식 패턴과 일치해야 함 | @Pattern(regexp = "^[a-zA-Z0-9]{5,15}$") private String userId; |
문자열이 이메일 형식이어야 함 | @Email private String emailAddress; | |
@Digits | 숫자가 지정된 정수와 소수 자릿수를 가져야 함 | @Digits(integer = 3, fraction = 2) private BigDecimal price; |
@DecimalMin | 숫자가 지정된 최소값 이상이어야 함 (소수점 포함) | @DecimalMin("0.1") private BigDecimal discount; |
@DecimalMax | 숫자가 지정된 최대값 이하이어야 함 (소수점 포함) | @DecimalMax("100.00") private BigDecimal percentage; |
사용법
1. Dependency 추가
build.gradle 방식
implementation 'org.springframework.boot:spring-boot-starter-validation'
2. 기본 제약 설정 및 검사
객체 validation annotation을 추가합니다.
package com.example.shoppingmall.member;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class MemberDTO {
@JsonProperty("user_id")
@NotBlank(message = "아이디가 비었습니다.")
private String userId;
@Pattern(regexp = "(?=.*[0-9])(?=.*[a-zA-Z])(?=.*\\\\W)(?=\\\\S+$).{8,15}", message = "비밀번호는 영문과 숫자, 특수기호가 적어도 1개 이상씩 포함된 8~15자의 비밀번호여야 합니다.")
private String pw;
private String name;
@Email(message = "이메일이 형식에 맞지 않습니다.")
private String email;
private String contact;
public Member convertToEntity(){
return new Member(userId, pw, name, email, contact);
}
}
Controller 의 @RequestBody 를 통해 객체를 받는 경우, 파라미터에 @Valid 라는 Annotation을 추가합니다
컨트롤러의 매개변수 앞에 @Valid를 붙여 유효성 검증하는 것입니다!
@PostMapping("/join/api/result") // after
public ApiUtils.ApiResult<String> joinByApiResult(@Valid @RequestBody MemberDto memberDto) {
if (isDuplicateId(memberDto)) {
return error("아이디 중복", HttpStatus.CONFLICT);
}
Member requestMember = fromDtoToEntity(memberDto);
Member requestMember = memberDto.convertToEntity();
String userId = memberService.join(requestMember);
return success(userId);
}
Validated란❓
Spring Framework에서 제공하는 어노테이션입니다. 주로 Spring의 서비스 계층에서 메서드 파라미터의 유효성을 검사할 때 사용됩니다. 이 어노테이션은 유효성 검사 그룹을 지정할 수 있는 기능을 추가로 제공합니다.
- 용도: 메서드 레벨에서 유효성 검사 수행 및 유효성 검사 그룹을 지정.
- 사용 위치: 주로 서비스 계층의 클래스나 메서드 파라미터.
- 특징: 특정 유효성 검사 그룹을 지정할 수 있으며, Spring AOP를 사용하여 메서드 인자 유효성을 검사합니다.
주요 차이점 요약
특징 @Valid @Validated
제공자 | Java Bean Validation 표준 | Spring Framework |
주요 사용 위치 | 컨트롤러 메서드 파라미터, DTO 필드 | 서비스 계층 클래스 및 메서드 파라미터 |
유효성 검사 그룹 지정 | 지원하지 않음 | 지원함 (유효성 검사 그룹 지정 가능) |
주 사용 사례 | 단순한 필드 또는 파라미터 유효성 검사 | 메서드 레벨 유효성 검사, 유효성 검사 그룹 사용 경우 |
'BackEnd' 카테고리의 다른 글
클라우드 기반 백엔드 기초 : 로그 레벨( Logging Level ) 이란? (2) | 2024.05.09 |
---|---|
클라우드 기반 백엔드 기초 : Build.Gradle 키워드 (0) | 2024.04.30 |
클라우드 기반 백엔드 기초 : 페어프로그래밍(2) (0) | 2024.04.29 |
클라우드 기반 백엔드 기초 : 웹 개요 및 MVC (0) | 2024.04.26 |
미니 프로젝트 회고 (0) | 2024.04.17 |