[Spring] MVC 1ํธ (7) - MVC ํ๋ ์์ํฌ ๋ง๋ค๊ธฐ v1, v2, v3
๐ ํ๋ก ํธ ์ปจํธ๋กค๋ฌ
โ ํ๋ก ํธ ์ปจํธ๋กค๋ฌ ๋์ ์
- ํ๋ก ํธ ์ปจํธ๋กค๋ฌ ๋์ ์ ์๋ ๊ฐ ์ปจํธ๋กค๋ฌ์์ ๊ณตํต ๋ก์ง์ ๊ตฌํํด์ค์ผ ํ๋ค.
โ ํ๋ก ํธ ์ปจํธ๋กค๋ฌ ๋์ ํ
- ๋ชจ๋ ์์ฒญ ๋ฉ์ธ์ง๋ ๊ณตํต ๋ก์ง์ด ๊ตฌํ๋์ด ์๋ ํ๋ก ํธ ์ปจํธ๋กค๋ฌ๋ก ๋ค์ด์จ๋ค.
- ํ๋ก ํธ ์ปจํธ๋กค๋ฌ๋ ์์ฒญ์ ๋ง๋ ์ปจํธ๋กค๋ฌ๋ฅผ ์ฐพ์ ํธ์ถํด์ค๋ค.
- ํ๋ก ํธ ์ปจํธ๋กค๋ฌ์์ ์์ฒญ ๋ฉ์ธ์ง๋ฅผ ๋งคํ ์์ผ์ฃผ๋ฉด, ๋๋จธ์ง ์ปจํธ๋กค๋ฌ๋ ์๋ธ๋ฆฟ์ ์ฌ์ฉํ์ง ์์๋ ๋๋ค.
์คํ๋ง ์น MVC์ ํต์ฌ๋ FrontController
→ ์คํ๋ง ์น MVC์ DispatcherServlet์ด FrontController ํจํด์ผ๋ก ๊ตฌํ๋์ด ์์!
๐ MVC ํ๋ ์์ํฌ ์ง์ ๋ง๋ค์ด๋ณด๊ธฐ
โ v1 - ํ๋ก ํธ ์ปจํธ๋กค๋ฌ ๋์
HTTP ์์ฒญ์ด ๋ค์ด์ค๋ฉด ํ๋ก ํธ ์ปจํธ๋กค๋ฌ๋ ์์ฒญ์ URL์ ๋ฐํ์ผ๋ก ๋งคํ ์ ๋ณด์์ ์์ฒญ URL๊ณผ ๋ง๋ ์ปจํธ๋กค๋ฌ๋ฅผ ์ฐพ์ ํธ์ถํ๋ค. ๊ฐ ์ปจํธ๋กค๋ฌ๋ dispatcher.forward()๋ฅผ ์ฌ์ฉํด์ ๋ทฐ๋ฅผ ํธ์ถํ๋ค.
ControllerV1 ์ธํฐํ์ด์ค
public interface ControllerV1 {
void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
}
- ๊ฐ ์ปจํธ๋กค๋ฌ๋ ์ด ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ค.
- ํ๋ก ํธ ์ปจํธ๋กค๋ฌ๋ ์ด ์ธํฐํ์ด์ค์ process() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ๋ก์ง์ ์ผ๊ด์ฑ์ ๊ฐ์ ธ๊ฐ ์ ์๋ค.
FrontControllerV1
@WebServlet(name = "frontControllerServletV1", urlPatterns = "/front-controller/v1/*") // v1์ ์ด๋ค url์ด ๋ค์ด์๋ ํ๋ก ํธ ์ปจํธ๋กค๋ฌ ์๋ธ๋ฆฟ์ด ๋ฌด์กฐ๊ฑด ๋จผ์ ํธ์ถ
public class FrontControllerServletV1 extends HttpServlet {
private Map<String, ControllerV1> controllerMap = new HashMap<>();
// ์๋ธ๋ฆฟ์ด ์์ฑ๋ ๋ url์ ๋งคํ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์์ (Map์ ํํ: key=url, value=๊ฐ ์ปจํธ๋กค๋ฌ ๊ตฌํ ๊ฐ์ฒด)
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();// ์์ฒญ์ผ๋ก ๋ค์ด์ค๋ URI๋ฅผ ๊ทธ๋๋ก ๋ฐ์ ์ ์์
ControllerV1 controller = controllerMap.get(requestURI); // ๋คํ์ฑ ํ์ฉ (์ธํฐํ์ด์ค ํ์
์ผ๋ก ์ปจํธ๋กค๋ฌ ๊ฐ์ ธ์ด)
if(controller == null) { // ๋ค์ด์จ URI๊ฐ ์์ ๋ ์์ธ ์ฒ๋ฆฌ
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
// ์ธํฐํ์ด์ค์ ๋ฉ์๋ ํธ์ถ
controller.process(request, response);
}
}
- urlPatterns๋ฅผ "/front-controller/v1/*"๋ก ์ค์ ํ๋ฉด /front-controller/v1๋ฅผ ํฌํจํ ๋ชจ๋ ํ์ ์์ฒญ์ ์ด ์๋ธ๋ฆฟ์ผ๋ก ๋ค์ด์จ๋ค.
- controllerMap์๋ ๊ฐ ์ปจํธ๋กค๋ฌ์ url ๋งคํ ์ ๋ณด๋ฅผ ์ ์ฅํ๊ณ , ์ด๋ ์๋ธ๋ฆฟ์ด ์์ฑ๋ ๋ ๊ฐ์ง๊ณ ์๋๋ค.
- request.getRequestURI()๋ก ์์ฒญ์ผ๋ก ๋ค์ด์จ URI๋ฅผ key๋ก ์ฌ์ฉํด controllerMap์์ ์ปจํธ๋กค๋ฌ๋ฅผ ์ธํฐํ์ด์ค ํ์ ์ผ๋ก ๊ฐ์ ธ์จ๋ค. (๋คํ์ฑ)
- ๋ง์ฝ ์ปจํธ๋กค๋ฌ ์ค ์์ฒญ URI์ ๋ง๋ ์ปจํธ๋กค๋ฌ๊ฐ ์์ผ๋ฉด NOT_FOUND ์ํ ์ฝ๋๋ฅผ ๋ฐํํ๋ค.
- ์ปจํธ๋กค๋ฌ๊ฐ ์์ผ๋ฉด ์ปจํธ๋กค๋ฌ์ ๊ณตํต์ผ๋ก ๊ตฌํ๋์ด ์๋ process() ๋ฉ์๋๋ฅผ ํธ์ถํ๋ค.
→ ํ๋ก ํธ ์ปจํธ๋กค๋ฌ๋ฅผ ๋์ ํ๊ณ , Controller์ ์ธํฐํ์ด์ค๋ฅผ ๋์ ํด์ ๋ ํ์ฅ์ฑ ์๊ณ ์ผ๊ด์ ์ผ๋ก ๋ก์ง์ ์ฒ๋ฆฌํ ์ ์๊ฒ ๋์๋ค!
โ v2 - View ๋ถ๋ฆฌ
String viewPath = "/WEB-INF/views/new-form.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
๋ชจ๋ ์ปจํธ๋กค๋ฌ์์ ๋ทฐ๋ก ์ด๋ํ๋ ๋ถ๋ถ์ ์ค๋ณต์ด ์๋ค.
๊ธฐ์กด์๋ ์ปจํธ๋กค๋ฌ์์ ์ง์ JSP๋ฅผ forward ํด์ฃผ์์ง๋ง, ์ด์ Controller๋ MyView ๊ฐ์ฒด๋ฅผ ์์ฑํด์ FrontController์๊ฒ ๋๊ฒจ์ฃผ๊ธฐ๋ง ํ๋ฉด FrontController์์ ๋ทฐ๋ก ์ด๋ํ๋ ๋ก์ง์ ์คํํ๋ค.
MyView
public class MyView {
private String viewPath;
public MyView(String viewPath) {
this.viewPath = viewPath;
}
// ์๋ธ๋ฆฟ์์ jsp๋ก ์ด๋ํด์ ๋ ๋๋ง ๋๋๋ก ๋์
public void render(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
}
}
MyView ํด๋์ค์๋ ๋ทฐ์ ๊ฒฝ๋ก๋ฅผ ์ ์ฅํ ๋ณ์์ JSP๋ฅผ forwardํด์ฃผ๋ render() ๋ฉ์๋๋ฅผ ๊ตฌํํ๋ค.
ControllerV2 ์ธํฐํ์ด์ค
public interface ControllerV2 {
MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
}
์ด์ ๊ฐ ์ปจํธ๋กค๋ฌ๋ ๋ก์ง์ ์ํํ๊ณ MyView ๊ฐ์ฒด๋ฅผ ์์ฑํด์ ๋ฐํํ๋ค. ์ด๋ ๊ฐ ๋ทฐ์ ๊ฒฝ๋ก๋ฅผ ์ ๋ ฅํ๋ค.
FrontControllerV2
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// ๋๋จธ์ง ๋ถ๋ถ v1๊ณผ ๋์ผ
MyView myView = controller.process(request, response);
myView.render(request, response);
}
- Map์์ ๊ฐ์ ธ์จ ์ปจํธ๋กค๋ฌ์ ํธ์ถ ๊ฒฐ๊ณผ๋ก MyView ๊ฐ์ฒด๋ฅผ ๋ฐ๋๋ค. view.render()๋ฅผ ํธ์ถํ๋ฉด ๊ฐ ์ปจํธ๋กค๋ฌ์ ๋ง๋ forward ๋ก์ง์ด ์ํ๋๋ค.
→ ์ด์ ๊ฐ ์ปจํธ๋กค๋ฌ๊ฐ ์ง์ JSP๋ฅผ forward ํ์ง ์๊ณ , ํ๋ก ํธ ์ปจํธ๋กค๋ฌ์์ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ ๊ฐ ์ปจํธ๋กค๋ฌ์ ์ค๋ณต์ผ๋ก ๋ค์ด๊ฐ๋ forward ์ฝ๋๋ฅผ ์์ฑํด์ฃผ์ง ์์๋ ๋๋ค.
โ v3 - ๋ชจ๋ธ ์ถ๊ฐ
- ์๋ธ๋ฆฟ ์ข ์์ฑ ์ ๊ฑฐ : ์ปจํธ๋กค๋ฌ ์ ์ฅ์์ request์ response ๊ฐ์ฒด๊ฐ ํ์ํ์ง ์๋ค. ์์ฒญ ํ๋ผ๋ฏธํฐ ์ ๋ณด๋ฅผ ์๋ฐ์ Map์ผ๋ก ๋์ ๋๊ธฐ๋๋ก ํ๋ฉด ์ปจํธ๋กค๋ฌ๋ ์๋ธ๋ฆฟ ๊ธฐ์ ์ ๋ชฐ๋ผ๋ ๋๋ค.
- ๋ทฐ ์ด๋ฆ ์ค๋ณต ์ ๊ฑฐ : ๊ฒฝ๋ก๋ฅผ ์ง์ ํ๋ ๋ถ๋ถ๊ณผ ํ์ผ์ ํ์ฅ์ ๋ถ๋ถ์ ์์ฑํ๋ ๋ถ๋ถ์ด ์ค๋ณต๋๋ค. ๊ฐ ์ปจํธ๋กค๋ฌ๋ ๋ ผ๋ฆฌ ์ด๋ฆ๋ง ๋ฐํํ๋๋ก ํ๊ณ , ๋ฌผ๋ฆฌ ์์น์ ์ด๋ฆ์ ํ๋ก ํธ ์ปจํธ๋กค๋ฌ์์ ์ฒ๋ฆฌํ๋๋ก ํ์. (์ ์ง๋ณด์ ํธ๋ฆฌ)
์ง๊ธ๊น์ง ์ปจํธ๋กค๋ฌ์์ ์๋ธ๋ฆฟ์ ์ข ์์ ์ธ HttpServletRequest๋ฅผ ์ฌ์ฉํ๊ณ , Model๋ request.setAttribute()๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ๋ณด๊ดํ๊ณ ๋ทฐ์ ์ ๋ฌํ๋ค. ์ด๋ฒ ๋ฒ์ ์์๋ ์๋ธ๋ฆฟ์ ์ข ์์ฑ์ ์ ๊ฑฐํ๊ธฐ ์ํด Model์ ์ง์ ๋ง๋ค๊ณ , ๋ทฐ์ ๋ ผ๋ฆฌ ์ด๋ฆ์ ๋ฌผ๋ฆฌ ์ด๋ฆ์ผ๋ก ๋ฐ๊ฟ์ฃผ๋ ๊ฐ์ฒด๋ ์์ฑํด๋ณผ ๊ฒ์ด๋ค.
ModelView
public class ModelView {
private String viewName;
private Map<String, Object> model = new HashMap<>(); // key=์ด๋ฆ, value=๊ฐ์ฒด
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์ ๋ด์์ค๋ค.
- ๊ฐ ์ปจํธ๋กค๋ฌ๋ ๋ก์ง ์ํ ํ ModelView๋ฅผ ๋ฐํํ๋ค.
ํ์ ์ ์ฅ ์ปจํธ๋กค๋ฌ
public class MemberSaveControllerV3 implements ControllerV3 {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
public ModelView process(Map<String, String> paramMap) {
// ๊ธฐ์กด ๋ฐฉ์์ด์๋ getParameter() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ๋ถ๋ถ์ front controller์์ ์ฒ๋ฆฌํด์ค
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;
}
}
- ์ด์ ์ปจํธ๋กค๋ฌ์์๋ paramMap์์ ์์ฒญ ํ๋ผ๋ฏธํฐ์ ๊ฐ์ ๊บผ๋ด์ ๋น์ฆ๋์ค ๋ก์ง์ ์ํํ๋ค.
- ์ปจํธ๋กค๋ฌ์์ ModelView ๊ฐ์ฒด๋ฅผ ์์ฑํ๋๋ฐ, ์ด๋ ์์ฑ์์ ๋งค๊ฐ๋ณ์๋ก ๋ ผ๋ฆฌ ์ด๋ฆ์ ์ ๋ ฅํ๋ค.
- ModelView ๊ฐ์ฒด์ model์ ๋ทฐ๋ฅผ ๋ ๋๋ง ํ ๋ ํ์ํ ๊ฐ์ฒด๋ฅผ ๋ด๊ณ ๋ฐํํ๋ค.
FrontControllerV3
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// ์๋ต
Map<String, String> paramMap = createParamMap(request);
// request, response ๋์ paraMap์ ๋๊ฒจ์ค์ผ ํจ
ModelView mv = controller.process(paramMap);
String viewName = mv.getViewName();
MyView view = viewResolver(viewName);// ๋
ผ๋ฆฌ ์ด๋ฆ์ ๋ฌผ๋ฆฌ ์ด๋ฆ์ผ๋ก ๋ฐ๊ฟ์ค
view.render(mv.getModel(), request, response);
} // service
private MyView viewResolver(String viewName) {
return new MyView("/WEB-INF/views/" + viewName + ".jsp");
}
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;
}
- HttpServletRequest์์ ํ๋ผ๋ฏธํฐ ์ ๋ณด๋ฅผ ๊บผ๋ด์ paramMap์ ๋ฃ์ด๋๋ค.
- ์ด๋ ์์ฑ๋ paramMap์ ์ปจํธ๋กค๋ฌ๊ฐ ํธ์ถ๋ ๋ ์ ๋ฌ๋๋ค.
- viewResolver ๋ฉ์๋๋ ๋ ผ๋ฆฌ ์ด๋ฆ์ ๋ฐ์ ๋ฌผ๋ฆฌ ๋ทฐ ๊ฒฝ๋ก๋ก ๋ณํํ๊ณ , ์ค์ ๋ฌผ๋ฆฌ ๊ฒฝ๋ก๊ฐ ์๋ MyView ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค.
- render()๋ฅผ ์ํํ๊ฒ ๋๋ฉด ๋ทฐ ๋ ๋๋งํ ๋ ํ์ํ ๋ฐ์ดํฐ๊ฐ ๋ด๊ธด ๋ชจ๋ธ Map๋ ๋๊ฒจ์ค์ผ ํ๋ค.
MyView
public class MyView {
// ...
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);
}
// model์ ์๋ ๋ฐ์ดํฐ๋ฅผ request์ attribute๋ก ์ค์ -> JSP ์ฌ์ฉ ์ ํ์
private void modelToRequestAttribute(Map<String, Object> model, HttpServletRequest request) {
model.forEach((key, value) -> request.setAttribute(key,value));
}
}
- MyView์์๋ ๋์ด์จ ๋ชจ๋ธ Map์ ๊ฐ์ง๊ณ ๊ฐ ๋ฐ์ดํฐ์ ๋ํด request.setAttribute๋ฅผ ์ํํ๋ค.
๊ฐ์ ๋งํฌ
์คํ๋ง MVC 1ํธ - ๋ฐฑ์๋ ์น ๊ฐ๋ฐ ํต์ฌ ๊ธฐ์ - ์ธํ๋ฐ | ๊ฐ์
์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ ๋ ํ์ํ ๋ชจ๋ ์น ๊ธฐ์ ์ ๊ธฐ์ด๋ถํฐ ์ดํดํ๊ณ , ์์ฑํ ์ ์์ต๋๋ค. ์คํ๋ง MVC์ ํต์ฌ ์๋ฆฌ์ ๊ตฌ์กฐ๋ฅผ ์ดํดํ๊ณ , ๋ ๊น์ด์๋ ๋ฐฑ์๋ ๊ฐ๋ฐ์๋ก ์ฑ์ฅํ ์ ์์ต๋๋ค., -
www.inflearn.com