minlog
article thumbnail

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>&nbsp;</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>

 

 

 

profile

minlog

@jimin-log

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!