Framework/Spring
[bootBoard] N:1(다대일) 연관관계: 11-7. 목록화면에서 검색 처리
bright jazz music
2022. 10. 12. 21:45
https://github.com/hojuncha997/bootBoard
GitHub - hojuncha997/bootBoard: 코드로 배우는 스프링부트 웹 프로젝트 ch.5
코드로 배우는 스프링부트 웹 프로젝트 ch.5. Contribute to hojuncha997/bootBoard development by creating an account on GitHub.
github.com
1. list.html에 아래 코드 추가
검색을 위한 폼과 버튼을 추가한다. 이 폼은 테이블 위에 존재할 것이다.
<!-- 검색을 위한 추가 -->
<form action="/board/list" method="get" id="searchForm">
<div class="input-group">
<input type="hidden" name="page" value = "1">
<div class="input-group-prepend">
<select class="custom-select" name="type">
<option th:selected="${pageRequestDTO.type == null}">-------</option>
<option value="t" th:selected="${pageRequestDTO.type =='t'}" >제목</option>
<option value="t" th:selected="${pageRequestDTO.type =='c'}" >내용</option>
<option value="t" th:selected="${pageRequestDTO.type =='w'}" >작성자</option>
<option value="tc" th:selected="${pageRequestDTO.type =='tc'}" >제목 + 내용</option>
<option value="tcw" th:selected="${pageRequestDTO.type =='tcw'}" >제목 + 내용 + 작성자</option>
</select>
</div>
<input class="form-control" name="keyword" th:value="${pageRequestDTO.keyword}">
<div class="input-group-append" id="button-addon4">
<button class="btn btn-outline-secondary btn-search" type="button">Search</button>
<button class="btn btn-outline-secondary btn-clear" type="button">Clear</button>
</div>
</div>
</form>
<!-- 검색을 위한 추가 끝-->
이전 포스팅에서 게시했던 list.html은 내가 일부 코드를 빼먹어서 오류가 발생하였다. 따라서 수정하였다.
아래는 수정한 list.html 파일의 전문이며 구동에 문제가 없었다.
list.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<th:block th:replace="~{/layout/basic :: setContent(~{this::content} )}">
<th:block th:fragment="content">
<h1 class="mt-4">Board List Page
<span>
<a th:href="@{/board/register}">
<button type="button" class="btn btn-outline-primary">REGISTER
</button>
</a>
</span>
</h1>
<!-- 검색을 위한 추가 -->
<form action="/board/list" method="get" id="searchForm">
<div class="input-group">
<input type="hidden" name="page" value = "1">
<div class="input-group-prepend">
<select class="custom-select" name="type">
<option th:selected="${pageRequestDTO.type == null}">-------</option>
<option value="t" th:selected="${pageRequestDTO.type =='t'}" >제목</option>
<option value="t" th:selected="${pageRequestDTO.type =='c'}" >내용</option>
<option value="t" th:selected="${pageRequestDTO.type =='w'}" >작성자</option>
<option value="tc" th:selected="${pageRequestDTO.type =='tc'}" >제목 + 내용</option>
<option value="tcw" th:selected="${pageRequestDTO.type =='tcw'}" >제목 + 내용 + 작성자</option>
</select>
</div>
<input class="form-control" name="keyword" th:value="${pageRequestDTO.keyword}">
<div class="input-group-append" id="button-addon4">
<button class="btn btn-outline-secondary btn-search" type="button">Search</button>
<button class="btn btn-outline-secondary btn-clear" type="button">Clear</button>
</div>
</div>
</form>
<!-- 검색을 위한 추가 끝-->
<table class="table table-striped">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Title</th>
<th scope="col">Writer</th>
<th scope="col">Regdate</th>
</tr>
</thead>
<tbody>
<tr th:each="dto : ${result.dtoList}">
<th scope="row">
<a th:href="@{/board/read(bno = ${dto.bno},
page= ${result.page},
type=${pageRequestDTO.type} ,
keyword = ${pageRequestDTO.keyword})}">
[[${dto.bno}]]
</a>
</th>
<td>[[${dto.title}]] ---------------- [<b th:text="${dto.replyCount}"></b>]</td>
<td>[[${dto.writerName}]] <small>[[${dto.writerEmail}]]</small></td>
<td>[[${#temporals.format(dto.regDate, 'yyyy/MM/dd')}]]</td>
</tr>
</tbody>
</table>
<!-- 페이징-->
<ul class="pagination h-100 justify-content-center align-items-center">
<li class="page-item " th:if="${result.prev}">
<a class="page-link" th:href="@{/board/list(page= ${result.start -1},
type=${pageRequestDTO.type} ,
keyword = ${pageRequestDTO.keyword} ) }" tabindex="-1">Previous</a>
</li>
<li th:class=" 'page-item ' + ${result.page == page?'active':''} " th:each="page: ${result.pageList}">
<a class="page-link" th:href="@{/board/list(page = ${page} ,
type=${pageRequestDTO.type} ,
keyword = ${pageRequestDTO.keyword} )}">
[[${page}]]
</a>
</li>
<li class="page-item" th:if="${result.next}">
<a class="page-link" th:href="@{/board/list(page= ${result.end + 1} ,
type=${pageRequestDTO.type} ,
keyword = ${pageRequestDTO.keyword} )}">Next</a>
</li>
</ul>
<!---->
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
<script th:inline="javascript">
var msg = [[${msg}]];
console.log(msg);
if(msg){
$(".modal").modal();
}
var searchForm = $("#searchForm");
$('.btn-search').click(function(e){
searchForm.submit();
});
$('.btn-clear').click(function(e){
searchForm.empty().submit();
});
</script>
</th:block>
</th:block>
2. BoardServiceImpl 클래스 코드 수정
getList() 일부 수정
//BoardServiceImpl.java
@Service
@RequiredArgsConstructor
@Log4j2
public class BoardServiceImpl implements BoardService {
private final BoardRepository repository; // 자동 주입 final
private final ReplyRepository replyRepository; //새롭게 추가
///...
//목록처리
@Override
public PageResultDTO<BoardDTO, Object[]> getList(PageRequestDTO pageRequestDTO) {
log.info(pageRequestDTO);
Function<Object[], BoardDTO> fn =
(en -> entityToDTO((Board)en[0], (Member)en[1], (Long)en[2]));
//Board board, Member member, Long replyCount
// Page<Object[]> result = repository.getBoardWithReplyCount(
// pageRequestDTO.getPageable(Sort.by("bno").descending()));
Page<Object[]> result = repository.searchPage(
pageRequestDTO.getType()
, pageRequestDTO.getKeyword()
, pageRequestDTO.getPageable(Sort.by("bno").descending())
);
return new PageResultDTO<>(result, fn);
}
///...
}
3. 프로젝트 구동
localhost:8080/board/list 접근
4. 검색 테스트
콘솔 로그
2022-10-12 22:39:19.728 INFO 1696 --- [nio-8080-exec-4] c.e.b.controller.BoardController : list.............PageRequestDTO(page=1, size=10, type=tcw, keyword=1)
2022-10-12 22:39:19.728 INFO 1696 --- [nio-8080-exec-4] c.e.bootboard.service.BoardServiceImpl : PageRequestDTO(page=1, size=10, type=tcw, keyword=1)
2022-10-12 22:39:19.728 INFO 1696 --- [nio-8080-exec-4] c.e.b.r.s.SearchBoardRepositoryImpl : searchPage............................
Hibernate:
select
board0_.bno as col_0_0_,
member1_.email as col_1_0_,
count(reply2_.rno) as col_2_0_,
board0_.bno as bno1_0_0_,
member1_.email as email1_1_1_,
board0_.moddate as moddate2_0_0_,
board0_.reg_date as reg_date3_0_0_,
board0_.content as content4_0_0_,
board0_.title as title5_0_0_,
board0_.writer_email as writer_e6_0_0_,
member1_.moddate as moddate2_1_1_,
member1_.reg_date as reg_date3_1_1_,
member1_.name as name4_1_1_,
member1_.password as password5_1_1_
from
board board0_
left outer join
member member1_
on (
board0_.writer_email=member1_.email
)
left outer join
reply reply2_
on (
reply2_.board_bno=board0_.bno
)
where
board0_.bno>?
and (
board0_.title like ? escape '!'
or board0_.content like ? escape '!'
or member1_.email like ? escape '!'
)
group by
board0_.bno
order by
board0_.bno desc limit ?
2022-10-12 22:39:19.731 INFO 1696 --- [nio-8080-exec-4] c.e.b.r.s.SearchBoardRepositoryImpl : [[Board(bno=102, title=Title...100, content=Content...100), Member(email=user100@aaa.com, password=11111, name=USER100), 0], [Board(bno=93, title=Title...91, content=Content...91), Member(email=user91@aaa.com, password=11111, name=USER91), 0], [Board(bno=83, title=Title...81, content=Content...81), Member(email=user81@aaa.com, password=11111, name=USER81), 1], [Board(bno=73, title=Title...71, content=Content...71), Member(email=user71@aaa.com, password=11111, name=USER71), 2], [Board(bno=63, title=Title...61, content=Content...61), Member(email=user61@aaa.com, password=11111, name=USER61), 0], [Board(bno=53, title=Title...51, content=Content...51), Member(email=user51@aaa.com, password=11111, name=USER51), 0], [Board(bno=43, title=Title...41, content=Content...41), Member(email=user41@aaa.com, password=11111, name=USER41), 0], [Board(bno=33, title=Title...31, content=Content...31), Member(email=user31@aaa.com, password=11111, name=USER31), 1], [Board(bno=23, title=Title...21, content=Content...21), Member(email=user21@aaa.com, password=11111, name=USER21), 1], [Board(bno=21, title=Title...19, content=Content...19), Member(email=user19@aaa.com, password=11111, name=USER19), 0]]
Hibernate:
select
count(distinct board0_.bno) as col_0_0_
from
board board0_
left outer join
member member1_
on (
board0_.writer_email=member1_.email
)
left outer join
reply reply2_
on (
reply2_.board_bno=board0_.bno
)
where
board0_.bno>?
and (
board0_.title like ? escape '!'
or board0_.content like ? escape '!'
or member1_.email like ? escape '!'
)
2022-10-12 22:39:19.732 INFO 1696 --- [nio-8080-exec-4] c.e.b.r.s.SearchBoardRepositoryImpl : COUNT: 20
where 절이 처리되는 방식을 주목할 것