Oracle, Mybatis, Bootstrap5 이용한 검색과 페이징 기능이 있는 기본 게시판입니다.
회원타입에 따른 접근 제한
비회원: 읽기, 쓰기 불가 (접근제한)
회원: 글읽기, 본인 글 수정, 본인 글만 댓글 확인 가능 (타인 글 댓글 읽기 불가), 쓰기 가능
관리자: 읽기, 쓰기, 댓글쓰기 가능
Domain - QnaBoard
@Data
public class QnaBoard {
private Integer qnaBoardNum;
private Integer memberNum;
private String memberName;
private String qnaBoardTitle;
private String qnaBoardContent;
private Date qnaBoardDate;
private Integer count;
private String cmtContent;
private Date cmtDate;
private String keyword;
public QnaBoard(Integer qnaBoardNum, Integer memberNum, String qnaBoardTitle, String qnaBoardContent, Date qnaBoardDate) {
this.qnaBoardNum = qnaBoardNum;
this.memberNum = memberNum;
this.qnaBoardTitle = qnaBoardTitle;
this.qnaBoardContent = qnaBoardContent;
this.qnaBoardDate = qnaBoardDate;
}
public QnaBoard(){}
Domain - QnaBoardWrite
@Data
public class QnaBoardWrite {
private String title;
private String content;
private Integer mno;
private Integer cno;
private Integer bno;
}
Domain - Paging
public class Paging {
private int productType;
private String keyword;
private int section, pageNum;
public Paging() {}
public Paging(int section, int pageNum, int productType) {
this.section = section;
this.pageNum = pageNum;
this.productType = productType;
}
public Paging(int section, int pageNum) {
this.section = section;
this.pageNum = pageNum;
}
public Paging(String keyword, int section, int pageNum) {
this.keyword = keyword;
this.section = section;
this.pageNum = pageNum;
}
public int getSection() {
return section;
}
public void setSection(int section) {
this.section = section;
}
public int getPageNum() {
return pageNum;
}
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
}
Controller - QnaBoardController 예시 (게시판 list)
@RequiredArgsConstructor
@Controller
public class QnaBoardController {
private final QnaBoardService qnaBoardService;
@GetMapping("/qnaBoard")
public String qnaBoardList(@ModelAttribute("QnaBoard") QnaBoard qnaBoard, Model model,
@RequestParam(value = "section", defaultValue = "1") int section,
@RequestParam(value = "pageNum", defaultValue = "1") int pageNum,
@RequestParam(value = "keyword", required = false) String keyword) {
if (keyword==null){
Paging paging = new Paging(section, pageNum);
int totalCnt = qnaBoardService.pagingCount();
List<QnaBoard> list = qnaBoardService.selectBoardPaging(paging);
String totalCntJudge = qnaBoardService.totalCntJudge(totalCnt);
model.addAttribute("totalCntJudge", totalCntJudge);
model.addAttribute("totalCnt", totalCnt);
model.addAttribute("section", section);
model.addAttribute("pageNum", pageNum);
model.addAttribute("boardList", list);
System.out.println("키워드 없음 실행");
} else if(keyword!=null){
Paging paging = new Paging(keyword,section, pageNum);
int totalCnt = qnaBoardService.pagingCountSearch(paging);
List<QnaBoard> list = qnaBoardService.selectBoardPaging(paging);
String totalCntJudge = qnaBoardService.totalCntJudge(totalCnt);
model.addAttribute("totalCntJudge", totalCntJudge);
model.addAttribute("totalCnt", totalCnt);
model.addAttribute("section", section);
model.addAttribute("pageNum", pageNum);
model.addAttribute("boardList", list);
System.out.println("키워드 있음 실행");
}
return "qnaBoard/list";
}
}
코드설명 : http://~~/qnaBoard 라는 게시판 링크를 타고 들어가면 첫 페이지에 보여줄 내용들을 키워드있는경우와 없는 경우로 구분해서 서비스를 통해 디비정보를 불러온다음에 model값에 넣어주고, return을 통해 templete의 qnaBoard/list.html을 돌려줍니다.
* 페이징은 JPA를 쓰지않아 다소 옛날 방식입니다.
Controller - QnaBoardController 예시 (게시판 상세보기- 목록의 특정 글 클릭시)
@GetMapping("/qnaBoard/view/{qnaBoardNum}") //회원만 접근 가능
public String qnaBoardView(@PathVariable("qnaBoardNum") int qnaBoardNum,
@ModelAttribute("QnaBoard") QnaBoard qnaBoard, Model model, HttpSession session) {
AuthInfo ai = (AuthInfo) session.getAttribute("authInfo");
if (ai == null) { //로그인 안했으면 게시글 읽기 불가
return "accessFail";
}
QnaBoard view = qnaBoardService.selectView(qnaBoardNum);
model.addAttribute("view", view);
List<Comment> cmt = qnaBoardService.cmtList(qnaBoardNum);
model.addAttribute("cmt", cmt);
return "qnaBoard/view";
}
ai에는 로그인의 세션정보가 들어갑니다. 실제 게시글의 내용과 코멘트를 출력하는 부분입니다.
게시글의 번호를 @PathVariable을 통해 가져와야합니다.
Service - QnaBoardService 예시
@Service
@RequiredArgsConstructor
public class QnaBoardService {
@Autowired
QnaBoardMapper qnaBoardMapper;
@Transactional
public QnaBoard selectView(Integer qnaBoardNum) {
QnaBoard view = qnaBoardMapper.selectView(qnaBoardNum);
return view;
}
@Transactional
public List<QnaBoard> selectBoardPaging(Paging paging) {
List<QnaBoard> list = qnaBoardMapper.selectBoardPaging(paging);
return list;
}
@Transactional
public String totalCntJudge(int totalCnt) {
String judge = "";
if(totalCnt > 100) judge = "101";
if(totalCnt == 100) judge = "100";
if(totalCnt < 100) judge = "99";
return judge;
}
@Transactional
public Integer pagingCount() {
Integer count = qnaBoardMapper.pagingCount();
return count;
}
@Transactional
public Integer pagingCountSearch(Paging paging) {
Integer count = qnaBoardMapper.pagingCountSearch(paging);
return count;
}
@Transactional
public List<Comment> cmtList(Integer qnaBoardNum) {
List<Comment> cmt = qnaBoardMapper.selectByNum(qnaBoardNum);
return cmt;
}
}
Mapper - QnaBoardMapper 예시
@Mapper
public interface QnaBoardMapper {
List<QnaBoard> selectAllList();
QnaBoard selectView(Integer qnaBoardNum);
List<QnaBoard> selectBoardPaging(Paging paging);
Integer pagingCount();
Integer pagingCountSearch(Paging paging);
List<Comment> selectByNum(Integer qnaBoardNum);
}
Resources - mapper - qnaBoardMapper.xml 예시
<mapper namespace="team.kyp.kypcoffee.mapper.QnaBoardMapper">
<select id="selectView" resultType="team.kyp.kypcoffee.domain.QnaBoard">
SELECT qnaBoardNum, b.memberNum, m.memberName, qnaBoardTitle, qnaBoardDate, qnaBoardContent
FROM qna_board b left outer join member m on b.memberNum = m.memberNum
WHERE qnaBoardNum=#{qnaBoardNum}
</select>
<select id="selectByNum" resultType="team.kyp.kypcoffee.domain.Comment">
SELECT * FROM cmt
WHERE qnaBoardNum=#{qnaBoardNum}
</select>
<select id="pagingCount" resultType="int">
SELECT COUNT(*) FROM qna_board
</select>
<select id="selectBoardPaging" resultType="team.kyp.kypcoffee.domain.QnaBoard">
SELECT RN ,qnaBoardNum, memberName, qnaBoardTitle,qnaBoardDate,qnaBoardContent,
(select count(*) from cmt c join qna_board b on b.qnaBoardNum = c.qnaBoardNum where b2.qnaBoardNum=b.qnaBoardNum) as count
FROM
(SELECT ROWNUM as RN ,qnaBoardNum, memberName, qnaBoardTitle,qnaBoardDate,qnaBoardContent
FROM (SELECT * FROM qna_board b1 join member m on b1.memberNum=m.memberNum
ORDER BY qnaBoardNum DESC)) b2
WHERE RN BETWEEN (#{section}-1)*100+(#{pageNum}-1)*10+1 AND (#{section}-1)*100+(#{pageNum})*10
</select>
Templates - qnaBoard - list.html 예시
<div class="cotainer">
<div class="row justify-content-center">
<div class="col-md-6 table-responsive">
<table class="table text-center" >
<thead class="table-dark">
<tr>
<th style="width: 10%">번호</th>
<th style="width: 60%">제목</th>
<th style="width: 15%">작성자</th>
<th style="width: 15%">작성일</th>
</tr>
</thead>
<tbody>
<tr th:each="list :${boardList}">
<td th:text="${list.qnaBoardNum}" style="width: 10%"></td>
<td style="text-align: left"><a th:href="@{/qnaBoard/view/{qnaBoardNum}(qnaBoardNum=${list.qnaBoardNum})}" th:text="${list.qnaBoardTitle}+' ['+${list.count}+']'" style="width: 60%"></a></td>
<td th:text="${list.memberName}" style="width: 15%"></td>
<td th:text="${#dates.format(list.qnaBoardDate,'yyyy-MM-dd')}" style="width: 15%"></td>
</tr>
</tbody>
</table><br>
<form action="/qnaBoard/search" method="GET">
<div style="text-align: left">
<input name="keyword" type="text" placeholder="작성자,제목,내용 검색"> <button type="submit" class="btn btn-primary btn-sm" style="background-color: #865439; border: 0;"><i class="fas fa-search"></i></button>
</div>
</form>
<div style="text-align: right">
<input type="button" value="목록" onclick="location.href='/qnaBoard'" class="btn btn-primary btn-sm" style="background-color: #865439; border: 0;">
<input type="button" value="글쓰기" onclick="location.href='/qnaBoard/write'" class="btn btn-primary btn-sm" style="background-color: #865439; border: 0;">
</div>
<div th:if="${keyword==null}" style="text-align: center"> <!-- 페이징 처리 -->
<th:block th:switch="${totalCntJudge}">
<th:block th:case="101">
<th:block th:if="${(section)*100<totalCnt}">
<th:block th:each="page : ${#numbers.sequence(1,10,1)}">
<th:block th:if="${section >1 && page==1}">
<a th:href="@{/qnaBoard(section=${section}-1, pageNum=10)}"> << </a>
</th:block>
<a th:href="@{/qnaBoard(section=${section}, pageNum=${page})}"><span th:text="${((section)-1)*10+page}"></span></a>
<th:block th:if="${page==10}">
<a th:href="@{/qnaBoard(section=${section+1}, pageNum=1)}"> >> </a>
</th:block>
</th:block>
</th:block>
<th:block th:if="${(section)*100>totalCnt}">
<th:block th:each="page : ${#numbers.sequence(1, (((totalCnt+9)-((section)-1)*100)/10) ,1)}">
<th:block th:if="${section >1 && page==1}">
<a th:href="@{/qnaBoard(section=${(section)-1}, pageNum=10)}"> << </a>
</th:block>
<a th:href="@{/qnaBoard(section=${section}, pageNum=${page})}"><span th:text="${((section)-1)*10+page}"></span></a>
</th:block>
</th:block>
<th:block th:if="${(section)*100==totalCnt}">
<th:block th:each="page : ${#numbers.sequence(1, 10 ,1)}">
<th:block th:if="${section >1 && page==1}">
<a th:href="@{/qnaBoard(section=${(section)-1}, pageNum=10)}"> << </a>
</th:block>
<a th:href="@{/qnaBoard(section=${section}, pageNum=${page})}"><span th:text="${((section)-1)*10+page}"></span></a>
</th:block>
</th:block>
</th:block>
<th:block th:case="100">
<th:block th:each="page : ${#numbers.sequence(1,10,1)}">
<a th:href="@{/qnaBoard(section=${section}, pageNum=${page})}"><span th:text="${page}"></span></a>
</th:block>
</th:block>
<th:block th:case="99">
<th:block th:each="page : ${#numbers.sequence(1,((totalCnt+9)/10),1)}">
<a th:href="@{/qnaBoard(section=${section}, pageNum=${page})}"><span th:text="${page}"></span></a>
</th:block>
</th:block>
</th:block>
</div>
</div>
</div>
</div>
728x90
'Portfolio > KYP COFFEE' 카테고리의 다른 글
Spring/Gradle/Thymeleaf 이용한 게시판 빌드 (검색, 페이징) [2] (0) | 2022.06.04 |
---|---|
KYP COFFEE PROJECT 시연 (0) | 2022.05.30 |
전체 DB구조 / 회원테이블 DB 생성 (0) | 2022.05.19 |
국세청 사업자등록번호 API 활용하기(Ajax) (0) | 2022.05.16 |
Spring/Gradle/Thymeleaf 이용한 로그인페이지 구현 +패스워드 찾기 (0) | 2022.05.16 |