필요성
동적인 html문서를 만들기 위해서는
java 파일 안에 저 html문서를 넣어야 하고
그러기 위해서는 out.write("<html>");처럼 코드 하나하나에
out.write()나 out.print()와 같은 코드를 추가해야 한다.
이는 매우 귀찮고 코드를 지저분하게 만들기 때문에
우리는 JSP의 Jasper를 통해서 html자체로 적되, 동적으로 만들어주는
방법을 이용하기로 했다.
따라서 이제는 .html문서가 아닌 .jsp문서를 통해서 view단을 만들기로 한다.
그 방법
이렇게 Jasper를 통해서 코드를 작성할 때
우리는 java코드를 심어야하는 경우가 있고 이를 코드 블럭이라고 한다.
이 코드블럭의 방법을 적절하게 이용해야 하며
<% %>,<%= %>,<%@ %>,<%! %> 이렇게 4가지의 코드 블럭이 있다.
1.<% %> 일반적이 로직
2.<%= %> 변수 출력
3.<%@ %> 지시 블럭
4.<%! %>함수,멤버변수
확장자는 .jsp이지만 결과물은 servlet이라는 것을 잊지말자
🐥 일단 앞서 50강에서 준비하 수업자료를 연다
이번 시간에 사용하는 코드 : notice> list.html
이를 복사해서 list2.jsp로 만든다.

list2.jsp를 열면 한글이 깨져 있다. 이는 우리가 한글에 대해서 response를 iso방식으로 받았기 때문이다.

따라서 Alt+Enter를 눌러서 Text file encoding 방식을 UTF-8로 바꿔주고 apply하면

이렇게 한글로 바뀐다.
하지만 요청이 들어와 응답을 할 때 브라우저가 이를 UTF-8 받아들이지 못했기 때문에
ctrl+f11을 하면

이와 같이 한글이 깨져서 나온다. 따라서 지시 블럭을 추가한다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
이를 외울 필요는 없다.
다른 방법이 있다.



이렇게 JSP 파일을 임의로 만들고 복사해서 가져와도 된다.

저 코드블럭을 넣었더니 한글이 제대로 출력되었다.
🐥 list2.jsp코드를 내려가다 보면 목록을 보여주는 부분이 있다.
이 부분을 이제 JDBC를 통해서 동적으로 DB에 있는 내용으로 바꾸기로 한다.
이번 시간에는 일단 for문을 이용해서 10개의 목록을 보여주는 부분을 배웠다.
<% for(int i=0;i<10;i++) { %>
<tr>
<td><%=i+1%></td>
<td class="title indent text-align-left"><a href="detail.html">스프링 8강까지의 예제 코드</a></td>
<td>newlec</td>
<td>
2019-08-18
</td>
<td>146</td>
</tr>
<%}%>
<%
String url ="jdbc:oracle:thin:@localhost:1521/xepdb1";
String sql = "SELECT * FROM NOTICE";
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con = DriverManager.getConnection(url,"NEWLEC","7351");
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(sql);
%>
이렇게 JDBC를 이용하기 위해서 코드블럭을 추가한다.
그런데 아마 빨간 줄이 그어질 텐데
이럴 때는 throws를 통해서 던지거나 import를 해야한다.
이 경우 클래스가 없기 때문에 import를 해야하며
그럴 경우 빨간줄 끝에 ctrl+space bar를 통해서 java.sql이라고 나와있는 클래스를 클릭한다.
그러면
<%@page import="java.sql.ResultSet"%>
<%@page import="java.sql.Statement"%>
<%@page import="java.sql.DriverManager"%>
<%@page import="java.sql.Connection"%>
<%
String url ="jdbc:oracle:thin:@localhost:1521/xepdb1";
String sql = "SELECT * FROM NOTICE";
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con = DriverManager.getConnection(url,"NEWLEC","비밀번호");
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(sql);
%>
위와 같이 import를 지시블럭이 추가된다.
이제 for문에 DB에 있는 내용을 가져오도록하자.
<% while(rs.next()){ %>
<tr>
<td><%= rs.getInt("id")%></td>
<td class="title indent text-align-left"><a href="detail.html"><%=rs.getString("title")%></a></td>
<td><%=rs.getString("writer_id") %></td>
<td>
<%=rs.getDate("regdate")%>
</td>
<td><%=rs.getInt("hit")%></td>
</tr>
<%}%>
그러기 위해서 저렇게 설정하고
ctrl+f11을 누르면

oracle driver를 찾을 수 없다는 에러창이 나온다.
왜냐하면 우리가 oracle driver을 로드하지 않았기 때문이다.
앞서 배웠던 JDBC에서 build path를 통해서 경로를 지정해줬지만
웹을 배포한다면 저렇게 하면 안된다.
왜냐하면 그 라이브러리가 함께 가야하기 때문이며
따라서 WEB_INF>lib안에 라이브러리를 포장해준다.
오라클 드라이버를 여기에 복사해서 포함시켜 놓자

이렇게 로드하고
다시 ctrl+f11 누르면

정상적으로 목록이 나왔다.
이번 강의에서 구현하는 코드 : list2.jsp , detail.jsp

이번 시간은 제목을 누르면 자세한 내용이 나오도록 페이지를 구현해보고자 한다.

목록의 주소는 위와 같다.

클릭해서 들어가면 공지사항 내용의 주소는 위와 같이 detail.jsp?id=1
로 되어져 있다.
즉 detail.jsp에 id=1이라는 쿼리를 줘 내용을 구분해보겠다는 이야기이다.
🐥list2.jsp 를 들어가서

링크 부분을 수정한다. 그 이전에는 <a href="detail.html">이었기 때문에
detail.html을 동적으로만 보여줬다.
🐥 먼저 강의에 주어진 notice>detail.html을 복사해서 detail.jsp로 만들어준다.
그 때 2개의 과정이 필요하다.
✔️ 한글깨짐을 없애기 위한 것이다.
앞에서 배웠다.
1. Alt+Enter를 눌러서 Text file encoding을 UTF-8로 고치기
2. 웹에서 한글 깨짐을 방지하기 위해 지시 블록 추가하기
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
위는 한글 깨짐을 방지하기 위한 것이다.
✔️ 이제는 JDBC를 통해서 DB에 있는 레코드를 가져와야 한다. 따라서
<%@page import="java.sql.ResultSet"%>
<%@page import="java.sql.Statement"%>
<%@page import="java.sql.DriverManager"%>
<%@page import="java.sql.Connection"%>
<%
String url ="jdbc:oracle:thin:@localhost:1521/xepdb1";
String sql = "SELECT * FROM NOTICE";
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con = DriverManager.getConnection(url,"NEWLEC","비밀번호");
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(sql);
%>
✔️list2.jsp에서 우리는 NOTICE의 id를 받아서 detail.jsp?id='받는 속성값'을 받아서
detail.jsp를 호출한다.
따라서 datail.jsp에는 파라미터를 받아야한다.

✔️ 공지사항의 내용을 동적으로 바꿔주자
<div class="margin-top first">
<h3 class="hidden">공지사항 내용</h3>
<table class="table">
<tbody>
<tr>
<th>제목</th>
<td class="text-align-left text-indent text-strong text-orange" colspan="3"><%=rs.getString("title") %>></td>
</tr>
<tr>
<th>작성일</th>
<td class="text-align-left text-indent" colspan="3"><%=rs.getDate("regdate") %></td>
</tr>
<tr>
<th>작성자</th>
<td><%=rs.getString("writer_id") %></td>
<th>조회수</th>
<td><%=rs.getInt("hit") %></td>
</tr>
<tr>
<th>첨부파일</th>
<td colspan="3"><%=rs.getString("files") %></td>
</tr>
<tr class="content">
<td colspan="4"><%=rs.getString("content") %></td>
</tr>
</tbody>
</table>
</div>

✔️ 마지막으로 목록을 누르면 이상한 페이지가 나온다. detail.jsp에서 목록의 링크를 list2.jsp로 고쳐주자
<a class="btn btn-list" href="list2.jsp">목록</a>
이번 수업 때 다루는 파일 : detail.jsp

내가 이전까지 만들었던 코드는 스파게티 코드이다.
JAVA와 HTML이 섞여있기 때문이다.
따라서 JAVA는 JAVA끼리 HTML은 HTML끼리 모아서 둬야 깔끔한 코드이다.

이렇게 Model이라는 임시 변수를 이용해서 실제 변수를 컨트롤하는 Control단과
HTML을 통해서 사용자에게 보여주는 View단을 분리하는 것을 MVC라고 한다.
✔️ 임시 변수들을 이용해서 Control단을 아래와 같이 만들었다.
모델에 레코드값들을 미리 옮겼기 때문에 ResultSet을 닫아도 그래도 값이 남아져있다.
<%@page import="java.util.Date"%>
<%@page import="java.sql.PreparedStatement"%>
<%@page import="java.sql.ResultSet"%>
<%@page import="java.sql.Statement"%>
<%@page import="java.sql.DriverManager"%>
<%@page import="java.sql.Connection"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
int id = Integer.parseInt(request.getParameter("id"));
String url ="jdbc:oracle:thin:@localhost:1521/xepdb1";
String sql = "SELECT * FROM NOTICE WHERE ID=?";
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con = DriverManager.getConnection(url,"NEWLEC","비밀번호");
PreparedStatement st = con.prepareStatement(sql);
st.setInt(1,id);
ResultSet rs = st.executeQuery();
rs.next();
String title = rs.getString("title");
Date regdate =rs.getDate("regdate");
String writerId =rs.getString("writer_id");
int hit =rs.getInt("hit") ;
String files =rs.getString("files");
String content =rs.getString("content");
//모델을 만들었다.
rs.close();
//모델에 미리 옮겨놓았기 때문에 close해도 상관없다.
st.close();
con.close();
%>
✔️ View단을 보면 <%=rs.getInt %>등으로 지저분했던 HTML부분은 변수들을 넣어 더 깔끔해졌다.
<div class="margin-top first">
<h3 class="hidden">공지사항 내용</h3>
<table class="table">
<tbody>
<tr>
<th>제목</th>
<td class="text-align-left text-indent text-strong text-orange" colspan="3"><%=title %></td>
</tr>
<tr>
<th>작성일</th>
<td class="text-align-left text-indent" colspan="3"><%=regdate %></td>
</tr>
<tr>
<th>작성자</th>
<td><%=writerId %></td>
<th>조회수</th>
<td><%=hit %></td>
</tr>
<tr>
<th>첨부파일</th>
<td colspan="3"><%=files %></td>
</tr>
<tr class="content">
<td colspan="4"><%=content %></td>
</tr>
</tbody>
</table>
</div>

model1은 같은 파일 안에 Control과 View가 같이 있었다. Model이라는 임시 변수를 통해서 이 둘의 내용을 공유했다.
하지만 model2는 이 Control과 View라는 부분을 물리적으로 분리한다.
생각해보면 JSP에 JAVA 코드를 넣는다는 것은 코드를 돌릴 때 부담이 크다.
왜냐하면 Jasper를 통해서 Servlet을 만들어야 하는데 코드블럭을 통해서 넣은 JAVA 코드마저
Servlet으로 만들어야 하기 때문이다.
또한 유지보수 측면이나 재사용성에 대해서도 model2가 더 장점이 많다.
그러나 여기서 드는 의문은 model1에서는 임시변수를 통해서 내용을 공유했다면
model2는 무엇으로 내용을 공유할 것인가? Dispatcher를 통해서 한다 이는 49강에서 이미 배웠다.
나는 앞서서 application, cookie, session에 대해서 배웠다.
하지만 여기서는 request를 이용하는데 request는 단지 요청이 들어온 것을 받는 것 뿐만 아니라 저장소의 역할을 한다는 것을 기억해야 한다.
여기서 다시 이번 강의에서 다루는 전체적인 파일을 정리해본다.
list2.jsp : 공지사항 목록 링크를 클릭하면<td class="title indent text-align-left"><a href="detail?id=<%=rs.getInt("id")%>"><%=rs.getString("title")%></a></td>➡️ int id = Integer.parseInt(request.getParameter("id")); id라는인자를 받아서 select문의 레코드를 검색하고 세부 글 내용을 DB에서 가져올 수 있도록 하는 JAVA 코드로 Controller: NoticeDetailController.java->글을 클릭하면 공지사항 내용을 보여주는 View단 detail.jsp
따라서 Controller를 통해서 request에 값을 저장하고 이 값을 View단에 보내줘야 한다.
먼저 NoticeDetailController.java를 만들어본다.
package com.newlecture.web.controller;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/notice/detail")
public class NoticeDetailController extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int id = Integer.parseInt(request.getParameter("id"));
String url ="jdbc:oracle:thin:@localhost:1521/xepdb1";
String sql = "SELECT * FROM NOTICE WHERE ID=?";
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con = DriverManager.getConnection(url,"NEWLEC","비밀번호");
PreparedStatement st = con.prepareStatement(sql);
st.setInt(1,id);
ResultSet rs = st.executeQuery();
rs.next();
String title = rs.getString("title");
Date regdate =rs.getDate("regdate");
String writerId =rs.getString("writer_id");
int hit =rs.getInt("hit") ;
String files =rs.getString("files");
String content =rs.getString("content");
//모델을 만들었다.
request.setAttribute("title", title);
request.setAttribute("regdate", regdate);
request.setAttribute("writerId", writerId);
request.setAttribute("hit", hit);
request.setAttribute("files", files);
request.setAttribute("content", content);
rs.close();
//모델에 미리 옮겨놓았기 때문에 close해도 상관없다.
st.close();
con.close();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
request.getRequestDispatcher("/notice/detail.jsp")
.forward(request, response);
}
}
여기서 다시 한번 눈여겨 볼 부분은 Dispather를 통해서 View단과 url-mapping을 했고 이를 거기에 forwarding 했다는 것이다.
...
request.setAttribute("title", title);
request.setAttribute("regdate", regdate);
request.setAttribute("writerId", writerId);
request.setAttribute("hit", hit);
request.setAttribute("files", files);
request.setAttribute("content", content);
...
request.getRequestDispatcher("/notice/detail.jsp")
.forward(request, response);
request.setAttribute("키",값);
request.getAttribute("키");
키와 값을 같이 저장하고 키로 값을 불러옴
url mapping을 했다.
이렇게 논리적으로 다 연결되어져 있다는 것 저런 생각을 했다는게 정말 놀랍고 재밌다.
따라서 View단이 detail.jsp는 아래와 같이 깔끔해졌다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>코딩 전문가를 만들기 위한 온라인 강의 시스템</title>
<meta charset="UTF-8">
<title>공지사항목록</title>
...
<div class="margin-top first">
<h3 class="hidden">공지사항 내용</h3>
<table class="table">
<tbody>
<tr>
<th>제목</th>
<td class="text-align-left text-indent text-strong text-orange" colspan="3"><%=request.getAttribute("title") %></td>
</tr>
<tr>
<th>작성일</th>
<td class="text-align-left text-indent" colspan="3"><%=request.getAttribute("regdate") %></td>
</tr>
<tr>
<th>작성자</th>
<td><%=request.getAttribute("writerId") %></td>
<th>조회수</th>
<td><%=request.getAttribute("hit") %></td>
</tr>
<tr>
<th>첨부파일</th>
<td colspan="3"><%=request.getAttribute("files") %></td>
</tr>
<tr class="content">
<td colspan="4"><%=request.getAttribute("content") %></td>
</tr>
</tbody>
</table>
</div>
이번 수업에 다루는 파일: list2.jsp로 id 쿼리 인자 전달-> Notice.java로 개체를 객체화 -> NoticeDetailController.java에서 객체화한 데이터 request에 저장한 후 url mapping을 통해 forward-> detail.jsp가 받아 View
request.setAttribute("title", title);
request.setAttribute("regdate", regdate);
request.setAttribute("writerId", writerId);
request.setAttribute("hit", hit);
request.setAttribute("files", files);
request.setAttribute("content", content);
예시의 경우 공지사항(id, title, writerId 등)=개념화된 데이터 = 개체 = entity = 구조화된 데이터라고 부른다.
프로그램을 만들면서 위와 같이 개체를 낱개의 데이터로 설정하는 경우 구분, 반복, 변수 이름 설정 등의 문제가 발생하기 때문에 우리는 이것을 묶어서 표현하기로 한다. 하나의 클래스 즉 객체로 만들어 버리는 것이다.
Notice notice = new Notice(
id,
title,
regdate,
writerId,
hit,
files,
content);
request.setAttribute("n",notice);
위와 같이 간단하게 만들었으며 이렇게 설정하기 위해서 우리는 Notice라는 클래스를 만들어야 한다.
Notice.java의 경우
package com.newlecture.web.entity;
import java.util.Date;
public class Notice {
private int id;
private String title ;
private Date regdate ;
private String writerId ;
private int hit;
private String files ;
private String content ;
public Notice() {
}
public Notice(int id, String title, Date regdate, String writerId, int hit, String files, String content) {
this.id = id;
this.title = title;
this.regdate = regdate;
this.writerId = writerId;
this.hit = hit;
this.files = files;
this.content = content;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Date getRegdate() {
return regdate;
}
public void setRegdate(Date regdate) {
this.regdate = regdate;
}
public String getWriterId() {
return writerId;
}
public void setWriterId(String writerId) {
this.writerId = writerId;
}
public int getHit() {
return hit;
}
public void setHit(int hit) {
this.hit = hit;
}
public String getFiles() {
return files;
}
public void setFiles(String files) {
this.files = files;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "Notice [id=" + id + ", title=" + title + ", regdate=" + regdate + ", writerId=" + writerId + ", hit="
+ hit + ", files=" + files + ", content=" + content + "]";
}
}
각 변수마다 setter와 getter가 있다. 이를 설정한 이유는
EL문을 사용하기 위해서다.
detail.jsp에서
<tr>
<th>작성일</th>
<td class="text-align-left text-indent" colspan="3">${n.regdate}</td>
</tr>
위와 같이 사용되며 이는 n.regdate는 객체 n에서 redate를 가져오는 것이 아닌 getRegdate()를 호출하여 값을 얻는 것 즉 함수의 get을 생략하고 대문자 R을 소문자 r로 표현한 것이다.
이번 수업에 다루는 파일: Notice.java로 개체를 객체화 -> NoticeListController.java로 JDBC 통해 받은 데이터 list<Notice>를 request에 저장하여 dispatcher를 통해 /list2.jsp url에 매핑한 후 전달 -> list2.jsp로 View단, id 쿼리 인자 전달-> NoticeDetailController.java에서 객체화한 데이터 request에 저장한 후 url mapping을 통해 forward-> detail.jsp가 받아 View
✔️list2.jsp에서 JAVA 코드 분리하여 NoticeListController.java 만들기
56강의 공지사항 세부 내용과 다르게 여기는 목록 전체를 나타내어야 하기 때문에
NOTICE테이블 전체 레코드를 받게 된다.
List<Notice> list = new ArrayList<>();
...
Notice notice = new Notice(
id,
title,
regdate,
writerId,
hit,
files,
content);
list.add(notice
레코드 하나하나를 list에 저장한 후 request를 통해 list2.jsp에 보내야 한다.
레코드 하나하나는 개체이며 이는 Notice 클래스를 통해서 객체화 했다.
package com.newlecture.web.controller;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
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 com.newlecture.web.entity.Notice;
@WebServlet("/notice/list")
public class NoticeListController extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//여기서는 notice객체 여러개
List<Notice> list = new ArrayList<>();
String url ="jdbc:oracle:thin:@localhost:1521/xepdb1";
String sql = "SELECT * FROM NOTICE";
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con = DriverManager.getConnection(url,"NEWLEC","비밀번호");
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(sql);
while(rs.next()){
int id = rs.getInt("id");
String title = rs.getString("title");
Date regdate =rs.getDate("regdate");
String writerId =rs.getString("writer_id");
int hit =rs.getInt("hit") ;
String files =rs.getString("files");
String content =rs.getString("content");
Notice notice = new Notice(
id,
title,
regdate,
writerId,
hit,
files,
content);
list.add(notice);
}
rs.close();
st.close();
con.close();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
request.setAttribute("list", list);
request.getRequestDispatcher("/notice/list2.jsp")
.forward(request, response);
}
}
✔️ 자 이제는 list2.jsp에서 request를 어떻게 처리해서 사용자에게 보여주는지 살펴보자
<%
List<Notice> list = (List<Notice>)(request.getAttribute("list"));
for(Notice n : list){
pageContext.setAttribute("n",n);
%>
<tr>
<td>${n.id}</td>
<td class="title indent text-align-left"><a href="detail?id=${n.id}">${n.title}</a></td>
<td>${n.writerId}</td>
<td>${n.regdate}</td>
<td>${n.hit}</td>
</tr>
<%} %>
pageContext.setAttribute("n",n); 이 부분 없이${n.id}이렇게 표현했을지도 모르지만 이는 불가능하다. 왜냐하면 EL은 ${request에 담겨진 키워드.(get)소문자}이기 때문이다. 즉 ${list.Id}이렇게 표현이 된다는 사실을 잊지 말자. 따라서 pageContext에 담아서 전달받는다.
전체적인 흐름을 보면
NoticeListController.java -> list2.jsp -> NoticeDetailController.java-> detail.jsp 순서로 간다.

즉 controller 먼저 실행되어야 그 DB에 있는 레코드를 View단에 넘겨줄 수 있다.
따라서 jsp를 먼저 실행할 수 없다. 위 그림을 보면 list.jsp를 먼저 실행한 경우 에러가 발생되었음을 알 수 있다.
그렇기 때문에 View단을 숨겨놓을 것이다.
어디다 숨길까?
바로 WEB-INF라는 곳이다. 이 곳은 사용자가 접근할 수 없는 곳이다.
이곳에 view라는 폴더를 만들어 그곳에 View단을 놓도록 하자.

이렇게 옮겨졌기 때문에 request의 디스패처를 통해 url mapping을 한 부분들의 url을 모두 고쳐야한다. /WEB-INF/view/notice/파일이름.jsp
이번 시간에 다루는 파일 : list2.jsp
<%
List<Notice> list = (List<Notice>)(request.getAttribute("list"));
for(Notice n : list){
pageContext.setAttribute("n",n);
%>
<tr>
<td>${n.id}</td>
<td class="title indent text-align-left"><a href="detail?id=${n.id}">${n.title}</a></td>
<td>${n.writerId}</td>
<td>${n.regdate}</td>
<td>${n.hit}</td>
</tr>
<%} %>
위와 같이 list2.jsp에 어쩔 수 없이 코드블럭을 넣었는데 이를
없애는 방법에 대해서 알아보자.
없애는 방법은 jstl을 이용하는 것인데 이는 태그를 활용한다.
우리가 태그를 배울 때 태그는 what을 설명할 뿐 행위를 나타내지 않았으나
이제 JSTL의 태그는 행위를 나타낸다.
먼저 jstl을 다운로드 받고 이 라이브러리를 이용해야한다.
https://mvnrepository.com/artifact/javax.servlet/jstl/1.2
여기 들어가서

Jar파일을 다운도르 받은다음
WEB-INF>lib에 넣어서 이용하자.

이 lib에는 JDBC Driver와 JSTL 라이브러리가 있다.
이제 실제로 활용해보자
먼저 태그 라이브러리를 사용하기 위해서는
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
위와 같은 설정을 한다.
저기 접두사 c를 통해서 태그를 불러온다.
따라서 이제 내려가서 for문을 제거하고 태그로 만들자.
<%-- <%
List<Notice> list = (List<Notice>)(request.getAttribute("list"));
for(Notice n : list){
pageContext.setAttribute("n",n);
%> --%>
<c:forEach var = "n" items="${list}" >
<tr>
<td>${n.id}</td>
<td class="title indent text-align-left"><a href="detail?id=${n.id}">${n.title}</a></td>
<td>${n.writerId}</td>
<td>${n.regdate}</td>
<td>${n.hit}</td>
</tr>
</c:forEach>
<%-- <%} % >--%>
저장소 request에 있는 녀석들을 items에 담고 반복될 때 마다 list에 저장된 하나하나를 n이라는 그릇에 담는다.
JSTL(Jsp Standar Tag Library)

JSTL은 크게 5가지 범주의 태그 라이브러리를 제공하고 있다.
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
왜 위와 같이 표현하는지 알아보자
uri는 주소라고 볼 수 있다. 즉 식별자이다.
우리가 태크 라이브러리를 만들 때

위와 같이 TagSuppor를 상속 받은 태그 라이브러리를 정의하는 클래스의 이름을 ForTag라는 클래스를 정의했다고 하자.
그리고 나서 tld파일을 만드는데 그 파일은 WEB-INF안에 존재한다.
보면 uri가 있는데 이 uri는 식별자이다.
만약에 다른 클래스의 같은 이름의 for 태그가 있을 때 이를 구별해주는 것은 uri이다.
따라서 uri에는 도메인 주소가 들어간다. 도메인 주소는 세계 유일한 것이기 때문이다.

그래서 실제로 태크를 사용할 때는 이 주소를 언급해야 한다.
<http://java.sun.com/jsp/jstl/core:forEach var ="n" items="${list}">
그러나 이렇게 표현하기에는 uri가 너무 길기 때문에
c라는 접두사로 받는 것이다.
<c:forEach var ="n" items="${list}">
따라서 Jasper는 이 c라는 접두사를 보고 이것은 HTML이 아닌 uri가 저런 태그 라이브러리임을 알 수 있는 것이다.

ForTag 클래스에는 3개의 함수가 Overriding되어져 있는데
doStartTag()는 시작은
doAfgerBody()는 for이 끝난 후 그 다음의 실행을
doEndTag()는 for문을 지나 그 다음으로 진행되게 한다.