자기 자신의 것을 스스로 참조하는거 = 셀프조인
CREATE TABLE students (
s_id INT PRIMARY KEY AUTO_INCREMENT,
s_name CHAR(20) NOT NULL,
s_manitto INT
);
INSERT INTO students (s_name, s_manitto) values
('a',2), ('b',3), ('c',null), ('d',1);
SELECT * FROM students;
--각 학생에 이름과 마니또 이름을 표시하라.
SELECT s1.s_name, s2.s_name
FROM sudents s1, student s2 --논리적으로 두개로 본다.
WHERE s1.s_id = s2.s_manitto;
SELECT s1.s_name, s2.s_name
FROM students s1 INNER JOIN students s2
ON s1.s_id = s2.s_manitto;
SELECT s1.s_name, s2.s_name
FROM students s1 LEFT OUTER JOIN students s2
ON s1.s_id = s2.s_manitto
WHERE s2.s_manitto IS NULL;
mysql에만 있다.
앞의 숫자는 시작위치(인덱스처럼 0부터 시작)
뒤의 숫자는 몇개를 보여줄 지 결정하는 숫자.
이걸 가지고 페이징처리를 한다.
SELECT FROM products LIMIT 3; -- 3넣으니까 3줄만 나온다.
SELECT FROM products LIMIT 2, 3; -- 2는 시작위치. 인덱스와 비슷한 느낌. 리밋은 mysql밖에 없다. 이걸 가지고 페이징처리를 할 것이다.
여기 안에 2개의 메서드를 적어준다.
getList()는 한페이지에 3개씩 나눠서 list를 구성한다는 것 같고,
getTotalCount()는 테이블의 레코드(행)의 총 개수를 구하는 것.
public Vector<Book> getList(Connection con, int pageNum, int perPage) {
Vector<Book> list = new Vector<Book>();
String sql = "SELECT * FROM a_book ORDER BY b_num DESC LIMIT ?, ?";
PreparedStatement pStmt = null;
ResultSet rs = null;
try {
pStmt = con.prepareStatement(sql);
pStmt.setInt(1, (pageNum -1) * perPage);
pStmt.setInt(2, perPage);
rs = pStmt.executeQuery();
while(rs.next()) {
list.add(rowMapping(rs));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(rs);
close(pStmt);
}
return list;
}
public int getTotalCount(Connection con) {
int count = 0;
String sql = "SELECT COUNT(*) FROM a_book";
PreparedStatement pStmt = null;
ResultSet rs = null;
try {
pStmt = con.prepareStatement(sql);
rs = pStmt.executeQuery();
if(rs.next()) {
count = rs.getInt(1); //열 순서임!
//이름으로 들고오면 문제가 있다.
//접근하는 속도도 이게 더 빠름.
//첫번째 열을 들고오라는 뜻인듯.
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(rs);
close(pStmt);
}
return count;
}
그 다음 listCmd를 아래와 같이 바꿔준다.
public class ListCmd implements ICmd {
//이걸 잘알아야 한다. 페이징하는 연산은 다 이렇게 생김.
페이징하려면 뭐가 필요한지 알지.
public void action(HttpServletRequest request) {
int perPage = 3;
int pageNum = 1;
String temp = request.getParameter("pageNum");
if(temp != null) {
pageNum = Integer.parseInt(temp);
}
BookDao dao = BookDao.getInstance();
Connection con = dao.connect();
int totalCount = dao.getTotalCount(con); //몇페이지까지 나오는지..
int pageCount = totalCount / perPage;
if(totalCount % perPage !=0) {
pageCount++; //딱 안떨어지면 한페이지 늘여야 하니까.
}
request.setAttribute("list", dao.getList(con,pageNum, perPage));
dao.disconnect(con);
request.setAttribute("pageNum", pageNum);
request.setAttribute("pageCount", pageCount);
}
}
<%= %> , out.println()과 같은 자바코드를 더 이상 사용하지 않고 좀더 간편하게 출력을 지원하기 위한 도구.
배열, List, map도 가능.
<결과>
<%@page import="java.util.Hashtable"%>
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<%@page import="kr.ac.green.Some" %>
<%@page import="java.util.*" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>elEx.jsp</title>
</head>
<body>
<%
//값을 잡아넣는 것은 jsp에서 하는 일이 아니다.
%>
<%
pageContext.setAttribute("myString", "aaa"); //영역이 다른데 이름이 같은 속성
request.setAttribute("myString", null);
Some s = new Some(100, "myValue");
session.setAttribute("some", s);
Vector<String> vec = new Vector<String>();
vec.add("a");
vec.add("b");
vec.add("c");
vec.add("d");
request.setAttribute("list", vec);
Map<String, String> map = new Hashtable<String,String>();
map.put("aKey", "aValue");
map.put("bKey", "bValue");
map.put("cKey", "cValue");
map.put("dKey", "dValue");
request.setAttribute("map", map);
Vector<String> otherList = new Vector<String>();
request.setAttribute("otherList", otherList);
request.setAttribute("arr", new int[]{});
%>
${ list[2] } ${ map["cKey"] } ${ empty otherList } ${ empty arr }
<%-- 배열도 되고 list도 된다. --%>
<%-- ${ empty otherList } null검사가 된다. null도 검사하고 원소가 몇개 들었는지도 알수 있다. 비었습니까? 이런느낌.
배열에서 empty는 원소값이 없음에도 false가 나온다. 배열은 안에 비었는지 알지 못한다. 배열이 길이가 0인거 만들면 걍 무조건 0이다.
null의 유무만 검사하고, 원소가 있는지 아닌지 배열이 비었는지는 검사하지 못한다./ not empty도 가능 --%>
<hr>
<%--jstl을 써야 for아니 if문 쓸 수 있다. 코드를 만들 수 있는 일을 태그로 사용한거...jstl은 외부라이브러리다. -->
<%
String str = (String) request.getAttribute("myString");
%>
<%=str %>
${ requestScope.myString } <%--표현식은 null값이 나오지만, requestScope는 null값이 표현되지 않고 결과가 안나온다!!! requestScope는 리퀘스트 객체가 아니라 그냥 속성값만 가져오는 것이다.--%>
<%-- ${ myString }--%> <% //얘는 4개의 객체를 차례로 검사 pageContext-request-session-application 순으로 있는지 없는지 확인하고 page가 먼저 나온다. 4개 다 없으면 null이 뜬다. %>
<hr>
<%
Some temp = (Some)session.getAttribute("some");
%>
<%= temp.getNum()%> <%=temp.getStr()%>
${ sessionScope.some.num }
<%--${ sessionScope.some.str } --%>
${some.str } <%--이렇게 써도 값은 똑같이 나온다. --%>
<%--${some[str] } --%><%--이렇게 써도 값은 똑같이 나온다. --%>
<hr>
<%=application.getInitParameter("pname") %>
${ initParam.pname }
<%-- http://localhost:8080/06.01/elEx.jsp?myParam=cat --%>
${ param.myParam }
<hr>
${ pageContext.request.contextPath } <%--pageContext.request : 이렇게 쓰면 레퀘스트 객체를 가져오게 된다. el에서 사용할 수 있는 것은 pageContext객체 밖에 안된다. 다른 3가지는 객체 직접 못 들고 온다.--%>
<hr>
${ 4 < 3 } <%-- 참거짓판단가능 --%>
${ 3 == 3 } <%-- 참거짓판단가능 --%>
</body>
</html>
JSP는 자신만의 태그를 추가할 수 있는 기능을 제공하고 있는데요.
<jsp:include>나 <jsp:usebean>과 같은 커스텀 태그처럼 연산이나 조건문이나 반복문인 if문, for문, DB를 편하게 처리할 수 있는것이 JSTL.
if문 사용 - else if 없음
<c:if test = ${}><c:if test**="${4 > 0}"> true </c:if>
if - else if - else문
<c:choose> <c:when test="${ myValue >10 }"> :if느낌. 10보다 크다 </c:when> <c:when test="${ myValue>5 }"> :else if느낌. 5보다 크다 </c:when> <c:otherwise> : else느낌. 5 이하이다. </c:otherwise> </c:choose>
for구문
end는 '이하'이다. 10을 포함함. 역순은 안된다.
var : 변수 step : 더해지는 단위<c:forEach var="i" begin="0" end="10" step="2"> ${ i } </c:forEach>
foreach문
varStatus="status":반복문의 정보를 가지고 있다.<c:foreach items="${리스트가 받아올 배열이름}"
var="for문 내부에서 사용할 변수"
varStatus="상태용 변수"><c:forEach items="${ list }" var="myString" varStatus="status"> ${ status.count }번째 반복 : ${ myString } -> ${ status.index } <br> </c:forEach>
<결과>
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page import ="java.util.*" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
<%
//int num = 100; //el에서 참조할 수 없다.${ num } 이렇게 못 쓴다. el는 getAttribute인 느낌인듯.
%>
<c:set var="num" value="100" scope="request" /> <%--이런 거 사용은 되는데 하지마라. jsp는 속성을 정의하는 곳이 아니다. --%>
${ num }
<c:remove var="num" scope="request"/> <%--이런 거 사용은 되는데 하지마라. jsp는 속성을 정의하는 곳이 아니다. --%>
${ num }
<hr><%--여기만 보기--%>
<c:if test="${4 > 0}"><%--else if가 없다. --%>
true
</c:if>
<c:set var="myValue" value="1"/>
<c:choose>
<c:when test="${ myValue >10 }"><%--if느낌. --%>
10보다 크다
</c:when>
<c:when test="${ myValue>5 }"><%--else if느낌. --%>
5보다 크다
</c:when>
<c:otherwise><%--else느낌. --%>
5 이하이다.
</c:otherwise>
</c:choose>
<hr><%--반복문--%>
<c:forEach var="i" begin="0" end="10" step="2"> <%--end는 '이하'이다. 10을 포함함. 역순은 안된다.--%>
${ i }
</c:forEach>
<hr>
<%
ArrayList<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
request.setAttribute("list", list);
%>
<c:forEach items="${ list }" var="myString" varStatus="status"> <%-- varStatus="status":반복문의 정보를 가지고 있다. --%>
${ status.count }번째 반복 : ${ myString } -> ${ status.index }
<br>
</c:forEach>
</body>
</html>
걍)
book의 list.jsp를 jstl로 바꾼 거
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<%@ taglib prefix ="c" uri ="http://java.sun.com/jsp/jstl/core" %>
<%@ page import="java.util.*" %>
<%@ page import="kr.ac.green.Book" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>list.jsp</title>
</head>
<body>
<h1>list</h1>
<a href="add.book">책 등록하기</a>
<hr>
<form action="findByTitle.book" method="get">
제목으로 검색할 수 있어요 : <input type="text" name="findTitle" />
<input type="submit" />
</form>
<hr>
<table>
<tr>
<th>번호</th>
<th>제목</th>
<th>저자</th>
</tr>
<c:choose>
<c:when test="${ empty list }">
<tr>
<td colspan="3">no data</td>
</tr>
</c:when>
<c:otherwise>
<c:forEach items="${ list }" var="book">
<tr onclick="showBookInfo(${ book.num})">
<td>${ book.num}</td>
<td>${ book.title}</td>
<td>${ book.writer}</td>
</tr>
</c:forEach>
</c:otherwise>
</c:choose>
<tr>
<th colspan ="3"/>
<c:forEach var="i" begin="1" end="${ pageCount }">
<c:choose>
<c:when test="${ i == pageNum }">
[${i }]
</c:when>
<c:otherwise>
<a href="list.book?pageNum=${i }"> [${i }]</a>
</c:otherwise>
</c:choose>
</c:forEach>
</tr>
</table>
<script>
function showBookInfo() {
location.href="view.book?num=" + arguments[0];
}
</script>
</body>
</html>
public Book[] getAllByArray(Connection con) {
Book[] arr = null;
PreparedStatement pStmt = null;
ResultSet rs =null;
String sql = "SELECT * FROM a_book";
try {
pStmt = con.prepareStatement(sql);
rs = pStmt.executeQuery();
rs.last(); //마지막으로 옮김. -> 다음게 없음. rs.last()가 제일 마지막 레코드로 이동함.
int count = rs.getRow();//현재 커서가 몇번째위치에 있는 지 알려주는 게 getRow()
arr = new Book[count];
rs.beforeFirst();//위치를 첫번째레코드 위에 있다. 최초위치에 있다.
int idx = 0;
while(rs.next()) {//next()의 의미 : 현재위치라는 게 있어야 한다. 다음레코드가 있습니까? 물어볼 수 있는 거. 처음위치가 어디있나? 열이름들 나오는 저기부분. 최초위치는 열이름있는 부분. 현재위치 담고있는 부분을 cursor라고 함.
arr[idx++] = rowMapping(rs);
}
//콜렉션 등도 기반이 배열이다. 길이가 늘어났을 때 배열을 바꾼다. 리스트등은 capacity 용량이라는 것을 가짐. 진짜로 몇개를 넣을 수 있는가의 정보. 용량이 먼저 10으로 잡혀있고, 나중에 10개 넘으면 2배로 양을 늘인다. 넣는 원소개수가 많은면 많을수록 공간의 낭비가 심해진다.
//가변길이인것처럼 보이게 한다.
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(rs);
close(pStmt);
}
return arr;
}
`클라이언트가 요청을 보낸다 -> 로직(커맨드클래스) -> 연결 -> 데이터베이스(질의연산)`