본문 바로가기

백엔드/스프링

스프링MVC의 Handler, View Resolver

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1

 

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., 원

www.inflearn.com

위 강의를 들으며 정리한 글입니다.

https://mvmvm.tistory.com/98

 

프론트 컨트롤러 패턴

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의 웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성..

mvmvm.tistory.com

이전 포스트 내용과 이어집니다.

 

직접 만들어본 스프링 MVC

저번 수업시간에 만들어본 MVC 버전5는 스프링 MVC와 매우 유사하다. 스프링은 viewResolver나 View를 인터페이스로 만들어서 확장성이 더 좋다. 그리고 스프링 MVC에서 프론트 컨트롤러는 Dispatcher Servlet 이다.

 

🎇 DispatcherServlet

Dispatcher Servlet은 HttpServlet을 상속받고 있고 실제로 Dispatcher Servlet의 코드를 보면 핸들러 매핑하고 핸들러를 처리해줄 어댑터를 찾는 등의 과정들이 모두 있다.

 

스프링의 핸들러 매핑과 어댑터

어노테이션으로 @Controller 달아서 쓰는것이 가장 많이 쓰이는 방식이고 제일 익숙하다. 근데 다른 방법으로도 컨트롤러를 만들 수 있다. 

@Component("/spring/old")
public class OldController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("controller 호출~");
        return new ModelAndView("new-form");
    }
}

@Controller 어노테이션을 달지 않고도 잘 동작하는 컨트롤러를 만들었다.

스프링에서 컨트롤러가 호출되려면 핸들러 매핑과 핸들러 어댑터가 필요하다. 스프링 부트가 자동 등록해주는 핸들러 매핑과 핸들러 어댑터에 대해서 알아보자.

HandlerMappping
0 = RequestMappingHandlerMapping : 애노테이션 기반 컨트롤러에 사용
1 = BeanNameUrlHandlerMapping : 스프링 빈의 이름으로 핸들러를 매핑
2, 3, 4 ...

위의 예시에서 OldController는 1번 방식이다. http://localhost:8080/spring/old 라고 하면 /spring/old의 이름으로 먼저 0번을 찾아보고 어노테이션 기반의 컨트롤러는 없으니 1번을 찾아본다. @Component("/spring/old") 라고 이름과 함께 등록했으니 1번 타입들을 찾는 과정에서 OldController가 찾아진다.

HandlerAdapter

0 = RequestMappingHandlerAdapter
1 = HttpRequestHandlerAdapter
2 = SimpleControllerHandlerAdapter
3,4, ...

0번 1번을 지나 2번을 보면

OldController가 구현한 Controller 인터페이스를 지원해준다는 것을 확인할 수 있다. 그래서 OldController는 2번 어댑터가 실행해줄 것이다. 1번 어댑터가 실행해줄 컨트롤러도 만들어보자

@Component("/spring/req-handler")
public class HttpHandler implements HttpRequestHandler {
    @Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("얘도 뜨네??");
    }
}

HttpRequestHandler 인터페이스를 구현했으므로 1번 어댑터에 의해 실행되는 컨트롤러이다.

 

뷰, 뷰리졸버

 

스프링 부트가 자동 등록해주는 뷰 리졸버
1 = BeanNameViewResolver : 빈 이름으로 뷰 찾아서 반환
2 = InternalResourceViewResolver : jsp를 처리하는 뷰 반환

1. 핸들러 어댑터를 통해 논리 뷰 이름을 얻는다.
2. 논리뷰 이름으로 viewResolver를 순서대로 호출하면서 찾아본다. 이전 시간에 만들었던 MVC는 jsp니까 2번 InternalResourceViewResolver가 뷰를 반환해줄 것이다.

 

스프링 MVC로 전환해보기

스프링에서 가장 우선순위가 높은 핸들러 매핑과 어댑터는 어노테이션 기반인 RequestMappingHandlerMapping과 RequestMappingHandlerAdapter이다. 

@Controller
public class SpringControllerMembersForm {
    @RequestMapping("/springmvc/v1/members/form")
    public ModelAndView process() {
        return new ModelAndView("new-form");
    }
    
    //MemberSave
    
    //MemberList
}

이렇게 만든 컨트롤러는 위의 핸들러매핑과 핸들러 어댑터가 처리해주는 컨트롤러가 될 것이다. 지금까지는 컨트롤러를 따로 클래스를 둬서 만들었지만 이제는 @RequestMapping이 메소드 레벨에 붙는 어노테이션이므로 한 클래스 안에 전부 가져올 수 있다.  하지만 항상 ModelAndView를 만들어서 반환해야하는 것이 조금 불편하다. 이를 개선해볼 것이다.

@Controller
@RequestMapping("/springmvc/v3/members")
public class V3Controller {
    private MemberRepository mr = MemberRepository.getInstance();
 
    @GetMapping("/form")
    public String newForm() {
        return "new-form";
    }

    @PostMapping("/save")
    public String save(Model model, @RequestParam("username") String username, @RequestParam("age") int age) {
        Member member = new Member(username, age);
        mr.save(member);
        model.addAttribute("member", member);
        return "save-result";
    }

    @GetMapping
    public String list(Model model) {
        List<Member> all = mr.findAll();
        model.addAttribute("members",all);
        return "members";
    }
}

스프링의 애노테이션 기반 컨트롤러는 ModelAndView로 반환해도 되고 문자로 반환해도 된다.

 

 

'백엔드 > 스프링' 카테고리의 다른 글

스프링 MVC - 요청 데이터  (0) 2021.08.19
스프링MVC 요청 매핑  (0) 2021.08.18
프론트 컨트롤러 패턴  (0) 2021.08.17
Http Request 데이터 형식 정리  (0) 2021.08.17
스프링 빈 스코프  (0) 2021.08.13