우리는 왜 Servlet을 사용하지 않고, JSP를 사용하는가?
JSP를 활용하는 방식이 프로그래밍 하기 편하기 때문이다.그렇다면 이번 시간에는 JSP만 사용하는 방식에는 어떤 문제가 있는지 알아보고 MVC 패턴의 탄생 과정에 대해서 알아보자.
모델 1은 뷰와 로직을 모두 JSP 페이지 하나에서 처리하는 구조를 말한다.
https://github.com/codingspecialist/web3
server.xml -> port -> 8080
web.xml -> welcome file list -> index.jsp
src.shop.mtcoding.web.Board
package shop.mtcoding.web3.model;
public class Board {
private int id;
private String title;
private int userId;
public Board(int id, String title, int userId) {
this.id = id;
this.title = title;
this.userId = userId;
}
public int getId() {
return id;
}
public String getTitle() {
return title;
}
public int getUserId() {
return userId;
}
}
src.shop.mtcoding.web.User
package shop.mtcoding.web3.model;
public class User {
private int id;
private String username;
private String password;
public User(int id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public int getId() {
return id;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}
src.shop.mtcoding.web.FakeDao
package shop.mtcoding.web3.model;
// Fake DataAccessObject (데이터베이스에 접근하는 클래스)
public class FakeDao {
public User userData(){
User u1 = new User(1, "ssar", "1234");
return u1;
}
public Board boardData(){
Board b1 = new Board(1, "제목1", 1);
return b1;
}
}
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Model 1</title>
</head>
<body>
<h1>모델1 실습</h1>
<hr/>
<p>유저 데이터가 필요하면 user.jsp 호출, 게시글 데이터가 필요하면 board.jsp 호출</p>
</body>
</html>
user.jsp
<%@ page import="shop.mtcoding.web3.model.User" %>
<%@ page import="shop.mtcoding.web3.model.FakeDao" %>
<%@ page import="java.io.PrintWriter" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String httpMethod = request.getMethod();
if(httpMethod.equals("POST")){
response.setContentType("text/html; charset=utf-8");
PrintWriter pw = response.getWriter();
pw.println("잘못된 요청입니다");
return;
}
User u1 = new FakeDao().userData();
%>
<html>
<head>
<title>Model 1</title>
</head>
<body>
<h1>유저</h1>
<hr/>
<h3>번호 : <%=u1.getId()%></h3>
<h3>유저명 : <%=u1.getUsername()%></h3>
<h3>비밀번호 : <%=u1.getPassword()%></h3>
</body>
</html>
board.jsp
<%@ page import="shop.mtcoding.web3.model.FakeDao" %>
<%@ page import="shop.mtcoding.web3.model.Board" %>
<%@ page import="java.io.PrintWriter" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String httpMethod = request.getMethod();
if(httpMethod.equals("POST")){
response.setContentType("text/html; charset=utf-8");
PrintWriter pw = response.getWriter();
pw.println("잘못된 요청입니다");
return;
}
Board b1 = new FakeDao().boardData();
%>
<html>
<head>
<title>Model 1</title>
</head>
<body>
<h1>게시글</h1>
<hr/>
<h3>번호 : <%=b1.getId()%></h3>
<h3>제목 : <%=b1.getTitle()%></h3>
<h3>작성자 번호 : <%=b1.getUserId()%></h3>
</body>
</html>
<%
String httpMethod = request.getMethod();
if(httpMethod.equals("POST")){
response.setContentType("text/html; charset=utf-8");
PrintWriter pw = response.getWriter();
pw.println("잘못된 요청입니다");
return;
}
Board b1 = new FakeDao().boardData();
%>
FrontContoller 패턴은 지휘자를 만드는 것이다. 여러 클라이언트들의 요청이 있고 해당하는 요청을 처리하는 JSP파일이 있다고 가정하자. 요청을 보낼 때마다 특정한 작업을 하는 것이 필수적이라면 요청이 들어올 때마다 해당 작업을 실어서 보내야 하는데 이 결과 코드의 중복이 생기고 해당 작업을 누락한다면 최악의 경우에는 장애로 이어질 수도 있다.
이러한 까닭에 앞에서 언급한 지휘자가 필요한데 요청을 처리하는 지휘자는 해당 작업을 가지고 있고 해당 작업을 처리한 뒤에 요청에 맞는 JSP에게 전달해주는 역할을 하게 된다. 이것이 바로 FrontController 패턴이다.
https://github.com/codingspecialist/web4.git
src.shop.mtcoding.web4.FrontController.java
package shop.mtcoding.web4.controller;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("*.do")
public class FrontController extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String httpMethod = req.getMethod();
if(httpMethod.equals("POST")){
resp.setContentType("text/html; charset=utf-8");
PrintWriter pw = resp.getWriter();
pw.println("잘못된 요청입니다");
return;
}
String action = req.getRequestURI();
System.out.println("uri : "+action);
if(action.equals("/board.do")){
resp.sendRedirect("board.jsp");
}else if(action.equals("/user.do")){
resp.sendRedirect("user.jsp");
}else{
resp.setContentType("text/html; charset=utf-8");
PrintWriter pw = resp.getWriter();
pw.println("잘못된 요청입니다");
}
}
}
board.jsp
<%@ page import="shop.mtcoding.web4.model.FakeDao" %>
<%@ page import="shop.mtcoding.web4.model.Board" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
Board b1 = new FakeDao().boardData();
%>
<html>
<head>
<title>Model 1</title>
</head>
<body>
<h1>게시글</h1>
<hr/>
<h3>번호 : <%=b1.getId()%></h3>
<h3>제목 : <%=b1.getTitle()%></h3>
<h3>작성자 번호 : <%=b1.getUserId()%></h3>
</body>
</html>
user.jsp
<%@ page import="shop.mtcoding.web4.model.User" %>
<%@ page import="shop.mtcoding.web4.model.FakeDao" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
User u1 = new FakeDao().userData();
%>
<html>
<head>
<title>Model 1</title>
</head>
<body>
<h1>유저</h1>
<hr/>
<h3>번호 : <%=u1.getId()%></h3>
<h3>유저명 : <%=u1.getUsername()%></h3>
<h3>비밀번호 : <%=u1.getPassword()%></h3>
</body>
</html>
문제점 1
user.jsp 를 호출할 수도 있고, user.do를 호출할 수 도 있기 때문에 강제성이 없다.
user.jsp를 다이렉트하게 호출하는 것을 막을 필요가 있다.문제점 2
jsp 파일에서 쓸데 없는 자바 코드가 많다.문제점 3
request에 저장된 body 데이터를 유지하려면 세션에 저장하는 방법밖에 없다. 그런데 세션에는 무거운 데이터를 저장하면 좋지 않다.
web4 소스코드를 변경하여 문제점에 대해서 확인해보자
세션 데이터 만료
1. 브라우저를 다 종료하면
2. 시간이 만료되면
3. 서버가 껐다가 다시 켜지면
4. 세션을 강제로 제거!!리퀘스트 데이터 만료
https://github.com/codingspecialist/web5.git
RequestDispatcher를 사용하면 request, response가 새로 생기지 않는다.
내부적으로 request와 response를 유지한 채로 재 요청을 한다.장점
tomcat에 의해서 막히는 WEB-INF 보안 폴더에 접근이 가능하다.
src.shop.mtcoding.web5.controller.FrontController.java
package shop.mtcoding.web5.controller;
import shop.mtcoding.web5.model.Board;
import shop.mtcoding.web5.model.FakeDao;
import shop.mtcoding.web5.model.User;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("*.do")
public class FrontController extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String httpMethod = req.getMethod();
if(httpMethod.equals("POST")){
resp.setContentType("text/html; charset=utf-8");
PrintWriter pw = resp.getWriter();
pw.println("잘못된 요청입니다");
return;
}
String action = req.getRequestURI();
System.out.println("uri : "+action);
if(action.equals("/board.do")){
Board b1 = new FakeDao().boardData();
req.setAttribute("board", b1);
req.getRequestDispatcher("/WEB-INF/views/board.jsp").forward(req, resp);
}else if(action.equals("/user.do")){
User u1 = new FakeDao().userData();
req.setAttribute("user", u1);
req.getRequestDispatcher("/WEB-INF/views/user.jsp").forward(req, resp);
}else{
resp.setContentType("text/html; charset=utf-8");
PrintWriter pw = resp.getWriter();
pw.println("잘못된 요청입니다");
}
}
}
web/WEB-INF/views/board.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Model 1</title>
</head>
<body>
<h1>게시글</h1>
<hr/>
<h3>번호 : ${board.id}</h3>
<h3>제목 : ${board.title}</h3>
<h3>작성자 번호 : ${board.userId}</h3>
</body>
</html>
web/WEB-INF/views/user.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Model 1</title>
</head>
<body>
<h1>유저</h1>
<hr/>
<h3>번호 : ${user.id}</h3>
<h3>유저명 : ${user.username}</h3>
<h3>비밀번호 : ${user.password}</h3>
</body>
</html>
MVC 소프트웨어 디자인 패턴
- 모델: 데이터와 비즈니스 로직을 관리합니다.
- 뷰: 레이아웃과 화면을 처리합니다.
- 컨트롤러: 명령을 모델과 뷰 부분으로 라우팅합니다.
https://github.com/codingspecialist/mvcapp.git
추운 겨울이 가고 봄이 온다. (스프링 프레임워크)