0. 개요
- 직접 Front Controller를 구현했을 때를 생각해보자.
- Front Controller를 시작으로 HandlerMapping, HandlerAdapter를 직접 구현했다.
- 그러므로 전체적인 Front Controller의 흐름을 직접 구현했다.
- Spring Boot를 사용하면 이를 직접 구현하지 않는다.
- Spring Boot 내부에는 이미 모든 것이 구현되어 있기 때문이다.
- 그렇다면 내부적으로 구현된 클래스 또는 인터페이스들을 어떻게 사용할까?
- 더불어 DispatcherServlet의 내부 동작 과정에 어떻게 컨트롤러를 전달(주입)할 수 있을까?
→ 내부 동작 과정이란, 이전 포스팅에서 다룬 DispatcherServlet의 동작원리를 의미한다.
- 그 해답은 annotation이 가지고 있다.
- Spring Boot는 annotation을 통해 각 클래스의 역할을 명시하도록 지원한다.
- 클래스에 부착된 annotation의 역할에 따라 DispatcherServlet은 내부 흐름에 알맞은 클래스를 사용하는 것이다.
→ TMI, 이 또한 IoC와 DIP의 특성이 발현되는 순간이다.
- 그렇다면 각 annotation이 어떻게 DispatcherServlet의 내부 동작에서 작용하는지,
Front Controller에서 직접 구현했던 내용을 annotation이 어떻게 해결하는지 알아보자.
* 본 포스팅은 Front Controller 시리즈의 내용입니다. 이전 포스팅을 읽는 것을 권장합니다.
1. @Controller, @RequestMapping
a) Front Controller에서는
- 이전 포스팅에서 Front Controller를 직접 구현했을 때를 생각해보자.
- HandlerMappingMap이라는 자료구조를 만들어 요청 URL과 해당하는 Controller를 직접 매핑시켜 저장했다.
b) Spring Boot에서는
- 당연히 Spring MVC에서도 이와 동일한 과정을 수행한다.
- 다만 annotation을 사용하여 이를 명시할 수 있다. 그러므로 개발자가 직접 구현할 필요가 없다.
c) @Controller의 기능
- 해당 클래스가 Controller임을 명시하는 annotation
- ComponentScan의 대상이며, Spring Bean으로 등록 및 관리된다.
- RequestMappingHandlerMapping의 조회 대상으로 등록된다.
d) @RequestMapping의 기능
- Controller에 URL을 매핑하는 annotation
- RequestMappingHandlerMapping이 handler(= controller)를 조회할 때 매핑된 URL이 사용된다.
e) @RequestMapping의 위치
- @RequestMapping은 class와 method 레벨에 명시할 수 있다.
- 메서드 레벨에 명시하는 경우, 매핑 URL의 일부가 중복 작성된다.
- 그러므로 @RequestMapping은 일반적으로 클래스 레벨에 명시된다.
f) @RequestMapping("url1", "url2")
- @RequestMapping에는 다수의 url을 매핑할 수 있다.
- 이는 @RequestMapping이 내부적으로 매핑된 url을 배열에 저장하여 관리하므로 가능하다.
// @RequstMapping을 메서드 레벨에 명시하는 경우 => URL 일부분 중복 작성
@Controller
public class ControllerA {
@RequestMapping("/springmvc/view/jsp1")
public ModelAndView process() {
return new ModelAndView("jsp1");
}
@RequestMapping("/springmvc/view/jsp2")
public ModelAndView process() {
return new ModelAndView("jsp2");
}
}
// @RequstMapping을 클래스 레벨에 명시하는 경우 => URL 중복 작성이 제거됨
@Controller
@RequestMapping("/springmvc/view1", "/springmvc/view2")
public class ControllerA {
@RequestMapping("/jsp1")
public ModelAndView process() {
return new ModelAndView("jsp1");
}
@RequestMapping("/jsp2")
public ModelAndView process() {
return new ModelAndView("jsp2");
}
}
2. @RequestParam을 이용한 Servlet 종속성 제거
a) Front Controller에서는
- Front Controller는 모든 요청을 받는 역할이자 단일 진입점으로, 모든 요청에 대한 Servlet 처리를 수행한다.
- Front Controller의 각 Controller에서 Servlet 대신 Front Controller로부터 URL parameter를 전달받거나,
Controller의 반환 값을 Front Controller에게 전달하기 위해서 ModelView라는 자료구조를 사용했다.
b) SpringBoot에서는
- Spring Boot에서는 이를 @RequestParam이라는 annotation 하나로 해결한다.
- 당연히 내부적으로는 Front Controller와 동일한 과정을 거친다. 다만, 개발자가 모든 흐름과 자료구조를 구현할 필요가 없다.
c) @RequestParam의 기능
- Servlet을 사용하지 않고 URL Parameter를 받아오는 역할이다.
- 만약 URL parameter로 username과 age가 넘어온다면, 다음과 같이 명시한다.
@Controller
@RequestMapping("/springmvc/view")
public class ControllerA {
@RequestMapping("/search")
public String search(
@RequestParam("username") String username,
@RequestParam("age") int age,
Model model)
{
// 비즈니스 로직 구현부
model.addAttribute("username", username);
model.addAttribute("age", age);
return "search-result";
}
}
3. ModelAndView 대신 String(= view 이름) 반환
a) Front Controller에서는
- 각 Controller에서 view를 처리하기 위해 ModelView 객체를 생성하여 반환하였다.
- 각 Controller에서 ModelView를 직접 생성하는 것이 SRP를 위배하므로, view 이름을 그대로 반환하는 방식을 사용하였다.
- 하지만 Adapter 패턴을 적용하면서 ModelView 자료구조를 다시 도입하였다.
b) Spring Boot에서는
- SpringBoot에서는 각 Controller에서 view 이름을 String으로 반환하는 형태를 기본으로 한다.
- View name만 String 자료형으로 반환하면 Spring이 알아서 이를 view name으로 인지하고 처리한다.
4. @RequestMapping을 이용한 HTTP 메서드 제약
a) Front Controller에서는
- 웹 서비스는 다양한 HTTP 메서드를 사용하여 요청을 전달한다. ex) GET, POST, PATCH, DELETE, etc
- 그러나 Front Controller에서는 따로 요청 메서드에 대한 제약을 두지 않았다.
- 사실 이에 대한 환경설정을 고려하지 않았으며, 모든 요청을 GET 방식으로 처리하였다.
b) Spring Boot에서는
- Spring Boot에서는 annotation을 사용하여 HTTP 요청 방식의 제약을 설정할 수 있다.
- 축양형 annotation을 사용하여 모든 HTTP 요청 메서드의 제약을 설정할 수 있다.
- 요청을 통해 전달되는 데이터를 공개/비공개 처리할지, 그 목적에 따라 사용되는 HTTP 요청 메서드는 달라진다.
- 각 Controller에 이를 명시하여 HTTP 요청 메서드의 제약을 설정한다.
c) @GetMapping("url")
- HTTP 요청의 가장 기본적인 방식이 Get 방식이다.
- Get 방식의 요청은 데이터를 URL parameter 형태로 전달한다.
- 따로 Get 방식의 설정을 하지 않아도 되지만, Get 방식으로 제약을 두지 않으면 다른 요청 메서드 또한 허락한다는 것이 문제다.
- 왜냐면 비즈니스 로직에서 모든 방식의 요청을 처리해야 하기 때문이다.
- @GetMapping을 사용하면 오직 Get 메서드를 통한 요청만을 허락한다.
d) @PostMapping("url")
- Post 방식의 요청은 데이터를 HTTP message body에 담아서 전달한다.
- 그러므로 전달하는 데이터가 URL에 표시되지 않는다.
- 전달하는 데이터의 보안을 고려하는 경우, Post 방식을 사용한다.
- 일반적으로 HTTP message body에 데이터를 담는 경우, JSON 형식을 사용한다.
e) @RequestMapping의 method 옵션
- @RequestMapping은 기본적으로 모든 HTTP 요청 메서드를 허락한다.
- @RequestMapping을 사용하여 HTTP 요청 메서드의 제약을 걸고 싶다면 method 옵션을 사용할 수 있다.
- method 옵션에는 Java 5에서 제공하는 RequestMethod의 상수를 사용한다.
- @RequestMapping을 클래스 레벨에서 사용하는 경우, method 옵션이 클래스 메서드에도 적용된다는 점을 인지하자.
@Controller
@RequestMapping("/springmvc/view")
public class ControllerA {
@GetMapping("/search")
public String search() {
return "search-result";
}
@PostMapping("/save")
public String save() {
return "save-result";
}
}
@Controller
@RequestMapping("/springmvc/view", method = "RequestMethod.메소드명")
public class ControllerA {
}
'Back-end > Spring MVC 개념' 카테고리의 다른 글
14. Request - URL parameter 조회방법 (0) | 2022.03.14 |
---|---|
13. Annotation 기반의 URL 매핑 (0) | 2022.03.10 |
11. Spring MVC의 특징 (0) | 2022.03.08 |
10. Front Controller(2) (0) | 2022.03.07 |
9. Front Controller (1) (0) | 2022.03.04 |
댓글