spring 게시판 구현 게시판 목록, 페이징 처리

박예린·2023년 2월 26일

게시판 게시글 목록 구현, 페이징 처리

로그인과 회원가입, 중복체크까지 구현을 완료함.
이어서 게시판 목록 보이기 구현
1. 로그인을 성공하면 게시글 목록(bbslist.jsp)로 이동
2. 컨트롤러(BbsController.jsp)에서 bbslist.do를 취함
3. mapper(Bbs.xml)에서 sql문으로 select해서 BbsDto에 담아 돌려줌
4. 이 결과를 model의 속성 값으로 추가함

데이터를 담기 위한 객체 생성

BbsDto.jsp

package mul.cam.a.dto;

import java.io.Serializable;

// BBS  Bulletin Board System
public class BbsDto implements Serializable {

	private int seq;		// sequence 글번호
	private String id;		// 작성자
	
	private int ref;		// 답글용	 	그룹번호(글번호)	
	private int step;		//			행번호
	private int depth;		//			깊이
	
	private String title;
	private String content;
	private String wdate;
	
	private int del;
	private int readcount;	// 조회수
	
	public BbsDto() {
	}

	public BbsDto(String id, String title, String content) {
		super();
		this.id = id;
		this.title = title;
		this.content = content;
	}

	public BbsDto(int seq, String id, int ref, int step, int depth, String title, String content, String wdate, int del,
			int readcount) {
		super();
		this.seq = seq;
		this.id = id;
		this.ref = ref;
		this.step = step;
		this.depth = depth;
		this.title = title;
		this.content = content;
		this.wdate = wdate;
		this.del = del;
		this.readcount = readcount;
	}

	public int getSeq() {
		return seq;
	}

	public void setSeq(int seq) {
		this.seq = seq;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public int getRef() {
		return ref;
	}

	public void setRef(int ref) {
		this.ref = ref;
	}

	public int getStep() {
		return step;
	}

	public void setStep(int step) {
		this.step = step;
	}

	public int getDepth() {
		return depth;
	}

	public void setDepth(int depth) {
		this.depth = depth;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public String getWdate() {
		return wdate;
	}

	public void setWdate(String wdate) {
		this.wdate = wdate;
	}

	public int getDel() {
		return del;
	}

	public void setDel(int del) {
		this.del = del;
	}

	public int getReadcount() {
		return readcount;
	}

	public void setReadcount(int readcount) {
		this.readcount = readcount;
	}

	@Override
	public String toString() {
		return "BbsDto [seq=" + seq + ", id=" + id + ", ref=" + ref + ", step=" + step + ", depth=" + depth + ", title="
				+ title + ", content=" + content + ", wdate=" + wdate + ", del=" + del + ", readcount=" + readcount
				+ "]";
	}	
}

웹페이지에서 보이게 될 게시글 목록 view

bbslist.jsp(View page)

(앞서 jsp에서 썼던 bbslist사용)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.3/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"></script>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>

<script type="text/javascript" src="./jquery/jquery.twbsPagination.min.js"></script>
<style type="text/css">
.table th, .table td {
	text-align: center;
	vertical-align: middle!important;
}
</style>

</head>
<body bgcolor="#e9e9e9">

<h1>게시판</h1>

<hr>

<div align="center">

<table style="margin-left: auto; margin-right: auto; margin-top: 3px; margin-bottom: 3px">
	<tr>
		<td style="padding-left: 5px">
			<select class="custom-select" id="choice" name="choice">
				<option selected>검색</option>
				<option value="title">제목</option>
				<option value="content">내용</option>
				<option value="writer">작성자</option>
			</select>
		</td>
		<td style="padding-left: 5px" class="align-middle">
			<input type="text" class="form-control" id="search" name="search" placeholder="검색어" value="<%=search %>">
		<td style="padding-left: 5px">
			<span>
				<button type="button" class="btn btn-primary" onclick="searchBtn()">검색</button>
			</span>
		</td>
	</tr>
</table>
<br>
<table class="table table-hover table-sm" style="width: 1000px">
<col width="70"><col width="600"><col width="100"><col width="150">
<thead>
<tr class="bg-primary" style="color: white;">
	<th>번호</th><th>제목</th><th>조회수</th><th>작성자</th>
</tr>
</thead>
</table>
</script>
</body>
</html>

Controller

BbsController.jsp

@Controller로 컨트롤러를 선언
@RequestMapping으로 경로 요청이 있을 경우 해당 컨르롤러 클래스를 매핑시켜 줌

package mul.cam.a.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import mul.cam.a.dto.BbsComment;
import mul.cam.a.dto.BbsDto;
import mul.cam.a.dto.BbsParam;
import mul.cam.a.service.BbsService;

@Controller
public class BbsController {
	
	@Autowired
	BbsService service;
	
	@GetMapping(value="bbslist.do")
					//들어오는 값 - param / 짐싸서 보내기 위한 - model
	public String bbslist(BbsParam param, Model model) {
	}

mapper

Bbs.xml

mapper에 해당 - sql문 작성
id

  • bbslist
  • getAllBbs
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
	
<mapper namespace="Bbs">

					<!-- parameterType은 단 하나만 존재! -->
<!-- parameterType - 들어오는 값, resultType - 나가는 값 -->
<select id="bbslist" parameterType="mul.cam.a.dto.BbsParam"
	resultType="mul.cam.a.dto.BbsDto">

	select seq, id, ref, step, depth, title, content, wdate, del, readcount
	from
		(select row_number()over(order by ref desc, step asc) as rnum,
			seq, id, ref, step, depth, title, content, wdate, del, readcount
		 from bbs
		 where 1=1
		 <if test="choice != null and choice != '' and search != null and search != '' ">
		 	<if test="choice == 'title'">
		 		and title like concat('%', #{search}, '%') and del=0
		 	</if>
		 	<if test="choice == 'content'">
		 		and content like concat('%', #{search}, '%') and del=0
		 	</if>
		 	<if test="choice == 'writer'">
		 		and id=#{search} and del=0
		 	</if>
		 </if>
		 order by ref desc, step asc) a
	where rnum between ${start} and ${end}
</select>
  
<!-- 글의 총 갯수 for paging -->
<select id="getAllBbs" parameterType="mul.cam.a.dto.BbsParam" resultType="java.lang.Integer">
	
	select ifnull(count(*), 0)
	from bbs
	<if test="choice != null and choice != '' and search != null and search != '' ">
	 	<if test="choice == 'title'">
	 		where title like concat('%', #{search}, '%')
	 	</if>
	 	<if test="choice == 'content'">
	 		where content like concat('%', #{search}, '%')
	 	</if>
	 	<if test="choice == 'writer'">
	 		where id=#{search}
	 	</if>
	 </if>
  </select>

DAO/Service

SpringMVC 패턴 구성

특정 도메인이 매핑되면 Controller가 해당 Service 호출
-> Service는 주입된 DAO의 리턴 값을 가지고 옴
-> DAO는 mapper의 쿼리의 결과값 반환
-> Controller는 Service의 결과값을 model에 담아 view로 보냄
-> view는 Controller로부터 받은 값을 출력

실제 비즈니스 로직을 처리하는 부분은 Service
DAO는 백엔드에서 서버-클라이언트 프로그램간 데이터를 주고받음

BbsDao.java

package mul.cam.a.dao;

import java.util.List;

import mul.cam.a.dto.BbsComment;
import mul.cam.a.dto.BbsDto;
import mul.cam.a.dto.BbsParam;

public interface BbsDao {
	
	/* 글과 페이지 넘기기 */
	List<BbsDto> bbslist(BbsParam bbs);
	
	//모든 글의 갯수 allBbs
	int getAllBbs(BbsParam bbs);

BbsDaoImpl.java

package mul.cam.a.dao.impl;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import mul.cam.a.dao.BbsDao;
import mul.cam.a.dto.BbsComment;
import mul.cam.a.dto.BbsDto;
import mul.cam.a.dto.BbsParam;

@Repository
public class BbsDaoImpl implements BbsDao {

	@Autowired
	SqlSession session;
	
	String ns = "Bbs.";

	@Override
	public List<BbsDto> bbslist(BbsParam bbs) {		
		return session.selectList(ns + "bbslist", bbs);
	}

	@Override
	public int getAllBbs(BbsParam bbs) {		
		return session.selectOne(ns + "getAllBbs", bbs);
	}

BbsService.java

package mul.cam.a.service;

import java.util.List;

import mul.cam.a.dto.BbsComment;
import mul.cam.a.dto.BbsDto;
import mul.cam.a.dto.BbsParam;

public interface BbsService {

	List<BbsDto> bbslist(BbsParam bbs);	
	int getAllBbs(BbsParam bbs);
	
	boolean writeBbs(BbsDto dto);
	
	BbsDto getBbs(int seq);

BbsServiceImpl.java

package mul.cam.a.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import mul.cam.a.dao.BbsDao;
import mul.cam.a.dto.BbsComment;
import mul.cam.a.dto.BbsDto;
import mul.cam.a.dto.BbsParam;
import mul.cam.a.service.BbsService;

@Service
public class BbsServiceImpl implements BbsService {

	@Autowired
	BbsDao dao;

	@Override
	public List<BbsDto> bbslist(BbsParam bbs) {		
		return dao.bbslist(bbs);
	}

	@Override
	public int getAllBbs(BbsParam bbs) {		
		return dao.getAllBbs(bbs);
	}

Controller를 통한 결과값 전달 / view페이지에서 결과값 출력

BbsController.java

@GetMapping(value="bbslist.do")
					//들어오는 값 - param / 짐싸서 보내기 위한 - model
	public String bbslist(BbsParam param, Model model) {
		
		// 글의 시작과 끝
		int pn = param.getPageNumber();  // 0 1 2 3 4
		int start = 1 + (pn * 10);	// 1  11
		int end = (pn + 1) * 10;	// 10 20 
		
		param.setStart(start);
		param.setEnd(end);
		
		List<BbsDto> list = service.bbslist(param);
		
		//페이지 총 갯수
		//총 길이값
		int len = service.getAllBbs(param);
		
		//게시글의 총 갯수가 아니라 페이지가 몇페이지인지 알고싶은거임
		int pageBbs = len / 10; 	//25/10 -> 2 나머지 5는 3page로 넘어감 +1필요
		if((len % 10)>0) {
			pageBbs = pageBbs + 1;
		}
		
		 if(param.getChoice() == null || param.getChoice().equals("")
				 || param.getSearch() == null || param.getSearch().equals("")) {
			 param.setChoice("검색"); 
			 param.setSearch("");
		 }
		 
		
		//짐싸!
		 model.addAttribute("bbslist", list);	// 게시판 리스트
		 model.addAttribute("pageBbs", pageBbs);	// 총 페이지수
		 model.addAttribute("pageNumber", param.getPageNumber()); // 현재 페이지
		 model.addAttribute("choice", param.getChoice());	// 검색 카테고리
		 model.addAttribute("search", param.getSearch());	// 검색어	
		
		return "bbslist";
	}

Bbslist.jsp

<%@page import="mul.cam.a.util.Utility"%>
<%@page import="mul.cam.a.dto.BbsDto"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.3/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"></script>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>

<script type="text/javascript" src="./jquery/jquery.twbsPagination.min.js"></script>
<style type="text/css">
.table th, .table td {
	text-align: center;
	vertical-align: middle!important;
}
</style>

</head>
<body bgcolor="#e9e9e9">

<%
/*
String choice = request.getParameter("choice");
String search = request.getParameter("search");

if(choice == null){
	choice = "";
}
if(search == null){
	search = "";
}
*/
// BbsDao dao = BbsDao.getInstance();

// List<BbsDto> list = dao.getBbsList();
// List<BbsDto> list = dao.getBbsSearchList(choice, search);

List<BbsDto> list = (List<BbsDto>)request.getAttribute("bbslist");
int pageBbs = (Integer)request.getAttribute("pageBbs");
int pageNumber = (Integer)request.getAttribute("pageNumber");
String choice = (String)request.getAttribute("choice");
String search = (String)request.getAttribute("search");
%>

<h1>게시판</h1>

<hr>

<div align="center">

<table style="margin-left: auto; margin-right: auto; margin-top: 3px; margin-bottom: 3px">
	<tr>
		<td style="padding-left: 5px">
			<select class="custom-select" id="choice" name="choice">
				<option selected>검색</option>
				<option value="title">제목</option>
				<option value="content">내용</option>
				<option value="writer">작성자</option>
			</select>
		</td>
		<td style="padding-left: 5px" class="align-middle">
			<input type="text" class="form-control" id="search" name="search" placeholder="검색어" value="<%=search %>">
		<td style="padding-left: 5px">
			<span>
				<button type="button" class="btn btn-primary" onclick="searchBtn()">검색</button>
			</span>
		</td>
	</tr>
</table>
<br>
<table class="table table-hover table-sm" style="width: 1000px">
<col width="70"><col width="600"><col width="100"><col width="150">
<thead>
<tr class="bg-primary" style="color: white;">
	<th>번호</th><th>제목</th><th>조회수</th><th>작성자</th>
</tr>
</thead>
<tbody>

<%
if(list == null || list.size() == 0){
	%>
	<tr>
		<td colspan="4">작성된 글이 없습니다</td>
	</tr>
	<%
}else{
	
	for(int i = 0;i < list.size(); i++)
	{
		BbsDto dto = list.get(i);
		%>
		<tr>
			<th><%=i + 1 + (pageNumber * 10) %></th>
			
			<td style="text-align: left;">
			<%
			if(dto.getDel() == 0){
				%>
					<%=Utility.arrow(dto.getDepth()) %>
					<a href="bbsdetail.do?seq=<%=dto.getSeq() %>">
						<%=dto.getTitle() %>
					</a>						
				<%
			}else if(dto.getDel() == 1){
				%>				
					<%=Utility.arrow(dto.getDepth()) %>
					<font color="#ff0000">*** 이 글은 작성자에 의해서 삭제되었습니다 ***</font>					
				<%
			}	
			%>
			</td>
			
			<td><%=dto.getReadcount() %></td>
			<td><%=dto.getId() %></td>
		</tr>
		<%
	}
}
%>

</tbody>
</table>

<br>

<%-- <%
for(int i = 0;i < pageBbs; i++){
	if(pageNumber == i){	// 현재 페이지
		%>
		<span style="font-size: 15pt;color: #0000ff">
			<%=i+1 %>
		</span>
		<%
	}else{					// 그밖에 다른 페이지
		%>
		<a href="#none" title="<%=i+1 %>페이지" onclick="goPage(<%=i %>)"
			style="font-size: 15pt; color: #000; text-decoration: none;">
			[<%=i+1 %>]
		</a>			
		<%
	}		
}
%> --%>

<div class="container">
    <nav aria-label="Page navigation">
        <ul class="pagination" id="pagination" style="justify-content:center"></ul>
    </nav>
</div>

<br>
<a href="bbswrite.do">글쓰기</a>

</div>

<script type="text/javascript">

let search = "<%=search %>";
console.log("search = " + search);
if(search != ""){
	let obj = document.getElementById("choice");
	obj.value = "<%=choice %>";
	obj.setAttribute("selected", "selected");
}

function searchBtn() {
	let choice = document.getElementById('choice').value;
	let search = document.getElementById('search').value;
	
	/* if(choice == ""){
		alert("카테고리를 선택해 주십시오");
		return;
	} */
	/* 
	if(search.trim() == ""){
		alert("검색어를 선택해 주십시오");
		return;
	} */
	
	location.href = "bbslist.do?choice=" + choice + "&search=" + search;
}

//페이징
$('#pagination').twbsPagination({
	startPage: <%=pageNumber+1 %>, 
    totalPages: <%=pageBbs %>,
    visiblePages: 10,
    first:'<span srid-hidden="true">«</span>',
    prev:"이전",
    next:"다음",
    last:'<span srid-hidden="true">»</span>',
    initiateStartPageClick:false,   // onPageClick 자동실행되지 않도록
    onPageClick: function (event, page) {
        // alert(page);
        let choice = document.getElementById('choice').value;
		let search = document.getElementById('search').value;
    	location.href = "bbslist.do?choice=" + choice + "&search=" + search + "&pageNumber=" + (page-1);
    }
});
</script>
</body>
</html>
profile
개발자를 꿈꾸는 귀여운 나

0개의 댓글