๐ก ์๋ณธ๊ธ : https://towardsdev.com/data-transfer-object-dto-in-spring-boot-c00678cc5946
์ด ๊ธ์์๋ Spring Boot์์ ๋ฐ์ดํฐ ์ ์ก ๊ฐ์ฒด(DTO)์ ์ด์ ์ ํ๊ตฌํ๋ฉฐ, ์๋ DTO ์์ฑ, ModelMapper, Lombok์ ํฌํจํ ์์ ๋ค์ ์ดํด๋ณผ ๊ฒ์ ๋๋ค.
Photo by Joshua Sortino on Unsplash
1. ๋ฐ์ดํฐ ์ ์ก ๊ฐ์ฒด(DTO)๋ ๋ฌด์์ธ๊ฐ?
๋ฐ์ดํฐ ์ ์ก ๊ฐ์ฒด(DTO)๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค๋ฅธ ๊ณ์ธต ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์บก์ํํ๊ณ ์ ์กํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ ๋์์ธ ํจํด์ ๋๋ค. DTO๋ ์ผ๋ฐ์ ์ผ๋ก ํ์ํ ํ๋๋ง ํฌํจํ๋ ๊ฐ๋ฒผ์ด ๊ฐ์ฒด๋ก, ๋น์ง๋์ค ๋ก์ง์ ํฌํจํ์ง ์์ต๋๋ค. ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค๋ฅธ ๋ถ๋ถ๋ค, ์๋ฅผ ๋ค์ด ํ๋ก ํธ์๋์ ๋ฐฑ์๋ ์ฌ์ด๋ ๋ถ์ฐ ์์คํ ๋ด์ ๋ค์ํ ๋ง์ดํฌ๋ก์๋น์ค ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ด๋ฐํ๋ ๊ตฌ์กฐ๋ก ์ฌ์ฉ๋ฉ๋๋ค.
ํนํ Spring Boot ์ ํ๋ฆฌ์ผ์ด์ ์์ DTO๋ ์ปจํธ๋กค๋ฌ ๊ณ์ธต, ์๋น์ค ๊ณ์ธต, ๊ทธ๋ฆฌ๊ณ ์์์ฑ ๊ณ์ธต ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ ์กํด์ผ ํ ๋ ์ ์ฉํฉ๋๋ค. DTO๋ฅผ ์ฌ์ฉํจ์ผ๋ก์จ ๋ด๋ถ ๋ฐ์ดํฐ ๋ชจ๋ธ๊ณผ ์ธ๋ถ ํํ(presentation)์ ๋ถ๋ฆฌํ ์ ์์ผ๋ฉฐ, ์ด๋ ๋ฐ์ดํฐ ์ ์ก์ ๋ํ ๋ ๋์ ํต์ ๋ฅผ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
2. Spring Boot ๋ด์์ DTO๋ฅผ ์ฌ์ฉ์ ์ด์
Spring Boot ์ ํ๋ฆฌ์ผ์ด์ ์์ DTO๋ฅผ ์ฌ์ฉํ๋ฉด ์ฌ๋ฌ ๊ฐ์ง ์ด์ ์ด ์์ต๋๋ค.
- ๋ฐ์ดํฐ ๊ฒฉ๋ฆฌ: DTO๋ฅผ ์ฌ์ฉํ๋ฉด ์ธ๋ถ ์ธ๊ณ์ ๋ ธ์ถ๋๋ ๋ฐ์ดํฐ๋ฅผ ๋ด๋ถ ๋๋ฉ์ธ ๋ชจ๋ธ๋ก๋ถํฐ ๋ถ๋ฆฌํ ์ ์์ต๋๋ค. ๋ฏผ๊ฐํ๊ฑฐ๋ ๋ถํ์ํ ๋ฐ์ดํฐ์ ๋ ธ์ถ์ ๋ฐฉ์งํ๊ณ , ๋ฐ์ดํฐ ๊ตํ์ ์ํ ๋ช ํํ ๊ท์น์ ์ ๊ณตํฉ๋๋ค.
- ์ค๋ฒํค๋ ๊ฐ์: DTO๋ ํน์ ํ ์ ์ค ์ผ์ด์ค์ ํ์ํ ํ๋๋ง ํฌํจํ ์ ์์ด, ๋คํธ์ํฌ๋ฅผ ํตํด ์ ์ก๋๋ ๋ฐ์ดํฐ ์์ ์ค์ผ ์ ์์ต๋๋ค. ์ด๋ ํฐ ๊ฐ์ฒด๋ฅผ ์ ์ก ํ ๋ ๋ฐ์ํ๋ ๋ถ๋ด์ ์ต์ํ ํฉ๋๋ค.
- ๋ฒ์ ๊ด๋ฆฌ ๋ฐ ํธํ์ฑ: DTO๋ ๋ฒ์ ๊ด๋ฆฌ๋ฅผ ์ฉ์ดํ๊ฒ ํ๊ณ , ์ญํธํ์ฑ์ ๋ณด์ฅ ํ๋๋ฐ ๋์์ ์ค๋๋ค. ๋๋ฉ์ธ ๋ชจ๋ธ๊ณผ ๋ณ๊ฐ๋ก DTO๋ฅผ ๋ฐ์ ์ํฌ์ ์์ด API ๋ณ๊ฒฝ์ ๋ ์ฝ๊ฒ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
- ๋ณด์ ํฅ์: DTO๋ฅผ ํตํด ๋ ธ์ถ๋๋ ๋ฐ์ดํฐ๋ฅผ ์ ์ดํจ์ผ๋ก์จ ๋ฐ์ดํฐ ์ค์ธ์ ๋ฐฉ์งํ๊ณ ๋ฏผ๊ฐํ ์ ๋ณด์ ๋ํ ์ ๊ทผ์ ์ ํํ์ฌ ๋ณด์์ ๊ฐํํ ์ ์์ต๋๋ค.
- ํ ์คํธ ํฅ์: DTO๋ ๋จ์ ํ ์คํธ๋ฅผ ๋จ์ํ ํฉ๋๋ค. ๋ณต์กํ ๋๋ฉ์ธ ๊ฐ์ฒด์ ์์กดํ์ง ์๊ณ ํ ์คํธ ์๋๋ฆฌ์ค์์ ์ฝ๊ฒ ์์ฑํ๊ณ ์กฐ์ํ ์ ์์ต๋๋ค.
3. Spring Boot์์ DTO์ฌ์ฉํ๋ ๋ค์ํ ๋ฐฉ๋ฒ
3.1. ์๋์ผ๋ก DTO๋ฅผ ์์ฑ
์ด ์ ๊ทผ ๋ฐฉ์์์๋ ๋๋ฉ์ธ ์ํฐํฐ์ ๊ตฌ์กฐ๋ฅผ ๋ฐ์ํด DTO ํด๋์ค๋ฅผ ์๋์ผ๋ก ์์ฑํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ๋๋ฉ์ธ ๊ฐ์ฒด์ DTO ์ฌ์ด์ ๋ฐ์ดํฐ๋ฅผ ๋งคํํ๊ธฐ ์ํ ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค.
public class UserDTO {
private Long id;
private String username;
private String email;
// Constructors, getters, and setters
}
์๋์ผ๋ก ๋งคํํ๋ ๊ณผ์ ์ด ์๋ controller ๋ฉ์๋๋ฅผ ๋ง๋ค์ด ์ฃผ๋ฉด ๋ฉ๋๋ค.
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public ResponseEntity getUserById(@PathVariable Long id) {
User user = userService.getUserById(id);
UserDTO userDTO = new UserDTO();
userDTO.setId(user.getId());
userDTO.setUsername(user.getUsername());
userDTO.setEmail(user.getEmail());
return ResponseEntity.ok(userDTO);
}
}
๊ฒฐ๊ณผ**:** GET ์์ฒญ์ผ๋ก /api/users/1์ ์์ฒญํ๋ฉด ์๋ต์ผ๋ก ์ ์ ๋ฐ์ดํฐ๋ฅผ ํฌํจํ ****JSON์ ๋ฐ์์ ์์ต๋๋ค.
{
"id": 1,
"username": "john_doe",
"email": "john.doe@example.com"
}
3.2. ModelMapper ์ฌ์ฉ
ModelMapper๋ฅผ Spring Boot ํ๋ก์ ํธ์์ ๋๋ฉ์ธ ๊ฐ์ฒด์ DTO ๊ฐ์ ๋งคํ์ ์๋ํ ํ๊ธฐ ์ํด ์ฌ์ฉํ๋ ค๋ฉด, pom.xml์์ ํด๋น ์์กด์ฑ์ ์ถ๊ฐํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ModeMapping๋ฅผ ์ฌ์ฉํ์ฌ ๋๋ฉ์ธ ๊ฐ์ฒด์ DTO ๊ฐ์ ๋งคํ์ ์ฝ๊ณ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.4.3</version>
</dependency>
Spring Boot ์ ํ๋ฆฌ์ผ์ด์ ์์ ModelMapper๋ฅผ Spring Bean์ผ๋ก ์ฌ์ฉํ๊ธฐ ์ํด, Configuration ํด๋์ค ๋๋ Main Application ํด๋์ค์ Bean์ ๋ฑ๋กํ ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฒด์์ ModelMapper์ ๊ตฌ์ฑ(Configuration)์ ํ ์ ์์ต๋๋ค.
Spring Boot ์ ํ๋ฆฌ์ผ์ด์ ์์ ModelMapper Bean์ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
import org.modelmapper.ModelMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyApplicationConfig {
@Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}
}
์ฌ๊ธฐ์ ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ DTO๋ก ๋ณํํ๊ธฐ ์ํด ModelMapper๋ฅผ ์๋์ ๊ฐ์ด ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค.
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@Autowired
private ModelMapper modelMapper; // Autowire the ModelMapper bean
@GetMapping("/{id}")
public ResponseEntity getUserById(@PathVariable Long id) {
User user = userService.getUserById(id);
UserDTO userDTO = modelMapper.map(user, UserDTO.class); // Use ModelMapper for mapping
return ResponseEntity.ok(userDTO);
}
}
๊ฒฐ๊ณผ: ์๋ DTO ์์ฑ ์์ ์ ๋์ผํ ๊ฒฐ๊ณผ๊ฐ ๋์ต๋๋ค.
3.3. Lombok ์ฌ์ฉ
Lombok ์์กด์ฑ์ pom.xml ํ์ผ์ ์ถ๊ฐํ์ธ์.
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
User ์ํฐํฐ์ DTO๋ฅผ ์์ฑํ๊ธฐ ์ํด ์๋์ ๊ฐ์ด ์์ฑํ์ธ์.
import lombok.Data;
@Data
public class UserDTO {
private Long id;
private String username;
private String email;
}
์ด์ ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ DTO๋ก ๋ณํํ๊ธฐ ์ํด ์๋์ ๊ฐ์ด Lombok์ ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค.
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public ResponseEntity getUserById(@PathVariable Long id) {
User user = userService.getUserById(id);
UserDTO userDTO = UserDTO.builder()
.id(user.getId())
.username(user.getUsername())
.email(user.getEmail())
.build();
return ResponseEntity.ok(userDTO);
}
}
๊ฒฐ๊ณผ: ์๋ DTO ์์ฑ ์์ ์ ๋์ผํ ๊ฒฐ๊ณผ๊ฐ ๋์ต๋๋ค.
4. DTO์์ ๋ค์ํ ์ ํ์ ๊ฐ ํฌ๋งทํ ํ๊ธฐ
DTO์์ ๋ค์ํ ์ ํ์ ๊ฐ์ ํฌ๋งทํ ํ๋ ๊ฒ์ ๋ฐ์ดํฐ๊ฐ ์ง๋ ฌํ๋๊ฑฐ๋ ํ์๋ ๋ ํน์ ํ์์ผ๋ก ์ ๊ณต๋๋๋ก ํ๋ ๋ฐ ํ์ํ ์ผ๋ฐ์ ์ธ ์๊ตฌ์ฌํญ์ ๋๋ค. ํฌ๋งทํ ํ๋ ค๋ ๊ฐ์ ์ ํ์ ๋ฐ๋ผ, ์ด๋ ธํ ์ด์ , ์ฌ์ฉ์ ์ ์ ๋ฉ์๋ ๋๋ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํฌํจํ ์ฌ๋ฌ ์ ๊ทผ ๋ฐฉ์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์๋์์๋ DTO์์ ๋ค์ํ ์ ํ์ ๊ฐ์ ํฌ๋งทํ ํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์ค๋ช ํ๊ฒ ์ต๋๋ค.
4.1. Date์ Time ํฌ๋งท
4.1.1. @JsonFormat ์ด๋ ธํ ์ด์ ์ฌ์ฉ(Jackson)
DTO์์ ๋ ์ง์ ์๊ฐ ๊ฐ์ ํฌ๋งทํ ํ๊ธฐ ์ํด, JSON ์ง๋ ฌํ์ ํํ ์ฌ์ฉ๋๋ Jackson ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ ๊ณตํ๋ @JsonFormat ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
import com.fasterxml.jackson.annotation.JsonFormat;
public class UserDTO {
private Long id;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "UTC")
private Date registrationDate;
// Other fields, getters, and setters
}
์ด ์์ ์์ registrationDate ํ๋๋ฅผ @JsonFormat์ ์ฌ์ฉํด์ ๋ ์ง์ ์๊ฐ์ ๋ํด์ ํน๋ณํ๊ฒ ๋ณํํ์์ต๋๋ค.
4.1.2. SimpleDateFormat ์ฌ์ฉ(Custom Method)
DTO ํด๋์ค ๋ด์ ์ฌ์ฉ์ ์ ์ gatter ๋ฉ์๋๋ฅผ ์ ๊ณตํจ์ผ๋ก์จ ๋ ์ง์ ์๊ฐ์ ํฌ๋งทํ ํ ์๋ ์์ต๋๋ค. ์ด ๋ฉ์๋๋ ํฌ๋งท๋ ๋ ์ง๋ฅผ ๋ฌธ์์ด๋ก ๋ฐํํฉ๋๋ค.
import java.text.SimpleDateFormat;
public class UserDTO {
private Long id;
private Date registrationDate;
public String getFormattedRegistrationDate() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(registrationDate);
}
// Other fields, getters, and setters
}
4.2. ์ซ์ ํฌ๋งทํ
4.2.1. @NumberFormat ์ด๋ ธํ ์ด์ ์ฌ์ฉ (Spring)
์ซ์๋ ํตํ์ ๊ฐ์ ์ซ์ ๊ฐ์ ํฌ๋งทํ ํ๊ธฐ ์ํด Spring์์ ์ ๊ณตํ๋ @NumberFormat ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ฉด ์ซ์ ํฌ๋งทํ ํจํด์ ์ง์ ํ ์ ์์ต๋๋ค.
import org.springframework.format.annotation.NumberFormat;
public class ProductDTO {
private Long id;
@NumberFormat(pattern = "#,###.00")
private BigDecimal price;
// Other fields, getters, and setters
}
์ด ์์ ์์๋ price ํ๋์ @NumberFormat ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํด์ ์ซ์๋ฅผ ํฌ๋งทํ ํ๋ ํจํด์ ์ง์ ํ์์ต๋๋ค.
4.2.2. DecimalFormat ์ฌ์ฉ (Custom Method)
DTO ํด๋์ค ๋ด์ ์ฌ์ฉ์ ์ ์ getter ๋ฉ์๋๋ฅผ ์ ๊ณตํ์ฌ ์ซ์๋ฅผ ํฌ๋งทํ ํ ์๋ ์์ต๋๋ค. ์ด ๋ฉ์๋๋ DecimalFormat์ ์ฌ์ฉํ์ฌ ํฌ๋งท๋ ์ซ์๋ฅผ ๋ฌธ์์ด๋ก ๋ฐํํฉ๋๋ค.
import java.text.DecimalFormat;
public class ProductDTO {
private Long id;
private BigDecimal price;
public String getFormattedPrice() {
DecimalFormat df = new DecimalFormat("#,###.00");
return df.format(price);
}
// Other fields, getters, and setters
}
4.3. String ํฌ๋งทํ
4.3.1. Custom Methods ์ฌ์ฉ
๋ฌธ์์ด ๊ฐ์ ํฌ๋งทํ ํ๊ธฐ ์ํด, ํ์์ ๋ฐ๋ผ ๋ฌธ์์ด์ ์กฐ์ํ๋ ์ฌ์ฉ์ ์ ์ getter ๋ฉ์๋๋ฅผ DTO ํด๋์ค ๋ด์ ์์ฑํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๊ณต๋ฐฑ์ ์๋ฅด๊ฑฐ๋, ๋จ์ด๋ฅผ ๋๋ฌธ์๋ก ๋ง๋ค๊ฑฐ๋, ๊ธฐํ ๋ค๋ฅธ ๋ฌธ์์ด ์กฐ์ ๋ก์ง์ ์ ์ฉํ ์ ์์ต๋๋ค.
public class ArticleDTO {
private Long id;
private String title;
public String getFormattedTitle() {
// Custom formatting logic here
return title.trim(); // Example: Trim whitespace
}
// Other fields, getters, and setters
}
4.4. Enum ํฌ๋งทํ
4.4.1. Custom Method ์ฌ์ฉ
DTO์์ ์ด๊ฑฐํ(enum)์ ๋ค๋ฃฐ ๋, ์ด๊ฑฐํ ๊ฐ์ ํฌ๋งท๋ ํํ์ ๋ฐํํ๋ ์ฌ์ฉ์ ์ ์ getter ๋ฉ์๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ์ด๊ฑฐํ ๊ฐ์ ๋๋ฌธ์๋ก ๋ณํํ๊ฑฐ๋ ๋ค๋ฅธ ํํ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
public class OrderDTO {
private Long id;
private OrderStatus status;
public String getFormattedStatus() {
return status.toString().toUpperCase(); // Example: Convert to uppercase
}
// Other fields, getters, and setters
}
4.5. Boolean ํฌ๋งทํ
4.5.1. Custom Methods ์ฌ์ฉ
Boolean ๊ฐ์ ๋ํด์๋ “true” ๋๋ “false๋์ ์ “Yes”, “No”์ ๊ฐ์ ํฌ๋งท๋ ํํ์ ์ฌ์ฉ์ ์ ์ getter ๋ฉ์๋๋ก ์์ฑํ ์ ์์ต๋๋ค.
public class UserDTO {
private Long id;
private boolean isActive;
public String getFormattedIsActive() {
return isActive ? "Yes" : "No"; // Example: Convert to "Yes" or "No"
}
// Other fields, getters, and setters
}
์ด๋ฌํ ์ ๊ทผ ๋ฐฉ๋ฒ๋ค์ ์ฌ์ฉํจ์ผ๋ก์จ, ํน์ ์๊ตฌ์ฌํญ์ ๋ฐ๋ผ DTO ๋ด์์ ๋ค์ํ ์ ํ์ ๊ฐ์ ํฌ๋งทํ ํ ์ ์์ผ๋ฉฐ, DTO๊ฐ ์ง๋ ฌํ๋๊ฑฐ๋ ํ์๋ ๋ ๋ฐ์ดํฐ๊ฐ ์ํ๋ ํ์์ผ๋ก ์ ๊ณต๋๋๋ก ํ ์ ์์ต๋๋ค.
5. ์ถ๊ฐ์ ์ผ๋ก ๊ณ ๋ คํด์ผ ํ ์ ๊ณผ Best Practice
5.1. DTO์์์ ์ ํจ์ฑ ๊ฒ์ฌ
DTO๋ฅผ ๋ค๋ฃฐ ๋ ๋ฐ์ดํฐ ๊ฒ์ฆ์ ๊ณ ๋ คํ๋ ๊ฒ์ด ํ์์ ์ ๋๋ค. DTO์ ๋ค์ด์ค๋ ๋ฐ์ดํฐ๊ฐ ํ์ํ ์ ์ฝ ์กฐ๊ฑด๊ณผ ๋น์ฆ๋์ค ๊ท์น์ ์ถฉ์กฑํ๋์ง ํ์ธํ๊ธฐ ์ํด ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ฆํด์ผ ํฉ๋๋ค. Spring์ @NotNull, @Size ๋๋ ์ฌ์ฉ์ ์ ์ ๊ฒ์ฆ ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ DTO ํ๋๋ฅผ ๊ฒ์ฆํ ์ ์์ต๋๋ค.
Spring์ @NotBlank ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ DTO ๊ฒ์ฆ์ ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
public class UserDTO {
@NotNull
private Long id;
@NotBlank
@Size(min = 5, max = 50)
private String username;
@Email
private String email;
// Constructors, getters, and setters
}
5.2. ๋ณต์กํ ์ค์ฒฉ ๊ฐ์ฒด DTO
์ค์ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์ค์ฒฉ๋ ๊ฐ์ฒด๋ ๊ด๊ณ๋ฅผ ๋ค๋ฃฐ ๋ DTO๊ฐ ๋ ๋ณต์กํด์ง ์ ์์ต๋๋ค. ์ด๋ฌํ ๊ตฌ์กฐ๋ฅผ ์ ํํ๊ฒ ๋ํ๋ด๊ธฐ ์ํด ์ค์ฒฉ๋ DTO๋ฅผ ์์ฑํ ํ์๊ฐ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, User๊ฐ ์ฌ๋ฌ Address ๊ฐ์ฒด์ ์ฐ๊ด๋์ด ์๋ค๋ฉด, ์ค์ฒฉ๋ AddressDTO๋ฅผ ํฌํจํ๋ UserDTO๋ฅผ ์์ฑํ ์ ์์ต๋๋ค:
public class UserDTO {
private Long id;
private String username;
private String email;
private List addresses;
// Constructors, getters, and setters
}
5.3. DTO ๋ฒ์ ๊ด๋ฆฌ
์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ฐ์ ํจ์ ๋ฐ๋ผ DTO์ ๋ณ๊ฒฝ์ ํด์ผ ํ ์๋ ์์ต๋๋ค. ์ญํธํ์ฑ์ ์ ์งํ๊ธฐ ์ํด DTO์ ๋ฒ์ ๊ด๋ฆฌ๋ฅผ ๊ณ ๋ คํด๋ณด์ธ์. ์ด๋ DTO ํด๋์ค์ ๋ฒ์ ์๋ณ์๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ํ์ํ ๋ ์๋ก์ด DTO ๋ฒ์ ์ ์์ฑํจ์ผ๋ก์จ ๋ฌ์ฑํ ์ ์์ต๋๋ค.
5.4. RESTful API์์์ DTO
DTO๋ ํด๋ผ์ด์ธํธ์ ์๋ฒ ๊ฐ์ ๊ตํ๋๋ ๋ฐ์ดํฐ๋ฅผ ๋ํ๋ด๊ธฐ ์ํด RESTful API์์ ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉ๋ฉ๋๋ค. RESTful ์๋ํฌ์ธํธ๋ฅผ ์ค๊ณํ ๋, ํน์ ์ฌ์ฉ ์ฌ๋ก์ ํด๋ผ์ด์ธํธ ์๊ตฌ์ฌํญ์ ๋ง๊ฒ DTO๋ฅผ ์ ์คํ๊ฒ ์ ํํ๊ณ ๊ตฌ์กฐํํด์ผ ํฉ๋๋ค. ์ด๋ ํจ์จ์ ์ธ ๋ฐ์ดํฐ ์ ์ก๊ณผ ๋ช ํํ API ๊ณ์ฝ์ ๋ณด์ฅํฉ๋๋ค.
6. Spring Validation๊ณผ DTO ์ฌ์ฉ
Spring์ ์ปจํธ๋กค๋ฌ ๋ฉ์๋์์ @Valid ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ DTO๋ฅผ ๊ฒ์ฆํ๋ ๊ฐ๋ ฅํ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค. DTO ํ๋ผ๋ฏธํฐ์ **@Valid**๋ฅผ ์ด๋ ธํ ์ด์ ์ผ๋ก ๋ฌ๋ฉด, Spring์ DTO ํด๋์ค์ ์ ์๋ ๊ฒ์ฆ ์ ์ฝ ์กฐ๊ฑด์ ๊ธฐ๋ฐ์ผ๋ก ์๋์ผ๋ก ๊ฒ์ฆ์ ํธ๋ฆฌ๊ฑฐํฉ๋๋ค.
์ปจํธ๋กค๋ฌ ๋ฉ์๋์์ DTO ๊ฒ์ฆ์ ์ฌ์ฉํ๋ ์์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/create")
public ResponseEntity createUser(@Valid @RequestBody UserDTO userDTO) {
// Your validation logic is automatically triggered
// Map UserDTO to User entity and save it
User user = modelMapper.map(userDTO, User.class);
User savedUser = userService.saveUser(user);
// Return the saved UserDTO
UserDTO savedUserDTO = modelMapper.map(savedUser, UserDTO.class);
return ResponseEntity.status(HttpStatus.CREATED).body(savedUserDTO);
}
}
์ด ์์ ์์๋ @Valid ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ UserDTO ํด๋์ค์์ ์ ์ํ ์ ์ฝ ์กฐ๊ฑด์ ๊ธฐ๋ฐ์ผ๋ก ๊ฒ์ฆ์ ํธ๋ฆฌ๊ฑฐํฉ๋๋ค. ๊ฒ์ฆ์ด ์คํจํ๋ฉด Spring์ ์๋์ผ๋ก ๊ฒ์ฆ์ ๋ํ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๊ณ ์ ์ ํ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ํฌํจํ ์๋ต์ ๋ฐํํฉ๋๋ค.
7. ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์์์ DTO
๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์์๋ DTO๊ฐ ๋ง์ดํฌ๋ก์๋น์ค ๊ฐ์ ๊ฒฝ๊ณ๋ฅผ ์ ์ํ๋ ์ค์ํ ์ญํ ์ ํฉ๋๋ค. ๊ฐ ๋ง์ดํฌ๋ก์๋น์ค๋ ์์ฒด์ ์ผ๋ก ํน์ ์๊ตฌ ์ฌํญ์ ๋ง๋ DTO ์ธํธ๋ฅผ ๊ฐ์ง ์ ์์ต๋๋ค. ์ด ๋ถ๋ฆฌ๋ ๋ง์ดํฌ๋ก์๋น์ค ๊ฐ์ ๋์จํ ๊ฒฐํฉ์ ๋ณด์ฅํ๊ณ ๋ ๋ฆฝ์ ์ผ๋ก ์งํํ ์ ์๋๋ก ํฉ๋๋ค.
DTO๋ ๋ํ ๋ง์ดํฌ๋ก์๋น์ค ๊ฐ์ ์ ์ก๋๋ ๋ฐ์ดํฐ ์์ ์ค์ด๋ ๋ฐ ๋์์ด ๋๋ฉฐ, ์ด๋ ๋ง์ดํฌ๋ก์๋น์ค ๊ธฐ๋ฐ ์์คํ ์ ์ฑ๋ฅ๊ณผ ํ์ฅ์ฑ์ ์ ์งํ๋ ๋ฐ ์ค์ํฉ๋๋ค.
8. ๊ฒฐ๋ก
๋ฐ์ดํฐ ์ ์ก ๊ฐ์ฒด (DTO)๋ Spring Boot ์ ํ๋ฆฌ์ผ์ด์ ์์ ํ์์ ์ด๋ฉฐ, ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค๋ฅธ ๋ ์ด์ด์ ์ธ๋ถ ์์คํ ์ฌ์ด์ ๋ค๋ฆฌ ์ญํ ์ ํฉ๋๋ค. DTO๋ฅผ ์ ์คํ๊ฒ ์ค๊ณํ๊ณ ์ฌ์ฉํจ์ผ๋ก์จ ๋ฐ์ดํฐ ๊ฒฉ๋ฆฌ๋ฅผ ๊ฐ์ ํ๊ณ ์ค๋ฒํค๋๋ฅผ ์ค์ด๋ฉฐ ๋ณด์์ ๊ฐํํ๊ณ ํ ์คํธ๋ฅผ ๋จ์ํํ ์ ์์ต๋๋ค. DTO๋ฅผ ์๋์ผ๋ก ์์ฑํ๊ฑฐ๋ ModelMapper์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ ์ฝ๋ ๊ฐ์ํ๋ฅผ ์ํด Lombok์ ํ์ฉํ๋ , ํต์ฌ์ ํ๋ก์ ํธ์ ์๊ตฌ ์ฌํญ๊ณผ ์ ์ง ๋ณด์์ฑ์ ๊ฐ์ฅ ์ ํฉํ ์ ๊ทผ ๋ฐฉ์์ ์ ํํ๋ ๊ฒ์ ๋๋ค. DTO๊ฐ ์ํคํ ์ฒ์ ์ค์ํ ๋ถ๋ถ์ผ๋ก ์กด์ฌํ๋ฉด, ๊ฒฌ๊ณ ํ๊ณ ํจ์จ์ ์ธ Spring Boot ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋ฐ ๋ ์ ๊ฐ์ถ์ด์ง๋๋ค.
์ถ๊ฐ์ ์ผ๋ก ์ฝ์ด๋ณผ๋งํ ๊ธ: