๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐ŸŒท Spring/Spring MVC_1

[Spring] ๊น€์˜ํ•œ ์Šคํ”„๋ง MVC_ ์„น์…˜5. MVC ํ”„๋ ˆ์ž„์›Œํฌ ๋งŒ๋“ค๊ธฐ

by ._.sori 2025. 7. 14.

<์ถœ์ฒ˜ ์ธํ”„๋Ÿฐ>



์„น์…˜ 5๋Š” ํ˜„์žฌ์˜ Spring MVC๊นŒ์ง€ ์˜ค๊ฒŒ๋œ ๊ณผ์ •์„ ์ฐจ๊ทผ์ฐจ๊ทผ ์‚ดํŽด๋ดค๋‹ค. ์•ž์„œ ๋ฐฐ์šด ์ ์—์„œ ๊ฐ€์žฅ ํฐ ๋ณ€ํ™”๋Š” ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ฒ˜๋ฆฌํ–ˆ๋˜ ๊ฒƒ๊ณผ ๋‹ฌ๋ฆฌ ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ์— ์—ญํ• ์„ ์ „๊ฐ€ํ•ด ๊ฐœ๋ฐœ์ž๋Š” ์ ์  ํŽธ๋ฆฌํ•˜๊ฒŒ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ค‘๋ณต๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์ตœ๋Œ€ํ•œ ์ค„์ด๋ฉฐ ์ ์ง„์ ์ธ ๊ตฌ์กฐ์  ๋ณ€ํ™”๋ฅผ ์ฃผ์—ˆ๋‹ค.

 

 

โ˜˜๏ธ 

์ž˜๋ชป๋œ ์ •๋ณด๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค 


 

โœ”๏ธ  V1_ ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋„์ž…ํ•˜์ž.

  • ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๋กœ ์š”์ฒญ์„ ๋ฐ›์•„ ์•Œ๋งž๋Š” ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ฐพ์•„ ํ˜ธ์ถœํ•œ๋‹ค.
  • ๋‚˜๋จธ์ง€ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์„œ๋ธ”๋ฆฟ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

โ–บ  ControllerV1.interface

public interface ControllerV1 {

    void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;

}
๋กœ์ง์˜ ์ผ๊ด€์„ฑ์„ ์œ„ํ•ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์„œ๋ธ”๋ฆฟ๊ณผ ๋น„์Šทํ•œ ๋ชจ์–‘์˜ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.

 

 

 

โ–บ MemberSaveControllerV1.class

  • ๊ฒฝ๋กœ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ ๊ทธ ๊ฒฝ๋กœ๋กœ ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ๋„˜๊ธด๋‹ค.
  • RequestDispatcher์„ ์‚ฌ์šฉํ•œ๋‹ค.
    @Override
    public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        int age = Integer.parseInt(request.getParameter("age"));

        Member member = new Member(username, age);
        memberRepository.save(member);

        request.setAttribute("member", member);

        String viewPath = "/WEB-INF/views/save-result.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
    }
๋“ค์–ด์˜จ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ์ด๋‹ค. ํ•ด๋‹น ์ปจํŠธ๋กค๋Ÿฌ๋Š” ๊ฒฝ๋กœ๋ฅผ ์ •์˜ํ•˜๊ณ  ์žˆ๊ณ , ์ •์˜๋œ ๊ฒฝ๋กœ๋ฅผ viewPath ๋‹ด์€ ํ›„ request.getRequestDispatcher๋กœ ์ด ๊ฒฝ๋กœ๋กœ ๊ฐˆ ์ˆ˜ ์žˆ๋Š” dispatcher์„ ๋งŒ๋“ค์–ด ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ๋„˜๊ธด๋‹ค. ์ด๋•Œ request์— member๋ฅผ ๋‹ด์•„ ๋„ฃ๊ธฐ๋Š” ์ด์œ ๋Š” ์–ด๋–ค ์š”์ฒญ์ธ์ง€ ์•Œ๊ธฐ ์œ„ํ•จ์ด๋‹ค. 

 

 

Q. ์™œ ์ •๋ณด๋ฅผ request์— ๋‹ด์„๊นŒ? response์— ๋‹ด์•„์„œ ํ™”๋ฉด์— ์ถœ๋ ฅํ•ด์•ผํ•˜๋Š”๊ฒŒ ์•„๋‹๊นŒ?

A. reponse๋Š” ๋ธŒ๋ผ์šฐ์ €์— ์‹ค์ œ๋กœ ๋ณด๋‚ด๋Š” ๋ฐ์ดํ„ฐ๋งŒ ๋‹ด๋Š”๋‹ค. request๋Š” JSP(JavaServer Page, ์ž๋ฐ” ์ฝ”๋“œ๋กœ HTML ํŒŒ์ผ์„ ๋งŒ๋“œ๋Š” ์„œ๋ฒ„์šฉ ํŒŒ์ผ)์—๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋„˜๊ฒจ์ฃผ๊ธฐ ์œ„ํ•œ ์ž„์‹œ ๋ฐ”๊ตฌ๋‹ˆ ๊ฐ™์€ ์šฉ๋„์ด๋‹ค. ๊ทธ๋ž˜์„œ ๋ณด๋‚ด๋Š” ์šฉ๋„๋กœ ์ž ๊น๋งŒ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด setAttribute๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. JSP๋Š” ์•„๋งˆ๋„ ์ด๋ฆ„ ๋ฐ์ดํ„ฐ์™€ ๋‚˜์ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•˜์„ ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฌ๋ฉด JSP๋Š” ํ™”๋ฉด์— ๋ณด๋‚ด๊ธฐ ์œ„ํ•œ HTML์„ ๋งŒ๋“  ํ›„, response์— ์ตœ์ข… ๊ฒฐ๊ณผ๋ฅผ ๋‹ด์•„ ์‚ฌ์šฉ์ž๊ฐ€ ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

 

 

โ–บ FrontControllerServletV1.class

    private Map<String, ControllerV1> controllerMap = new HashMap<>();

    public FrontControllerServletV1() {
        controllerMap.put("/front-controller/v1/members/new-form", new MemberFormControllerV1());
        controllerMap.put("/front-controller/v1/members/save", new MemberSaveControllerV1());
        controllerMap.put("/front-controller/v1/members", new MemberListControllerV1());
    }
์›น์ด ์ฒ˜์Œ ์ผœ์ง€๋ฉด ์œ„์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์„œ controllerMap์— ์ €์žฅํ•œ๋‹ค. URL์ด ํ‚ค๊ฐ€ ๋˜๊ณ  ์ปจํŠธ๋กค๋Ÿฌ ๊ฐ์ฒด๊ฐ€ ๊ฐ’์ด ๋œ๋‹ค.

 

        System.out.println("FrontControllerServletV1.service");

        String requestURI = request.getRequestURI();

        ControllerV1 controller = controllerMap.get(requestURI);
        if(controller == null) {
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        controller.process(request,response);
์‹ค์ œ ์š”์ฒญ์ด /front-controller/v1/members/save ๊ฒฝ๋กœ๋กœ ๋“ค์–ด์˜ค๋ฉด requestURI์— ๋„ฃ์–ด์ง„๋‹ค. ๊ทธ๋ฆฌ๊ณ  requestURI๋ฅผ ๊ฐ€์ง€๊ณ  controllerMap์—์„œ ๋ฏธ๋ฆฌ ์ €์žฅํ•ด๋’€๋˜ MemberSaveControllerV1 ๊ฐ์ฒด๋ฅผ ๊บผ๋‚ด์„œ process( ) ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ด๋•Œ

MemberSaveControllerV1.class์˜ process ๋ฉ”์„œ๋“œ๊ฐ€ ์ง„ํ–‰๋œ๋‹ค.

์•„๊นŒ ์œ„์— ์ ์—ˆ๋“ฏ์ด MemberSaveControllerV1.class์—์„œ dispatcher๋ฅผ ํ†ตํ•ด ๋ธŒ๋ผ์šฐ์ €์— ์‘๋‹ต์„ ๋ณด๋‚ธ๋‹ค. 

 

 

 

โ–ถ ์ˆœ์„œ (MemberSaveController)

  • ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ(FrontControllerServletV1)๋กœ ์š”์ฒญ์ด ๋“ค์–ด์˜จ๋‹ค
  • ๋“ค์–ด์˜จ ๊ฒฝ๋กœ๋กœ ์ €์žฅํ•ด๋‘” ๊ฐ์ฒด๋ฅผ ๊บผ๋‚ธ๋‹ค.
  • ๊บผ๋‚ธ ๊ฐ์ฒด์˜ process ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.
  • process ๋ฉ”์„œ๋“œ์—์„œ ์ด๋ฆ„๊ณผ ๋‚˜์ด๋ฅผ ์ €์žฅํ•œ๋‹ค.
  • dispatcher๋กœ HTML์„ ๋งŒ๋“ค์–ด ๋ธŒ๋ผ์šฐ์ €๋กœ ๋ณด๋‚ธ๋‹ค.

 

 


 

 

 

โœ”๏ธ  V2_ View๋ฅผ ๋ถ„๋ฆฌํ•˜์ž.

  • ๋ธŒ๋ผ์šฐ์ €์— ์ถœ๋ ฅํ•˜๊ธฐ ์œ„ํ•œ(view ๋ถ€๋ถ„) ์ฝ”๋“œ๋ฅผ ๋ชจ๋“  ์ปจํŠธ๋กค๋Ÿฌ์— ์ค‘๋ณตํ•ด์„œ ์ฝ”๋“œ๋ฅผ ์ ์–ด์•ผํ–ˆ๋‹ค.
  • ์ค‘๋ณต๋œ ์ฝ”๋“œ๋ฅผ ์—†์• ๊ณ  view๋ฅผ ๋ถ„๋ฆฌํ•œ๋‹ค.

 

โ–บ  MyView.class

    private String viewPath;

    public MyView(String viewPath) {
        this.viewPath = viewPath;
    }

    public void render(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException  {
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
    }
V1์—์„œ๋Š” Controller๊ฐ€ dispatcher.forward๊นŒ์ง€ ์ฒ˜๋ฆฌํ–ˆ๋‹ค. V2์—์„œ๋Š” MyView ํด๋ž˜์Šค๋ฅผ ๋”ฐ๋กœ ๋งŒ๋“ค์–ด View๋ฅผ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ–ˆ๋‹ค. ์•„๋งˆ๋„ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ํ™”๋ฉด์— ํ‘œ์‹œ๋  ๊ฒฝ๋กœ๋ฅผ MyView๋กœ ๋ฐ˜ํ™˜ํ•  ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿผ ๊ทธ ๊ฒฝ๋กœ๋ฅผ ๋ฐ›์•„ render ๋ฉ”์„œ๋“œ์—์„œ ์ฒ˜๋ฆฌํ•ด ์‚ฌ์šฉ์ž ํ™”๋ฉด์— ์ถœ๋ ฅ๋œ๋‹ค.

 

 

 

โ–บ MemberSaveControllerV2.class

    @Override
    public MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        int age = Integer.parseInt(request.getParameter("age"));

        Member member = new Member(username, age);
        memberRepository.save(member);

        request.setAttribute("member", member);

        return new MyView("/WEB-INF/views/save-result.jsp");
    }
ํ•ด๋‹น ๊ฒฝ๋กœ๋ฅผ ๊ฐ€์ง€๊ณ  MyView ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ–ˆ๋‹ค. ์–ด๋–ค ๋ทฐ๋กœ ๋ณด์—ฌ์ค„์ง€ ์ •๋ณด๋งŒ ๋„˜๊ธด ํ›„, ์‹ค์ œ ํ™”๋ฉด์€ MyView ๊ฐ์ฒด๊ฐ€ ๋‹ด๋‹นํ•  ๊ฒƒ์ด๋‹ค.

 

 

 

โ–บ FrontControllerServletV2.class

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

        String requestURI = request.getRequestURI();

        ControllerV2 controller = controllerMap.get(requestURI);
        if(controller == null) {
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        MyView view = controller.process(request, response);
        view.render(request, response);
    }
V1์€ controller.process()๋งŒ ํ˜ธ์ถœ๋๋‹ค. V2๋Š” controller.process()์—์„œ view์— ๋„˜๊ธธ ๋ฐ์ดํ„ฐ๋ฅผ ์ค€๋น„ํ•ด์„œ request์— ๋‹ด๊ณ , ์–ด๋–ค JSP๋กœ ๊ฐˆ์ง€ MyView๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๊ทธ ๋‹ค์Œ view.render๋ฅผ ํ†ตํ•ด ์ง€์ •๋œ JSP๋กœ forwardํ•ด์„œ ๋ธŒ๋ผ์šฐ์ €์— ํ™”๋ฉด์ด ๋ณด์ด๋„๋ก ํ•œ๋‹ค.

 

 

 

 

โ–ถ ์ˆœ์„œ (MemberSaveController)

  • ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ(FrontControllerServletV1)๋กœ ์š”์ฒญ์ด ๋“ค์–ด์˜จ๋‹ค
  • ๋“ค์–ด์˜จ ๊ฒฝ๋กœ๋กœ ์ €์žฅํ•ด๋‘” ๊ฐ์ฒด๋ฅผ ๊บผ๋‚ธ๋‹ค.
  • ๊บผ๋‚ธ ๊ฐ์ฒด์˜ process ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.
  • process ๋ฉ”์„œ๋“œ์—์„œ ์ด๋ฆ„๊ณผ ๋‚˜์ด๋ฅผ ์ €์žฅํ•œ๋‹ค.
  • process ๋ฉ”์„œ๋“œ์—์„œ ๊ฒฝ๋กœ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ๋ฐ˜ํ™˜๋œ ๊ฒฝ๋กœ๋กœ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  MyView ํด๋ž˜์Šค์˜ render ๋ฉ”์„œ๋“œ์— ๊ฐ„๋‹ค.
  • render์—์„œ ํ™”๋ฉด์„ ๋งŒ๋“ ๋‹ค.

 

 


 

 

 

โœ”๏ธ  V3_ ์„œ๋ธ”๋ฆฟ ์ข…์†์„ฑ์„ ์ œ๊ฑฐํ•˜์ž.

  • HttpServletRequest, HttpServletResponse์ด ๊ผญ ํ•„์š”ํ•˜์ง„ ์•Š์€ ๊ฒƒ ๊ฐ™๋‹ค.
  • request ๊ฐ์ฒด๋ฅผ Model๋กœ ๋Œ€์‹ ํ•ด ์‚ฌ์šฉํ•ด๋ณธ๋‹ค.
  • ๋ทฐ ์ด๋ฆ„์˜ ์ค‘๋ณต์„ ์ง€์›Œ๋ณธ๋‹ค.

 

โ–บ MemberSaveControllerV3.class

    @Override
    public ModelView process(Map<String, String> paramMap) {
        String username = paramMap.get("username");
        int age = Integer.parseInt(paramMap.get("age"));

        Member member = new Member(username, age);
        memberRepository.save(member);

        ModelView mv = new ModelView("save-result");
        mv.getModel().put("member", member);
        return mv;
    }
mv์—๋Š” "save-result"์™€ member ์ •๋ณด๊ฐ€ ๋‹ด๊ธด model์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. 

 

 

 

 

โ–บFrontControllerServeltV3.class

        Map<String, String> paramMap = createParamMap(request);
        ModelView mv = controller.process(paramMap);

        String viewName = mv.getViewName();
        MyView view = viewResolver(viewName);
        view.render(mv.getModel(), request, response);
    private MyView viewResolver(String viewName) {
        return new MyView("/WEB-INF/views/" + viewName + ".jsp");
    }
service( ) ๋ฉ”์„œ๋“œ์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์ ์–ด ๋„ฃ์€ ๋ฐ์ดํ„ฐ๋ฅผ createParamMap( ) ๋ฉ”์„œ๋“œ๋กœ ๊บผ๋‚ธ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ ์ •๋ณด๋ฅผ ์ปจํŠธ๋กค๋Ÿฌ์— ์žˆ๋Š” process( ) ๋ฉ”์„œ๋“œ๋กœ ๋ณด๋‚ธ๋‹ค. process( ) ๋ฉ”์„œ๋“œ์—์„œ ๊ฒฐ๊ณผ์ ์œผ๋กœ "save-result"๋ผ๋Š” view ์ด๋ฆ„๊ณผ ("member", member)๋ฅผ mv์— ๋‹ด์•˜๊ณ , ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๋Š” mv๋ฅผ ๋ฐ›๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋ฉด mv.getViewName( )์„ ํ†ตํ•ด ๋ทฐ ์ด๋ฆ„์„ ๊บผ๋‚ด๊ณ , ๋ทฐ ์ด๋ฆ„์„ viewResolver( ) ๋ฉ”์„œ๋“œ๋กœ ๋ณด๋‚ด ์‹ค์ œ ๋ฌผ๋ฆฌ ๋ทฐ ๊ฒฝ๋กœ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.

V1๊ณผ V2๋Š” ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์ง์ ‘ request์— ์ •๋ณด๋ฅผ ๋„ฃ์—ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ V3์—์„œ๋Š” ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ Model์— ๋ฐ์ดํ„ฐ๋งŒ ๋„ฃ๊ณ , ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ view.render( )๋กœ ์ „๋‹ฌํ•ด ๊ทธ ์•ˆ์—์„œ setAttribute๊ฐ€ ์ด๋ค„์ง„๋‹ค.

 

 

 

โ–บ  MyView.class

 public void render(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        modelToRequestAttribute(model, request);
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);

    }

    private static void modelToRequestAttribute(Map<String, Object> model, HttpServletRequest request) {
        model.forEach((key, value) -> request.setAttribute(key, value));
    }
render ๋ฉ”์„œ๋“œ๋ฅผ ์ƒˆ๋กญ๊ฒŒ ์˜ค๋ฒ„๋กœ๋”ฉ(๊ฐ™์€ ์ด๋ฆ„์˜ ๋ฉ”์„œ๋“œ, ๋‹ค๋ฅธ ์‹œ๊ทธ๋‹ˆ์ฒ˜)ํ–ˆ๋‹ค. ๊ทธ ์ด์œ ๋Š” view.render์— mv.getModel์ด ์ถ”๊ฐ€๋˜์–ด ๊ทธ๊ฑธ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” model์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋„ฃ์–ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

render( ) ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด modelToRequestAttribute( ) ๋ฉ”์„œ๋“œ์—์„œ model์— ๋„ฃ์–ด๋‘” ์ •๋ณด๋ฅผ forEach๋กœ ๊บผ๋‚ด setAttribute๋กœ request์— ์ž ์‹œ ์ €์žฅํ•˜๊ณ , dispatcher.forward( ) ๋ฉ”์„œ๋“œ๋กœ ์‚ฌ์šฉ์ž ๋ธŒ๋ผ์šฐ์ €์— ํ™”๋ฉด์ด ์†ก์ถœ๋  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค. 

 

 

 

 

โ–ถ ์ˆœ์„œ (MemberSaveController)

  • ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ(FrontControllerServletV1)๋กœ ์š”์ฒญ์ด ๋“ค์–ด์˜จ๋‹ค
  • ๋“ค์–ด์˜จ ๊ฒฝ๋กœ๋กœ ์ €์žฅํ•ด๋‘” ๊ฐ์ฒด๋ฅผ ๊บผ๋‚ธ๋‹ค.
  • ๊บผ๋‚ธ ๊ฐ์ฒด์˜ process ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.
  • process ๋ฉ”์„œ๋“œ์—์„œ ์ด๋ฆ„๊ณผ ๋‚˜์ด๋ฅผ ์ €์žฅํ•œ๋‹ค.
  • process ๋ฉ”์„œ๋“œ์—์„œ ๋…ผ๋ฆฌ ๋ทฐ ์ด๋ฆ„์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • mv์— ์ •๋ณด์™€ ๋…ผ๋ฆฌ ๋ทฐ ์ด๋ฆ„์„ ๊ฐ€์ง€๊ณ  ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ์— ์˜จ๋‹ค.
  • ๋…ผ๋ฆฌ ๋ทฐ ์ด๋ฆ„์„ viewResolver ๋ฉ”์„œ๋“œ๋กœ ๋ฌผ๋ฆฌ ๋ทฐ ์ด๋ฆ„์œผ๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค.
  • ๊ทธ ๊ฒฝ๋กœ๋กœ render ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋œ๋‹ค.
  • MyView ํด๋ž˜์Šค์—์„œ model์„ request.setAttribute๋กœ ๋ณ€๊ฒฝํ•˜๊ณ 
  • ๊ทธ ํ›„ ๋ธŒ๋ผ์šฐ์ €์— ์†ก์ถœํ•œ๋‹ค.

 

 


 

 

 

โœ”๏ธ  V4_ ์ข€ ๋” ์‹ค์šฉ์ ์ด๊ฒŒ ์ฝ”๋“œ๋ฅผ ๋ฐ”๊ฟ”๋ณด์ž.

  • ModelView ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๋Š” ๋ถ€๋ถ„์ด ์กฐ๊ธˆ์€ ๋ฒˆ๊ฑฐ๋กญ๋‹ค.

     

โ–บ MemberSaveControllerV4.class

    @Override
    public String process(Map<String, String> paramMap, Map<String, Object> model) {
        String username = paramMap.get("username");
        int age = Integer.parseInt(paramMap.get("age"));

        Member member = new Member(username, age);
        memberRepository.save(member);

        model.put("member", member);
        return "save-result";
    }
V3๋Š” model ๊ฐ์ฒด๋ฅผ ๋”ฐ๋กœ ๋งŒ๋“ค์—ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ V4๋Š” model.put์œผ๋กœ ์ •๋ณด๋ฅผ ๋„ฃ๊ณ , reuturn์„ ํ†ตํ•ด ๊ฐ„๋‹จํ•˜๊ฒŒ ๋…ผ๋ฆฌ ๋ทฐ ์ด๋ฆ„์„ ๋ฐ˜ํ™˜ํ–ˆ๋‹ค. ๊ทธ์ € ์ปจํŠธ๋กค๋Ÿฌ๋Š” map์— ๊ฐ’์„ ๋„ฃ๊ณ  view ์ด๋ฆ„๋งŒ ๋ฐ˜ํ™˜ํ•œ ๊ฒƒ์ด๋‹ค. ๊ทธ๋ž˜์„œ V3์— ์žˆ๋˜ mv๊ฐ€ V4์— ์—†๋‹ค.

 

 

 

โ–บFrontControllerServletV4.class

        Map<String, String> paramMap = createParamMap(request);
        Map<String, Object> model = new HashMap<>();

        String viewName = controller.process(paramMap, model);

        MyView view = viewResolver(viewName);
        view.render(model, request, response);
Map์œผ๋กœ ๋ฐ›๋Š” model ์ฝ”๋“œ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ๋‹ค. V3์˜ ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ๋Š” model ๊ฐ์ฒด๋ฅผ ๊ณ„์†ํ•ด์„œ ๋งŒ๋“ค์–ด์ค˜์•ผํ–ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋ฒˆ๊ฑฐ๋กœ์›€์„ V4๊ฐ€ Map์œผ๋กœ model์„ ์ง์ ‘ ๋งŒ๋“ค์–ด ๋„˜๊ฒจ์ฃผ๋‹ˆ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ๊ทธ๋ƒฅ model.put๋งŒ ํ•˜๋ฉด ๋˜๋Š” ๊น”๋”ํ•œ ์ฝ”๋“œ๊ฐ€ ์™„์„ฑ๋๋‹ค.

 

 

 

โ–ถ ์ˆœ์„œ (MemberSaveController)

  • ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ(FrontControllerServletV1)๋กœ ์š”์ฒญ์ด ๋“ค์–ด์˜จ๋‹ค
  • ๋“ค์–ด์˜จ ๊ฒฝ๋กœ๋กœ ์ €์žฅํ•ด๋‘” ๊ฐ์ฒด๋ฅผ ๊บผ๋‚ธ๋‹ค.
  • ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ Map์œผ๋กœ ๋งŒ๋“ ๋‹ค.
  • ๋น„์–ด์žˆ๋Š” model(Map)์„ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•œ๋‹ค.
  • ๊บผ๋‚ธ ๊ฐ์ฒด์˜ process ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.
  • process ๋ฉ”์„œ๋“œ์—์„œ ์ด๋ฆ„๊ณผ ๋‚˜์ด๋ฅผ ์ €์žฅํ•œ๋‹ค.
  • process ๋ฉ”์„œ๋“œ์—์„œ ๋…ผ๋ฆฌ ๋ทฐ ์ด๋ฆ„์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • model์€ ์ด๋ฏธ ํ”„๋ก ํ„ฐ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ map์œผ๋กœ ๊ตฌํ˜„ํ•ด๋†จ๊ธฐ์— ํŽธ๋ฆฌํ•˜๊ฒŒ
    model.put์œผ๋กœ ์ •๋ณด๋ฅผ ๋„ฃ๋Š”๋‹ค. (model์˜ ๊ฐ์ฒด ์ƒ์„ฑ์ด ํ•„์š” ์—†์–ด์ง)
  • ๋…ผ๋ฆฌ ๋ทฐ ์ด๋ฆ„์„ viewResolver ๋ฉ”์„œ๋“œ๋กœ ๋ฌผ๋ฆฌ ๋ทฐ ์ด๋ฆ„์œผ๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค.
  • ๊ทธ ๊ฒฝ๋กœ๋กœ render ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋œ๋‹ค.
  • MyView ํด๋ž˜์Šค์—์„œ model์„ request.setAttribute๋กœ ๋ณ€๊ฒฝํ•˜๊ณ 
  • ๊ทธ ํ›„ ๋ธŒ๋ผ์šฐ์ €์— ์†ก์ถœํ•œ๋‹ค.

 

 


 

 

 

โœ”๏ธ  V5 (1)_ ํ•ธ๋“ค๋Ÿฌ ์–ด๋Œ‘ํ„ฐ ๋งŒ๋“ค๊ธฐ

  • ModelView ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๋Š” ๋ถ€๋ถ„์ด ์กฐ๊ธˆ์€ ๋ฒˆ๊ฑฐ๋กญ๋‹ค.

     

โ–บ FrontControllerServletV5.class

    private final Map<String, Object> handlerMappingMap = new HashMap<>();
    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());
    }
hanlderMappingMap์ด๋ž€ ์ €์žฅ์†Œ๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค. ์ด ์ €์žฅ์†Œ์—” V3์— ๊ด€๋ จ๋œ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋‹ด์„ ๊ฒƒ์ด๋‹ค. key๋Š” ์š”์ฒญ์ด ๋“ค์–ด์˜จ ์ฃผ์†Œ๊ฐ€ ๋  ๊ฒƒ์ด๊ณ , ์ฃผ์†Œ๋กœ ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด ๊ทธ์— ๋งž๋Š” ๊ฐ์ฒด๋ฅผ ๊บผ๋‚ผ ๊ฒƒ์ด๋‹ค.

 

 

    private final List<MyHandlerAdapter> handlerAdapters = new ArrayList<>();
    private void initHandlerAdapters() {
        handlerAdapters.add(new ControllerV3HandlerAdapter());
    }
V3๋ฅผ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ์–ด๋Œ‘ํ„ฐ๋ฅผ handlerAdapters์— ์ถ”๊ฐ€ํ–ˆ๋‹ค. ํ˜„์žฌ ์ฝ”๋“œ์—์„œ๋Š” V3๋งŒ ๋„ฃ์–ด๋†จ์ง€๋งŒ, V4๋„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ List ํ˜•ํƒœ๋กœ ์ €์žฅํ•œ๋‹ค. 

 

 

    @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;
        }
    private Object getHandler(HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        return handlerMappingMap.get(requestURI);
    }
request๋กœ ๊ฒฝ๋กœ๊ฐ€ ๋“ค์–ด์˜ค๋ฉด handlerMappingMap์— ๊ฐ€์„œ ๊ฒฝ๋กœ์— ๋งž์ถฐ ๋ฏธ๋ฆฌ ์ €์žฅํ•ด๋‘” ๊ฐ์ฒด๋ฅผ ๊บผ๋‚ธ๋‹ค. ๊บผ๋‚ธ ๊ฐ์ฒด๋Š” handler์— ๋„ฃ์–ด๋‘”๋‹ค.

 

 

 MyHandlerAdapter adapter = getHandlerAdapter(handler);
    private MyHandlerAdapter getHandlerAdapter(Object handler) {
        for (MyHandlerAdapter adapter : handlerAdapters) {
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
        throw new IllegalArgumentException("handler adapter๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. handler=" + handler);
    }
handler์—๋Š” ๊ฐ์ฒด๊ฐ€ ๋“ค์–ด์žˆ๋‹ค. ๋งŒ์•ฝ ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฆ„๊ณผ ๋‚˜์ด๋ฅผ ์ €์žฅํ•˜๋Š” ํŽ˜์ด์ง€๋ฅผ ๋„์› ๋‹ค๋ฉด, MemberSaveControllerV3() ๊ฐ์ฒด๊ฐ€ ๋“ค์–ด์žˆ์„ ๊ฒƒ์ด๋‹ค. ๊ทธ๊ฑธ getHandlerAdapter๊ฐ€ ์ธ์ž๋กœ ๋ฐ›์•˜๋‹ค.

handlerAdapter์—๋Š” new ControllerV3HandlerAdapter()๋ฅผ ๋„ฃ์–ด๋†จ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด adapter ์ค‘ MemberSaveControllerV3()๊ฐ€  ControllerV3HandlerAdapter()๊ฐ€ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋งž๋Š”์ง€ supports ๋ฉ”์„œ๋“œ๋กœ ํ™•์ธํ•  ๊ฒƒ์ด๋‹ค. 

 

 

 

โ–บ ControllerV3HandlerAdapter.class

    @Override
    public boolean supports(Object handler) {
        return (handler instanceof ControllerV3);
    }
๊ฐ™์€ ์ธ์Šคํ„ฐ์Šค๊ฐ€ ๋งž๋Š”์ง€ instanceof๋ฅผ ํ†ตํ•ด ํ™•์ธํ•œ๋‹ค. ๊ฐ™์€ ์ธ์Šคํ„ด์Šค๋ผ๋ฉด true๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

 

Q. handler๋Š” ControllerV3์˜ ์ธ์Šคํ„ด์Šค์ธ์ง€ ์–ด๋–ป๊ฒŒ ์•„๋Š”๊ฑธ๊นŒ?

A. MemberSaveControllerV3๊ฐ€ ControllerV3๋ฅผ implementsํ•˜๊ณ  ์žˆ๋‹ค.
public class MemberSaveControllerV3 implements ControllerV3โ€‹


์ž๋ฐ” ํƒ€์ž… ๊ฒ€์‚ฌ๋กœ ์ฒดํฌํ•˜์—ฌ true๊ฐ€ ๋‚˜์˜จ๋‹ค.

 

 

    @Override
    public ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
        ControllerV3 controller = (ControllerV3) handler;

        Map<String, String> paramMap = createParamMap(request);
        ModelView mv = controller.process(paramMap);
        return mv;
    }
handle ๋ฉ”์„œ๋“œ์— ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ Object handler๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค. supports ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด handler(MemberSaveControllerV3 ๋ผ๊ณ  ๊ฐ€์ •)๊ฐ€ ControllerV3์™€ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค์ธ์ง€ ํ™•์ธ์„ ํ–ˆ๊ณ  ์ฐธ์ด ๋‚˜์™”๋‹ค. ๊ทธ๋Ÿฌ๋ฉด request๋กœ ๋ฐ›์•„์˜จ ๋‚˜์ด์™€ ์ด๋ฆ„ ์ •๋ณด๋ฅผ paramMap์„ ๋“ค๊ณ  MemberSaveControllerV3์˜ process ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœ์‹œํ‚จ๋‹ค.

process ๋ฉ”์„œ๋“œ๋Š” ๋ชจ๋ธ๋ทฐ ํƒ€์ž…์œผ๋กœ mv๋ฅผ ๋ฐ˜ํ™˜ํ–ˆ๋‹ค. ๋ฐ˜ํ™˜๋œ mv๋Š” handle ๋ฉ”์„œ๋“œ๋กœ ์™€ ๋‹ค์‹œ return mv๊ฐ€ ๋œ๋‹ค. ๊ทธ ํ›„ ์ด mv๋Š” ํ”„๋ก ํŠธ์ปจํŠธ๋กค๋Ÿฌ์˜ service ๋ฉ”์„œ๋“œ๋กœ ์ „๋‹ฌ๋œ๋‹ค.

 

 

 

โ–บ FrontControllerServletV5.class

        MyHandlerAdapter adapter = getHandlerAdapter(handler);

        ModelView mv = adapter.handle(request, response, handler);

        String viewName = mv.getViewName();
        MyView view = viewResolver(viewName);
        view.render(mv.getModel(), request, response);
handler์—๋Š” MemberSaveControllerV3๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž. ๊ทธ๋Ÿฌ๋ฉด ๊ทธ์— ๋งž๋Š” ์–ด๋Œ‘ํ„ฐ๋ฅผ getHandAdatper๋ฅผ ํ†ตํ•ด ๊บผ๋‚ด์˜ฌ ๊ฒƒ์ด๋‹ค. ๊ทธ๋ ‡๊ฒŒ ๊บผ๋‚ด์˜จ ์–ด๋Œ‘ํ„ฐ๋Š” ControllerV3HandlerAdapter๊ฐ€ ๋œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  adapter.handle์€ ControllerV3HandlerAdapter์˜ handle ๋ฉ”์„œ๋“œ๊ฐ€ ๋˜๊ณ  ์ด๋ถ€๋ถ„์— ๋Œ€ํ•œ ๋‚ด์šฉ์ด ๋ฐ”๋กœ ์œ„์— ์žˆ๋Š” ๊ฒƒ์ด๋‹ค. handle ๋ฉ”์„œ๋“œ๋Š” ์ตœ์ข…์ ์œผ๋กœ mv๋ฅผ ๋ฆฌํ„ดํ–ˆ๋‹ค. ๊ทธ๋Ÿผ ModelView mv = adapter.handle(request, response, handler);์— ๋ฆฌํ„ด๋œ mv๊ฐ€ ๋“ค์–ด์˜ค๊ฒŒ ๋˜๊ณ , ๋ธŒ๋ผ์šฐ์ €์— ๊ฒฐ๊ณผ๊ฐ€ ๋ณด์ด๊ฒŒ ๋œ๋‹ค.

 

 

 

โ–ถ ์ˆœ์„œ (MemberSaveController)

  • ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ(FrontControllerServletV1)๋กœ ์š”์ฒญ์ด ๋“ค์–ด์˜จ๋‹ค
  • ๋“ค์–ด์˜จ ๊ฒฝ๋กœ๋กœ ์ €์žฅํ•ด๋‘” ๊ฐ์ฒด๋ฅผ ๊บผ๋‚ธ๋‹ค.
  • ๊ฐ์ฒด์™€ ์–ด๋Œ‘ํ„ฐ๊ฐ€ ๋งž๋Š”์ง€ supports ๋ฉ”์„œ๋“œ๋กœ ํ™•์ธ ํ›„ ๋งž์œผ๋ฉด ์ฐธ์„ ๋ณด๋‚ธ๋‹ค.
  • true๊ฐ€ ๋‚˜์˜ค๋ฉด ํ•ด๋‹น ์ปจํŠธ๋กค๋Ÿฌ ํด๋ž˜์Šค ๋‚ด๋ถ€์— ์žˆ๋Š” process ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.
  • ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด ์–ด๋Œ‘ํ„ฐ๊ฐ€ ๋ฐ›๊ณ  ์–ด๋Œ‘ํ„ฐ๋Š” ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋ฐ˜ํ™˜๋œ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ๋ทฐ๋กœ ๋ณด๋‚ธ๋‹ค.