@ModelAttribute와 인터페이스

1. @ModelAttribute

- 요청 파라미터를 특정 객체에 바인딩 할 때 사용된다.

- 주로 DTO나 데이터 클래스를 받아서 요청 데이터를 객체로 변환하는데 사용한다.

DTO를 매개변수로 받는 예시 ▼

//--------------------Controller----------------------------
@GetMapping("/user")
fun getUser(@ModelAttribute request: UserRequest): String {
	return "Hello, ${request.name}"
}
//----------------------------------------------------------

//-------------------DTO class------------------------------
data class UserRequest(val name: String, val age: Int)
//----------------------------------------------------------

GET /user?name=John&age=25 요청이 오면 `UserRequest(name="John", age=25)` 객체가 생성된다.


2. 인터페이스를 @ModelAttribute로 받을 수 있는가?

- 일반적으로 인터페이스는 인스턴스화 할 수 없으므로 직접 바인딩 되지 않는다.

- 하지만 스프링이 자동으로 빈을 주입하는 방식을 이용하면 가능할 수 있다.


2-1. 빈으로 등록된 구현체가 있는 경우

인터페이스가 빈으로 등록된 구현체가 존재하면 스프링이 @ModelAttribute를 사용할 때 자동으로 주입할 수도 있다.

interface NameService{
	fun getName(): String
}

@Service // NameService 인터페이스를 상속 받으면서 @Service 어노테이션을 사용하여 빈으로 등록하는 모습
class NameServiceImpl : NameService { // Spring이 ~~Impl 빈을 찾아서 자동으로 등록할 가능성
	override fun getName() = "Spring Boot"
}

하지만 일반적으로 @ModelAttribute는 DTO 객체를 바인딩할 때 사용하고, 인터페이스 주입을 위한 방법으로는 적절하지 않다.


2-2. 스프링이 직접 바인딩 할 수 있는 경우 (커스텀 바인더를 사용한다)

요청 파라미터에서 NameService의 구현체를 생성하는 커스텀 바인더를 등록하면 가능하다. 하지만 이 방법은 일반적이지 않다.


3. 보통 빈을 주입하는 건 @Autowired나 생성자 주입을 권장한다

@RestController
class NameController(private val nameService: NameService) {
	@GetMapping("/check")
	suspend fun checkName(): String {
    	return nameService.getName()
    }
}

이 방법대로라면 Spring이 NameServiceImpl을 자동으로 주입해준다.

@ModelAttribute 없이도 빈을 컨트롤러에 주입할 수 있다.


4. ModelAttribute의 동작과정

https://velog.io/@jmjmjmz732002/Springboot-ModelAttribute

'【 개발 이야기 】' 카테고리의 다른 글

14자, 20자 날짜 포맷  (1) 2025.03.31
[Intellij] 외부 라이브러리 직접 추가하기  (2) 2025.03.28
Throwable & Exception  (0) 2025.03.26
NotBlank, NotNull, NotEmpty 차이  (0) 2025.03.21
직렬화  (0) 2025.03.21