개발자입니다
[비트캠프] 75일차(16주차2일) - Servlet(MVC 모델II, EL, JSTL), myapp-47~48 본문
[비트캠프] 75일차(16주차2일) - Servlet(MVC 모델II, EL, JSTL), myapp-47~48
끈기JK 2023. 2. 21. 19:05
Web Application Architecture
1단계:
사용자가 ServletContainer 로 요청하면 여기서 Servlet 을 call 한다. 여기서 JDBC API 를 call 하고 여기서 DBMS 에 SQL 질의한다. 이를 리턴해서 사용자에게 응답한다.
2단계:
사용자가 ServletContainer 로 요청하면 여기서 Servlet 을 call 한다. Servlet 은 자바코드 중심이다. 여기서 DAO 를 call 하고 여기서 JDBC API 를 call 하고 여기서 DBMS 에 SQL 질의한다. 이를 리턴해서 사용자에게 응답한다.
- 데이터 처리를 캡슐화 → 객체로 분리
3단계:
사용자가 SevletContainer 로 요청하면 여기서 JSP 를 call 한다. JSP는 출력 중심 → UI 생성(view 역할)이 쉽고, 업무에 따라 DAO 의 작업흐름 제어(출력제어) → 트랜잭션 제어 → Controller 역할 한다. JSP 에서 DAO (데이터 처리 → model 역할)를 call 하고 여기서 JDBC API 를 call 하고 여기서 DBMS 에 SQL 질의한다. 이를 리턴해서 사용자에게 응답한다.
- MVC I (모델) 아키텍처
47. MVC 모델 II
① MVC 모델 I
요청이 들어오면 ServletContainer 가 JSP 로 전달한다. 여기서 DAO 를 call 하고 (JDBC API 생략) 여기서 DBMS 로 SQL 질의한다. 그리고 리턴받아 응답한다.
→ JSP: Controller 와 View 역할을 쪼갠다.
② MVC 모델 II
요청이 들어오면 ServletContainer 가 Servlet 을 call 한다. Servlet(Controller) 은 업무로직 수행 → 실행흐름 제어 → UI 출력 제어한다. Servlet 에서 DAO(Model, 데이터 처리) 를 call 하고 여기서 DBMS 로 SQL 질의한다. 그리고 리턴받는데 Servlet 에서 Mobile 용 또는 Desktop 용 JSP(View) 로 결과를 던진다. 각 JSP 에서 Mobile 용 또는 Desktop 용 UI 생성해서 리턴하고 그걸 사용자에게 응답한다.
47. MVC 모델 II 예)
① 요청을 ServletContainer 가 받으면 ② service() 실행을 《Controller》BoardListServlet 에게 시킨다. 여기서 ③ findAll() 실행을 《Model》BoardDao 에게 시킨다. 여기서 DBMS 로 ④ SQL 질의하고 ⑤ 응답 받는다. Board List 를 ⑥ 생성하고 BoardListServlet 에게 ⑦ return 한다. 여기서 《View》list.jsp 로 ⑧ forward 하면 여기서 Board List 를 ⑨ 사용해서 ⑩ HTML UI 생성 해서 BoardListServlet 으로 ⑪ 리턴한다. 여기서 ServletContainer 로 ⑫ 리턴하면 사용자에게 ⑬ 응답 한다.
### 47. JSP에 있는 자바 코드를 Servlet으로 분리하기: MVC 모델 II
- MVC 구조에서 각 컴포넌트의 역할을 이해.
- include/forward 동작 원리를 이해.
myapp-45-server 에 있는 servlet 패키지를 복사해서 다시 가져온다.
Servlet 에 모두 Dispatcher 로 forward 보낸다.
@WebServlet("/student/list")
public class StudentListServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private StudentDao studentDao;
@Override
public void init() {
ServletContext ctx = getServletContext();
studentDao = (StudentDao) ctx.getAttribute("studentDao");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String keyword = request.getParameter("keyword");
List<Student> students = this.studentDao.findAll(keyword);
request.setAttribute("students", students);
request.getRequestDispatcher("/student/list.jsp").forward(request, response);
}
}
@WebServlet("/student/view")
public class StudentViewServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private StudentDao studentDao;
@Override
public void init() {
ServletContext ctx = getServletContext();
studentDao = (StudentDao) ctx.getAttribute("studentDao");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int studentNo = Integer.parseInt(request.getParameter("no"));
Student student = this.studentDao.findByNo(studentNo);
if (student != null) {
request.setAttribute("student", student);
}
request.getRequestDispatcher("/student/view.jsp").forward(request, response);
}
}
@WebServlet("/student/form")
public class StudentFormServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.getRequestDispatcher("/student/form.jsp").forward(request, response);
}
}
@WebServlet("/student/insert")
public class StudentInsertServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private TransactionManager txManager;
private MemberDao memberDao;
private StudentDao studentDao;
@Override
public void init() {
ServletContext ctx = getServletContext();
txManager = (TransactionManager) ctx.getAttribute("txManager");
memberDao = (MemberDao) ctx.getAttribute("memberDao");
studentDao = (StudentDao) ctx.getAttribute("studentDao");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Student student = new Student();
student.setName(request.getParameter("name"));
student.setEmail(request.getParameter("email"));
student.setPassword(request.getParameter("password"));
student.setTel(request.getParameter("tel"));
student.setPostNo(request.getParameter("postNo"));
student.setBasicAddress(request.getParameter("basicAddress"));
student.setDetailAddress(request.getParameter("detailAddress"));
student.setWorking(request.getParameter("working") != null);
student.setGender(request.getParameter("gender").charAt(0));
student.setLevel(Byte.parseByte(request.getParameter("level")));
txManager.startTransaction();
try {
memberDao.insert(student);
studentDao.insert(student);
txManager.commit();
} catch (Exception e) {
txManager.rollback();
e.printStackTrace();
request.setAttribute("error", "other");
}
request.getRequestDispatcher("/student/insert.jsp").forward(request, response);
}
}
@WebServlet("/student/update")
public class StudentUpdateServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private TransactionManager txManager;
private MemberDao memberDao;
private StudentDao studentDao;
@Override
public void init() {
ServletContext ctx = getServletContext();
txManager = (TransactionManager) ctx.getAttribute("txManager");
memberDao = (MemberDao) ctx.getAttribute("memberDao");
studentDao = (StudentDao) ctx.getAttribute("studentDao");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Student student = new Student();
student.setNo(Integer.parseInt(request.getParameter("no")));
student.setName(request.getParameter("name"));
student.setEmail(request.getParameter("email"));
student.setPassword(request.getParameter("password"));
student.setTel(request.getParameter("tel"));
student.setPostNo(request.getParameter("postNo"));
student.setBasicAddress(request.getParameter("basicAddress"));
student.setDetailAddress(request.getParameter("detailAddress"));
student.setWorking(request.getParameter("working") != null);
student.setGender(request.getParameter("gender").charAt(0));
student.setLevel(Byte.parseByte(request.getParameter("level")));
txManager.startTransaction();
try {
if (memberDao.update(student) == 1 &&
studentDao.update(student) == 1) {
txManager.commit();
} else {
request.setAttribute("error", "data");
}
} catch (Exception e) {
txManager.rollback();
e.printStackTrace();
request.setAttribute("error", "other");
}
request.getRequestDispatcher("/student/update.jsp").forward(request, response);
}
}
@WebServlet("/student/delete")
public class StudentDeleteServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private TransactionManager txManager;
private MemberDao memberDao;
private StudentDao studentDao;
@Override
public void init() {
ServletContext ctx = getServletContext();
txManager = (TransactionManager) ctx.getAttribute("txManager");
memberDao = (MemberDao) ctx.getAttribute("memberDao");
studentDao = (StudentDao) ctx.getAttribute("studentDao");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int studentNo = Integer.parseInt(request.getParameter("no"));
txManager.startTransaction();
try {
if (studentDao.delete(studentNo) == 1 &&
memberDao.delete(studentNo) == 1) {
txManager.commit();
} else {
request.setAttribute("error", "data");
}
} catch (Exception e) {
txManager.rollback();
e.printStackTrace();
request.setAttribute("error", "other");
}
request.getRequestDispatcher("/student/delete.jsp").forward(request, response);
}
}
jsp 파일은 데이터 처리 코드를 제거한다.
<%@page import="bitcamp.myapp.vo.Student"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%!
private static String getLevelText(int level) {
switch (level) {
case 0: return "비전공자";
case 1: return "준전공자";
default: return "전공자";
}
}
%>
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<title>비트캠프 - NCP 1기</title>
</head>
<body>
<h1>학생(JSP + MVC2)</h1>
<div><a href='form'>새 학생</a></div>
<table border='1'>
<tr>
<th>번호</th> <th>이름</th> <th>전화</th> <th>재직</th> <th>전공</th>
</tr>
<%
String keyword = request.getParameter("keyword");
List<Student> students = (List<Student>) request.getAttribute("students");
for (Student student : students) {
%>
<tr>
<td><%=student.getNo()%></td>
<td><a href='view?no=<%=student.getNo()%>'><%=student.getName()%></a></td>
<td><%=student.getTel()%></td>
<td><%=student.isWorking() ? "예" : "아니오"%></td>
<td><%=getLevelText(student.getLevel())%></td>
</tr>
<%
}
%>
</table>
<form action='list' method='get'>
<input type='text' name='keyword' value='<%=keyword != null ? keyword : ""%>'>
<button>검색</button>
</form>
</body>
</html>
<%@page import="bitcamp.myapp.vo.Student"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<title>비트캠프 - NCP 1기</title>
</head>
<body>
<h1>학생(JSP + MVC2)</h1>
<%
Student student = (Student) request.getAttribute("student");
if (student == null) {
%>
<p>해당 번호의 학생이 없습니다.</p>
<%
} else {
%>
<form id='student-form' action='update' method='post'>
<table border='1'>
<tr>
<th>번호</th>
<td><input type='text' name='no' value='<%=student.getNo()%>' readonly></td>
</tr>
<tr>
<th>이름</th>
<td><input type='text' name='name' value='<%=student.getName()%>'></td>
</tr>
<tr>
<th>이메일</th>
<td><input type='email' name='email' value='<%=student.getEmail()%>'></td>
</tr>
<tr>
<th>암호</th>
<td><input type='password' name='password'></td>
</tr>
<tr>
<th>전화</th>
<td><input type='tel' name='tel' value='<%=student.getTel()%>'></td>
</tr>
<tr>
<th>우편번호</th>
<td><input type='text' name='postNo' value='<%=student.getPostNo()%>'></td>
</tr>
<tr>
<th>기본주소</th>
<td><input type='text' name='basicAddress' value='<%=student.getBasicAddress()%>'></td>
</tr>
<tr>
<th>상세주소</th>
<td><input type='tel' name='detailAddress' value='<%=student.getDetailAddress()%>'></td>
</tr>
<tr>
<th>재직여부</th>
<td><input type='checkbox' name='working' <%=student.isWorking() ? "checked" : ""%>> 재직중</td>
</tr>
<tr>
<th>성별</th>
<td><input type='radio' name='gender' value='M' <%=student.getGender() == 'M' ? "checked" : ""%>>
<input type='radio' name='gender' value='W' <%=student.getGender() == 'W' ? "checked" : ""%>> 여</td>
</tr>
<tr>
<th>전공</th>
<td><select name='level'>"
<option value='0' <%=student.getLevel() == 0 ? "selected" : ""%>>비전공자</option>
<option value='1' <%=student.getLevel() == 1 ? "selected" : ""%>>준전공자</option>
<option value='2' <%=student.getLevel() == 2 ? "selected" : ""%>>전공자</option>
</select></td>
</tr>
<tr>
<th>등록일</th>
<td><%=student.getCreatedDate()%></td>
</tr>
</table>
<%
}
%>
<div>
<button id='btn-list' type='button'>목록</button>
<button>변경</button>
<button id='btn-delete' type='button'>삭제</button>
</div>
</form>
<script>
document.querySelector('#btn-list').onclick = function() {
location.href = 'list';
}
document.querySelector('#btn-delete').onclick = function() {
var form = document.querySelector('#student-form');
form.action = 'delete';
form.submit();
}
</script>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<title>비트캠프 - NCP 1기</title>
</head>
<body>
<h1>학생(JSP + MVC2)</h1>
<form action='insert' method='post'>
<table border='1'>
<tr>
<th>이름</th>
<td><input type='text' name='name'></td>
</tr>
<tr>
<th>이메일</th>
<td><input type='email' name='email'></td>
</tr>
<tr>
<th>암호</th>
<td><input type='password' name='password'></td>
</tr>
<tr>
<th>전화</th>
<td><input type='tel' name='tel'></td>
</tr>
<tr>
<th>우편번호</th>
<td><input type='text' name='postNo'></td>
</tr>
<tr>
<th>기본주소</th>
<td><input type='text' name='basicAddress'></td>
</tr>
<tr>
<th>상세주소</th>
<td><input type='tel' name='detailAddress'></td>
</tr>
<tr>
<th>재직여부</th>
<td><input type='checkbox' name='working'> 재직중</td>
</tr>
<tr>
<th>성별</th>
<td><input type='radio' name='gender' value='M' checked> 남
<input type='radio' name='gender' value='W'> 여</td>
</tr>
<tr>
<th>전공</th>
<td><select name='level'>
<option value='0'>비전공자</option>
<option value='1'>준전공자</option>
<option value='2'>전공자</option>
</select></td>
</tr>
</table>
<div>
<button>등록</button>
<button id='btn-cancel' type='button'>취소</button>
</div>
</form>
<script>
document.querySelector('#btn-cancel').onclick = function() {
location.href = 'list';
}
</script>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<meta http-equiv='Refresh' content='1;url=list'>
<title>비트캠프 - NCP 1기</title>
</head>
<body>
<h1>학생(JSP + MVC2)</h1>
<%
String error = (String) request.getAttribute("error");
if (error == null) {
%>
<p>입력했습니다.</p>
<%
} else {
%>
<p>입력 실패입니다.</p>
<%
}
%>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<meta http-equiv='Refresh' content='1;url=list'>
<title>비트캠프 - NCP 1기</title>
</head>
<body>
<h1>학생(JSP + MVC2)</h1>
<%
String error = (String) request.getAttribute("error");
if (error == null) {
%>
<p>변경했습니다.</p>
<%
} else if (error.equals("data")) {
%>
<p>해당 번호의 학생이 없습니다.</p>
<%
} else {
%>
<p>변경 실패입니다.</p>
<%
}
%>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<meta http-equiv='Refresh' content='1;url=list'>
<title>비트캠프 - NCP 1기</title>
</head>
<body>
<h1>학생(JSP + MVC2)</h1>
<%
String error = (String) request.getAttribute("error");
if (error == null) {
%>
<p>삭제했습니다.</p>
<%
} else if (error.equals("data")) {
%>
<p>해당 번호의 학생이 없습니다.</p>
<%
} else {
%>
<p>삭제 실패입니다.</p>
<%
}
%>
</body>
</html>
JSP 구동 원리
list.jsp 실행해달라고 ServletContainer 에게 요청한다. ServletContaine 는
JSP 파일이 변경되었나? 묻고
yes면(또는 한 번도 실행한 적이 없다면) list.jsp 를 JSP Engine 이 list.java (서블릿 구현 클래스 자바 소스 파일)로 ① 생성한다. list.java 를 Java Compiler 가 ② 컴파일해서 list.class 를 만든다. 여기서 ③ new 로 인스턴스 생성하고 init() 호출한다.
no면 서블릿 인스턴스의 service() 호출한다.
list.jsp 가 JSP Engine 에 의해 변경된 파일은 list_jsp.java 의 형식으로 저장되며 경로는 다음과 같다.
eclipse-workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\work\Catalina\localhost\web\
org\apache\jsp\board\list_jsp.java
JSP 파일에 작성한 엘리먼트 들은 해당 파일에 다음과 같이 저장된다.
<%내용 %> → _jspService(...) {
내용
}
<%!선언 %> → class list_jsp ... {
선언
...
}
<%@내용 %> → import 는 최상단에
contentType="text/html; charset=UTF-8" 는 다음 자바 코드 생성
response.setContentType("text/html; charset=UTF-8");
기타 다른 코드들도 있다.
<%=a %> → out.print(a);
a → out.print("a");
_jspservice() 의 변수로 pageContext, session, application, page, out, config 등이 정의되어 있어서 .jsp 에서 사용할 수 있는 것이다.
public final class list_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
if (!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
final java.lang.String _jspx_method = request.getMethod();
if ("OPTIONS".equals(_jspx_method)) {
response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
return;
}
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) {
response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP들은 오직 GET, POST 또는 HEAD 메소드만을 허용합니다. Jasper는 OPTIONS 메소드 또한 허용합니다.");
return;
}
}
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html; charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\r\n");
out.write("\r\n");
out.write("<!DOCTYPE html>\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("<meta charset='UTF-8'>\r\n");
out.write("<title>비트캠프 - NCP 1기</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write("<h1>게시판(JSP + MVC2 + EL + JSTL)</h1>\r\n");
out.write("\r\n");
out.write("<div><a href='form'>새 글</a></div>\r\n");
out.write("\r\n");
out.write("<table border='1'>\r\n");
out.write("<tr>\r\n");
out.write(" <th>번호</th> <th>제목</th> <th>작성일</th> <th>조회수</th>\r\n");
out.write("</tr>\r\n");
if (_jspx_meth_c_005fforEach_005f0(_jspx_page_context))
return;
out.write("\r\n");
out.write("</table>\r\n");
out.write("\r\n");
out.write("<form action='list' method='get'>\r\n");
out.write(" <input type='text' name='keyword' value='");
out.write((java.lang.String) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${param.keyword}", java.lang.String.class, (javax.servlet.jsp.PageContext)_jspx_page_context, null));
out.write("'>\r\n");
out.write(" <button>검색</button>\r\n");
out.write("</form>\r\n");
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>\r\n");
out.write("\r\n");
} catch (java.lang.Throwable t) {
/* 생략 */
위 list_jsp 클래스는 HttpJspBase 를 상속한다.
(C:\Users\bitcamp\server\apache-tomcat-9.0.71-src\java\org\apache\jasper\runtime\HttpJspBase.java)
여기서 init() 재정의되어 있는데 super.init() 을 먼저 호출하고 jspInit() 을 호출한다. destroy() 도 마찬가지이다.
service() 실행하면 _jspService() 실행한다.
public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {
private static final long serialVersionUID = 1L;
protected HttpJspBase() {
}
@Override
public final void init(ServletConfig config)
throws ServletException
{
super.init(config);
jspInit();
_jspInit();
}
@Override
public String getServletInfo() {
return Localizer.getMessage("jsp.engine.info", Constants.SPEC_VERSION);
}
@Override
public final void destroy() {
jspDestroy();
_jspDestroy();
}
/**
* Entry point into service.
*/
@Override
public final void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
_jspService(request, response);
}
@Override
public void jspInit() {
}
public void _jspInit() {
}
@Override
public void jspDestroy() {
}
protected void _jspDestroy() {
}
@Override
public abstract void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException;
}
JSP 엔진이 서블릿 클래스를 만드는 규칙
list.jsp (template 파일)로 서블릿 클래스를 생성한다. 서블릿 클래스는 《abstract》HttpServlet 를 상속한다. 여기는 《abstract》GenericServlet 를 상속한다. 여기는 《interface》Servlet 을 구현한다.
서블릿 클래스는 또한 《interface》HttpJspPage 를 구현하는데 이는 《interface》JspPage 를 상속한다. 여기는 《interface》Servlet 을 상속한다.
JspPage 는 jspInit(), jspDestroy() 가 있다. HttpJspPage 는 _jspService() 가 있다.
해당 서블릿의 service() {-} 를 호출하면 서블릿 클래스(list_jsp.java)의 @Override _jspService() {-} 를 call 한다.
해당 서블릿의 init() {-} 를 호출하면 서블릿 클래스의 @Override jspInit() {-} 를 call 한다.
해당 서블릿의 destroy() {-} 를 호출하면 서블릿 클래스의 @Override jspDestroy() {-} 를 call 한다.
48. EL, JSTL, JSP 액션태그 사용하기
Java API 문서 참고 : https://docs.oracle.com/javaee/7/api/
bitcamp.myapp.vo.Board 에서
bitcamp.myapp.vo : 패키지
Board : 클래스
<jsp:useBean id="---"></jsp:useBean> 에서
<jsp...> : 시작태그
</jsp...> : 끝태그
jsp : namespace
useBean : element = tag
id : attribute
JSP 액션태그에서 없는 번호를 지정하면 0이다.
JSTL 설치
central.sonatype.com 에서 jstl javax 검색 후 나오는 코드 복사한다.
build.gradle 에 붙여넣고 gradle eclipse 한다.
라이브러리 보면 jstl 추가되는데, org.apache.taglibs.standard 가 있어야 구현체가 있는 것이다.
Server-rendering vs Client-rendering
① Server Rendering → 서버에서 UI 생성
Web Browser 가 ① 요청을 Application Server 로 한다. 여기서 App 을 ② 실행한다. 여기서 ③ 작업 수행 → ④ UI 생성 하고 결과를 Application Server로 ⑤ return 한다. 여기서 Web Browser 로 ⑥ 응답(+ UI 코드) 한다. 여기서 ⑦ HTML/CSS/JS 출력 한다.
② Client Rendering → 클라이언트에서 UI 생성
Web Browser 가 ① 요청을 Application Server 로 한다. 여기서 App 을 ② 실행한다. 여기서 ③ 작업 수행 → ④ JSON/XML 생성 하고 Application Server로 결과를 ⑤ return 한다. 여기서 Web Browser 로 ⑥ 응답(JSON/XML) 한다. 여기서 ⑦ JSON/XML 형식의 데이터를 가지고 UI 생성 및 출력 한다.
### 48. EL과 JSTL 사용하기: JSP에서 자바 코드 제거하는 방법
- EL 사용법: OGNL 표기법으로 객체 프로퍼티를 좀 더 쉽게 다루기
- JSTL 사용법
/student/* 를 예를 들 코드 첨부 한다.
list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<title>비트캠프 - NCP 1기</title>
</head>
<body>
<h1>학생(JSP + MVC2 + EL + JSTL)</h1>
<div><a href='form'>새 학생</a></div>
<table border='1'>
<tr>
<th>번호</th> <th>이름</th> <th>전화</th> <th>재직</th> <th>전공</th>
</tr>
<c:forEach items="${students}" var="student">
<tr>
<td>${student.no}</td>
<td><a href='view?no=${student.no}'>${student.name}</a></td>
<td>${student.tel}</td>
<td>${student.working ? "예" : "아니오"}</td>
<td>
<c:choose>
<c:when test="${student.level == 0}">비전공자</c:when>
<c:when test="${student.level == 1}">준전공자</c:when>
<c:when test="${student.level == 2}">전공자</c:when>
<c:otherwise>기타</c:otherwise>
</c:choose>
</td>
</tr>
</c:forEach>
</table>
<form action='list' method='get'>
<input type='text' name='keyword' value='${param.keyword}'>
<button>검색</button>
</form>
</body>
</html>
view.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<title>비트캠프 - NCP 1기</title>
</head>
<body>
<h1>학생(JSP + MVC2 + EL + JSTL)</h1>
<c:if test="${empty student}">
<p>해당 번호의 학생이 없습니다.</p>
<div>
<button id='btn-list' type='button'>목록</button>
</div>
</c:if>
<c:if test="${not empty student}">
<form id='student-form' action='update' method='post'>
<table border='1'>
<tr>
<th>번호</th>
<td><input type='text' name='no' value='${student.no}' readonly></td>
</tr>
<tr>
<th>이름</th>
<td><input type='text' name='name' value='${student.name}'></td>
</tr>
<tr>
<th>이메일</th>
<td><input type='email' name='email' value='${student.email}'></td>
</tr>
<tr>
<th>암호</th>
<td><input type='password' name='password'></td>
</tr>
<tr>
<th>전화</th>
<td><input type='tel' name='tel' value='${student.tel}'></td>
</tr>
<tr>
<th>우편번호</th>
<td><input type='text' name='postNo' value='${student.postNo}'></td>
</tr>
<tr>
<th>기본주소</th>
<td><input type='text' name='basicAddress' value='${student.basicAddress}'></td>
</tr>
<tr>
<th>상세주소</th>
<td><input type='tel' name='detailAddress' value='${student.detailAddress}'></td>
</tr>
<tr>
<th>재직여부</th>
<td><input type='checkbox' name='working' ${student.working ? "checked" : ""}> 재직중</td>
</tr>
<tr>
<th>성별</th>
<td><input type='radio' name='gender' value='M' ${student.gender == 'M'.charAt(0) ? "checked" : ""}> 남
<input type='radio' name='gender' value='W' ${student.gender == 'W'.charAt(0) ? "checked" : ""}> 여</td>
</tr>
<tr>
<th>전공</th>
<td><select name='level'>"
<option value='0' ${student.level == 0 ? "selected" : ""}>비전공자</option>
<option value='1' ${student.level == 1 ? "selected" : ""}>준전공자</option>
<option value='2' ${student.level == 2 ? "selected" : ""}>전공자</option>
</select></td>
</tr>
<tr>
<th>등록일</th>
<td>${student.createdDate}</td>
</tr>
</table>
<div>
<button id='btn-list' type='button'>목록</button>
<button>변경</button>
<button id='btn-delete' type='button'>삭제</button>
</div>
</form>
</c:if>
<script>
document.querySelector('#btn-list').onclick = function() {
location.href = 'list';
}
<c:if test="${not empty student}">
document.querySelector('#btn-delete').onclick = function() {
var form = document.querySelector('#student-form');
form.action = 'delete';
form.submit();
}
</c:if>
</script>
</body>
</html>
form.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<title>비트캠프 - NCP 1기</title>
</head>
<body>
<h1>학생(JSP + MVC2)</h1>
<form action='insert' method='post'>
<table border='1'>
<tr>
<th>이름</th>
<td><input type='text' name='name'></td>
</tr>
<tr>
<th>이메일</th>
<td><input type='email' name='email'></td>
</tr>
<tr>
<th>암호</th>
<td><input type='password' name='password'></td>
</tr>
<tr>
<th>전화</th>
<td><input type='tel' name='tel'></td>
</tr>
<tr>
<th>우편번호</th>
<td><input type='text' name='postNo'></td>
</tr>
<tr>
<th>기본주소</th>
<td><input type='text' name='basicAddress'></td>
</tr>
<tr>
<th>상세주소</th>
<td><input type='tel' name='detailAddress'></td>
</tr>
<tr>
<th>재직여부</th>
<td><input type='checkbox' name='working'> 재직중</td>
</tr>
<tr>
<th>성별</th>
<td><input type='radio' name='gender' value='M' checked> 남
<input type='radio' name='gender' value='W'> 여</td>
</tr>
<tr>
<th>전공</th>
<td><select name='level'>
<option value='0'>비전공자</option>
<option value='1'>준전공자</option>
<option value='2'>전공자</option>
</select></td>
</tr>
</table>
<div>
<button>등록</button>
<button id='btn-cancel' type='button'>취소</button>
</div>
</form>
<script>
document.querySelector('#btn-cancel').onclick = function() {
location.href = 'list';
}
</script>
</body>
</html>
insert.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<meta http-equiv='Refresh' content='1;url=list'>
<title>비트캠프 - NCP 1기</title>
</head>
<body>
<h1>학생(JSP + MVC2 + EL + JSTL)</h1>
<c:choose>
<c:when test="${empty error}">
<p>입력했습니다.</p>
</c:when>
<c:otherwise>
<p>입력 실패입니다.</p>
</c:otherwise>
</c:choose>
</body>
</html>
update.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<meta http-equiv='Refresh' content='1;url=list'>
<title>비트캠프 - NCP 1기</title>
</head>
<body>
<h1>학생(JSP + MVC2 + EL + JSTL)</h1>
<c:choose>
<c:when test="${empty error}">
<p>변경했습니다.</p>
</c:when>
<c:when test="${error == 'data'}">
<p>해당 번호의 학생이 없습니다.</p>
</c:when>
<c:otherwise>
<p>변경 실패입니다.</p>
</c:otherwise>
</c:choose>
</body>
</html>
delete.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<meta http-equiv='Refresh' content='1;url=list'>
<title>비트캠프 - NCP 1기</title>
</head>
<body>
<h1>학생(JSP + MVC2 + EL + JSTL)</h1>
<c:choose>
<c:when test="${empty error}">
<p>삭제했습니다.</p>
</c:when>
<c:when test="${error == 'data'}">
<p>해당 번호의 학생이 없습니다.</p>
</c:when>
<c:otherwise>
<p>삭제 실패입니다.</p>
</c:otherwise>
</c:choose>
</body>
</html>
조언
*전체 개발 업체 중 Servlet/JSP 40%, Thymeleaf 10%, 나머지는 프론트, 백 분리
*실무에서 기술 전체를 다 알고 일하는게 아니다. 필요한 부분을 부분적으로 빨리 학습해서 앞으로 나아간다. 단, 정제된 기술이 아니다. 책 한 권을 다보고 하면 가장 좋다.
과제
학습
- eomcs-java\eomcs-servlet\app\src\main\webapp 폴더의 el, jstl
'네이버클라우드 AIaaS 개발자 양성과정 1기 > DBMS, SQL, JDBC, Servlet' 카테고리의 다른 글
[비트캠프] 76일차(16주차3일) - Servlet(세션, 쿠키, 리다이렉트), myapp-49(로그인, 권한별 기능 제한) (0) | 2023.02.22 |
---|---|
[Java] 예제 소스 정리 - EL, JSTL (0) | 2023.02.21 |
[Java] 예제 소스 정리 - JSP (0) | 2023.02.20 |
[비트캠프] 74일차(16주차1일) - Servlet(보관소, 필터, 리스너, MVC 모델I), JSP(기초), myapp-44~46 (0) | 2023.02.20 |
[JDBC] 예제 소스 정리 - Servlet(서블릿, 필터, 리스너, 멀티파트, 썸네일, 리프레시, 리다이렉트, 쿠키, 세션) (0) | 2023.02.18 |