[์ฐธ๊ณ ๊ฐ์] ๊น์ํ๋์ ์คํ๋ง MVC 1ํธ - ๋ฐฑ์๋ ์น ๊ฐ๋ฐ ํต์ฌ ๊ธฐ์
์ปจํธ๋กค๋ฌ ์
์ฅ์์ HttpServletRequest, HttpServletResponse๊ฐ ๊ผญ ํ์ํ ๊น?
์์ฒญ ํ๋ผ๋ฏธํฐ ์ ๋ณด๋ ์๋ฐ์ Map์ผ๋ก ๋์ ๋๊ธฐ๋๋ก ํ๋ฉด ์ง๊ธ ๊ตฌ์กฐ์์๋ ์ปจํธ๋กค๋ฌ๊ฐ ์๋ธ๋ฆฟ ๊ธฐ์ ์ ๋ชฐ๋ผ๋ ๋์ํ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ request ๊ฐ์ฒด๋ฅผ Model๋ก ใ
์ฉํ๋ ๋์ ์ ๋ณ๋์ Model ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ ๋ฐํํ๋ฉด ๋๋ค.
์ปจํธ๋กค๋ฌ์์ ์ง์ ํ๋ ๋ทฐ ์ด๋ฆ์ ์ค๋ณต์ด ์๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์ปจํธ๋กค๋ฌ๋ ๋ทฐ์ ๋
ผ๋ฆฌ ์ด๋ฆ์ ๋ฐํํ๊ณ , ์ค์ ๋ฌผ๋ฆฌ ์์น์ ์ด๋ฆ์ ํ๋ก ํธ ์ปจํธ๋กค๋ฌ์์ ์ฒ๋ฆฌํ๋๋ก ๋จ์ํํ์.
์ด๋ฌ๋ฉด ๋์ค์ ๋ทฐ ํด๋ ์์น๊ฐ ํจ๊ป ์ด๋ํด๋ ํ๋ก ํธ ์ปจํธ๋กค๋ฌ๋ง ๊ณ ์น๋ฉด๋๋ค.
ex) /WEB-INF/views/new-form.jsp
-> new-form
์๋ธ๋ฆฟ์ ์ข ์์ฑ์ ์ ๊ฑฐํ๊ธฐ ์ํด Model์ ์ง์ ๋ง๋ค๊ณ , ์ถ๊ฐ๋ก View ์ด๋ฆ๊น์ง ์ ๋ฌํ๋ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด๋ณด์.
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 ๊ฐ์ฒด๋ฅผ ๊ฐ์ง๊ณ ์๋ค. model์ ๋จ์ํ map์ผ๋ก ๋์ด ์์ผ๋ฏ๋ก ์ปจํธ๋กค๋ฌ์์ ๋ทฐ์ ํ์ํ ๋ฐ์ดํฐ๋ฅผ key, value๋ก ๋ฃ์ด์ฃผ๋ฉด ๋๋ค.
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;
}
}
paramMap.get("username");
ํ๋ผ๋ฏธํฐ ์ ๋ณด๋ map์ ๋ด๊ฒจ์๋ค. map์์ ํ์ํ ์์ฒญ ํ๋ผ๋ฏธํฐ๋ฅผ ์กฐํํ๋ฉด ๋๋ค.
mv.getModel().put("member", member);
๋ชจ๋ธ์ ๋จ์ํ map์ด๋ฏ๋ก ๋ชจ๋ธ์ ๋ทฐ์์ ํ์ํ member ๊ฐ์ฒด๋ฅผ ๋ด๊ณ ๋ฐํํ๋ค.
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;
}
}
@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/v2/members/new-form", new MemberFormControllerV3());
controllerMap.put("/front-controller/v2/members/save", new MemberSaveControllerV3());
controllerMap.put("/front-controller/v2/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;
}
//paramMap
Map<String, String> paramMap = createParamMap(request);
ModelView mv= controller.process(paramMap);
String viewName = mv.getViewName();//๋
ผ๋ฆฌ ์ด๋ฆ new-form
MyView view = viewResolver(viewName);
view.render(mv.getModel(), request, response);
}
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;
}
}
view.render(mv.getModel(), request, response)
์์ ์ปดํ์ผ ์ค๋ฅ๊ฐ ๋๋ฏ๋ก ๋ค์ ์ฝ๋๋ฅผ ์ฐธ๊ณ ํด์ MyView๊ฐ์ฒด์ ํ์ํ ๋ฉ์๋๋ฅผ ์ถ๊ฐํ์
createParamMap()
HttpServletRequest์์ ํ๋ผ๋ฏธํฐ ์ ๋ณด๋ฅผ ๊บผ๋ด์ Map์ผ๋ก ๋ณํํ๋ค. ๊ทธ๋ฆฌ๊ณ ํด๋น Map(paramMap)์ ์ปจํธ๋กค๋ฌ์ ์ ๋ฌํ๋ฉด์ ํธ์ถํ๋ค.
MyView view = viewResolver(viewName)
์ปจํธ๋กค๋ฌ๊ฐ ๋ฐํํ ๋
ผ๋ฆฌ ๋ทฐ ์ด๋ฆ์ ์ค์ ๋ฌผ๋ฆฌ ๋ทฐ ๊ฒฝ๋ก๋ก ๋ณ๊ฒฝํ๋ค. ๊ทธ๋ฆฌ๊ณ ์ค์ ๋ฌผ๋ฆฌ ๊ฒฝ๋ก๊ฐ ์๋ MyView ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค
view.render(mv.getModel(), request, response)
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));
}
}
v3 ์ปจํธ๋กค๋ฌ๋ ์๋ธ๋ฆฟ ์ข
์์ฑ์ ์ ๊ฑฐํ๊ณ ๋ทฐ ๊ฒฝ๋ก์ ์ค๋ณต์ ์ ๊ฑฐํ๋ฉฐ ์ ์ค๊ณ๋ ์ปจํธ๋กค๋ฌ์ด์ง๋ง, ํญ์ ModelView ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๋ฐํํด์ผ ํ๋ ๋ถ๋ถ์ด ์กฐ๊ธ ๋ฒ๊ฑฐ๋กญ๋ค.
v4๋ v3๋ฅผ ์กฐ๊ธ ๋ณ๊ฒฝํด์ ์ค์ฉ์ฑ ์๋ ์ฝ๋๋ก ๋ฐ๊ฟ๋ณด๊ฒ ๋ค!
์ปจํธ๋กค๋ฌ๊ฐ ModelView๋ฅผ ๋ฐํํ์ง ์๊ณ , ViewName๋ง ๋ฐํํ๋ค
public interface ControllerV4 {
String process(Map<String, String> paramMap, Map<String, Object> model);
}
model ๊ฐ์ฒด๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋๊ฒจ์ฃผ๊ณ ๊ฒฐ๊ณผ๋ก ๋ทฐ์ ์ด๋ฆ๋ง ๋ฐํํด์ค๋ค
public class MemberFormControllerV4 implements ControllerV4 {
@Override
public String process(Map<String, String> paramMap, Map<String, Object> model) {
return "new-form";
}
}
์ ๋ง ๋จ์ํ๊ฒ new-form์ด๋ผ๋ ๋ทฐ์ ๋ ผ๋ฆฌ ์ด๋ฆ๋ง ๋ฐํํ๋ฉด ๋๋ค!
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";
}
}
๋ชจ๋ธ์ด ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌ๋๊ธฐ ๋๋ฌธ์, ๋ชจ๋ธ์ ์ง์ ์์ฑํ์ง ์์๋ ๋๋ค.
public class MemberListControllerV4 implements ControllerV4 {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
public String process(Map<String, String> paramMap, Map<String, Object> model) {
List<Member> members = memberRepository.findAll();
model.put("members", members);
return "members";
}
}
์ด์ ๋ฒ์ ๊ณผ ๊ฑฐ์ ๋์ผํ๋ค
๋ชจ๋ธ ๊ฐ์ฒด ์ ๋ฌ
Map<String, Object> model = new HashMap<>(); //์ถ๊ฐ
๋ชจ๋ธ ๊ฐ์ฒด๋ฅผ ํ๋ก ํธ ์ปจํธ๋กค๋ฌ์์ ์์ฑํด์ ๋๊ฒจ์ค๋ค. ์ปจํธ๋กค๋ฌ์์ ๋ชจ๋ธ ๊ฐ์ฒด์ ๊ฐ์ ๋ด์ผ๋ฉด ์ฌ๊ธฐ์ ๊ทธ๋๋ก ๋ด๊ฒจ์๊ฒ ๋๋ค.
๋ทฐ์ ๋ ผ๋ฆฌ ์ด๋ฆ์ ์ง์ ๋ฐํ
String viewName = controller.process(paramMap, model);
MyView view = viewResolver(viewName);
ํ๋ ์์ํฌ๋ ๊ณตํต ๊ธฐ๋ฅ์ด ์๊ณ ๋ก์์ผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์๊ฐ ํธ๋ฆฌํด์ง๋ค!