월루를 꿈꾸는 대학생
[MVC-1] 스프링 MVC - 구조 이해 본문
스프링 MVC 전체 구조
그 전 공부했던 프레임워크 구조
==스프링 프레임워크 ==
동작 순서
- 핸들러 조회 : 핸들러 매핑을 통해 url에 매핑된 핸들러 = 컨트롤러 조회
- 핸들러 어댑터 조회 : 핸들러 실행할 어댑터를 조회
- 핸들러 어댑터 실행 : 핸들러 어댑터 실행
- 핸들러 실행 : 어뎁터가 핸들러=컨트롤러를 실행
- ModelAndView 반환 : 핸들러 어댑터가 핸들러가 반환한 정보를 ModelAndView로 변환해서 보냄
- viewReslover호출 : 뷰 리졸버를 찾고 실행 : 논리를 물리로
- View반환 : 물리적 경로 기반으로 랜더링할 뷰를 반환한다
- 뷰 랜더링: 뷰를 받아서 랜더링함
비교
- 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가 호출되기 위해서는 핸들러 매핑 , 핸들러 어댑터가 필요하다
- HanlderMapping
- 핸들러 매핑에서 OldController찾기
- 스프링 빈 이름으로 핸들러 찾아야함
- HandlerAdapter
- 핸들러 매핑에서 찾은 핸들러 실행시킬 어댑터 찾기
- Controller 인터페이스를 실행할 수 있는 어댑터 찾고 실행
실행 순서
- HandlerMapping을 실행 시킨 후 0인지 1인지 그 외인지 차례때로 호출 후 찾기
- OldController는 빈이름으로 찾으니까 1번임
- 1번에 해당하는 핸들러 OldController 반환하고 HandlerAdapter에서 OldController가 가지고 있는 Controller인터페이스에 해당하는 2번 어댑터 반환
- 2번에 해당하는 Controller인터페이스 어댑터 실행하고 핸들러 정보도 넘겨줌
- 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");
}
}
- HandlerMapping 실행후 핸들러 찾음
- 또 빈이름이니까 1번 핸들러인 거 확인 후 핸들러인 MyHttpReqeustHandler를 반환
- 핸들러 어댑터를 찾기 위해 support()메서드 돌리고 그 중 해당하는 HttpReqeustHandlerAdapter를 확인
- 해당 어댑터 실행하면서 핸들러 정보 넘겨주고 어댑터는 핸들러를 실행하고 결과를 반환한다
뷰 리졸버
application.properties 코드에 추가
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
뷰리졸버 - InternalResourceViewResolver
- 뷰 리졸버를 자동 등록하고 이때 위의 파일에 설정을 읽어서 등록함
- 논리적 경로에 위의 설정처럼 앞 뒤에 붙어서 물리적 경로를 완성
- 핸들러 어댑터를 통해서 new-form 의 논리 경로 흭득
- viewResolver호출해서 2번 jsp 처리 가능한 뷰를 반환할 InternalResourceViewResolver 리졸버를 호출
- InternalResourceView를 반환
- 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
'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 |