본문 바로가기
Back-end/Spring MVC 개념

12. Annotation 기반의 Spring MVC

by devraphy 2022. 3. 9.

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

댓글