월루를 꿈꾸는 대학생

[MVC-1] 스프링 MVC - 구조 이해 본문

Programing/Spring Boot

[MVC-1] 스프링 MVC - 구조 이해

하즈시 2023. 8. 1. 22:08
728x90

스프링 MVC 전체 구조

그 전 공부했던 프레임워크 구조

==스프링 프레임워크 ==

동작 순서

  1. 핸들러 조회 : 핸들러 매핑을 통해 url에 매핑된 핸들러 = 컨트롤러 조회
  2. 핸들러 어댑터 조회 : 핸들러 실행할 어댑터를 조회
  3. 핸들러 어댑터 실행 : 핸들러 어댑터 실행
  4. 핸들러 실행 : 어뎁터가 핸들러=컨트롤러를 실행
  5. ModelAndView 반환 : 핸들러 어댑터가 핸들러가 반환한 정보를 ModelAndView로 변환해서 보냄
  6. viewReslover호출 : 뷰 리졸버를 찾고 실행 : 논리를 물리로
  7. View반환 : 물리적 경로 기반으로 랜더링할 뷰를 반환한다
  8. 뷰 랜더링: 뷰를 받아서 랜더링함

비교

  • FrontController -> DispatcherServlet
  • handlerMappingMap -> HandlerMapping
  • MyHandlerAdapter -> HandlerAdapter
  • ModelView -> ModelAndView
  • viewResolver -> ViewResolver
  • MyView -> View
DispatcherServlet 구조 살펴보기
  • 스프링 mvc -> 프론트 컨트롤러 패턴 = 디스패처 서블릿
  • 스프링부트는 DispacherServlet을 서블릿으로 자동 등록하고 모든 경로에 대해서 매핑
요청 흐름
  • 서블릿 호출시 HttpServlet 의 service()메서드가 호출
  • service()메서드가 호출 되면서 DisapcherSErvlet.doDispatch() 가 호출됨 -> 흐름은 위와 동일
인터페이스 살펴보기
  • 스프링mvc 강점은 DispatcherServlet의 코드 변경없이 인터페이스 구현해서 등록만 하면 기능을 변경하거나 확장할 수 있는 것
정리
  • 스프링mvc는 우리가 필요로 하는 대부분의 기능이 있음 앞에 했던 것 처럼 일일이 만들지 않아도 이미 제공해줄 확률 99%
  • 핵심 동작을 알아야 나중에 에러가 났을 때 찾을 수 있고 확장포인트를 캐치 할 수 있음

핸들러 매핑과 핸들러 어댑터

옛날에는 애노테이션 기반이 아닌 인터페이스로 개발때림

옛날 컨트롤러 인터페이스를 구현한 클래스

@Component("/springmvc/old-controller") // 스프링빈의 이름을 /springmvc/old-controller 라고 지정  
public class OldController implements Controller {  
    @Override  
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {  
        System.out.println("OldController.handRequest");  
        return null;    }  
}

web에다가 /springmvc/old-controller를 치면 이 빈이름으로 매핑이 되서 oldController 클래스가 호출됨

해당 OldController가 호출되기 위해서는 핸들러 매핑 , 핸들러 어댑터가 필요하다

  1. HanlderMapping
    1. 핸들러 매핑에서 OldController찾기
    2. 스프링 빈 이름으로 핸들러 찾아야함
  2. HandlerAdapter
    1. 핸들러 매핑에서 찾은 핸들러 실행시킬 어댑터 찾기
    2. Controller 인터페이스를 실행할 수 있는 어댑터 찾고 실행

실행 순서

  1. HandlerMapping을 실행 시킨 후 0인지 1인지 그 외인지 차례때로 호출 후 찾기
  2. OldController는 빈이름으로 찾으니까 1번임
  3. 1번에 해당하는 핸들러 OldController 반환하고 HandlerAdapter에서 OldController가 가지고 있는 Controller인터페이스에 해당하는 2번 어댑터 반환
  4. 2번에 해당하는 Controller인터페이스 어댑터 실행하고 핸들러 정보도 넘겨줌
  5. SimpleCOntrollerHandlerAdapter의 핸들러 OldController를 내부에서 실행후 결과 반환
HttpRequesteHandler
@Component("/springmvc/reqeust-handler")  
public class MyHttpReqeustHandler implements HttpRequestHandler {  

    @Override  
    public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
        System.out.println("MyHttpReqeustHandler.handleRequest");  
    }  
}
  1. HandlerMapping 실행후 핸들러 찾음
  2. 또 빈이름이니까 1번 핸들러인 거 확인 후 핸들러인 MyHttpReqeustHandler를 반환
  3. 핸들러 어댑터를 찾기 위해 support()메서드 돌리고 그 중 해당하는 HttpReqeustHandlerAdapter를 확인
  4. 해당 어댑터 실행하면서 핸들러 정보 넘겨주고 어댑터는 핸들러를 실행하고 결과를 반환한다

뷰 리졸버

application.properties 코드에 추가

spring.mvc.view.prefix=/WEB-INF/views/  
spring.mvc.view.suffix=.jsp
뷰리졸버 - InternalResourceViewResolver
  • 뷰 리졸버를 자동 등록하고 이때 위의 파일에 설정을 읽어서 등록함
  • 논리적 경로에 위의 설정처럼 앞 뒤에 붙어서 물리적 경로를 완성

  1. 핸들러 어댑터를 통해서 new-form 의 논리 경로 흭득
  2. viewResolver호출해서 2번 jsp 처리 가능한 뷰를 반환할 InternalResourceViewResolver 리졸버를 호출
  3. InternalResourceView를 반환
  4. view.render()가 호출되고 InternalResourceView는 forward() 사용해서 jsp 실행

스프링 MVC - 시작하기

스프링은 애노테이션 기반 동작

@RequestMapping
  • @RequestMapping 기반의 애노테이션 컨트롤러를 주로 사용

@RequestMapping

  • @RequestMappingHandlerMapping
  • @RequestMappingHandlerAdpater
  • 주로 99% 스프링에서 위의 컨트롤러를 사용해서 구현하고 있음
@Controller  
public class SpringMemberFOrmControllerV1 {  
    @RequestMapping("/springmvc/v1/members/new-form")  
    public ModelAndView process(){  
        return new ModelAndView("new-form");  
    }  
}

@Controller

  • 내부에 @Component 애노테이션 있어서 컴포넌트 스캔이 됨 = 자동 빈 등록
  • 애노테이션 기반 컨트롤러로 인식 : @RequestMappingHandlerMapping이 @Controller가 붙어 있는 컨트롤러를 꺼낼 수 있는 대상으로 인식 = 핸들러 매핑에서 끄낼 대상으로 인식

@RequestMapping

  • 요청 정보를 매핑
  • 매핑된 URL이 호출되면 이 메서드가 호출됨

@RequestMappingHandlerMapping은 스프링 빈 중에서 @RequstMapping @Controller가 붙은 클래스들만 인식해서 매핑 정보로 사용

그러니까 즉 mvc쓰니까 핸들러 및 어댑터 따로 구현하지 않아도 알아서
@RequestMapping

  • @RequestMappingHandlerMapping
  • @RequestMappingHandlerAdpater
    요 친구들이 해주니까 코드가 훨씬 깔끔해져버림

참고
https://www.inflearn.com/questions/785398


스프링 mvc 컨트롤러 통합

@RequestMapping은 클래스 단위가 아닌 메서드 단위에 적용

메서드에 있는 @RequestMapping의 공통된 경로를 클래스에 끄집어내서 정리가능

@Controller  
@RequestMapping("/springmvc/v2/members")  
public class SpringMemberControllerV2 {  
    private MemberRepository memberRepository = MemberRepository.getInstance();  

    @RequestMapping("/new-form")  
    public ModelAndView newForm() {  
        return new ModelAndView("new-form");  
    }
    // 욤마는 그냥 /springmvc/v2/members 요 경로니까 아무것도 안 적음 
    @RequestMapping  
    public ModelAndView members() {  
        List<Member> members = memberRepository.findAll();  
        ModelAndView mav = new ModelAndView("members");  
        mav.addObject("members", members);  
        return mav;  
    }
}

클래스 레벨과 메서드 레벨의 조합으로 좀 더 간편해짐

그래도 보면 컨트롤러가 모델뷰도 만들어야해서 이거 고칠 필요가 있음
지난 시간에 유연한 컨트롤러보면 단순히 논리적 경로만 제출하고 끝이었던 것 처럼

public class MemberFormControllerV4 implements ControllerV4 {  

    @Override  
    public String process(Map<String, String> paramMap, Map<String, Object> model) {  
        return "new-form";  
    }  
}

스프링 mvc - 실용적인 방식

@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";  
    }
}
  • 모델 파라미터 : 스프링이 알아서 제공해주는 편의 긴으

model에 담긴 객체가 어떻게 jsp로 전달이 될까??
https://www.inflearn.com/questions/289267

model은 단순히 map이라고 생각하자
model 객체는 단슨히 컨트롤러에서 뷰로 파라미터 전달하기 위해 존재하는 그릇

  • @RequestParm

    • RequestParam("username") String username 와 같이 파라미터를 http 요청에 있는 값들을 가져와서 별도의 작업없이 사용해서 처리 가능
  • @RequestMapping -> @GetMapping , @PostMapping

출처
https://inf.run/wFfL

728x90

'Programing > Spring Boot' 카테고리의 다른 글

[MVC-1] 스프링 MVC -웹 페이지  (0) 2023.08.08
[MVC-1] 스프링 MVC - 기본 기능  (0) 2023.08.01
[MVC-1] MVC 프레임 워크 만들기  (0) 2023.08.01
[MVC-1] 서블릿 , JSP , MVC패턴  (0) 2023.07.25
[MVC-1] 서블릿  (0) 2023.07.25