로그인 성공 후 → 게시글 목록 페이지로 이동하기 위해 게시글 목록 페이지를 만들어준다.
css와 데이터베이스 자료는 생성되어 있던 것 사용
boardList.jsp
)PagingUtil
, BoardService
, BoardDao
, BoardController
, SearchDto
, BoardDto
)boardList.jsp
)boardList.jsp
)boardList.jsp
)Pagination(or Paging)
다수의 정보를 한 화면에 출력할 때, 출력할 내용의 개수를 제한하고 책의 페이지처럼 여러 화면으로 분리하는 방식.
DB(MySQL)에 SQL의 LIMIT 구문을 사용하여 한 화면에 출력할 데이터를 나눠서 가져오는 방식을 사용한다.
페이지의 번호에 pageNum 값을 다르게 링크하는 형식의 HTML 태그 코드를 작성.
전체 데이터의 양과 한 페이지에 보여질 개수 등의 정보를 가지고, 간단한 수식을 사용하여 자동으로 계산하는 객체를
사용하여 처리.
생성자를 활용하자!
Lombok의 @AllArgsConstructor
어노테이션
생성자란? 객체를 생성할 때 new 키워드 뒤에 호출하는 멤버변수(또는 인스턴스) 초기화 메소드
header와 footer는 jsp:include 코드로 import 해온다.
<header>
<jsp:include page="header.jsp"></jsp:include>
</header>
<footer>
<jsp:include page="footer.jsp"></jsp:include>
</footer>
<section>
<div class="content">
<div class="board-form">
<div class="user-info">
<div class="user-info-sub">
<p>등급 [${mb.g_name}]</p>
<p>POINT [${mb.m_point}]</p>
</div>
</div>
<h2 class="login-header">게시글 목록</h2>
<div class="search-area">
<select id="sel">
<option value="b_title" selected>
제목
</option>
<option value="b_contents">
내용
</option>
</select>
<input type="text" id="keyword">
<button id="search">검색</button>
</div>
<div class="data-area">
<div class="title-row">
<div class="t-no p-10">번호</div>
<div class="t-title p-30">제목</div>
<div class="t-name p-15">작성자</div>
<div class="t-data p-30">작성일</div>
<div class="t-view p-15">조회수</div>
</div>
<div class="data-row">
<c:if test="${empty bList}">
<div style="width: 100%">
게시글이 없습니다.
</div>
</c:if>
<c:if test="${!empty bList}">
<c:forEach var="bitem" items="${bList}">
<div class="t-no p-10">${bitem.b_num}</div>
<div class="t-title p-30">
<a href="/contents?b_num=${bitem.b_num}">${bitem.b_title}</a>
</div>
<div class="t-name p-15">${bitem.m_name}</div>
<div class="t-date p-30">
<fmt:formatDate value="${bitem.b_date}" pattern="yyyy-MM-dd HH:mm:ss"></fmt:formatDate>
</div>
<div class="t-views p-15">${bitem.b_views}</div>
</c:forEach>
</c:if>
</div>
</div>
</div>
</div>
</section>
위 그럼처럼 게시글을 분리하기 위한 페이징 작업
다음 버튼을 누르면 6페이지부터 게시글을 다시 불러온다.
@Data
public class BoardDto {
private int b_num;
private String b_title;
private String b_contents;
private String b_id;
private String m_name;
private Timestamp b_date;
private int b_views;
}
게시글 작성에 필요한 제목, 내용, 작성자 등 데이터
//변수 선언 영역
@AllArgsConstructor
public class PagingUtil {
private int maxNum;//전체 글 개수.
private int pageNum;//현재 보이는 페이지 번호.
private int listCnt;//페이지 당 글 개수.
private int pageCnt;//보여질 페이지 번호 개수.
private String listName;//목록 페이지가 여러개인 경우
//페이징 처리할 목록 페이지 url.
//페이징용 html 코드를 만드는 메소드
public String makePaging(){
String page = null;
StringBuffer sb = new StringBuffer();
//1. 전체 페이지 개수 구하기(페이지 당 listCnt만큼 출력)
// 전체 데이터가 4개 : 1 페이지
// 전체 데이터가 6개 : 2 페이지
int totalPage = (maxNum % listCnt) > 0 ?
maxNum / listCnt +1 :
maxNum / listCnt;
//2. 현재 페이지가 속해 있는 그룹 번호 구하기
int curGroup = (pageNum % pageCnt) > 0 ?
pageNum /pageCnt + 1 :
pageNum / pageCnt;
//3. 현재 보이는 페이지 그룹의 시작 번호 구하기
int start = (curGroup * pageCnt) - (pageCnt - 1);
//두번째 그룹의 시작번호 = (2 * 5) - (5 - 1) = 6
//4. 현재 보이는 페이지 그룹의 마지막 번호 구하기
int end = (curGroup * pageCnt) >= totalPage ?
totalPage : curGroup * pageCnt;
//totalPage 9, curGroup * pageCnt 10 -> totalPage가 마지막 번호
//'이전' 버튼 처리. 시작번호가 1일 때는 버튼 생성 x.
if(start != 1){
sb.append("<a class='pno' href='/" + listName
+ "pageNum=" + (start -1) + "'>");
sb.append(" 이전 </a>");
}
//중간 페이지 번호 버튼 처리
for(int i = start; i <= end; i++){
if(pageNum != i){//현재 페이지가 아닌 번호
sb.append("<a class='pno' href='/" + listName +
"pageNum=" + i + "'>");
sb.append(" " + i + " </a>");
} else { //현재 페이지 번호(링크x)
sb.append("<font class='pno' style='color: red;'>");
sb.append(" " + i + " </font>");
//<font class='pno' style='color: red;'> 1 </font>
}
}//for end
//'다음' 버튼 처리.
if(end != totalPage){
sb.append("<a class='pno' href='/" + listName
+ "pageNum=" + (end + 1) + "'>");
sb.append(" 다음 </a>");
//<a class='pno' href='/list?pageNum=6'> 다음 </a>
}
//StringBuffer에 저장된 내용을 문자열로 변환.
page = sb.toString();
return page;
}
@Data
public class SearchDto {
private String colname;
private String keyword;
private int pageNum;//보여질 페이지 번호
private int listCnt;//페이지 당 출력할 게시글 개수
}
페이징과 검색에 필요한 데이터 타입 모음
//Dao 객체
@Autowired
private BoardDao bDao;
@Autowired
private MemberDao mDao;
private ModelAndView mv;
private int lcnt = 5;//목록에 보여질 게시글 개수
Dao @Autowired
어노테이션하고 ModelAndView
사용
private String getPaging(SearchDto sdto) {
String pageHtml = null;
//전체 글개수 구하기.
int maxNum = bDao.selectBoardCnt(sdto);
//페이지에 보여질 번호 개수
int pageCnt = 5;
String listName = null;
if(sdto.getColname() != null){
listName = "list?colName" + sdto.getColname() + "&keyword=" + sdto.getKeyword() + "&";
}//list?colname=b_title&keyword=4&
else {
listName = "list?";
}
PagingUtil paging = new PagingUtil(maxNum, sdto.getPageNum(), sdto.getListCnt(), pageCnt, listName);
pageHtml = paging.makePaging();
return pageHtml;
}
데이터베이스에 저장되어 있는 전체 글 개수를 구하고 게시글 목록 페이지에 보여질 개수를 pageCnt
로 지정한다.
pageHtml
로 리턴
public ModelAndView getBoardList(SearchDto sdto, HttpSession session){
log.info("getBoardList()");
mv = new ModelAndView();
//SQL 쿼리문의 limit 부분 설정
int num = sdto.getPageNum();
//출력할 게시물 수가 설정되지 않으면 기본값(5)로 설정
if(sdto.getListCnt() == 0){
sdto.setListCnt(lcnt);
}
//페이지번호를 limit 시작 번호로 변경
sdto.setPageNum((num - 1) * sdto.getListCnt());
//Dao로 게시글 목록 가져오기
List<BoardDto> bList = bDao.selectBoardList(sdto);
mv.addObject("bList", bList);
//페이징처리
sdto.setPageNum(num);
String pageHtml = getPaging(sdto);
mv.addObject("paging", pageHtml);
//세션에 필요 정보 저장(pageNum, 검색관련 정보)
//페이지 번호 저장 - 글쓰기 또는 상세보기 화면에서
//목록으로 돌아갈 때
session.setAttribute("pageNum", num);
//검색 결과 목록으로 돌아갈 때
if(sdto.getColname() != null){
//검색 결과 목록
session.setAttribute("sdto", sdto);
} else {
//검색이 아닐 때는 searchDto를 제거
//세션에 저장한 데이터 삭제 : removeAttribute()
session.removeAttribute("sdto");
}
mv.setViewName("boardList");
return mv;
}
getPaging
메소드에서 만든 페이징 정보와 Dao의 sql 명령어 결과를 가져오는 메소드
@Mapper
public interface BoardDao {
//게시글 목록 가져오는 메소드 선언
List<BoardDto> selectBoardList(SearchDto sdto);
//게시글 개수 가져오는 메소드 선언
int selectBoardCnt(SearchDto sdto);
}
BoardDao.java
에서 메소드를 먼저 선언한 후 generate로 BoardDao.xml
에 쿼리를 만든다.
<mapper namespace="com.raspberry.board.dao.BoardDao">
<select id="selectBoardList" resultType="BoardDto" parameterType="SearchDto">
select * from blist <if test="colname != null and colname != ''">
where ${colname} like concat('%', #{keyword}, '%')
</if>
limit #{pageNum}, #{listCnt}
</select>
<select id="selectBoardCnt" resultType="java.lang.Integer" parameterType="SearchDto">
select count(*) from blist
<if test="colname != null and colname != ''">
where ${colname} like concat('%',#{keyword},'%')
</if>
</select>
글쓰기 버튼 생성 후 onclick="location.href='/writeForm'"
에 대한 처리는 글쓰기 처리를 하면서 작업한다.
<%--data-area--%>
<div class="btn-area">
<div class="paging">${paging}</div>
<button class="wr-btn" onclick="location.href='/writeForm'">글쓰기</button>
</div> <%--btn-area--%>
로그인 성공 여부나 글 작성 등 동작에 대한 결과를 나타내주는 메시지 출력 명령어와 사용자 정보를 출력하는 함수
<script>
$(function(){
//메시지 출력 부분
let m = "${msg}";
if(m != ""){
alert(m);
}
//로그인한 회원 정보 및 로그아웃 출력
let loginName = "${mb.m_name}";
$("#mname").html(loginName + "님");
$(".suc").css("display", "block");
$(".bef").css("display", "none");
});
</script>
제목 또는 내용으로 게시글을 검색하는 스크립트
<script>
//검색 기능
$("#search").click(function () {
let keyword = $("#keyword").val();
if(keyword == ""){
alert("검색어를 입력하세요.");
return;
}
let select = $("#sel").val(); //제목 or 내용
console.log(select, keyword);
location.href = "/list?colname=" + select + "&keyword=" + keyword + "&pageNum=1";
// localhost/list?colname=b_title&keyword=4&pageNum=1
});
</script>
2023.05.24 작성