35일차(3)/jsp(23) : 게시판 조회수 기능, 페이징 처리 기능 구현
- 조회수 기능 구현
- 게시판 페이징 처리
- 글 자세히 보기(detail.jsp) 페이지에 들어가면 viewCount의 숫자가 늘어나도록 코딩하면 된다.
<CafeDao> - 조회수를 올리는 메소드 addViewCount 추가
//글의 조회수를 올리는 메소드
public boolean addViewCount(int num) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
String sql = "UPDATE board_cafe"
+ " SET viewCount=viewCount+1"
+ " WHERE num=?";
pstmt = conn.prepareStatement(sql);
//?에 바인딩
pstmt.setInt(1, num);
//INSERT or UPDATE or DELETE문을 수행하고 수정,삭제,추가된 row의 개수 리턴
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
} catch (Exception e2) {
}
}
if (rowCount > 0) {
return true;
} else {
return false;
}
}
- sql문에서도 위와 같은 연산처리가 가능!
CafeDao.getInstance().addViewCount(num);
- detail.jsp에도 한줄 추가! detail.jsp가 실행될 때마다 addViewCount 메소드가 실행되며 조회수가 늘어나도록 처리한 것!
- 게시물 클릭시 조회수가 증가된 것이 확인된다.
- list에 bootstrap css를 적용하고, 페이징 처리
- 전체 글의 갯수를 리턴하는 메소드 만들기
SELECT MAX(ROWNUM) AS num FROM board_cafe
- 전체 글의 갯수는 현재 작성된 데이터의 ROWNUM 중에서 가장 큰 값을 가져오면 된다.
- getList의 인자로 dto를 받아오도록 메소드 수정
- dto를 생성한 후, startRowNum, endRowNum을 dto에 저장해서
해당 rownum에 해당하는 데이터만 list로 출력해주도록 수정!
<CafeDao>에 getCount 메소드 추가
//글의 갯수를 리턴하는 메소드
public int getCount() {
int count=0;
//필요한 객체를 담을 지역변수를 미리 만들어둔다.
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
//Connection Pool에서 Connection 객체를 하나 얻어온다.
conn = new DbcpBean().getConn();
//실행할 sql문의 뼈대 구성하기
String sql = "SELECT MAX(ROWNUM) AS num "
+ " FROM board_cafe";
//sql문의 ?에 바인딩할게 있으면 한다.
pstmt = conn.prepareStatement(sql);
//SELECT문을 수행하고 결과값을 받아온다.
rs = pstmt.executeQuery();
//반복문 돌면서 resultSet에서 필요한 값을 얻어낸다.
if (rs.next()) {
count=rs.getInt("num");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close(); //Connection Pool에 Connection 반납하기
} catch (Exception e2) {
}
}
return count;
}
- Rownum을 계산하여 숫자 값을 리턴하는 메소드 만들기
SELECT *
FROM
(SELECT result1.*, ROWNUM AS rnum
FROM
(SELECT num, writer, title, viewCount, regdate
FROM board_cafe
ORDER BY DESC) result1)
WHERE rnum BETWEEN ? AND ?
- 정렬된 데이터(result1)에 ROWNUM을 부여하고,
그 result1 테이블의 일정 범위 안에 있는 값만 출력되도록 하는 sql문
- result1.* : result1 테이블에 있는 모든 내용!
TO_CHAR(regdate, 'YYYY.MM.DD HH24:MI') AS regdate
- 편리한 사용을 위해 regdate를 문자 처리해주기
<Dao>의 getList 수정하기 (startRowNum, endRowNum을 세팅하는 sql문으로 수정)
//글 목록 리턴하기
public List<CafeDto> getList(CafeDto dto) {
//회원 목록을 담을 객체 생성
List<CafeDto> list = new ArrayList<>();
//필요한 객체를 담을 지역변수를 미리 만들어둔다.
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
//Connection Pool에서 Connection 객체를 하나 얻어온다.
conn = new DbcpBean().getConn();
//실행할 sql문의 뼈대 구성하기
String sql = "SELECT *"
+ " FROM"
+ " (SELECT result1.*, ROWNUM AS rnum"
+ " FROM "
+ " (SELECT num, writer, title, viewCount, TO_CHAR(regdate, 'YYYY.MM.DD HH24:MI') AS regdate"
+ " FROM board_cafe"
+ " ORDER BY num DESC) result1)"
+ " WHERE rnum BETWEEN ? AND ?";
//sql문의 ?에 바인딩할게 있으면 한다.
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, dto.getStartRowNum());
pstmt.setInt(2, dto.getEndRowNum());
//SELECT문을 수행하고 결과값을 받아온다.
rs = pstmt.executeQuery();
//반복문 돌면서 resultSet에서 필요한 값을 얻어낸다.
while (rs.next()) {
CafeDto tmp=new CafeDto();
tmp.setNum(rs.getInt("num"));
tmp.setWriter(rs.getString("writer"));
tmp.setTitle(rs.getString("title"));
tmp.setViewCount(rs.getInt("viewCount"));
tmp.setRegdate(rs.getString("regdate"));
//CafeDto 객체의 참조값을 List 에 누적 시키기
list.add(tmp);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close(); //Connection Pool에 Connection 반납하기
} catch (Exception e2) {
}
}
return list;
}
<list.jsp>
<%@page import="test.cafe.dto.CafeDto"%>
<%@page import="test.cafe.dao.CafeDao"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//한 페이지에 몇개씩 표시한 것인지
final int PAGE_ROW_COUNT=5;
//하단 페이지를 몇개씩 표시할 것인지
final int PAGE_DISPLAY_COUNT=5;
//보여줄 페이지의 번호를 일단 1이라고 초기값 지정
int pageNum=1;
//페이지 번호가 파라미터로 전달되는지 읽어와 본다.
String strPageNum=request.getParameter("pageNum");
//만일 페이지 번호가 파라미터로 넘어온다면
if(strPageNum != null){
//숫자로 바꿔서 보여줄 페이지 번호로 지정한다.
pageNum=Integer.parseInt(strPageNum);
}
//보여줄 페이지의 시작 ROWNUM
int startRowNum=1+(pageNum-1)*PAGE_ROW_COUNT;
//보여줄 페이지의 끝 ROWNUM
int endRowNum=pageNum*PAGE_ROW_COUNT;
//하단 시작 페이지 번호
int startPageNum=1+((pageNum-1)/PAGE_DISPLAY_COUNT)*PAGE_DISPLAY_COUNT;
//하단 끝 페이지 번호
int endPageNum=startPageNum+PAGE_DISPLAY_COUNT-1;
//전체 글의 갯수
int totalRow=CafeDao.getInstance().getCount();
//전체 페이지의 갯수 구하기
int totalPageCount=(int)Math.ceil(totalRow/(double)PAGE_ROW_COUNT);
//끝 페이지번호가 이미 전체 페이지 갯수보다 크게 계산되었다면 잘못된 값이다.
if(endPageNum>totalPageCount){
endPageNum=totalPageCount; //끝 페이지번호 값을 보정해준다.
}
//CafeDto 객체를 생성해서
CafeDto dto=new CafeDto();
//위에서 계산된 startRowNum, endRowNum을 담고
dto.setStartNum(startRowNum);
dto.setEndRowNum(endRowNum);
//CafeDto를 인자로 전달해서 글목록 얻어오기
List<CafeDto> list=CafeDao.getInstance().getList(dto);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/cafe/list.jsp</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3" crossorigin="anonymous"></script>
</head>
<body>
<div class="container">
<a href="${pageContext.request.contextPath }/cafe/private/insertform.jsp">새글 작성</a>
<h3>카페 글 목록입니다.</h3>
<table class="table table-striped">
<thead class="table-info">
<tr>
<th>글번호</th>
<th>작성자</th>
<th>제목</th>
<th>조회수</th>
<th>작성일</th>
</tr>
</thead>
<tbody>
<%for(CafeDto tmp:list) {%>
<tr>
<td><%=tmp.getNum() %></td>
<td><%=tmp.getWriter() %></td>
<td>
<a href="detail.jsp?num=<%=tmp.getNum() %>"><%=tmp.getTitle() %></a>
</td>
<td><%=tmp.getViewCount() %></td>
<td><%=tmp.getRegdate() %></td>
</tr>
<%} %>
</tbody>
</table>
<nav>
<ul class="pagination justify-content-center">
<%if(startPageNum !=1) {%>
<li class="page-item">
<a class="page-link" href="list.jsp?pageNum=<%=startPageNum-1%>">Prev</a>
</li>
<%} %>
<%for(int i=startPageNum; i<=endPageNum; i++) {%>
<li class="page-item <%=pageNum == i ? "active" : "" %>">
<a class="page-link" href="list.jsp?pageNum=<%=i %>"><%=i %></a>
</li>
<%} %>
<%-- 마지막 페이지 번호가 전체 페이지의 갯수보다 작으면 Next링크를 제공한다. --%>
<%if(endPageNum< totalPageCount) {%>
<li class="page-item">
<a class="page-link" href="list.jsp?pageNum=<%=endPageNum+1%>">Next</a>
</li>
<%} %>
</ul>
</nav>
</div>
</body>
</html>
- startRowNum, endRowNum에 각각의 계산식 넣어주기
- 하단에 <nav>요소 추가해주고, 페이지 번호를 <li> 형태로 작성한다.
- for문을 돌면서 페이지번호를 출력해준다.
(i의 최소값은 startPageNum, 최대값은 endPageNum으로 지정하면 된다.)
- for문의 i 값을 사용해서 bootstrap css의 active효과를 줄 페이지 번호도 지정하기.
- 게시판 페이징 처리와 테이블 css까지 적용!
'국비교육(22-23)' 카테고리의 다른 글
36일차(2)/jsp(24) : 회원가입시 유효성 검증(validation) 기능 구현 (0) | 2022.11.28 |
---|---|
36일차(1)/CSS(7) : bootstrap CSS 적용하기 (0) | 2022.11.28 |
35일차(2)/jsp(22) : 게시판 SmartEditor 적용 / 글 수정, 삭제 기능 구현 (0) | 2022.11.27 |
35일차(1)/jsp(21) : 게시판 목록 보기, 새 글 작성, 글 상세보기 기능 구현 (0) | 2022.11.25 |
34일차(2)/jsp(20) : 회원 프로필 이미지 등록, 수정 기능 구현 (0) | 2022.11.25 |