
0. 지연
손가락을 다쳤고 쓰고 있던 글의 임시 저장이 안 되어 새로 작성.
1. 게시판 목록 기능 구현
1-1) form
<tbody>
<c:forEach items="${list}" var="post" varStatus="status">
<tr role="row" class="<c:if test=" ${status.count % 2 == 0}">odd</c:if>
<c:if test="${status.count % 2 != 0}">even</c:if>">
<td class="sorting_1">
<c:out value="${post.pst_no }"></c:out>
</td>
<td>
<a class="move" href="<c:out value=" ${post.pst_no }"></c:out>">
<c:out value="${post.pst_title }"></c:out>
</a>
</td>
<td>
<c:out value="${post.pst_writer }"></c:out>
</td>
<td>
<fmt:formatDate value="${post.pst_wr_date }" pattern="yyyy-MM-dd" />
</td>
<td>
<c:out value="${post.pst_hit }"></c:out>
</td>
<td>
<c:out value="${post.pst_cmt_cnt }"></c:out>
</td>
<td>
<c:out value="${post.pst_itr }"></c:out>
</td>
</tr>
</c:forEach>
</tbody>
게시물 여러 개를 보이기 위해 collection 반복문 성격인 forEach문 사용.
1-2) Service, ServiceImpl, Controller
// 게시판 글 목록
@GetMapping("/list")
public void list(Model model) {
List<PostVO> list = service.getList();
model.addAttribute("list", list);
}
model parameter를 이용하여 list의 data를 jsp에서 보여 주도록 함.
<select id="getList" resultType="com.comunity.domain.PostVO">
SELECT pst_no, pst_title, pst_content, pst_writer, pst_wr_date, pst_update_date, pst_hit, pst_itr, pst_cmt_cnt FROM post_tb
</select>
a) 목록이 나오지 않는 오류가 있었는데 캐시 비우기+새로고침 이후 정상적으로 노출이 됨.
2. Paging 및 검색 기능
2-1) PageDTO 객체, Criteria 객체 생성
public class Criteria {
private int pageNum; // 선택한 page로 이동
private int amount; // page마다 출력할 게시물 개수
private String type; // 검색 종류
private String keyword; // 검색어
// /post/list 주소 request 시 자동 호출
// 기본 값 1 page, 출력 게시물 수 10개 지정
public Criteria() {
this(1, 10);
}
public Criteria(int pageNum, int amount) {
// TODO Auto-generated constructor stub
this.pageNum = pageNum;
this.amount = amount;
}
// 검색 조건 배열
public String[] getTypeArr() {
return type == null? new String[] {} : type.split("");
}
public String getListLink() {
UriComponentsBuilder builder = UriComponentsBuilder.fromPath("")
.queryParam("pageNum", this.pageNum)
.queryParam("amount", this.getAmount())
.queryParam("type", this.getType())
.queryParam("keyword", this.getKeyword());
return builder.toUriString();
}
}
Criteria는 page 자체를 관리하는 객체.
url이 parameter를 토대로 만들어 지기 때문에 (ex.?pageNum=7&amount=10&type=W&keyword=user2) redirect하게 되면 그때마다 parameter를 addAttribute로 받아야 함. 번거롭기 때문에, uriComponentsBuilder를 이용하면 해당 method가 호출될 때마다 queryParam을 통해 자동으로 URL 형태로 만들어 줌.
public PageDTO(Criteria cri, int total) {
this.cri = cri;
this.total = total;
int pageSize = 10;
int endPageInfo = pageSize - 1;
this.endPage = (int) (Math.ceil(cri.getPageNum() / (double) pageSize)) * pageSize;
this.startPage = this.endPage - endPageInfo;
int realEnd = (int) (Math.ceil((total * 1.0) / cri.getAmount()));
if(realEnd <= this.endPage) {
this.endPage = realEnd;
}
this.prev = this.startPage > 1;
this.next = this.endPage < realEnd;
}
PageDTO는 Paging 관련 변수.
endPage = 현재 pageNum / 한 page에 출력할 게시물 개수 * 페이지에 출력할 게시물 개수
소숫점이 남지 않도록 ceil method 이용.
하지만 위는 총 게시물 수가 10 page를 넘지 않는 경우가 있지만 현재 page에 1을 넣고 계산하면 10이 나오기 때문에 이를 보완해야 함.
realEnd = 총 게시물 * 1.0 / 총 게시물 수
2-2) mapper sql문
<sql id="criteria">
<trim prefix="(" suffix=") AND " prefixOverrides="OR">
<foreach collection="typeArr" item="type">
<trim prefix="OR">
<choose>
<when test="type == 'T'.toString()">
title like '%' || #{keyword} || '%'
</when>
<when test="type == 'C'.toString()">
content like '%' || #{keyword} || '%'
</when>
<when test="type == 'W'.toString()">
writer like '%' || #{keyword} || '%'
</when>
</choose>
</trim>
</foreach>
</trim>
</sql>
<sql> tag. 다른 구문에서 재사용이 가능한 SQL 구문을 정의할 때 사용. 주의할 점은 해당 query를 재사용하고 싶다면 재사용할 query의 상단에 선언되어야 함. 제작하면서 강의 내용 다시 보다가 왜 가장 위 순서에 있는지 의문스러웠는데 그런 주의점이 있었다. 다시 상기.
그리고 해당 query를 재사용(호출)하는 방법은 아래 query 중간의 <include> tag.
<select id="getListWithPaging" parameterType="com.comunity.domain.Criteria" resultType="com.comunity.domain.PostVO">
<![CDATA[
SELECT pst_no, pst_title, pst_content, pst_writer, pst_wr_date, pst_update_date, pst_hit, pst_itr, pst_cmt_cnt
FROM (
SELECT /*+ index_desc(post_tb pk_post) */ rownum rn, pst_no, pst_title, pst_content, pst_writer, pst_wr_date, pst_update_date, pst_hit, pst_itr, pst_cmt_cnt
FROM post_tb
WHERE
]]>
<include refid="criteria"></include>
<![CDATA[
rownum <= (#{pageNum} * #{amount})
)
WHRER rn > ((#{pageNum) - 1) * #{amount})
]]>
</select>
<select id="getTotalCount" resultType="int">
SELECT count(*) FROM post_tb WHERE
<include refid="criteria"></include>
bno > 0
</select>
Criteria에 검색 조건이 있므로 WHERE을 쓰고 include로 criteria를 호출시킴.
2-3) Controller 수정
@GetMapping("/list")
public void list(Criteria cri, Model model) {
// 1) list.jsp(view) 목록 data
List<PostVO> list = service.getList();
model.addAttribute("list", list);
// list.jsp(view) paging
int total = service.getTotalCount(cri);
PageDTO pageDTO = new PageDTO(cri, total);
model.addAttribute("pageMaker", pageDTO);
}
paging query: 총 게시물 수를 통해 page 개수를 가져옴.
pageMaker: startPage, endPage 등 field를 jsp에서 사용하도록 하는 query. view에서 사용할 수 있도록 pageMaker 속성에 pageDTO 변수들을 저장.
2-4) list form 수정
<div class="row">
<div class="col-sm-5 dataTables_info">
<form id="searchForm" action="/post/list" method="get">
<select name="type">
<option value=""
<c:out value="${pageMaker.cri.type == null? 'selected':'' }" />>--</option>
<option value="T"
<c:out value="${pageMaker.cri.type eq 'T'? 'selected':'' }" />>제목</option>
<option value="C"
<c:out value="${pageMaker.cri.type eq 'C'? 'selected':'' }" />>내용</option>
<option value="W"
<c:out value="${pageMaker.cri.type eq 'W'? 'selected':'' }" />>작성자</option>
<option value="TC"
<c:out value="${pageMaker.cri.type eq 'TC'? 'selected':'' }" />>제목 or 내용</option>
<option value="TW"
<c:out value="${pageMaker.cri.type eq 'TW'? 'selected':'' }" />>제목 or 작성자</option>
<option value="TWC"
<c:out value="${pageMaker.cri.type eq 'TWC'? 'selected':'' }" />>제목 or 작성자 or 내용</option>
</select>
<input type="text" name="keyword" value="<c:out value="${ pageMaker.cri.keyword}" />">
<input type="hidden" name="pageNum" value="${pageMaker.cri.pageNum}">
<input type="hidden" name="amount" value="${pageMaker.cri.amount}">
<button class="btn btn-primary">Search</button>
</form>
<!--
<div class="dataTables_info" id="example2_info" role="status"
aria-live="polite">Showing 1 to 10 of 57 entries</div>
-->
</div>
<div class="col-sm-7">
<div class="dataTables_paginate paging_simple_numbers"
id="example2_paginate">
<ul class="pagination">
<c:if test="${pageMaker.prev }">
<li class='paginate_button previous ${pageMaker.prev ? "": "disabled" }'
id="example2_previous"><a href="${pageMaker.startPage - 1}"
aria-controls="example2" data-dt-idx="0" tabindex="0">Previous</a></li>
</c:if>
<c:forEach begin="${pageMaker.startPage }" end="${pageMaker.endPage }" var="num">
<li class='paginate_button ${pageMaker.cri.pageNum == num ? "active":"" }'><a href="${num}"
aria-controls="example2" data-dt-idx="1" tabindex="0">${num}</a></li>
</c:forEach>
<c:if test="${pageMaker.next }">
<li class="paginate_button next" id="example2_next"><a
href="${pageMaker.endPage + 1}" aria-controls="example2" data-dt-idx="7"
tabindex="0">Next</a></li>
</c:if>
</ul>
</div>
</div>
<!--prev,page number, next 를 클릭하면 아래 form이 작동된다.-->
<form id="actionForm" action="/board/list" method="get">
<!--list.jsp 가 처음 실행되었을 때 pageNum의 값을 사용자가 선택한 번호의 값으로 변경-->
<input type="hidden" name="pageNum" value="${pageMaker.cri.pageNum}">
<input type="hidden" name="amount" value="${pageMaker.cri.amount}">
<input type="hidden" name="type" value="${pageMaker.cri.type}">
<input type="hidden" name="keyword" value="${pageMaker.cri.keyword}">
<!--글번호추가-->
</form>
</table>
<!-- list nav bar -->
<div class="row page-list">
<div class="col-sm-6">
<div class="dataTables_info" id="example2_info" role="status" aria-live="polite">Showing 1 to 10 of 57
entries</div>
</div>
<div class="col-sm-6">
<div class="dataTables_paginate paging_simple_numbers" id="example2_paginate">
<ul class="pagination">
<li class="paginate_button previous disabled" id="example2_previous"><a href="#"
aria-controls="example2" data-dt-idx="0" tabindex="0">Previous</a></li>
<li class="paginate_button active"><a href="#" aria-controls="example2" data-dt-idx="1"
tabindex="0">1</a></li>
<li class="paginate_button "><a href="#" aria-controls="example2" data-dt-idx="2"
tabindex="0">2</a></li>
<li class="paginate_button "><a href="#" aria-controls="example2" data-dt-idx="3"
tabindex="0">3</a></li>
<li class="paginate_button "><a href="#" aria-controls="example2" data-dt-idx="4"
tabindex="0">4</a></li>
<li class="paginate_button "><a href="#" aria-controls="example2" data-dt-idx="5"
tabindex="0">5</a></li>
<li class="paginate_button "><a href="#" aria-controls="example2" data-dt-idx="6"
tabindex="0">6</a></li>
<li class="paginate_button next" id="example2_next"><a href="#" aria-controls="example2"
data-dt-idx="7" tabindex="0">Next</a></li>
</ul>
</div>
</div>
<form id="actionForm" action="/board/list" method="get">
<!--list.jsp 가 처음 실행되었을 때 pageNum의 값을 사용자가 선택한 번호의 값으로 변경-->
<input type="hidden" name="pageNum" value="${pageMaker.cri.pageNum}">
<input type="hidden" name="amount" value="${pageMaker.cri.amount}">
<input type="hidden" name="type" value="${pageMaker.cri.type}">
<input type="hidden" name="keyword" value="${pageMaker.cri.keyword}">
<!--글번호추가-->
</form>
</div>
a) 500번 mapper에서 sql문 오류. 오타가 있어서 수정.
b) vscode랑 동시에 쓰다가 위 내용 저장 전으로 덮어 씌워져서 다시 작업.
c) 10개씩 보이게 만들었는데 게시글 전체가 나옴...
service getList>getListWithPaging(cri)로 수정. list는 paging query 없이 그냥 전부 가져만 오는 거고 ListWithPaging이 Paging query가 들어간 method임
2-5) 게시글 읽기(get) 및 게시글 수정, 삭제
// 게시물 읽기, 수정 form
@GetMapping({"/get", "/modify"})
public void get(@RequestParam("pst_no") Long pst_no, @ModelAttribute("cri") Criteria cri, Model model) {
log.info("get..." + pst_no);
PostVO post = service.get(pst_no);
model.addAttribute("post", post);
}
@PostMapping("/modify")
public String modify(PostVO post, Criteria cri, RedirectAttributes rttr) {
log.info("modify: " + post);
service.modify(post);
return "redirect:/post/list" + cri.getListLink();
}
@PostMapping("/remove") // /board/remove
public String remove(@RequestParam("pst_no") Long pst_no, Criteria cri, RedirectAttributes rttr) {
service.delete(pst_no);
return "redirect:/post/list" + cri.getListLink();
}
1보 1오류 경험 중. controller에 수정, 삭제 추가. 읽기 코드 일부 수정.
a) 게시글을 클릭했을 때 조회가 안 됨 pst_no를 받아 올 수 없다는 400번 오류.
Criteria에서 pageNum 부분 getPageNum 아닌 그냥 pageNum Parameter로 가져와서 잘못된 건 줄 알았는데 아님.
b) 500번 오류 There is no getter for property named 'pageNum) - 1) * #{amount' in 'class com.comunity.domain.Criteria'
amount랑 pagenum 둘 다 못 가져옴 쿼리에서 오타 난 것 수정
c) 10개 노출은 되나 페이지 이동이 안 됨 404에러... list script 작업이 안 돼서 그런 것 같음
$(document).ready(function() {
let actionForm = $("#actionForm");
$(".move").on("click", function(e) {
e.preventDefault();
let bno = $(this).attr("href");
console.log("글번호" + bno);
actionForm.append("<input type='hidden' name='bno' value='" + $(this).attr("href") + "'>");
actionForm.attr("action", "/board/get");
actionForm.submit();
});
$(".paginate_button a").on("click", function(e){
e.preventDefault();
actionForm.find("input[name='pageNum']").val($(this).attr("href"));
console.log("click");
actionForm.submit();
});
}); // paging end
'취준 > Portfolio' 카테고리의 다른 글
[포트폴리오] 커뮤니티 게시판 제작 10 (0) | 2022.04.11 |
---|---|
[포트폴리오] 커뮤니티 게시판 제작 08 (0) | 2022.03.16 |
[포트폴리오] 커뮤니티 게시판 제작 07 (0) | 2022.03.14 |
[포트폴리오] 커뮤니티 게시판 제작 06 (0) | 2022.03.06 |
[포트폴리오] 커뮤니티 게시판 제작 05 (0) | 2022.03.02 |