@Controller
1. 개요
1. 개요
@Controller는 스프링 프레임워크의 스프링 MVC 모듈에서 제공하는 핵심 어노테이션이다. 이 어노테이션은 자바 기반의 웹 애플리케이션 개발에서 MVC 패턴의 컨트롤러 역할을 담당하는 클래스를 표시하는 데 사용된다. 클래스 선언부에 @Controller를 추가하면, 스프링의 컴포넌트 스캔 메커니즘에 의해 해당 클래스가 웹 요청을 처리하는 빈으로 자동 등록된다.
주요 목적은 사용자의 HTTP 요청을 받아 적절한 비즈니스 로직을 수행하는 서비스 계층에 처리를 위임하고, 그 결과 데이터를 뷰에 전달하여 응답을 생성하는 흐름을 관리하는 것이다. 이는 전통적인 서버 사이드 렌더링 방식의 웹 페이지 구성에 적합한 구조를 제공한다. @Controller는 @Component 어노테이션을 메타 어노테이션으로 포함하고 있어, 특수화된 형태의 스테레오타입 어노테이션으로 분류된다.
@Controller가 표시된 클래스 내부의 메서드는 @RequestMapping, @GetMapping, @PostMapping 등의 메서드 수준 어노테이션과 함께 사용되어 특정 URL 패턴에 대한 요청을 매핑한다. 이 어노테이션의 등장으로 개발자는 복잡한 서블릿 설정 없이도 선언적인 방식으로 깔끔한 웹 계층 코드를 작성할 수 있게 되었다.
2. 역할과 특징
2. 역할과 특징
@Controller 어노테이션은 스프링 프레임워크의 스프링 MVC 모듈에서 제공하는 핵심 어노테이션이다. 이 어노테이션은 클래스가 MVC 패턴의 컨트롤러 역할을 수행함을 명시적으로 선언한다. 주로 자바 기반의 웹 애플리케이션 개발에서 사용자의 HTTP 요청을 처리하는 진입점으로 활용되며, 스프링 빈으로 등록되어 스프링 컨테이너에 의해 관리된다.
이 어노테이션의 주요 역할은 클라이언트의 요청을 매핑받아 비즈니스 로직을 처리하는 서비스 계층에 전달하고, 처리 결과를 뷰에 전송하여 최종 응답을 생성하도록 조정하는 것이다. 디스패처 서블릿은 @Controller가 붙은 클래스를 핸들러로 인식하고, 클래스 내부의 @RequestMapping과 같은 메서드 레벨 어노테이션을 통해 구체적인 요청 URL을 매핑한다.
@Controller의 특징은 주로 뷰 리졸버를 통한 HTML 페이지와 같은 뷰의 이름을 반환한다는 점이다. 메서드의 반환 값이 문자열인 경우, 이는 논리적인 뷰의 이름으로 해석되어 해당 뷰 템플릿을 찾아 렌더링한다. 또한 모델 객체를 이용해 뷰에 전달할 데이터를 담을 수 있어, 동적인 웹 페이지 생성을 지원한다.
이 어노테이션은 컴포넌트 스캔의 대상이 되므로, 스프링 부트 애플리케이션에서는 별도의 XML 설정 없이도 자동으로 빈으로 등록된다. 이는 @Component 어노테이션을 메타 어노테이션으로 포함하기 때문이며, 따라서 의존성 주입을 위한 다른 스테레오타입 어노테이션들과 동일한 방식으로 동작한다.
3. 작동 방식
3. 작동 방식
@Controller 어노테이션이 적용된 클래스는 스프링 프레임워크의 컴포넌트 스캔 과정에서 자동으로 빈으로 등록된다. 이는 스프링 컨테이너가 애플리케이션 시작 시 특정 패키지 경로를 스캔하여 @Component를 비롯한 스테레오타입 어노테이션이 붙은 클래스를 찾아 IoC 컨테이너에 관리 객체로 등록하는 메커니즘 덕분이다. 따라서 개발자는 XML 설정이나 자바 Config 클래스를 통해 수동으로 빈을 정의하지 않아도 된다.
이렇게 등록된 컨트롤러 빈은 DispatcherServlet에 의해 요청 처리를 담당하게 된다. DispatcherServlet은 프론트 컨트롤러 패턴을 구현한 서블릿으로, 모든 HTTP 요청을 먼저 받아들인다. 그 후, 핸들러 매핑을 통해 요청 URL을 처리할 적절한 컨트롤러 메서드(핸들러)를 찾아낸다. 이때 컨트롤러 클래스 내부의 메서드에는 @RequestMapping이나 @GetMapping, @PostMapping 등의 메서드 수준 어노테이션이 부여되어 특정 요청 경로와 HTTP 메서드를 매핑한다.
요청이 특정 컨트롤러 메서드로 라우팅되면, 해당 메서드는 비즈니스 로직을 수행하기 위해 서비스 계층이나 리포지토리를 호출할 수 있다. 메서드 실행이 완료되면, 일반적으로 결과 데이터(모델)와 사용자에게 보여줄 뷰의 논리적 이름을 포함한 ModelAndView 객체를 반환하거나, 메서드 인자로 받은 Model 객체에 데이터를 추가한 후 뷰 이름을 문자열로 반환한다. 이후 DispatcherServlet은 뷰 리졸버를 통해 이 논리적 뷰 이름을 실제 뷰 객체(예: JSP, Thymeleaf 템플릿)로 변환하고, 모델 데이터를 뷰에 전달하여 최종 HTML 응답을 생성하게 한다.
4. 주요 어노테이션
4. 주요 어노테이션
@Controller 어노테이션과 함께 자주 사용되는 주요 어노테이션으로는 요청 매핑을 정의하는 @RequestMapping이 가장 기본적이다. 이 어노테이션은 클래스나 메서드 수준에서 URL 경로와 HTTP 메서드를 지정하여 특정 웹 요청을 처리할 메서드를 매핑하는 역할을 한다. 구체적인 메서드 타입을 지정하는 @GetMapping, @PostMapping, @PutMapping, @DeleteMapping 등의 어노테이션도 @RequestMapping의 축약형으로 널리 활용된다.
요청 파라미터나 경로 변수, HTTP 세션, 모델 객체 등을 메서드의 매개변수로 쉽게 받아오기 위해 사용되는 어노테이션들도 중요하다. 예를 들어, @RequestParam은 쿼리 문자열 파라미터를, @PathVariable은 URL 경로의 일부를 변수로 바인딩하며, @ModelAttribute는 요청 파라미터를 자바빈즈 객체에 자동으로 바인딩한다. 또한 @RequestBody는 HTTP 요청의 본문(JSON 또는 XML)을 자바 객체로 변환하여 받을 수 있게 해준다.
메서드가 반환하는 값을 어떻게 처리할지 결정하는 어노테이션도 있다. @ResponseBody는 메서드의 반환 값을 HTTP 응답 본문에 직접 쓰도록 지시하며, REST API를 만들 때 @RestController 대신 @Controller와 함께 사용된다. 한편, @ResponseStatus는 응답의 HTTP 상태 코드를 명시적으로 지정할 때 활용할 수 있다. 이러한 어노테이션들을 조합하여 스프링 MVC는 복잡한 웹 요청 처리 흐름을 간결한 코드로 구현할 수 있게 지원한다.
5. 사용 예시
5. 사용 예시
@Controller 어노테이션을 사용한 기본적인 컨트롤러 클래스의 예시는 다음과 같다. 이 예시는 사용자의 요청을 처리하고, 뷰 이름을 반환하는 전형적인 스프링 MVC 패턴을 보여준다.
```java
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/list")
public String getUserList(Model model) {
List<User> userList = userService.findAllUsers();
model.addAttribute("users", userList);
return "user/list";
}
@GetMapping("/detail/{id}")
public String getUserDetail(@PathVariable Long id, Model model) {
User user = userService.findUserById(id);
model.addAttribute("user", user);
return "user/detail";
}
@PostMapping("/create")
public String createUser(@ModelAttribute User user) {
userService.saveUser(user);
return "redirect:/user/list";
}
}
```
위 코드에서 @GetMapping과 @PostMapping은 각각 HTTP GET 요청과 POST 요청을 처리하는 메서드임을 나타낸다. @RequestMapping("/user")는 클래스 수준에서 모든 메서드의 기본 URL 경로를 /user로 설정한다. Model 객체는 뷰에 데이터를 전달하는 데 사용되며, 메서드가 반환하는 문자열은 뷰 리졸버에 의해 해석될 뷰 템플릿의 논리적 이름(예: user/list.html)에 해당한다. @PathVariable은 URL 경로의 변수 값을, @ModelAttribute는 폼 데이터를 메서드 매개변수에 바인딩한다.
보다 복잡한 시나리오에서는 세션, 쿠키 처리, 파일 업로드, 또는 JSON 데이터를 직접 응답으로 반환하는 경우도 있다. 예를 들어, AJAX 요청에 JSON을 응답해야 할 때는 메서드에 @ResponseBody 어노테이션을 추가하여 뷰 이름 대신 직렬화된 객체를 반환하도록 할 수 있다. 이러한 경우 @RestController를 사용하는 것이 더 일반적이다.
6. 다른 컴포넌트와의 비교
6. 다른 컴포넌트와의 비교
6.1. @RestController와의 차이
6.1. @RestController와의 차이
@Controller와 @RestController는 모두 스프링 프레임워크에서 웹 요청을 처리하는 컴포넌트를 표시하는 어노테이션이다. 두 어노테이션의 가장 근본적인 차이는 HTTP 응답의 형태에 있다. @Controller는 전통적인 스프링 MVC 패턴을 따르며, 메서드가 반환하는 값은 일반적으로 뷰(View)의 논리적 이름으로 해석되어 HTML과 같은 뷰 템플릿을 통해 렌더링된 결과를 클라이언트에게 전송한다. 반면에 @RestController는 RESTful 웹 서비스를 구축하기 위해 설계되었으며, 이 어노테이션이 붙은 클래스의 모든 메서드는 @ResponseBody 어노테이션이 기본적으로 적용된 것으로 간주한다. 이는 메서드가 반환하는 객체 데이터가 JSON이나 XML과 같은 형식으로 직렬화되어 HTTP 응답 본문에 직접 쓰여짐을 의미한다.
구조적으로 @RestController는 @Controller와 @ResponseBody 어노테이션을 결합한 메타 어노테이션[13]이다. 따라서 @RestController를 사용하면 API 엔드포인트를 구현할 때 각 메서드마다 @ResponseBody를 반복적으로 선언할 필요가 없어 코드가 간결해진다. 주요 사용 목적에 따라 선택이 이루어지는데, 서버 사이드에서 JSP나 Thymeleaf 같은 템플릿 엔진을 사용하여 완전한 웹 페이지를 생성하여 제공하는 전통적인 웹 애플리케이션에는 @Controller가 적합하다. 모바일 앱이나 싱글 페이지 애플리케이션(SPA)이 소비하는 데이터 중심의 백엔드 API 서버를 구축할 때는 @RestController가 표준적으로 사용된다.
두 방식은 내부적으로 핸들러 매핑이나 요청 처리 흐름에는 큰 차이가 없지만, 반환 값을 처리하는 뷰 리졸버(View Resolver)의 동작에 차이가 발생한다. @Controller를 사용하는 경우, 문자열을 반환하면 뷰 리졸버가 해당 이름의 뷰 템플릿 파일을 찾아 렌더링한다. @RestController에서는 동일한 문자열을 반환하더라도 뷰를 찾지 않고, 해당 문자열 자체가 응답 본문이 된다. 이 차이점은 스프링 부트(Spring Boot)의 자동 구성에서도 반영되어, 클래스패스에 웹 MVC 관련 의존성이 있을 때 적절한 빈들을 구성한다.
6.2. @Service, @Repository와의 관계
6.2. @Service, @Repository와의 관계
@Controller는 스프링 프레임워크의 MVC 패턴에서 컨트롤러 계층을 담당하는 컴포넌트이다. 이는 @Service와 @Repository 어노테이션과 함께 애플리케이션의 계층형 구조를 구성하는 핵심 요소로, 각각 비즈니스 로직 계층과 데이터 접근 계층을 담당한다. 이 세 가지 어노테이션은 모두 @Component를 메타 어노테이션으로 포함하고 있어 스프링 컨테이너에 의해 빈으로 자동 등록되는 공통점이 있다. 그러나 각각이 담당하는 역할과 책임을 명확히 구분함으로써 코드의 가독성과 유지보수성을 높인다.
@Controller는 주로 사용자의 HTTP 요청을 처리하는 엔드포인트를 정의한다. 클라이언트로부터 요청을 받으면, @Controller는 해당 요청을 분석하여 적절한 @Service 계층의 메서드를 호출한다. @Service는 비즈니스 로직을 캡슐화하고 처리하는 역할을 하며, 필요 시 @Repository를 통해 데이터베이스에 접근한다. @Repository는 데이터 접근 객체 패턴을 구현하여, CRUD 연산과 같은 데이터 저장소와의 구체적인 상호작용을 담당한다.
이러한 관계는 의존성 주입을 통해 느슨하게 결합된다. 예를 들어, @Controller 클래스는 내부에서 @Service 인터페이스에 의존성을 선언하고, @Service 구현체는 @Repository 인터페이스를 사용한다. 스프링 컨테이너는 실행 시점에 각 계층의 구현체를 주입하여 완전한 동작 흐름을 만들어낸다. 이는 각 계층이 독립적으로 개발, 테스트, 변경될 수 있도록 하는 관심사의 분리 원칙을 실현한다.
따라서 @Controller, @Service, @Repository는 함께 협력하여 웹 애플리케이션의 핵심 아키텍처를 형성한다. @Controller는 외부 요청의 진입점으로서 프레젠테이션 계층을, @Service는 복잡한 비즈니스 규칙을 처리하는 서비스 계층을, @Repository는 영속성을 관리하는 데이터 접근 계층을 대표한다. 이들의 명확한 역할 구분은 대규모 애플리케이션 개발에서 코드의 구조화와 유지보수에 필수적이다.
7. 구현 및 설정
7. 구현 및 설정
@Controller 어노테이션을 사용한 컨트롤러 클래스를 구현하려면 먼저 스프링 프레임워크 프로젝트에 스프링 MVC 의존성이 추가되어 있어야 한다. Maven이나 Gradle 같은 빌드 도구를 통해 spring-webmvc 모듈을 프로젝트에 포함시키는 것이 일반적이다.
구현의 첫 단계는 클래스 선언부에 @Controller 어노테이션을 추가하는 것이다. 이 어노테이션은 클래스가 컨트롤러 역할을 한다는 것을 스프링 컨테이너에 알리고, 컴포넌트 스캔의 대상이 되어 빈으로 자동 등록되게 한다. 따라서 스프링 부트 애플리케이션의 경우 메인 애플리케이션 클래스가 위치한 패키지 하위에 컨트롤러 클래스를 두거나, 명시적으로 컴포넌트 스캔 범위를 설정해야 한다.
클래스 내부에서는 @RequestMapping, @GetMapping, @PostMapping 등의 메서드 레벨 어노테이션을 사용하여 특정 URL 패턴과 HTTP 메서드를 처리할 메서드를 매핑한다. 이 메서드들은 주로 서비스 계층의 빈을 주입받아 비즈니스 로직을 호출하고, 그 결과를 Model 객체에 담거나 String 타입의 뷰 이름을 반환한다. 뷰 리졸버는 이 이름을 기반으로 실제 JSP나 Thymeleaf 템플릿 같은 뷰를 찾아 응답을 완성한다.
기본적인 설정으로도 동작하지만, 인터셉터, 예외 처리, 뷰 리졸버 커스터마이징 등을 위해 WebMvcConfigurer 인터페이스를 구현한 자바 설정 클래스를 추가할 수 있다. 또한, 컨트롤러가 특정 URL 패턴을 공통으로 가지도록 클래스 레벨에 @RequestMapping을 선언하는 것도 일반적인 구현 패턴이다.
