ABAP DUMP ERROR 24시

Spring Boot의 Handler의 과정 본문

[WEB]Back-end/Spring MVC

Spring Boot의 Handler의 과정

이운형 2022. 2. 14. 17:21
반응형

# 인프런 김영한의 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 개인적으로 정리한 글입니다.

 

 

정리


 

1. @RequestMapping 왜써?

Spring boot는 HanlderMapping과 HandlerAdapter를 탑재하고있어

HandlerMapping과 HandlerAdapter를 구현하기위해서 사용해!

HandlerMapping 과 HanlderAdapter는  RequestMappingHandlerxxx 시리즈를 가장 먼저 탐색하는데

@RequestMapping이 RequestMappingHandlerxxx 시리즈를 가지고 있어!

(핸들러 기능과 아답터 기능을 보유)

2. @Controller는 왜 사용할까?

Spring boot는 ViewResolver를 탑재하고있어

저기 viewResolver 보이지? 

1순위로 BeanNameViewResolver를 찾는데

@Controller는 @component를 포함하고 있어서 Bean을 스프링 부트가 관리하게 도와주는 역할을 하거든!

그래서 사용하는거야.

 

Bean을 등록해서 빈 이름으로 뷰를 찾아서 반환시키기 위함이지!

 

 

 

 

살펴보기


 

과거 이렇게 일일히 작성했던 코드들...

@WebServlet(name = "frontControllerServletV5", urlPatterns = "/front-controller/v5/*")
public class FrontControllerServletV5 extends HttpServlet {

    private final Map<String, Object> handlerMappingMap = new HashMap<>();
    private final List<MyHandlerAdapter> handlerAdapters = new ArrayList<>();

    public FrontControllerServletV5() {
        initHandlerMappingMap(); // 핸들러 매핑 초기화
        initHandlerAdapters(); //  어댑터 초기화
    }

    private void initHandlerMappingMap() {
        handlerMappingMap.put("/front-controller/v5/v3/members/new-form", new MemberFormControllerV3());
        handlerMappingMap.put("/front-controller/v5/v3/members/save", new MemberSaveControllerV3());
        handlerMappingMap.put("/front-controller/v5/v3/members", new MemberListControllerV3());

        handlerMappingMap.put("/front-controller/v4/members/new-form", new MemberFormControllerV4());
        handlerMappingMap.put("/front-controller/v4/members/save", new MemberSaveControllerV4());
        handlerMappingMap.put("/front-controller/v4/members", new MemberListControllerV4());
    }

    private void initHandlerAdapters() {
        handlerAdapters.add(new ControllerV3HandlerAdapter()); //ControllerV3 아답터 탑재
        handlerAdapters.add(new ControllerV4HandlerAdapter()); // ControllerV4 아답터 탑재
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        Object handler = getHandler(request); // handler 조회
        if (handler == null) {
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        MyHandlerAdapter adapter = getHandlerAdapter(handler); // 핸들러 처리할수 있는 핸들러 아답터 조회 + 핸들러 호출
        ModelView mv = adapter.handle(request, response, handler); // 호출된 handler를 ModelView로 반환

        MyView view = viewResolver(mv.getViewName()); //viewResolver를 호출 후 Myview를 반환
        view.render(mv.getModel(), request, response); // myview에서 HTML 응답.
    }
    // Handler 조회
    private Object getHandler(HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        System.out.println("requestURI = " + requestURI);
        return handlerMappingMap.get(requestURI);
    }
    private MyHandlerAdapter getHandlerAdapter(Object handler) {
        for (MyHandlerAdapter adapter : handlerAdapters) {
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
        throw new IllegalArgumentException("handler adapter를 찾을 수 없습니다. handler=" + handler);
    }
    private MyView viewResolver(String viewName) {
        return new MyView("/WEB-INF/views/" + viewName + ".jsp");
    }
}

다음과 같이 간편하게 바뀌었다.

package hello.servlet.web.springmvc.v3;

import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@Controller
@RequestMapping("/springmvc/v3/members")
public class SpringMemberControllerV3 {

    private MemberRepository memberRepository  = MemberRepository.getInstance();

    @GetMapping("/new-form" )
    public String newForm() {
        return "new-form";
    }

    @PostMapping("/save")
    public String save(
            @RequestParam("username") String username,
            @RequestParam("age") int age,
            Model model){
        Member member = new Member(username ,age);
        memberRepository.save(member);

        model.addAttribute("member", member);
        return "save-result";

    }

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


}

 

기본 JAVA로 Handler 를 호출하고

  Adapter를 호출하고

  따로 dispater를 만들어서 FrontController의 역할을 하던

복잡했던 코드가.

 

@Controller , @RequestMapping , @RequestParam 이라는 어노테이션들로 간단히 압축되어 나타난다.

 

 

어떻게 이렇게 간편하게 바뀔수 있었을까?

 

 

오늘 주목할점은 Spring Boot의  Handler의 과정이다.

 

옛 코드와 같이  HandlerMapping 과 HandlerAdapter의 기능들은 Spring boot에서 지원한다.

 

HandlerMapping 과 HandlerAdatper를 사용하기 위해서는

RequestMappingHandlerMapping , RequestMappingHandlerAdapter

가 필요한데

 

 

 

그 기능을 @RequestMapping이 가지고 있다.

HandlerMapping과 HandlerMapping을 구현하기위해서는

@RequestMapping이라는 어노테이션을  통해 사용하자.

 

이렇게 처리한 Mapping된 정보들을 ViewResolver로 보내게 되는데...

 

이때 1순위는 Bean을 통해 추출하므로

@Controller를 통해 스프링이 자동으로 스프링 빈으로 등록하게 도와준다.

 

 

반응형
Comments