Notice
Recent Posts
Recent Comments
Link
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
Tags
more
Archives
Today
Total
관리 메뉴

개발자입니다

[비트캠프] 75일차(16주차2일) - Servlet(MVC 모델II, EL, JSTL), myapp-47~48 본문

네이버클라우드 AIaaS 개발자 양성과정 1기/DBMS, SQL, JDBC, Servlet

[비트캠프] 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