- 회원 관리 웹 애플리케이션 요구사항
1. 회원 정보
1. 이름 : username
2. 나이 : age
2. 기능 요구사항
1. 회원 저장
2. 회원 목록 조회
- Servlet
@WebServlet(name = "memberFormServlet", urlPatterns = "/servlet/members/new-form")
public class MemberFormServlet extends HttpServlet {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
PrintWriter w = resp.getWriter();
w.write("<!DOCTYPE html>\n" +
"<html>\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>Title</title>\n" +
"</head>\n" +
"<body>\n" +
"<form action=\"/servlet/members/save\" method=\"post\">\n" +
" username: <input type=\"text\" name=\"username\" />\n" +
" age: <input type=\"text\" name=\"age\" />\n" +
" <button type=\"submit\">전송</button>\n" +
"</form>\n" +
"</body>\n" +
"</html>\n");
}
}
- 서블릿으로 회원 등록 폼을 전부 만들기 위해선 보이는 화면까지 자바 코드로 HTML을 작성해야 한다.
- 파라미터로 넘어오는 값은 String이기 때문에 int로 사용하고 싶다면 parseInt와 같이 형변환을 한 후 사용해야 한다.
- 템플릿엔진을사용하면 HTML 문서에서필요한곳만코드를적용해서동적으로변경할수있다.
- 템플릿엔진에는 JSP, Thymeleaf, Freemarker, Velocity등이있다.
- JSP
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
- 첫줄은 JSP문서라는뜻이다. JSP 문서는이렇게시작해야한다.
<%@ page import="hello.servlet.domain.member.Member" %>
<%@ page import="hello.servlet.domain.member.MemberRepository" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
//request, response 그냥 문법상 사용 가능
MemberRepository memberRepository = MemberRepository.getInstance();
System.out.println("MemberSaveServlet.service");
String username = request.getParameter("username");
int age = Integer.parseInt(request.getParameter("age"));
Member member = new Member(username, age);
memberRepository.save(member);
%>
<html>
<head>
<title>Title</title>
</head>
<body>
성공
<ul>
<li>id=<%=member.getId()%></li>
<li>username=<%=member.getUsername()%></li>
<li>age=<%=member.getAge()%></li>
</ul>
<a href="/index.html">메인</a>
</body>
</html>
- JSP는자바코드를그대로다사용할수있다.
- <%@ page import="hello.servlet.domain.member.MemberRepository" %>자바의 import 문과같다.
- <% ~~ %>이부분에는자바코드를입력할수있다.
- <%= ~~ %>이부분에는자바코드를출력할수있다.
- 회원저장 JSP를보면, 회원저장서블릿코드와같다. 다른점이있다면, HTML을중심으로하고, 자바코드를부분부분입력해주었다.<% ~ %>를사용해서 HTML 중간에자바코드를출력하고있다.
- JSP만 사용하게 되면 JSP에 JAVA코드, Repository, 등 다양한 코드가 노출이 되어 있다.
- MVC 패턴
- Model View Controller
- MVC 패턴은지금까지학습한것처럼하나의서블릿이나, JSP로처리하던것을컨트롤러(Controller)와뷰(View)라는영역으로서로역할을나눈것을말한다. 웹애플리케이션은보통이 MVC 패턴을사용한다.
1. 컨트롤러: HTTP 요청을받아서파라미터를검증하고, 비즈니스로직을실행한다. 그리고뷰에전달할결과데이터를조회해서모델에담는다.
2. 모델: 뷰에출력할데이터를담아둔다. 뷰가필요한데이터를모두모델에담아서전달해주는덕분에뷰는비즈니스로직이나데이터접근을몰라도되고, 화면을렌더링하는일에집중할수있다.
3. 뷰: 모델에담겨있는데이터를사용해서화면을그리는일에집중한다. 여기서는 HTML을생성하는부분을말한다.
- 서블릿을컨트롤러로사용하고, JSP를뷰로사용해서 MVC 패턴을적용한다.
- Model은 HttpServletRequest 객체를사용한다.
- request는내부에데이터저장소를가지고있는데,request.setAttribute(),request.getAttribute()를사용하면데이터를보관하고, 조회할수있다.
@WebServlet(name = "mvcMemberFormServlet", urlPatterns = "/servlet-mvc/members/new-form")
public class MvcMemberFormServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String viewPath = "/WEB-INF/views/new-form.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);//controller에서 view로 이동할 때 사용한다.
dispatcher.forward(request, response);
}
}
- dispatcher.forward() : 다른서블릿이나 JSP로이동할수있는기능이다. 서버내부에서다시호출이 발생한다.
- /WEB-INF : 이경로안에 JSP가있으면외부에서직접 JSP를호출할수없다. 우리가기대하는것은항상컨트롤러를통해서 JSP를호출하는것이다.
- redirect vs forward
1. 리다이렉트는실제클라이언트(웹브라우저)에응답이나갔다가, 클라이언트가 redirect 경로로다시요청한다. 따라서클라이언트가인지할수있고, URL 경로도실제로변경된다. 반면에포워드는서버내부에서일어나는호출이기때문에클라이언트가전혀인지하지못한다.
- new-form.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 상대경로 사용, [현재 URL이 속한 계층 경로 + /save] -->
<form action="save" method="post">
username: <input type="text" name="username" />
age: <input type="text" name="age" />
<button type="submit">전송</button>
</form>
</body>
</html>
- 여기서 form의 action을보면절대경로(/로시작)가아니라상대경로(/로시작X)인것을확인할수있다. 이렇게상대경로를사용하면폼전송시현재 URL이속한계층경로 + save가호출된다.
1. 현재계층경로:/servlet-mvc/members/
2. 결과:/servlet-mvc/members/save
@WebServlet(name = "mvcMemberSaveServlet", urlPatterns = "/servlet-mvc/members/save")
public class MvcMemberSaveServlet extends HttpServlet {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
int age = Integer.parseInt(req.getParameter("age"));
Member member = new Member(username, age);
memberRepository.save(member);
//Model에 데이터를 보관한다.
req.setAttribute("member", member);
String viewPath = "/WEB-INF/views/save-result.jsp";
RequestDispatcher dispatcher = req.getRequestDispatcher(viewPath);
dispatcher.forward(req,resp);
}
}
- HttpServletRequest를 Model로사용한다.
- request가제공하는setAttribute()를사용하면 request 객체에데이터를보관해서뷰에전달할수있다.
- 뷰는request.getAttribute()를사용해서데이터를꺼내면된다.
- save-result.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
성공
<ul>
<li>id=${member.id}</li>
<li>username=${member.username}</li>
<li>age=${member.age}</li>
</ul>
<a href="/index.html">메인</a>
</body>
</html>
- <%= request.getAttribute("member")%>로모델에저장한 member 객체를꺼낼수있지만, 너무복잡해진다.
- JSP는${}문법을제공하는데, 이문법을사용하면 request의 attribute에담긴데이터를편리하게조회할수있다.
@WebServlet(name = "mvcMemberListServlet", urlPatterns = "/servlet-mvc/members")
public class MvcMemberListServlet extends HttpServlet {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
List<Member> members = memberRepository.findAll();
req.setAttribute("members", members);
String viewPath = "/WEB-INF/views/members.jsp";
RequestDispatcher dispatcher = req.getRequestDispatcher(viewPath);
dispatcher.forward(req, resp);
}
}
- request 객체를사용해서List<Member> members를모델에보관했다.
- members.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/index.html">메인</a>
<table>
<thead>
<th>id</th>
<th>username</th>
<th>age</th>
</thead>
<tbody>
<c:forEach var="item" items="${members}">
<tr>
<td>${item.id}</td>
<td>${item.username}</td>
<td>${item.age}</td>
</tr>
</c:forEach>
</tbody>
</table>
</body>
</html>
- 모델에담아둔 members를 JSP가제공하는 taglib기능을사용해서반복하면서출력했다.members리스트에서member를순서대로꺼내서item변수에담고, 출력하는과정을반복한다.
- <c:forEach>이기능을사용하려면다음과같이선언해야한다.
* <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
- MVC 패턴 - 한계
- 포워드중복
1. View로이동하는코드가항상중복호출되어야한다. 물론이부분을메서드로공통화해도되지만, 해당메서드도항상직접호출해야한다.
- 사용하지않는코드
1. 다음코드를사용할때도있고, 사용하지않을때도있다. 특히 response는현재코드에서사용되지않는다.
- 공통 처리가 어렵다
출처 : 인프런 - 우아한 형제들 기술이사 김영한의 스프링 완전 정복 (스프링 핵심원리 - 기본 편)
'Programming > Servlet, JSP' 카테고리의 다른 글
Spring - Servlet + JSP를 이용한 MVC 동작 과정 정리 V5 (0) | 2023.06.16 |
---|---|
Spring - Servlet + JSP를 이용한 MVC 동작 과정 정리 V4 (0) | 2023.06.16 |
Spring - Servlet + JSP를 이용한 MVC 동작 과정 정리 V3 (0) | 2023.06.14 |
HttpServletRequest (1) | 2023.06.14 |
Spring - Servlet (0) | 2023.06.13 |