Spring 강의/springMVC

springMVC 활용 - (6) MVC프레임워크 구조

lxexjx 2022. 5. 11. 09:18

[MVC 프레임워크 구조]

FrontController → DispatcherServlet
handlerMappingMap → HandlerMapping
MyHandlerAdapter → HandlerAdapter
ModelView → ModelAndView
viewResolver → ViewResolver
MyView → View

1. 핸들러 조회: 핸들러 매핑을 통해 요청 URL에 매핑된 핸들러(컨트롤러)를 조회한다.

2. 핸들러 어댑터 조회: 핸들러를 실행할 수 있는 핸들러 어댑터를 조회한다.

3. 핸들러 어댑터 실행: 핸들러 어댑터를 실행한다.

4. 핸들러 실행: 핸들러 어댑터가 실제 핸들러를 실행한다.

5. ModelAndView 반환: 핸들러 어댑터는 핸들러가 반환하는 정보를 ModelAndView로 변환해서 반환한다.

6. viewResolver 호출: 뷰 리졸버를 찾고 실행한다. JSP의 경우: InternalResourceViewResolver 가 자동 등록되고, 사용

7. View 반환: 뷰 리졸버는 뷰의 논리 이름을 물리 이름으로 바꾸고, 렌더링 역할을 담당하는 뷰 객체를 반환.

8. 뷰 렌더링: 뷰를 통해서 뷰를 렌더링

 

[DispatcherServlet]

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

DispatcherServlet 의 부모인 FrameworkServlet 에서 service() 를 오버라이드.

FrameworkServlet.service() 를 시작으로 여러 메서드가 호출되면서 DispacherServlet.doDispatch() 가 호출.

 

서블릿이 호출되면 HttpServet이 제공하는 service()호출→

[doDispatch]

1.핸들러 조회

2.핸들러 어댑터 찾고

3.핸들러 어댑터 실행을 하면 4.핸들러 어댑터를 통해 핸들러 실행

5.ModelAndView 반환

6.뷰 리졸버로 뷰 찾기 7.뷰 반환

8.뷰 렌더링

 


 

<과거 버전 스프링 컨트롤러>

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

 

 

스프링빈 이름을 url로 맞춤

 

1. 핸들러 매핑으로 핸들러 조회

2. 핸들러 어댑터 조회

3. 핸들러 어댑터 실행

 

OR <HttpRequestHandler>

public class MyHttpRequestHandler implements HttpRequestHandler {
    @Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("MyHttpRequestHandler.handleRequest");

    }
}

 

 

 


 

 

[뷰 리졸버]

<application.properties>에 spring.mvc.view.prefix=/WEB-INF/views/ spring.mvc.view.suffix=.jsp 추가

 

1. 핸들러 어댑터 호출 핸들러 어댑터를 통해 new-form 이라는 논리 뷰 이름을 획득

2. ViewResolver 호출 new-form 이라는 뷰 이름으로 viewResolver를 순서대로 호출한다. BeanNameViewResolver 는 new-form 이라는 이름의 스프링 빈으로 등록된 뷰를 찾아야 하는데 없다. InternalResourceViewResolver 가 호출된다.

3. InternalResourceViewResolver 이 뷰 리졸버는 InternalResourceView 를 반환한다.

4. 뷰 - InternalResourceView InternalResourceView 는 JSP처럼 포워드 forward() 를 호출해서 처리할 수 있는 경우에 사용

5. view.render() view.render() 가 호출되고 InternalResourceView 는 forward() 를 사용해서 JSP를 실행

 

 

 


 

 

[@RequestMapping]

이 어노테이션이 있으면 RequestMappingHandlerMapping과 RequestMappingHandlerAdaptor이 사용됨

 

 

@Controller 가 돼있으면 → 그림1의 RequestMappingHandlerMapping가 핸들러를 꺼내주고, 2,3번의 RequestMappingHandlerAdaptor는 핸들러매핑이 준애를 처리할 수 있음

 

<SpringMemberFormControllerV1> - 회원 등록 폼

//@Controller를 사용하거나 밑에 구대를 같이 사용하거나
@Component
@RequestMapping

public class SpringMemberFormControllerV1 {

    @RequestMapping("/springmvc/v1/members/new-form")
    public ModelAndView process() {
        return new ModelAndView("new-form");
    }
}

*@Controller :

    1. 스프링이 자동으로 스프링 빈으로 등록 (내부에 @Component 애노테이션이 있어서 컴포넌트 스캔의 대상이 됨) 

    2. 스프링 MVC에서 애노테이션 기반 컨트롤러로 인식  (RequestMappingHandlerMapping 은 스프링 빈 중에서                       @RequestMapping 또는 @Controller 가 클래스 레벨에 붙어 있는 경우에 매핑 정보로 인식).

 

*@RequestMapping : 요청 정보를 매핑한다. 해당 URL이 호출되면 이 메서드가 호출된다. 애노테이션을 기반으로 동작(RequestMappingHandlerMapping 은 스프링 빈 중에서 @RequestMapping 또는 @Controller 가 클래스 레벨에 붙어 있는 경우에 매핑 정보로 인식)

 

*ModelAndView : 모델과 뷰 정보를 담아서 반환하면 된다

 

물론 컴포넌스 스캔 없이 다음과 같이 스프링 빈으로 직접 등록.

@RequestMapping public class SpringMemberFormControllerV1 { @RequestMapping("/springmvc/v1/members/new-form") public ModelAndView process() { return new ModelAndView("new-form"); } }
+
ServletApplication //스프링 빈 직접 등록
@Bean TestController testController() { return new TestController(); }

 

 

 

<SpringMemberSaveControllerV1> - 회원 저장

@Controller
public class SpringMemberSaveControllerV1 {
    private MemberRepository memberRepository = MemberRepository.getInstance();

    @RequestMapping("/springmvc/v1/members/save")
    public ModelAndView process(HttpServletRequest request, HttpServletResponse
            response) {
        String username = request.getParameter("username");
        int age = Integer.parseInt(request.getParameter("age"));

        Member member = new Member(username, age);
        System.out.println("member = " + member);
        memberRepository.save(member);

        ModelAndView mv = new ModelAndView("save-result");
        mv.addObject("member", member);

        return mv;
    }
}

 

 

<SpringMemberListControllerV1> - 회원 목록

@Controller
public class SpringMemberListControllerV1 {
    private MemberRepository memberRepository = MemberRepository.getInstance();

    @RequestMapping("/springmvc/v1/members")
    public ModelAndView process() {
        List<Member> members = memberRepository.findAll();
        ModelAndView mv = new ModelAndView("members");
        mv.addObject("members", members);
        return mv;
    }
}

 

 


 

[컨트롤러 통합]

 

<SpringMemberControllerV2> 하나의 컨트롤러에 넣음

@Controller
@RequestMapping("/springmvc/v2/members")

public class SpringMemberControllerV2 {

    private MemberRepository memberRepository = MemberRepository.getInstance();
    
        @RequestMapping("/new-form")
        public ModelAndView newForm() {
            return new ModelAndView("new-form");
        }

        @RequestMapping("/save")
        public ModelAndView save(HttpServletRequest request, HttpServletResponse
                response) {
            String username = request.getParameter("username");
            int age = Integer.parseInt(request.getParameter("age"));
            Member member = new Member(username, age);
            memberRepository.save(member);
            ModelAndView mav = new ModelAndView("save-result");
            mav.addObject("member", member);
            return mav;
        }

        @RequestMapping
        public ModelAndView members() {
            List<Member> members = memberRepository.findAll();
            ModelAndView mav = new ModelAndView("members");
            mav.addObject("members", members);
            return mav;
        }
}

 

 


[어노테이션 기반 spring] v3->v4, 인터페이스반환해도 되고 문자를 반화해도 되고

<SpringMemberControllerV3>

/**
 * v3
 * Model 도입
 * ViewName 직접 반환
 * @RequestParam 사용
 * @RequestMapping -> @GetMapping, @PostMapping
 */
 
@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", members);
        return "members";
    }
}