[Spring] 4.MVC ํ”„๋ ˆ์ž„์›Œํฌ ๋งŒ๋“ค๊ธฐ

 

1. ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ ํŒจํ„ด ์†Œ๊ฐœ

[ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ ๋„์ž… ์ „]

- ํด๋ผ์ด์–ธํŠธ์˜ ํ˜ธ์ถœ์„ ๋ฐ›๋Š” ์ž…๊ตฌ๊ฐ€ ์—†์Œ

 

[ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ ๋„์ž… ํ›„]

- ์ˆ˜๋ฌธ์žฅ ์—ญํ• ํ•˜๋Š” ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ ์„œ๋ธ”๋ฆฟ ํ•˜๋‚˜๋กœ ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ ๋ฐ›์Œ

- ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์š”์ฒญ์— ๋งž๋Š” ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ฐพ์•„์„œ ํ˜ธ์ถœ

- ๊ณตํ†ต ์ฒ˜๋ฆฌ ๊ธฐ๋Šฅ

- ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์„œ๋ธ”๋ฆฟ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋จ

 ์Šคํ”„๋ง ์›น MVC์˜ ํ•ต์‹ฌ๋„ ๋ฐ”๋กœ 'Front Controller'
'DispatcherServlet'์ด Front Controller ํŒจํ„ด์œผ๋กœ ๊ตฌํ˜„๋˜์–ด์žˆ์Œ

2. ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ  ๋„์ž… - v1

๋‹จ๊ณ„์ ์œผ๋กœ ๋„์ž…

๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์ตœ๋Œ€ํ•œ ์œ ์ง€ํ•˜๋ฉด์„œ ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ ๋„์ž…

๋จผ์ € ๊ตฌ์กฐ๋ฅผ ๋งž์ถ”๊ณ  ์ ์ง„์ ์œผ๋กœ ๋ฆฌํŒฉํ† ๋ง

 

'v1 ๊ตฌ์กฐ'

ControllerV1

 public interface ControllerV1 {
   void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
  }

- ์ปจํŠธ๋กค๋Ÿฌ ์ธํ„ฐํŽ˜์ด์Šค ๋„์ž…

- ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ์ปจํŠธ๋กค๋Ÿฌ ๋งŒ๋“ค์–ด์•ผํ•จ

- ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ˜ธ์ถœํ•ด์„œ ๊ตฌํ˜„๊ณผ ๊ด€๊ณ„์—†์ด ๋กœ์ง์˜ ์ผ๊ด€์„ฑ ๊ฐ€์ ธ๊ฐˆ ์ˆ˜ ์žˆ์Œ

 

์™œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“œ๋Š”๊ฐ€?

- ๊ฐ ์ปจํŠธ๋กค๋Ÿฌ ๋งŒ๋“ค๊ฑด๋ฐ ์š”์ฒญ ์ •๋ณด ๋“ค์–ด์™”์„๋•Œ ๋งตํ•‘ ์ •๋ณด ์ฐพ์•„์„œ ํ˜ธ์ถœํ•  ๋•Œ ์ผ๊ด€์„ฑ์žˆ๊ฒŒ ๋‹คํ˜•์„ฑ ์‚ฌ์šฉํ•ด์„œ Front Controller๋Š” ์ธํ„ฐํŽ˜์ด์Šค์— ์˜์กดํ•˜๋ฉด์„œ ํŽธ๋ฆฌํ•˜๊ฒŒ ํ˜ธ์ถœ ๊ฐ€๋Šฅ

 

 

ํšŒ์› ๋“ฑ๋ก ์ปจํŠธ๋กค๋Ÿฌ

MemberFormControllerV1

public class MemberFormControllerV1 implements ControllerV1 {
  @Override
  public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String viewPath = "/WEB-INF/views/new-form.jsp";
    RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
    dispatcher.forward(request, response);
  } 
}

 

ํšŒ์› ์ €์žฅ ์ปจํŠธ๋กค๋Ÿฌ

public class MemberSaveControllerV1 implements ControllerV1 {
  
  private MemberRepository memberRepository = MemberRepository.getInstance();
  
  @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);
  }
}

 

ํšŒ์› ๋ชฉ๋ก ์ปจํŠธ๋กค๋Ÿฌ

public class MemberListControllerV1 implements ControllerV1 {

  private MemberRepository memberRepository = MemberRepository.getInstance();
   
  @Override
  public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    List<Member> members = memberRepository.findAll();
    request.setAttribute("members", members);
    
    String viewPath = "/WEB-INF/views/members.jsp";
    RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
    dispatcher.forward(request, response);
  } 
}

 

์ค‘์š”) **

์œ„ ์ปจํŠธ๋กค๋Ÿฌ๋“ค์€ ๋ชจ๋‘ web-frontcontroller-v1-controller ํด๋” ์•ˆ์— ์กด์žฌ

ํ•˜์ง€๋งŒ ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ์˜ ๊ฒฝ์šฐ web-frontcontroleller-v1์— ์ƒ์„ฑ

 

ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ

@WebServlet(name = "frontControllerServletV1", urlPatterns = "/front-controller/v1/*")
public class FrontControllerServletV1 extends HttpServlet {
  
  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());
  }
  
  @Override
  protected void service(HttpServletRequest request, HttpServletResponse response)
              throws ServletException, IOException {
    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);
  }
}

- v1/* : v1ํ•˜์œ„์— ๋ญ๊ฐ€ ๋“ค์–ด์™€๋„ ์ง€๊ธˆ ํ•ด๋‹น ์„œ๋ธ”๋ฆฟ์ด ๋ฌด์กฐ๊ฑด ํ˜ธ์ถœ๋จ

* ์‹ค์ œ ๊ฐœ๋ฐœํ•  ๋• ์ ˆ๋Œ€๊ฒฝ๋กœ๋ฅผ ๋งŽ์ด ์”€

* ํŒจํ„ด ๋น„์Šทํ•œ ๊ฒฝ์šฐ ์ƒ๋Œ€๊ฒฝ๋กœ๋ฅผ ์จ๋„ ๋จ


3. ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ  ๋„์ž… - v2

๋ชจ๋“  ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋ทฐ๋กœ ์ด๋™ํ•˜๋Š” ๋ถ€๋ถ„์— ์ค‘๋ณต์ด ์žˆ๋Š” ๋ฌธ์ œ ํ•ด๊ฒฐ

-> ๋ทฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฐ์ฒด ์ƒ์„ฑ

1) ํด๋ผ์ด์–ธํŠธ๊ฐ€ HTTP ์š”์ฒญ

2) ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์ปจํŠธ๋กค๋Ÿฌ ์ฐพ์•„์™€์„œ ํ˜ธ์ถœ

3) ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์ง์ ‘ ํฌ์›Œ๋”ฉํ•˜์ง€ ์•Š๊ณ  MyView ๊ฐ์ฒด ๋งŒ๋“ค์–ด์„œ ๋ฐ˜ํ™˜ํ•˜๋ฉด,

4) ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๋Œ€์‹  JSP ํฌ์›Œ๋”ฉ

 

MyView

public class MyView {
  
  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);
  }
}

 

ControllerV2

public interface ControllerV2 {
  MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
}

 

ํšŒ์› ๋“ฑ๋ก ํผ

public class MemberFormControllerV2 implements ControllerV2 {
  @Override
  public MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    return new MyView("/WEB-INF/views/new-form.jsp");
  }
}

- ์ด์ œ ๊ฐ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ๋ณต์žกํ•œ dispatcher.forward() ํ˜ธ์ถœ ํ•„์š” ์—†์Œ

 

ํšŒ์› ์ €์žฅ

public class MemberSaveControllerV2 implements ControllerV2 {
  
  private MemberRepository memberRepository = MemberRepository.getInstance();
  
  @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");
  } 
}

 

ํšŒ์› ๋ชฉ๋ก

public class MemberListControllerV2 implements ControllerV2 {

  private MemberRepository memberRepository = MemberRepository.getInstance();

  @Override
  public MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    List<Member> members = memberRepository.findAll();
    request.setAttribute("members", members);
    return new MyView("/WEB-INF/views/members.jsp");
  }
}

 

ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ V2

@WebServlet(name = "frontControllerServletV2", urlPatterns = "/front-controller/v2/*")
public class FrontControllerServletV2 extends HttpServlet {

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

  public FrontControllerServletV2() {
    controllerMap.put("/front-controller/v2/members/new-form", new MemberFormControllerV2());
    controllerMap.put("/front-controller/v2/members/save", new MemberSaveControllerV2());
    controllerMap.put("/front-controller/v2/members", new MemberListControllerV2());
  }
  
  @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);
  }
}

- ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ ๋„์ž…์œผ๋กœ MyView ๊ฐ์ฒด์˜ render() ํ˜ธ์ถœํ•˜๋Š” ๋ถ€๋ถ„์„ ๋ชจ๋‘ ์ผ๊ด€๋˜๊ฒŒ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ

- ๊ฐ๊ฐ์˜ ์ปจํŠธ๋กค๋Ÿฌ๋Š” MyView ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ๋งŒํ•ด์„œ ๋ฐ˜ํ™˜ํ•˜๋ฉด๋จ


4. Model ์ถ”๊ฐ€ - v3

[์„œ๋ธ”๋ฆฟ ์ข…์†์„ฑ ์ œ๊ฑฐ]

- ์ปจํŠธ๋กค๋Ÿฌ ์ž…์žฅ์—์„œ request, response ํ•„์š”์—†์Œ  

- ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ์ •๋ณด < request.getParameter("") > ๋Š” ์ž๋ฐ”์˜ Map์œผ๋กœ ๋Œ€์‹  ๋„˜๊ธฐ๋ฉด ์ง€๊ธˆ ๊ตฌ์กฐ์—์„œ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์„œ๋ธ”๋ฆฟ ๊ธฐ์ˆ  ๋ชฐ๋ผ๋„ ๋™์ž‘ ๊ฐ€๋Šฅ

- request๊ฐ์ฒด๋ฅผ Model๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  ๋ณ„๋„์˜ Model ๊ฐ์ฒด ๋งŒ๋“ค์–ด์„œ ๋ฐ˜ํ™˜

 

์ฆ‰ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์„œ๋ธ”๋ฆฟ ๊ธฐ์ˆ  ์ „ํ˜€ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก

-> ์ฝ”๋“œ ๋‹จ์ˆœ / ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ ์‰ฌ์›Œ์ง!

 

[๋ทฐ ์ด๋ฆ„ ์ค‘๋ณต ์ œ๊ฑฐ]

- ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ง€์ •ํ•˜๋Š” ๋ทฐ ์ด๋ฆ„์— ์ค‘๋ณต์ด ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธ ๊ฐ€๋Šฅ

- ์ปจํŠธ๋กค๋Ÿฌ๋Š” '๋ทฐ์˜ ๋…ผ๋ฆฌ ์ด๋ฆ„'์„ ๋ฐ˜ํ™˜, ์‹ค์ œ ๋ฌผ๋ฆฌ ์œ„์น˜์˜ ์ด๋ฆ„์€ ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ฒ˜๋ฆฌํ•˜๋„๋ก ๋‹จ์ˆœํ™”

- ํ–ฅํ›„ ๋ทฐ์˜ ํด๋” ์œ„์น˜๊ฐ€ ํ•จ๊ป˜ ์ด๋™ํ•ด์„œ ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๋งŒ ๊ณ ์น˜๋ฉด ๋จ!

-> ๋ณ€๊ฒฝ์˜ ์ง€์ ์„ ํ•˜๋‚˜๋กœ ๋‘˜ ์ˆ˜ ์žˆ์Œ

/WEB-INF/views/new-form.jsp new-form
/WEB-INF/views/save-result.jsp save-result
/WEB-INF/views/members.jsp members

 

V3 ๊ตฌ์กฐ

ModelView

- ์„œ๋ธ”๋ฆฟ ์ข…์†์„ฑ ์ œ๊ฑฐํ•˜๊ธฐ ์œ„ํ•ด Model ์ง์ ‘ ๋งŒ๋“ค๊ณ  ์ถ”๊ฐ€๋กœ View ์ด๋ฆ„๊นŒ์ง€ ์ „๋‹ฌํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์•ผํ•จ

- ModelView ๊ฐ์ฒด๋Š” ๋‹ค๋ฅธ ๋ฒ„์ „์—์„œ๋„ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ํŒจํ‚ค์ง€๋ฅผ frontcontroller์— ๋‘ 

public class ModelView {
  
  private String viewName; // ๋ทฐ ๋…ผ๋ฆฌ์  ์ด๋ฆ„
  
  private Map<String, Object> model = new HashMap<>(); // ๋ชจ๋ธ
  
  public ModelView(String viewName) {
    this.viewName = viewName;
  }

  public String getViewName() {
    return viewName;
  }

  public void setViewName(String viewName) {
    this.viewName = viewName;
  }
  
  public Map<String, Object> getModel() {
    return model;
  }

  public void setModel(Map<String, Object> model) {
    this.model = model;
  } 
}

- ๋ทฐ ์ด๋ฆ„๊ณผ ๋ทฐ ๋ Œ๋”๋ง์‹œ ํ•„์š”ํ•œ model ๊ฐ์ฒด ๊ฐ€์ง€๊ณ ์žˆ์Œ

 

ControllerV3

public interface ControllerV3 {
  ModelView process(Map<String, String> paramMap);
}

- ํ”„๋ ˆ์ž„์›Œํฌ์— ์ข…์†์ ์ž„

- ์„œ๋ธ”๋ฆฟ์— ๋”์ด์ƒ ์ข…์†์ ์ด์ง€ ์•Š์Œ

์„ค๋ช…)

์ด ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์„œ๋ธ”๋ฆฟ ๊ธฐ์ˆ ์„ ์ „ํ˜€ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.
๋”ฐ๋ผ์„œ ๊ตฌํ˜„์ด ๋งค์šฐ ๋‹จ์ˆœํ•ด์ง€๊ณ , ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ์‹œ ํ…Œ์ŠคํŠธ ํ•˜๊ธฐ ์‰ฝ๋‹ค.

HttpServletRequest
๊ฐ€ ์ œ๊ณตํ•˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ paramMap์— ๋‹ด์•„์„œ ํ˜ธ์ถœํ•ด์ฃผ๋ฉด ๋œ๋‹ค.
์‘๋‹ต ๊ฒฐ๊ณผ๋กœ ๋ทฐ ์ด๋ฆ„๊ณผ ๋ทฐ์— ์ „๋‹ฌํ•  Model ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•˜๋Š” ModelView ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋œ๋‹ค

ํšŒ์› ๋“ฑ๋ก ํผ

public class MemberFormControllerV3 implements ControllerV3 {
  @Override
  public ModelView process(Map<String, String> paramMap) {
    return new ModelView("new-form");
  }
}

- ModelView ์ƒ์„ฑํ•  ๋•Œ new-form์ด๋ผ๋Š” view์˜ ๋…ผ๋ฆฌ์ ์ธ ์ด๋ฆ„ ์ง€์ •

- ์‹ค์ œ ๋ฌผ๋ฆฌ์  ์ด๋ฆ„์€ ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ฒ˜๋ฆฌ

 

ํšŒ์› ์ €์žฅ

public class MemberSaveControllerV3 implements ControllerV3 {
  
  private MemberRepository memberRepository = MemberRepository.getInstance();
  
  @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;
  } 
}

- ํŒŒ๋ผ๋ฏธํ„ฐ ์ •๋ณด๋Š” map์— ๋‹ด๊ฒจ์žˆ๊ธฐ ๋•Œ๋ฌธ์— map์—์„œ ํ•„์š” ํŒŒ๋ผ๋ฏธํ„ฐ ์กฐํšŒํ•˜๋ฉด ๋จ

- ๋ทฐ์— ํ•„์š”ํ•œ ๊ฐ์ฒด๋Š” map์— ๋‹ด์•„์„œ ๋ฐ˜ํ™˜

 

ํšŒ์› ๋ชฉ๋ก

public class MemberListControllerV3 implements ControllerV3 {
  
  private MemberRepository memberRepository = MemberRepository.getInstance();
  
  @Override
  public ModelView process(Map<String, String> paramMap) {
    List<Member> members = memberRepository.findAll();
    
    ModelView mv = new ModelView("members");
    mv.getModel().put("members", members);
    
    return mv;
  } 
}

 

๋จผ์ € MyView ์ˆ˜์ •

public class MyView {
  
  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);
  }

  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 void modelToRequestAttribute(Map<String, Object> model, HttpServletRequest request) {
    model.forEach((key, value) -> request.setAttribute(key, value));
  }
  
}

 

ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ ์„œ๋ธ”๋ฆฟ

@WebServlet(name = "frontControllerServletV3", urlPatterns = "/front-controller/v3/*")
public class FrontControllerServletV3 extends HttpServlet {
  
  private Map<String, ControllerV3> controllerMap = new HashMap<>();
  
  public FrontControllerServletV3() {
    controllerMap.put("/front-controller/v3/members/new-form", new MemberFormControllerV3());
    controllerMap.put("/front-controller/v3/members/save", new MemberSaveControllerV3());
    controllerMap.put("/front-controller/v3/members", new MemberListControllerV3());
  }
  
  @Override
  protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    String requestURI = request.getRequestURI();
    ControllerV3 controller = controllerMap.get(requestURI);
    
    if (controller == null) {
      response.setStatus(HttpServletResponse.SC_NOT_FOUND);
      return; 
    }
    
    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 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;
  }

  private MyView viewResolver(String viewName) {
    return new MyView("/WEB-INF/views/" + viewName + ".jsp");
  } 
}

 

createParamMap()

HttpServletRequest์—์„œ ํŒŒ๋ผ๋ฏธํ„ฐ ์ •๋ณด๋ฅผ ๊บผ๋‚ด์„œ Map์œผ๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น Map( paramMap )์„
์ปจํŠธ๋กค๋Ÿฌ์— ์ „๋‹ฌํ•˜๋ฉด์„œ ํ˜ธ์ถœํ•œ๋‹ค.

 

๋ทฐ ๋ฆฌ์กธ๋ฒ„

์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ๋…ผ๋ฆฌ ๋ทฐ ์ด๋ฆ„์„ ์‹ค์ œ ๋ฌผ๋ฆฌ ๋ทฐ ๊ฒฝ๋กœ๋กœ ๋ณ€๊ฒฝ
๊ทธ๋ฆฌ๊ณ  ์‹ค์ œ ๋ฌผ๋ฆฌ ๊ฒฝ๋กœ๊ฐ€ ์žˆ๋Š” MyView ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜

๋…ผ๋ฆฌ ๋ทฐ ์ด๋ฆ„: members
๋ฌผ๋ฆฌ ๋ทฐ ๊ฒฝ๋กœ: /WEB-INF/views/members.jsp

 

๋ทฐ ๋ Œ๋”

๋ทฐ ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด์„œ HTML ํ™”๋ฉด์„ ๋ Œ๋”๋ง ํ•œ๋‹ค.
๋ทฐ ๊ฐ์ฒด์˜ render() ๋Š” ๋ชจ๋ธ ์ •๋ณด๋„ ํ•จ๊ป˜ ๋ฐ›๋Š”๋‹ค.
JSP
๋Š” request.getAttribute() ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋ชจ๋ธ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊บผ๋‚ด์„œ request.setAttribute() ๋กœ ๋‹ด์•„๋‘”๋‹ค.
JSP
๋กœ ํฌ์›Œ๋“œ ํ•ด์„œ JSP๋ฅผ ๋ Œ๋”๋ง ํ•œ๋‹ค.

5. ๋‹จ์ˆœํ•˜๊ณ  ์‹ค์šฉ์ ์ธ ์ปจํŠธ๋กค๋Ÿฌ - v4

ModelView ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ถ€๋ถ„ ๋ฒˆ๊ฑฐ๋กœ์›€-> ์‹ค์ œ ๊ฐœ๋ฐœ ์‹œ ๋‹จ์ˆœ, ํŽธ๋ฆฌ ์‚ฌ์šฉ ์ค‘์š”(์‹ค์šฉ์„ฑ)

 

ํŽธ๋ฆฌํ•˜๊ฒŒ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๋Š” v4

v4 - v3์—์„œ ๊ฐœ์„ ๋œ ์ 

- ModelView๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๊ณ  ViewName ๋ฐ˜ํ™˜

 

ControllerV4

 public interface ControllerV4 {
      /**
       * @param paramMap
       * @param model
       * @return viewName
       */
      String process(Map<String, String> paramMap, Map<String, Object> model);
  }

- ์ธํ„ฐํŽ˜์ด์Šค์— ModelView๊ฐ€ ์—†์Œ -> ModelView๊ฐ€ ์•„๋‹Œ String(View์ด๋ฆ„)๋งŒ ๋ฐ˜ํ™˜

 

ํšŒ์› ์ €์žฅ

public class MemberSaveControllerV4 implements ControllerV4 {
  
  private MemberRepository memberRepository = MemberRepository.getInstance();
  
  @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";
  } 
}

* model์— ๋‹ด๊ธฐ๋งŒํ•˜๋ฉด ๊ทธ๋Œ€๋กœ ๋‚จ์•„์žˆ์–ด์„œ ๋ฐ˜ํ™˜ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค

* view์ด๋ฆ„๋งŒ ๋ฐ˜ํ™˜

@WebServlet(name = "frontControllerServletV4", urlPatterns = "/front-controller/v4/*")
public class FrontControllerServletV4 extends HttpServlet {
  
  private Map<String, ControllerV4> controllerMap = new HashMap<>();
  
  public FrontControllerServletV4() {
    controllerMap.put("/front-controller/v4/members/new-form", new MemberFormControllerV4());
    controllerMap.put("/front-controller/v4/members/save", new MemberSaveControllerV4());
    controllerMap.put("/front-controller/v4/members", new MemberListControllerV4());
  }
  
  @Override
  protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    String requestURI = request.getRequestURI();
    ControllerV4 controller = controllerMap.get(requestURI);
    if (controller == null) {
      response.setStatus(HttpServletResponse.SC_NOT_FOUND);
      return; 
    }
  
    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);
  }

  private 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;
  }
  
  private MyView viewResolver(String viewName) {
    return new MyView("/WEB-INF/views/" + viewName + ".jsp");
  } 
}

- frontcontroller๋Š” ์ด์ „๋ฒ„์ „๊ณผ ๋™์ผ (process์— model ์ถ”๊ฐ€๋กœ ๋„ฃ์–ด์ฃผ๋Š” ๊ฒƒ ๋ง๊ณ ๋Š”)


6. ์œ ์—ฐํ•œ ์ปจํŠธ๋กค๋Ÿฌ

์–ด๋–ค ๊ฐœ๋ฐœ์ž๋Š” V3๋ฐฉ์‹์œผ๋กœ ๊ฐœ๋ฐœํ•˜๊ณ ์‹ถ๊ณ , ์–ด๋–ค ๊ฐœ๋ฐœ์ž๋Š” V4๋ฐฉ์‹์œผ๋กœ ๊ฐœ๋ฐœํ•˜๊ณ ์‹ถ๋‹ค๋ฉด?

public interface ControllerV3 {
  ModelView process(Map<String, String> paramMap);
}
public interface ControllerV4 {
  String process(Map<String, String> paramMap, Map<String, Object> model);
}

 

์–ด๋Œ‘ํ„ฐ ํŒจํ„ด

- ๋‘ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ํ˜ธํ™˜์ด ๋ถˆ๊ฐ€

-> ์–ด๋Œ‘ํ„ฐ ํŒจํ„ด์„ ์‚ฌ์šฉํ•ด ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์˜ ์ปจํŠธ๋กค๋Ÿฌ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ณ€๊ฒฝํ•ด์•ผํ•จ

 

V5

ํ•ธ๋“ค๋Ÿฌ ์–ด๋Œ‘ํ„ฐ : ๋‹ค์–‘ํ•œ ์ข…๋ฅ˜์˜ ์ปจํŠธ๋กค๋Ÿฌ ํ˜ธ์ถœ ๊ฐ€๋Šฅ

ํ•ธ๋“ค๋Ÿฌ : ์ปจํŠธ๋กค๋Ÿฌ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํ•ด๋‹นํ•˜๋Š” ์ข…๋ฅ˜์˜ ์–ด๋Œ‘ํ„ฐ๋งŒ ์žˆ๋‹ค๋ฉด ๋ชจ๋‘ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ

 

MyHandlerAdapter

public interface MyHandlerAdapter {

  boolean supports(Object handler);
  
  ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException;
}

boolean supports (Object handler)

- handler๋Š” ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋งํ•จ

- ์–ด๋Œ‘ํ„ฐ๊ฐ€ ํ•ด๋‹น ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํŒ๋‹จํ•˜๋Š” ๋ฉ”์„œ๋“œ

 

ModelView handle()

- ์–ด๋Œ‘ํ„ฐ๋Š” ์‹ค์ œ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ๋กœ ModelView ๋ฐ˜ํ™˜ํ•ด์•ผํ•จ

- ์‹ค์ œ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ModelView ๋ฐ˜ํ™˜ํ•˜์ง€ ๋ชปํ•˜๋ฉด ์–ด๋Œ‘ํ„ฐ๊ฐ€ ModelView๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•ด์„œ๋ผ๋„ ๋ฐ˜ํ™˜ํ•ด์•ผํ•จ

- ์ด์ „์—” ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์‹ค์ œ ์ปจํŠธ๋กค๋Ÿฌ ํ˜ธ์ถœํ–ˆ์ง€๋งŒ ์ด์   ์ด ์–ด๋Œ‘ํ„ฐ๋ฅผ ํ†ตํ•ด ์‹ค์ œ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ํ˜ธ์ถœ๋จ

 

ControllerV3HandlerAdapter

public class ControllerV3HandlerAdapter implements MyHandlerAdapter {
  
  @Override
  public boolean supports(Object handler) {    // controllerV3 ์ฒ˜๋ฆฌํ•˜๋Š” ์–ด๋Œ‘ํ„ฐ
    return (handler instanceof ControllerV3);  
  }
  
  @Override
  public ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    ControllerV3 controller = (ControllerV3) handler; // ํ˜•๋ณ€ํ™˜ (ํƒ€์ž…๋ณ€ํ™˜ supports๋กœ ๊ฑธ๋Ÿฌ์ง€๋ฏ€๋กœ ์ž˜๋จ)
    Map<String, String> paramMap = createParamMap(request);
    ModelView mv = controller.process(paramMap);
    return mv; 
  }
  
  private 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;
  }
}

 

FrontControllerServletV5

@WebServlet(name = "frontControllerServletV5", urlPatterns = "/front-controller/v5/*")
public class FrontControllerServletV5 extends HttpServlet {
  
  private final Map<String, Object> handlerMappingMap = new HashMap<>();
  private final List<MyHandlerAdapter> handlerAdapters = new ArrayList<>();
  
  public FrontControllerServletV5() { // ์ƒ์„ฑ์ž
    initHandlerMappingMap();          // ํ•ธ๋“ค๋Ÿฌ ๋งตํ•‘ ์ดˆ๊ธฐํ™”
    initHandlerAdapters();            // ์–ด๋Œ‘ํ„ฐ์ดˆ๊ธฐํ™”
  }
  
  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());
  }

  private void initHandlerAdapters() {
    handlerAdapters.add(new ControllerV3HandlerAdapter());
  }

  @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);
  }
  
  private Object getHandler(HttpServletRequest request) {
    String requestURI = request.getRequestURI();
    return handlerMappingMap.get(requestURI);
  }
  
  private MyHandlerAdapter getHandlerAdapter(Object handler) {
    for (MyHandlerAdapter adapter : handlerAdapters) {
      if (adapter.supports(handler)) {
        return adapter;
      } 
    }
    throw new IllegalArgumentException("handler adapter๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. handler=" + handler);
  }
  
  private MyView viewResolver(String viewName) {
    return new MyView("/WEB-INF/views/" + viewName + ".jsp");
  }
}

์ปจํŠธ๋กค๋Ÿฌ <-> ํ•ธ๋“ค๋Ÿฌ

์–ด๋–ค ๊ฒƒ์ด๋ผ๋„ URL์— ๋งตํ•‘ ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•ธ๋“ค๋Ÿฌ

 

V6

์—ฌ๊ธฐ์— ControllerV4 ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ธฐ๋Šฅ ์ถ”๊ฐ€

@WebServlet(name = "frontControllerServletV6", urlPatterns = "/front-controller/v6/*")
public class FrontControllerServletV6 extends HttpServlet {
  
  private final Map<String, Object> handlerMappingMap = new HashMap<>();
  private final List<MyHandlerAdapter> handlerAdapters = new ArrayList<>();
  
  public FrontControllerServletV5() { // ์ƒ์„ฑ์ž
    initHandlerMappingMap();          // ํ•ธ๋“ค๋Ÿฌ ๋งตํ•‘ ์ดˆ๊ธฐํ™”
    initHandlerAdapters();            // ์–ด๋Œ‘ํ„ฐ์ดˆ๊ธฐํ™”
  }
  
  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());
    
    // V4์ถ”๊ฐ€
    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());
  }

  private void initHandlerAdapters() {
    handlerAdapters.add(new ControllerV3HandlerAdapter());
    handlerAdapters.add(new ControllerV4HandlerAdapter()); //V4 ์ถ”๊ฐ€
  }

  @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);
  }
  
  private Object getHandler(HttpServletRequest request) {
    String requestURI = request.getRequestURI();
    return handlerMappingMap.get(requestURI);
  }
  
  private MyHandlerAdapter getHandlerAdapter(Object handler) {
    for (MyHandlerAdapter adapter : handlerAdapters) {
      if (adapter.supports(handler)) {
        return adapter;
      } 
    }
    throw new IllegalArgumentException("handler adapter๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. handler=" + handler);
  }
  
  private MyView viewResolver(String viewName) {
    return new MyView("/WEB-INF/views/" + viewName + ".jsp");
  }
}

 

ControllerV4HandlerAdapter

public class ControllerV4HandlerAdapter implements MyHandlerAdapter {

  @Override
  public boolean supports(Object handler) {
    return (handler instanceof ControllerV4);
  }

  @Override
  public ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    ControllerV4 controller = (ControllerV4) handler;
    Map<String, String> paramMap = createParamMap(request);
    Map<String, Object> model = new HashMap<>();
    String viewName = controller.process(paramMap, model);
    ModelView mv = new ModelView(viewName);
    mv.setModel(model);
    return mv; 
  }
  
  private 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;
  }
 }

ControllerV4๋Š” ๋ทฐ์˜ ์ด๋ฆ„ ๋ฐ˜ํ™˜ -> ์–ด๋Œ‘ํ„ฐ๋Š” ๋ทฐ์˜ ์ด๋ฆ„์ด ์•„๋‹ˆ๋ผ ModelView๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋ฐ˜ํ™˜ํ•ด์•ผํ•จ 

-> ModelView ํ˜•์‹์œผ๋กœ ๋ฐ˜ํ™˜ํ•ด์คŒ

  • ๋„ค์ด๋ฒ„ ๋ธ”๋Ÿฌ๊ทธ ๊ณต์œ ํ•˜๊ธฐ
  • ๋„ค์ด๋ฒ„ ๋ฐด๋“œ์— ๊ณต์œ ํ•˜๊ธฐ
  • ํŽ˜์ด์Šค๋ถ ๊ณต์œ ํ•˜๊ธฐ
  • ์นด์นด์˜ค์Šคํ† ๋ฆฌ ๊ณต์œ ํ•˜๊ธฐ