- 해당 게시물은 인프런 - "스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술" 강의를 참고하여 작성한 글 입니다.
- 유료강의이므로 자세한 내용은 없고, 간단한 설명 위주로 정리했습니다.
강의 링크 -> 김영한 - 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술(유료강의)
동작 순서
- 핸들러 조회: 핸들러 매핑을 통해, 요청 URL에 매핑된 핸들러(컨트롤러)를 조회
- 핸들러 어댑터 조회: 핸들러(컨트롤러)를 호출할 수 있는 핸들러 어댑터를 조회
- 핸들러 어댑터 실행: 핸들러 어댑터 호출
- 핸들러 실행: 핸들러 어댑터가 실제 핸들러(컨트롤러) 호출
- ModelAndView 반환: 핸들러 어댑터는 핸들러(컨트롤러)가 반환하는 정보를 ModelAndView로 변환해서 반환
- viewResolver 호출: 뷰 리졸버를 찾고 호출
- View 반환: 뷰의 논리 이름을 물리 이름으로 바꾸고, 렌더링 역할을 담당하는 뷰 객체를 반환
- 뷰 렌더링: 뷰를 통해서 뷰를 렌더링
스프링 MVC는 프론트 컨트롤러 패턴으로 구현되어 있으며,
바로 그 프론트 컨트롤러가 DispatcherServlet이다.
그래서 DispatcherServlet가 스프링 MVC의 핵심이다.
스프링 부트는 DispacherServlet 을 서블릿으로 자동으로 등록하면서 모든 경로( urlPatterns="/" )에 대해서 매핑한다.
지금은 전혀 사용하지 않지만,
과거에 주로 사용했던 스프링이 제공하는 간단한 컨트롤러로 핸들러 매핑과 어댑터를 이해할 것이다.
src/main/java/hello/servlet/web/springmvc/old.OldController
@Component("/springmvc/old-controller")
public class OldController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("OldController.handleRequest");
return null;
}
}
이 컨트롤러는 "/springmvc/old-controller" 라는 이름의 스프링 빈으로 등록되어,
http://localhost:8080/springmvc/old-controller에 들어가면 화면은 없지만 정상적으로 실행되는 것을 볼 수 있다.
정상적으로 호출이 된 이유는,
스프링이 필요한 컨트롤러를 찾는 핸들러 매핑과 찾은 핸들러를 실행할 수 있게 하는 핸들러 어댑터를 대부분 구현해두었기 때문이다.
핸들러 매핑도, 핸들러 어댑터도 모두 순서대로 찾고 만약 없으면 다음 순서로 넘어간다
HandlerMapping
- 0 = RequestMappingHandlerMapping: 애노테이션 기반의 컨트롤러인 @RequestMapping에서
사용- 1 = BeanNameUrlHandlerMapping: 스프링 빈의 이름으로 핸들러를 찾음
HandlerAdapter
- 0 = RequestMappingHandlerAdapter: 애노테이션 기반의 컨트롤러인 @RequestMapping에서
사용- 1 = HttpRequestHandlerAdapter: HttpRequestHandler 처리
- 2 = SimpleControllerHandlerAdapter: Controller 인터페이스(애노테이션X, 과거에 사용) 처리
그래서 OldController 를 실행하면서 사용된 객체는 BeanNameUrlHandlerMapping, SimpleControllerHandlerAdapter 이다.
뷰 리졸버에 대해서 자세히 알아보기 위해, View를 조회할 수 있도록 변경할 것이다.
src/main/java/hello/servlet/web/springmvc/old/OldController
return new ModelAndView("new-form");
src/main/resources/application.properties
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
http://localhost:8080/springmvc/old-controller에 들어가면 정상적으로 form 화면이 보인다.
왜냐하면 스프링 부트는 InternalResourceViewResolver 라는 뷰 리졸버를 자동으로 등록하는데,
이때 application.properties
에 등록한 spring.mvc.view.prefix, spring.mvc.view.suffix 설정 정보를 사용해서 등록하기 때문이다.
ViewResolver
- 1 = BeanNameViewResolver: 빈 이름으로 뷰를 찾아서 반환
- 2 = InternalResourceViewResolver: JSP를 처리할 수 있는 뷰를 반환
@RequestMapping 애노테이션을 사용하는 컨트롤러를 사용하여
매우 유연하고, 실용적인 코드를 작성할 것이다.
@RequestMapping
- RequestMappingHandlerMapping
- RequestMappingHandlerAdapter
즉, @RequestMapping는
스프링에서 주로 사용하는 애노테이션 기반의 컨트롤러를 지원하는 핸들러 매핑과 어댑터이다 .
src/main/java/hello/servlet/web/springmvc/v1/SpringMemberFormControllerV1
@Controller // 스프링이 자동으로 스프링 빈으로 등록하고, 스프링 MVC에서 애노테이션 기반 컨트롤러로 인식
public class SpringMemberFormControllerV1 {
@RequestMapping("/springmvc/v1/members/new-form") // 요청 정보를 매핑해, 해당 URL이 호출되면 메서드 호출
public ModelAndView process() {
return new ModelAndView("new-form");
}
}
이러한 방식으로 SpringMemberListControllerV1
, SpringMemberSaveControllerV1
를 만들어 준다.
이는 ModelAndView를 리턴해주기 때문에 전에 만들었던 web/frontcontroller/v3/controller
를 참고하여 만들면 된다.
추가적으로 스프링이 제공하는 ModelAndView를 통해 Model 데이터를 추가할 때는, addObject() 를 사용한다.
그래서 http://localhost:8080/springmvc/v1/members/new-form에 들어가면 정상적으로 동작하는 것을 볼 수 있다.
@RequestMapping을 보면 클래스 단위가 아니라 메서드 단위에 적용된 것을 확인할 수 있다.
따라서 컨트롤러 클래스를 유연하게 하나로 통합할 수 있다.
src/main/java/hello/servlet/web/springmvc/v2/SpringMemberControllerV2
@Controller
@RequestMapping("/springmvc/v2/members")
public class SpringMemberControllerV2 {
// Member Form
@RequestMapping("/new-form")
public ModelAndView newForm() {
}
// Member Save
@RequestMapping("/save")
public ModelAndView save(HttpServletRequest request, HttpServletResponse response) {
}
// Member List
@RequestMapping
public ModelAndView members() {
}
}
http://localhost:8080/springmvc/v2/members/new-form에 들어가면 정상적으로 동작하는 것을 볼 수 있다.
src/main/java/hello/servlet/web/springmvc/v3/SpringMemberControllerV3
@GetMapping("/new-form")
public String newForm() {
return "new-form"; // ViewName 직접 반환
}
ModelView를 생성하고 반환하는 일이 귀찮기 때문에
스프링 MVC는 ViewName을 직접 반환하여 뷰의 논리이름을 반환할 수 있게 해준다.
그리고 HTTP Method를 구분할 수 있게 Get, Post, Put, Delete, Patch에 대한 애노테이션이 있으며,
해당 메서드의 HTTP Method는 GET이므로 @GetMapping을 사용해준다.
@PostMapping("/save")
public String save(
@RequestParam("username") String username,
@RequestParam("age") int age,
Model model) {
...
model.addAttribute("member", member);
return "save-result";
}
스프링은 HTTP 요청 파라미터를 @RequestParam으로 받을 수 있고,
Model을 파라미터로 받을 수 있다.
그래서 http://localhost:8080/springmvc/v3/members/new-form에 들어가면 정상적으로 동작하는 것을 볼 수 있다.
지금까지 김영한 - 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술(유료강의) 강의를 참고하여 스프링 MVC - 구조 이해 에 대해 공부하였다.