1. MVC의 디자인 패턴
우리는 지금까지 백단에서의 MVC 패턴을 배웠다.
주로 Spring Framework, Struts Framwork이다.
그런데 프론트단에서도 MVC 패턴을 사용하는 것이 있다.
주로 AngularJS, Vue, React 등이다.
백에서는 MVC가 접근하기 어렵지 않지만 프론트단에서의 접근은 생각보다 어려운 면이 있다.
왜냐하면 순차적 코딩이 아니라 이벤트 단위의 코딩이 필요하기 때문이다.
여기서 디자인 패턴이란 건축으로치면 공법에 해당하는 것으로 소프트웨어의 개발 방법을 공식화 한 것이다.
소수의 뛰어난 엔지니어가 해결한 문제를 다수의 엔지니어들이 처리 할 수 있도록 한 규칙이면서, 구현자들 간의 커뮤니케이션의 효율성을 높이는 기법인 것이다.
2. MVC패턴을 웹에 적용시켜보기
MVC의 개념을 웹에 적용해보자.
- 사용자가 웹사이트에 접속한다. (Uses)
- Controller는 사용자가 요청한 웹페이지를 서비스 하기 위해서 모델을 호출한다. (Manipulates)
- 모델은 데이터베이스나 파일과 같은 데이터 소스를 제어한 후에 그 결과를 리턴한다.
- Controller는 Model이 리턴한 결과를 View에 반영한다. (Updates)
- 데이터가 반영된 VIew는 사용자에게 보여진다. (Sees)
3. MVC 개념의 이해
1) Controller
사용자가 접근 한 URL에 따라서 사용자의 요청사항을 파악한 후에 그 요청에 맞는 데이터를 Model에 의뢰하고, 데이터를 View에 반영해서 사용자에게 알려준다.
2) Model
일반적으로 CI의 모델은 데이터베이스 테이블에 대응된다. 이를테면 Topic이라는 테이블은 topic_model이라는 Model을 만든다. 그런데 이 관계가 강제적이지 않기 때문에 규칙을 일관성 있게 정의하는 것이 필요하다.
3) View
View는 클라이언트 측 기술인 html/css/javascript들을 모아둔 컨테이너이다.
4) CI의 MVC 규칙
아래는 CI에서 Controller과 Model과 View 간의 관계를 시각화한 것이다.
4. MVC의 디자인 패턴 사용해보기
1) 직접 명령어로 삽입시키기
연습을 위해서 로그인 폼을 하나 만들고 MVC 디자인 패턴을 사용해보려 한다.
아래와 같은 형태의 로그인 폼이다.
회원 로그인
이 페이지의 주소는 http://localhost:9090/basic05_mvc/control/loginForm.jsp 이다.
이것을 우선 서블릿을 통해 JSP 페이지를 호출시키려 한다.
우선 클래스 파일을 만들고 HttpServlet 을 상속시킨 뒤 doGet() 메서드에 페이지를 이동하는 메서드를 이용해 JSP 페이지를 호출했다.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 전송방식 method=get 요청
// 페이지 이동
resp.sendRedirect("control/loginForm.jsp");
} // doGet() end
그리고 http://localhost:9090/basic05_mvc/login.do 를 입력했더니 어떻게 되었을까?
login.do 명령어를 통해 jsp 페이지를 곧바로 호출하는 것을 확인할 수 있다.
그런데 url 경로를 저렇게 쓰고 싶지 않다면?
내 jsp 파일의 경로를 노출시키고 싶지 않다면?
그래서 사용하는 것이 바로 RequestDispatcher 객체이다.
String view = "control/loginForm.jsp";
RequestDispatcher rd = req.getRequestDispatcher(view);
rd.forward(req, resp);
위의 코드를 보면 알다시피 이동하고자 하는 경로를 문자열로 담아둔 뒤 RequestDispatcher 를 활용하여 담아준다.
그리고 forward("요청한 값", "응답") 메서드를 사용하여 사용자에게 결과 페이지를 응답해준다.
결과를 봐보자.
url 주소가 변하지 않는 것을 확인할 수 있다.
2) 폼의 action을 사용하여 명령어 실행시키기
다음으론 폼이 submit 될 때 취해지는 action 요소에 명령어를 담아서 페이지 이동을 시키려한다.
<form method="post" action="loginproc.do">
loginproc.do 명령어를 web.xml에 등록시킨 뒤 class 까지 만들어주었다.
그리고 버튼을 눌러서 submit을 시키자 loginproc.do 명령어를 실행시킨다.
<!-- LoginProc.java 서블릿 등록 -->
<servlet>
<servlet-name>loginproc</servlet-name>
<servlet-class>net.control.LoginProc</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loginproc</servlet-name>
<url-pattern>/loginproc.do</url-pattern>
</servlet-mapping>
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 전송방식 method=post 요청
try {
// 1) 한글 인코딩
req.setCharacterEncoding("UTF-8");
// 2) 사용자가 요청한 정보를 req에서 가져와서 변수에 옮겨 담기
String uid = req.getParameter("uid").trim();
String upw = req.getParameter("upw").trim();
// 3) 요청한 사용자에게 응답
resp.setContentType("text/html; charset=UTF-8");
PrintWriter out = resp.getWriter();
out.print(" <!DOCTYPE html> ");
out.print(" <html> ");
out.print(" <head> ");
out.print(" <meta charset='UTF-8'> ");
out.print(" <title>환영합니다</title> ");
out.print(" </head> ");
out.print(" <body> ");
out.print(" <strong>로그인 결과</strong><br> ");
out.print(" 아이디 : <strong>" + uid + "</strong><br>");
out.print(" 비밀번호 : <strong>" + upw + "</strong>");
out.print(" </body> ");
out.print(" </html> ");
out.close();
} catch (Exception e) {
System.out.println("요청 실패 : " + e);
} // end
} // doPost() end
3) RequestDispatcher 클래스 사용하기
2번의 방식대로 하니 단점이 있다.
바로 출력에 있어서 너무 하드 코딩이 필요하다는 점.
그래서 이번에는 RequestDispatcher 클래스를 사용하여서 뷰단에 출력을 시키려한다.
우선 LoginProc.java 파일부터 확인해보자.
package net.control;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginProc extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 전송방식이 post 이면 service() 함수가 doPost() 함수를 호출함
try {
req.setCharacterEncoding("UTF-8");
String uid = req.getParameter("uid").trim();
String upw = req.getParameter("upw").trim();
if(uid.equals("itwill") && upw.equals("1234")) {
// 로그인 여부 확인(원래는 DAO에서 작업)
// 로그인 성공
req.setAttribute("r_uid", uid);
req.setAttribute("r_upw", upw);
} else {
// 로그인 실패
req.setAttribute("r_uid", "guest");
req.setAttribute("r_upw", "guest");
}
// 뷰 페이지 이동
String view = "control/loginResult.jsp";
RequestDispatcher rd = req.getRequestDispatcher(view);
rd.forward(req, resp);
} catch (Exception e) {
System.out.println("요청 실패 : " + e);
}
} // doPost() end
} // class end
코드를 살펴보면 알 수 있듯 RequestDispatcher 의 forward() 메서드를 활용하여 페이지를 이동시킨다.
이 때 전달되어지는 값들은 Request 스코프에 해당되기 때문에 페이지간 값이 공유되어진다.
이 값을 loginResult.jsp 로 넘겨주어서 아래와 같이 JSP 페이지에 출력시켰다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>환영합니다</title>
</head>
<body>
<h3><strong>로그인 결과</strong></h3>
1) JSP<br>
아이디 : <%=request.getAttribute("r_uid")%><br>
비밀번호 : <%=request.getAttribute("r_upw")%><br>
2) EL<br>
아이디 : ${requestScope.r_uid}<br>
비밀번호 : ${requestScope.r_upw}<br>
3) EL(스코프 생략)<br>
아이디 : ${r_uid}<br>
비밀번호 : ${r_upw}<br>
</body>
</html>
쓰여진 값에 주목하자.
JSP 방식과 EL 방식 모두 request 객체를 통해 불러오고 있다.
위에서 작성했던 LoginProc에 저장된 값들을 그대로 받아온 것이다.
최종 결과 화면은 아래와 같다.
* 로그인을 유지하고 싶을 시 request가 아니라 session이나 application 영역에 담아야 한다.
HttpSession session = req.getSession(); // 요청한 사용자의 session 객체 선언
ServletContext application = req.getServletContext(); // 요청한 사용자의 application 객체 선언
session.setAttribute("s_uid", uid);
session.setAttribute("s_upw", upw);
application.setAttribute("a_uid", uid);
application.setAttribute("a_upw", upw);
'⁂ JSP > : 기본 익히기' 카테고리의 다른 글
[JSP] #12-2 Sevlet의 생명주기(LifeCycle) (0) | 2022.10.27 |
---|---|
[JSP] #12-1 HttpServlet 파헤치기! (0) | 2022.10.27 |
[JSP] #11-5 JSTL 제어문 (0) | 2022.10.26 |
[JSP] #11-4 JSTL(JSP Standard Tag Library, JSP전용태그) (0) | 2022.10.26 |
[JSP] #11-3 EL(Expression Language) - 내장 객체 (0) | 2022.10.26 |