전체 정리를 한번 해보자.
요청이 들어온다.
그러면 먼저 프론트컨트롤러에서 나에게 등록된 컨트롤러들에서 매핑을 해서 가져온다.
(예를 들어 uri 등(더 많지만) 그것과 내가 등록한 컨트롤러에 등록한(이 uri로 요청이 들어오면 이걸 실행해줘~ 라고 내가 RequestMapping으로 등록한 것)이 있는지 찾아본 다음에, 있으면 그걸 가져온다. )
private void initHandlerMappingMap(Map<String, Object> handlerMappingMap){
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/v5/v4/members/new-form",new MemberFormControllerV4());
handlerMappingMap.put("/front-controller/v5/v4/members/save",new MemberSaveControllerV4());
handlerMappingMap.put("/front-controller/v5/v4/members",new MemberListControllerV4());
}
우리가 등록했을때는 이렇게 uri와, 그 종류, 그러니까 어떤 인터페이스였는지 그걸 등록했었음.
아마 이게 나중에 가서는 MemberListControllerV3, MemberSaveControllerV3 등등 이렇게 나눠진게 아니라, 같은 결 끼리는 저걸 메소드로 묶는데,
@Controller
@RequestMapping("springmvc/v3/members")
public class SpringMemberControllerV3 {
MemberRepository memberRepository = MemberRepository.getInstance();
// @RequestMapping(value = "/save", method = RequestMethod.POST)
@PostMapping("/save")
public String save(@RequestParam("username") String username, @RequestParam("age") int age, Model model) {
Member member = new Member(username, age);
Member savedMember = memberRepository.save(member);
model.addAttribute("member",member);
return "save-result";
}
// @RequestMapping(method = RequestMethod.GET)
@GetMapping
public String findAll(Model model) {
List<Member> members = memberRepository.findAll();
model.addAttribute("members", members);
return "members";
}
// @RequestMapping(value = "/new-form",method = RequestMethod.GET)
@GetMapping("/new-form")
public String newMemberForm() {
return "new-form";
}
}
이렇게, 아마 이런 것도 다 Bean으로 등록되어서, 싱글톤화 되기 때문에, 좀 컨테이너에서 Bean으로써 가져오는 그런 모양새가 아닐까 함.
여튼 그런 식으로 가져오고,
그 다음 그 handler를 가져오는데,
private void initHandlerAdapters(List<MyHandlerAdapter> handlerAdapters){
handlerAdapters.add(new ControllerV3HandlerAdapter());
handlerAdapters.add(new ControllerV4HandlerAdapter());
}
이런 식이여서 핸들러도 저 Bean을 토대로 다 등록이 될 듯~
여기 핸들러 보면
public class ControllerV3HandlerAdapter implements MyHandlerAdapter {
@Override
public boolean supports(Object handler) {
return handler instanceof ControllerV3;
}
@Override
public ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
ControllerV3 controller = (ControllerV3) handler;
Map<String, String> paramMap = createParamMap(request);
return controller.process(paramMap);
}
private static Map<String, String> createParamMap(HttpServletRequest request) {
Map<String, String> paramMap = new HashMap<>();
request.getParameterNames().asIterator()
.forEachRemaining(paramName -> paramMap.put(paramName, request.getParameter(paramName)));
return paramMap;
}
}
이런 식임.
그러니까 supports가 있고, 거기서 그냥 자기와 맞는 핸들러인지 확인하고,
맞으면,
private MyHandlerAdapter getHandlerAdapter(Object handler){
for( MyHandlerAdapter adapter : handlerAdapters){
if(adapter.supports(handler)) return adapter;
}
throw new IllegalArgumentException("handler adapter를 찾을 수 없습니다. handler = " + handler);
}
이런 식으로 그 어댑터를 가져옴.
그 다음, 그 어댑터를 통해서 handler를 실행하는 거임.
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Object handler = getHandler(request);
if(handler == null){
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
MyHandlerAdapter adapter = getHandlerAdapter(handler);
ModelView mv = adapter.handle(request, response, handler);
MyView view = viewResolver(mv.getViewName());
view.render(mv.getModel(), request, response);
}
저기 보면 mv 받는 곳에 adapter.handle 있음.
위 그림대로 ModelAndView를 반환.
그 다음 viewResolver를 통해서 논리이름을 물리이름으로 변환받아서 그걸 그려주는걸 담당하는 View객체에 담아서, return해줌. 그 다음, view.render해주면 그려줌.
view.render같은 경우는 이제 보통 jsp면 실제로 그냥 forward() 해주는 거고, 다른 건 그냥 자바로 response 메시지바디에 html을 넣어서 응답해줌.
근데 또 알아야 할 게, 여러 방식에 대해 지원해주는 handler가 인자를 받는 것.
이거는, adapter가 ArgumentResolver를 호출해줘서 handler에 인자로 넣어주는 것 임.
이 ArgumentResolver도 마찬가지로 어댑터 패턴으로 계속 맞는지 돌려봐서, 맞으면 request에서 온 정보들을 가지고 있는 객체에서 뒤져봐서(추정), 인자가 필요한 정보에 맞게 잘 섞어서 주는거임. 그걸 이 ArgumentResolver가 모두 객체로 만들어서 전달을 해주는 거임. 먼저 필요한 인자들을 모두 객체로 만들어 준 다음에, 다 만들어 줬으면 전달.
그 다음 ReturnValueHandler로 마찬가지임.
우리가 View까지 가는데 필요한 정보들이 있잖음? 이 ReturnValueHandler가 view가 처리할 수 있는 어떤 무언가로 변환해 줌.
그럼 그걸 viewResolver가 가지고 가서 또 어댑터패턴으로 찾은 다음에, view를 반환해주고, 그걸통해 render(model)하면 됨.
'스프링 > 3. 스프링 MVC' 카테고리의 다른 글
52. 요구사항 (0) | 2023.08.14 |
---|---|
51. 요청 파라미터 및 메시지바디의 데이터 정리 (0) | 2023.08.13 |
49. 컨버터가 실행되는 위치, ArgumentResolver (0) | 2023.08.13 |
48. HTTP 메시지 컨버터 (0) | 2023.08.13 |
47. HTTP API (0) | 2023.08.13 |