1차 과제는 VO와 DAO를 사용한 Model 2 방식을 사용한 게시판 만들기이다. 최근 배운 것들을 활용해 보기 위한 프로젝트인데, 기본적인 게시판 리스트 출력, 상세 페이지, 수정, 삭제가 가능하게 되어있는 파일에 선생님이 요청한 기능들을 작업하여 제출하는 작은 프로젝트이다. / 작업 (제출) 기간 7일
💡 게시판에 추가되어야 할 기능
페이징 구현 / 리스트 검색 기능 구현 / 게시물 저장 시 첨부파일 저장, 수정, 삭제 / 상세 페이지 조회수 추가
1. 게시판 페이징 버튼 기능
💡 페이징에 필요한 정보
■ 기본 세팅 값
■ 현제 페이지가 변환될 때 함께 변경될 내용 ( 처음 셋팅 값 1 또는 0 )
1. 페이지 당 리스트 수 ( 10 개 )
2. 블록 당 페이지 수 ( 5 개 )
- 전체 리스트 수에 따라 변경되는 숫자
3. 전체 리스트 수 ( 0 )
4. 전체 페이지 수 ( 0 )
5. 전체 블록 수 ( 0 )
- 현재 위치를 알기 위한 변수
6. 현재 페이지 번호 ( 1 )
7. 현재 블록 ( 1 )
- 블럭 이동을 위한 값
8. 한 블록에서 시작 페이지
9. 한 블록에서 끝 페이지
10. 이전 블럭 Prev ( 0 )
11. 다음 블럭 Next ( 0 )
- DB에서 리스트 추출에 사용될 번호
12. 조회 시작번호 ( 0 )
13. 조회 끝 번호 ( 1 )
2. 게시판 페이징 버튼 기능 구현하기
🍫 PagingVo.java
1. 페이징을 위한 클래스(Class) 파일을 생성 / 위에서 정리한 필요 내용들을 멤버 변수로 선언.
//기본 셋팅 값
private int numPerRecord = 10; // 한 페이지 당 리스트 수
private int numPerPage = 5; //한 블럭당 페이지 수
// 초기화
private int totalRecord = 0; // 전체 리스트 수
private int totalPage = 0; // 전체 페이지 수
private int totalBlock = 0; // 전체 블럭수
private int nowPage = 1; // 현재 페이지
private int nowBlock = 1; // 현재 블럭
//블럭 이동을 위한 값
private int startPage = 1; //한 블럭에서 시작 페이지
private int endPage = 1; // 한 블럭에서 끝 페이지
private int prev = 0;
private int next = 0;
//디비 게시물 리스트
private int start = 0; //디비의 select 시작번호
private int end = 10; // 시작번호로 부터 가져올 select 갯수
3. 외부에서 접근을 위한 멤버 변수의 Set / Get 메서드 추가
4. 전체 리스트 수와 현재 페이지 번호가 변할 할때, 필요한 값을 변경 시켜주기 위한 생성자 추가
파라미터로 정해져서 넘어갈 값
전체 리스트 수 : 검색 결과에 따라 리스트 수가 변경
현재 페이지 번호 : 페이징 버튼 클릭 시 보이는 리스트가 변경
1) 전체 리스트 수에 따라 변경되는 숫자
전체 리스트 수 = ※ SQL 로 전체 리스트의 COUNT 값을 구해서 파라미터로 값을 받아 넣어준다.
this.totalRecord = totalRecord;
전체 페이지 수 = 전체 리스트 수 / 한 블록 당 페이지 수
this.totalPage = (int)Math.ceil((double)totalRecord / numPerPage);
전체 블럭 수 = 전체 페이지 수 / 한 블록 당 페이지 수
this.totalBlock = (int) Math.ceil((double) totalPage / numPerPage);
※ java.lang.Math : Math 클래스는 수학에서 자주 사용하는 상수들과 함수들을 미리 구현해 놓은 클래스
Math.ceil : 소수값이 존재할 때 값을 올리는 역할을 하는 함수
Math.floor : 소수값이 존재할 때 소수값을 버리는 역할을 하는 함수
Math.round : 소수값에 따라 올리거나 버리는 역할을 하는 반올림 함수
2) 현재 위치를 알기위한 변수
현재 페이지 번호 = 선택(클릭) 되어 있는 페이지 번호를 파라미터로 받아서 값을 넣어준다.
this.nowPage = nowPage;
현재 블록 = 현제 페이지 번호 / 한 블럭 당 페이지 수
this.nowBlock = (int) Math.ceil((double) nowPage/numPerPage);
ex ) 13 / 5 = 3 | 5개 페이지가 넘어간다면 3번째 블록에 13페이지가 있다.
3) 블럭 이동을 위한 값
한 블럭에서 끝 페이지 = ( 올림 ( 현제 페이지 / 한 블록 당 페이지 수 ) ) * 한 블록 당 페이지 수
this.endPage = (int) Math.ceil((double) nowPage / numPerPage)* numPerPage;
ex) ? = ( 2 / 5 ) * 5
한 블록에서 처음 페이지 = 한 블록에서 끝페이지 - 한 블록 당 페이지 수 + 1;
this.startPage = endBlock - numPerPage + 1;
ex) 6 = 10 - 5 + 1
이전 블록 ( 에서 첫 페이지 ) = 현제 블록에서 첫 페이지 번호 - 한 블록 당 페이지 수
this.prev = getStartPage() - getNumPerPage ();
ex) 6 = 11 - 5
다음 블록 ( 에서 첫 페이지 ) = 현제 블록 * 블록 당 페이지 수 + 1
this.next = getNowBlock() * getNumPerPage() + 1;
ex) 11 = 2 * 5
4) DB에서 리스트 추출에 사용될 번호
한 페이지에서 ( 디비 ) 리스트 시작 번호 = ( 현제 페이지 * 한 페이지당 리스트 개수 ) - 한 페이지당 리스트 개수 + 1
this.start = (nowPage * numPerRecord ) - numPerRecord + 1;
ex) ( 2 * 10 ) - 10 + 1 = 11 | 2번 페이지는 리스트 11번 ~부터 시작된다.
한 페이지에서 ( 디비 ) 리스트 마지막 번호 = ( 현제페이지 * 한 페이지당 리스트 개수 )
this.end = nowPage * numPerRecord ;
ex) 2 * 10 = 20 | 2번 페이지는 리스트 ~ 19번이 마지막이다.
만약 해당 블록에서 마지막 페이지 수가 전체 페이지 수 보다 크면 마지막 페이지 수 = 전체 페이지 수
if( this.endPage > this.totalPage) this.endPage = this.totalPage;
한 블록당 마지막 페이지의 계산 값은, 한 블럭당 들어가는 페이지 수만큼 값이 나온다.
하지만, 실제 리스트 데이터가 끝나는 페이지 부분은 더 적을 수 있다.
때문에 실제 계산된 전체 페이지 수보다 마지막페이지 수가 더 높게 나올경우, 마지막 페이지 수는 전체 페이지 수로 변경해 준다.
public pageingVo(int totalRecord,int nowPage) {
this.nowPage = nowPage;
this.totalRecord = totalRecord;
this.nowBlock = (int)Math.ceil((double)nowPage/numPerPage);
this.totalRecord = totalRecord;
this.totalPage = (int)Math.ceil((double)totalRecord / numPerPage);
this.totalBlock = (int)Math.ceil((double)totalPage / numPerPage);
this.nowPage = nowPage;
this.nowBlock = (int)Math.ceil((double)nowPage/ numPerPage);
this.endPage = (int)Math.ceil((double) nowPage / numPerPage)* numPerPage;
this.startPage = endBlock - numPerPage + 1;
this.prev = getStartPage() - getNumPerPage ();
this.next = getNowBlock() * getNumPerPage() + 1;
this.start = (nowPage * numPerRecord ) - numPerRecord;
this.end = nowPage * numPerRecord ;
if( this.endPage > this.totalPage) this.endPage = this.totalPage;
}
🍫 BoardDao.java
게시판에서 사용할 기능을 인터페이스에서 추가 선언하여 사용 (기능 구현과 실제 구동을 분리)
1. 전체 리스트 개수 와 페이징 을 구하기 위한 메서드 추가
public pageingVo getPaging(String kwd,String _nowPage);
1 ) 페이징 생성을 위해 필요한 것.
pageingVo pageing = new pageingVo( 전체 리스트 수 , 현재 페이지 번호)
- 메서드를 사용해 전체 리스트 수를 구해주어야 페이징 생성이 가능하다.
- 현재 페이지 번호를 알아야 한다.
2 ) 페이징 안에 값이 변해야 하는 순간.
- 처음 리스트 접속 : 받는 값이 아무것도 없을 경우, 초기값
- 페이징 버튼 클릭 : 현재 페이지 번호를 다시 받을 경우
- 게시판 검색 : 검색 키워드를 받을 경우, 전체 리스트 수가 달라질 수 있다. 해당 리스트 안에서 페이징 버튼 클릭 가능.
※ 메서드 실행 결과 반환 값 pageingVo
why? 값이 생성된 pageingVo를 사용하여 인터페이스(사용자의 화면)에서 안에 값들을 얻어 사용할 수 있다.
🍫 BoardDaoImpl.java
BoardDao.java 인터페이스를 상속받아 오버라이딩 하여 내용을 구현한다.
1. 전체 리스트 개수 구하기
1 ) 처음 리스트 접속 : 받는 값이 아무것도 없을 경우를 대비해 초기값을 넣어준다. ( 검색 키워드 / 현재 페이지 번호 )
처음 리스트에 접속했을 때 받아야 하는 기본값을 입력한다.
- 전달받은 키워드 NULL = "" ,
- 현재 페이지 번호 NULL 또는 없음 "" = 1번
public pageingVo getPaging(String kwd,String nowPage_) {
int nowPage;
if(nowPage_ == null && nowPage_.equals("")) {
nowPage = Integer.parseInt("1");
}else {
nowPage = Integer.parseInt(nowPage_);
}
if(kwd == null) kwd = "";
2 ) 전체 리스트 수를 구하기 위한 데이터베이스 초기화
- SQL문 사용을 위해 초기화 내용 작성
- 데이터베이스 연결이 실행되지 못해도 pageingVo 가 반환 될 수 있도록 초기화
// 0. import java.sql.*;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
List<BoardVo> list = new ArrayList<BoardVo>();
String kwdup = "%" + kwd + "%";
// PagingVo 반환값 초기화
int totalRecord = 0; // 총페이지
pageingVo pageing = new pageingVo(0,1); // 초기화
3 ) 전체 리스트 수를 구하는 쿼리문 수행
Select절에서 count() 함수를 사용하여 총게시물의 개수를 구하고 있다.
전달받은 검색어의 앞과 뒤로 '%'를 추가하여 문장 내에 해당 단어가 있을 시 찾아낼 수 있다. ex) % 검색어%
검색어가 있을 경우 검색한 내역에서의 총 게시물 개수가 구해진다.
검색어가 없을 경우도 위에서 파라미터 값으로 전달받은 kwd가 '%%'로 전달되어 전체 게시물의 수가 리턴된다.
※ % 는 무엇이 나올지 모를 때 사용.
try {
conn = getConnection();
// 3. SQL문 준비 / 바인딩 / 실행
String query = "SELECT count(b.NO)" + // 총개수
"FROM (" +
" SELECT ROWNUM num,T1.NO,T1.TITLE,T1.HIT,T1.REG_DATE ,T1.CONTENT,T1.USER_NO,T2.NAME " +
" FROM (SELECT * " +
" FROM BOARD " +
" ORDER BY REG_DATE desc)T1 " +
" INNER JOIN USERS T2 " +
" ON (T1.USER_NO = T2.NO) " +
" WHERE T1.TITLE LIKE ?" +
" OR T1.CONTENT LIKE ? " +
" OR T1.REG_DATE LIKE ?" +
" OR T2.NAME LIKE ? ) b";
pstmt = conn.prepareStatement(query);
pstmt.setString(1, kwdup);
pstmt.setString(2, kwdup);
pstmt.setString(3, kwdup);
pstmt.setString(4, kwdup);
rs = pstmt.executeQuery();
// 4.결과처리
if (rs.next()) {
totalRecord = rs.getInt(1);
}
2. 전체 리스트 수와 현제 페이지 값을 넣은 페이징 생성
사용자 페이지에서 사용할 수 있도록 구해준 페이징을 반환한다.
// 전체 리스트 수와 현제 페이지 값을 넣은 페이징 생성
pageing= new pageingVo(totalRecord, nowPage);
} catch (SQLException e) {
System.out.println("error:" + e);
} finally {
// 5. 자원정리
try {
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
System.out.println("error:" + e);
}
}
return pageing; // 페이징 반환
}
🍫 BoardServlet.jsp
Model2 패턴을 사용하고 있으므로 사용자가 클라이언트에 정보를 요청하면
서블릿에서 해당 요청을 실행하고 JSP 화면으로 전달해 준다.
1. 리스트 페이지 요청
현제 BoardServlet은 게시판과 관련된 기능들을 전부 한 곳에서 요청을 받아 어떤 값인지에 따라 실행을 if문으로 구분 지어 실행시켜주고 있다.
어떤 값인지 확인이 가능한 것은 파라미터 a 태그로 행동을 구분하고 있다.
list로 이동하는 요청 = name : a 파라미터의 값이 value : list 일 때.
@WebServlet("/board")
public class BoardServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String actionName = request.getParameter("a");
if ("list".equals(actionName)) {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
2. 리스트 페이지 요청
1) 기본 세팅 : 받아올 내용의 언어를 세팅해 준다. ( 한글이 가능하게 utf-8 )
request.setCharacterEncoding("utf-8");
2 ) 키워드값과 현제 페이지 정보를 Request로 받아온다.
String kwd = request.getParameter("kwd");
String nowpage = request.getParameter("nowPage");
3 ) 받아온 값이 없을 때 (기본 리스트 이동) , 키워드와 현재 위치 값이 오류가 나지 않도록 null 값을 초기화시켜 준다.
if(kwd == null) kwd = "";
if(nowpage == null) nowpage = "1";
4 ) BoardDaoImpl에게 받아온 정보를 전달하고 사용자(JSP)에게 전달할 내용을 받아준다.
// 리스트 가져오기
BoardDao dao = new BoardDaoImpl();
List<BoardVo> list = dao.getList(kwd,nowpage);
// 전체 갯수 및 페이지징 설정 셋팅
pageingVo pageing = dao.getPaging(kwd,nowpage);
5 ) BoardDaoImpl에게 받아온 내용을 request로 이동할 페이지에 전달해 준다.
request.setAttribute("name", value); 로 전달해 준다.
// 리스트 화면에 보내기
request.setAttribute("pageing", pageing);
request.setAttribute("list", list);
WebUtil.forward(request, response, "/WEB-INF/views/board/list.jsp");
}
🍫 list.jsp
1. 리스트 페이지에서 pageing 파일을 import 해서 사용
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<link href="/mysite_jimin/assets/css/board.css" rel="stylesheet" type="text/css">
<title>게시판 예시</title>
</head>
<body>
<div id="container">
<c:import url="/WEB-INF/views/includes/header.jsp"></c:import>
<c:import url="/WEB-INF/views/includes/navigation.jsp"></c:import>
<div id="content">
<div id="board">
<form id="search_form" action="/mysite_jimin/board" method="post">
<input type="hidden" name="a" value="search">
<input type="hidden" name="nowPage" value="1">
<input type="text" id="kwd" name="kwd" value="${param.kwd}">
<input type="submit" value="찾기">
</form>
<table class="tbl-ex">
<tr>
<th>번호</th>
<th>제목</th>
<th>내용</th>
<th>글쓴이</th>
<th>조회수</th>
<th>작성일</th>
<th> </th>
</tr>
<c:if test="${list.size() == 0}">
<tr>
<td colspan="7" style="text-aling:center;">내용이 없습니다</td>
</tr>
</c:if>
<c:forEach items="${list}" var="vo">
<tr>
<td>${vo.num }</td>
<td><a href="/mysite_jimin/board?a=read&no=${vo.no }&nowPage=${pageing.nowPage}">${vo.title}</a></td>
<td>${vo.content}</td>
<td>${vo.userName}</td>
<td>${vo.hit}</td>
<td>${vo.regDate}</td>
<td>
<c:if test="${authUser.no == vo.userNo }">
<a href="/mysite_jimin/board?a=delete&no=${vo.no }&nowPage=7" class="del">삭제</a>
</c:if>
</td>
</tr>
</c:forEach>
</table>
<c:import url="../includes/pager.jsp" />
<c:if test="${authUser != null }">
<div class="bottom">
<a href="/mysite_jimin/board?a=writeform" id="new-book">글쓰기</a>
</div>
</c:if>
</div>
</div>
<c:import url="/WEB-INF/views/includes/footer.jsp"></c:import>
</div><!-- /container -->
</body>
</html>
🍫 pager.jsp
1. import를 사용해서 pageingVo.java파일을 사용하고 있다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="com.javaex.vo.pageingVo" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
2. 블록 이동, FIRST / PREV 버튼
JSTL과 EL태그사용, ${ pageing. 가져올 요소 } 서블릿에서 request로 전달받은 name(pageing)으로 PageingVo 안에 요소들을 가져와 사용.
1 ) EL 태그 <c:if test=" --------- ">를 사용, 조건을 만족하면 안에 있는 처음/ 이전 페이지 버튼을 나타나게 해 주었다.
< c : if test = " $ { pageing.getNowBlock( ) > 1 } " >
현제 블록이 1보다 클 때 처음 / 이전 버튼이 노출된다.
2 ) 처음 버튼 / 이전버튼
<li><a href="/mysite_jimin/board?a=list&kwd=${param.kwd}&nowPage=1"> 처음 </a></li>
<li><a href="/mysite_jimin/board?a=list&kwd=${param.kwd}&nowPage=${pageing.getPrev()}"> 이전 </a></li>
파라미터로 받아야 하는 값을 쿼리스트링에 직접 넣어 클릭 시 해당 값을 받을 수 있도록 해준다.
<div class="pager">
<ul>
<c:if test="${pageing.getNowBlock() > 1}">
<li><a href="/mysite_jimin/board?a=list&kwd=${param.kwd}&nowPage=1">◀</a></li>
<li><a href="/mysite_jimin/board?a=list&kwd=${param.kwd}&nowPage=${pageing.getPrev()}">◀</a></li>
</c:if>
3. 페이지이동 버튼을 개수에 맞게 뿌려준다.
1) EL 태그 forEach를 사용, 현재 블록에서 첫 페이지 번호부터 마지막 페이지 번호까지 뿌려준다.
<c:forEach var="i" begin="${pageing.getStartPage()}" end="${pageing.getEndPage()}" >
2 ) EL 태그 when을 사용해서 i 값이 현제 블록과 같으면 링크를 없애고 선택된 상태를 나타낸다.
<c:when test="${i == pageing.getNowPage()}">
3 ) 페이지 버튼을 클릭했을 시, 파라미터로 받아야 하는 값을 쿼리스트링에 직접 넣어 해당 값을 받을 수 있도록 해준다.
<a href="/mysite_jimin/board?a=list&kwd=${param.kwd}&nowPage=${i}">${i}</a>
<c:forEach var="i" begin="${pageing.getStartPage()}" end="${pageing.getEndPage()}" >
<c:choose>
<c:when test="${i == pageing.getNowPage()}">
<li>${i}</li>
</c:when>
<c:otherwise>
<li><a href="/mysite_jimin/board?a=list&kwd=${param.kwd}&nowPage=${i}">${i}</a></li>
</c:otherwise>
</c:choose>
</c:forEach>
4. 블록 이동, LAST / NEXT 버튼
마지막으로 이동하는 버튼과 다음 버튼을 만들어준다. IF를 사용해서
<c:if test="${pageing.getEndPage() < pageing.getTotalPage()}">
마지막 페이지 번호가 전체 페이지 번호보다 작을 때 노출이 되고 , 마지막 페이지 번호가 전체 페이지 번호 보다 클 때는 노출이 되지 않는다.
<c:if test="${pageing.getEndPage() < pageing.getTotalPage()}">
<li><a href="/mysite_jimin/board?a=list&kwd=${param.kwd}&nowPage=${pageing.getNext()}">▶</a></li>
<li><a href="/mysite_jimin/board?a=list&kwd=${param.kwd}&nowPage=${pageing.getTotalPage()}">▶</a></li>
</c:if>
</ul>
</div>
'BackEnd > Servlet · JSP' 카테고리의 다른 글
[ Servlet / JSP ] Model 1 방식과 Model 2 방식 비교 (0) | 2023.02.22 |
---|---|
[ Project / Servlet · JSP ] 1차 과제 Model 2 방식 - (2) 게시판 만들기 ( 검색 기능 ) (0) | 2023.02.16 |
[ Servlet / JSP ] JDBC 연동 (0) | 2023.02.05 |
[ Servlet / JSP ] JSTL · EL 기본 문법 (0) | 2023.02.05 |
[ Servlet / JSP ] Form태그 GET · POST 데이터 · 파일 전송 (0) | 2023.02.04 |