[Spring] 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 강의 정리 - 5

JJAM·2022년 9월 22일
0
post-thumbnail

📖 스프링 MVC - 구조 이해

📒 스프링 MVC 전체 구조

동작 순서

  1. 핸들러 조회: 핸들러 매핑을 통해, 요청 URL에 매핑된 핸들러(컨트롤러)를 조회
  2. 핸들러 어댑터 조회: 핸들러(컨트롤러)를 호출할 수 있는 핸들러 어댑터를 조회
  3. 핸들러 어댑터 실행: 핸들러 어댑터 호출
  4. 핸들러 실행: 핸들러 어댑터가 실제 핸들러(컨트롤러) 호출
  5. ModelAndView 반환: 핸들러 어댑터는 핸들러(컨트롤러)가 반환하는 정보를 ModelAndView로 변환해서 반환
  6. viewResolver 호출: 뷰 리졸버를 찾고 호출
  7. View 반환: 뷰의 논리 이름을 물리 이름으로 바꾸고, 렌더링 역할을 담당하는 뷰 객체를 반환
  8. 뷰 렌더링: 뷰를 통해서 뷰를 렌더링

✏️ DispatcherServlet

스프링 MVC프론트 컨트롤러 패턴으로 구현되어 있으며,
바로 그 프론트 컨트롤러가 DispatcherServlet이다.

그래서 DispatcherServlet스프링 MVC의 핵심이다.

스프링 부트는 DispacherServlet서블릿으로 자동으로 등록하면서 모든 경로( urlPatterns="/" )에 대해서 매핑한다.

요청 흐름

  • 서블릿이 호출되면 HttpServlet이 제공하는 serivce()가 호출된다.
  • FrameworkServlet.service()를 시작으로 여러 메서드가 호출되면서 DispacherServlet.doDispatch() 가 호출된다.

📒 핸들러 매팅과 핸들러 어댑터

지금은 전혀 사용하지 않지만,
과거에 주로 사용했던 스프링이 제공하는 간단한 컨트롤러로 핸들러 매핑어댑터를 이해할 것이다.

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를 처리할 수 있는 뷰를 반환

📒 스프링 MVC - 시작하기

@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에 들어가면 정상적으로 동작하는 것을 볼 수 있다.

📒 스프링 MVC - 컨트롤러 통합

@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에 들어가면 정상적으로 동작하는 것을 볼 수 있다.

📒 스프링 MVC - 실용적인 방식

src/main/java/hello/servlet/web/springmvc/v3/SpringMemberControllerV3

@GetMapping("/new-form")
public String newForm() {
	return "new-form"; // ViewName 직접 반환
}

ModelView를 생성하고 반환하는 일이 귀찮기 때문에
스프링 MVCViewName을 직접 반환하여 뷰의 논리이름을 반환할 수 있게 해준다.

그리고 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 - 구조 이해 에 대해 공부하였다.

profile
☘️

0개의 댓글