코드로 배우는 스프링부트 웹 프로젝트 Day 11
/* Annotation들은 스프링부트 프로젝트의 Annotation 정리 페이지에 따로 정리해두었습니다. */
GuestbookServiceImpl에서 목록을 조회할 때 사용하는 getList()는 기존의 코드를 조금 수정해서 작성
GuestbookServiceImpl 클래스 수정
@Override
public PageResultDTO<GuestbookDTO, Guestbook> getList(PageRequestDTO requestDTO) {
Pageable pageable = requestDTO.getPageable(Sort.by("gno").descending());
BooleanBuilder booleanBuilder = getSearch(requestDTO); // 검색 조건 처리
Page<Guestbook> result = repository.findAll(booleanBuilder, pageable); // Querydsl 사용
Function<Guestbook, GuestbookDTO> fn = (entity -> entityToDto(entity));
return new PageResultDTO<>(result, fn);
}
테스트 코드로 검색이 잘 이루어지는지 확인
GuestbookServiceTests 수정
@Test
public void testSearch() {
PageRequestDTO pageRequestDTO = PageRequestDTO.builder()
.page(1)
.size(10)
.type("tc") // 검색 조건 t, c, w, tc, tw, ...
.keyword("한글") // 검색 키워드
.build();
PageResultDTO<GuestbookDTO, Guestbook> resultDTO = service.getList(pageRequestDTO);
System.out.println("PREV: " + resultDTO.isPrev());
System.out.println("NEXT: " + resultDTO.isNext());
System.out.println("TOTAL: " + resultDTO.getTotalPage());
System.out.println("------------------------------------------------");
for (GuestbookDTO guestbookDTO : resultDTO.getDtoList()) {
System.out.println(guestbookDTO);
}
System.out.println("=================================================");
resultDTO.getPageList().forEach(System.out::println);
}
제목이나 내용에 "한글" 키워드가 있는지 검색하는 테스트
gno > 0 은 쿼리의 where절에서 처리되지 않는 것을 확인할 수 있음
[목록 페이지 검색 처리]
검색 처리를 하기 위해서는 화면에 검색 타입과 키워드를 입력할 수 있는 UI가 필요함
list.html에 검색 타입과 키워드를 입력할 공간과, 검색 버튼을 추가
list.html
<form action="/guestbook/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="c" th:selected="${pageRequestDTO.type == 't'}">내용</option>
<option value="w" th:selected="${pageRequestDTO.type == 't'}">작성자</option>
<option value="tc" th:selected="${pageRequestDTO.type == 't'}">제목 + 내용</option>
<option value="tcw" th:selected="${pageRequestDTO.type == 't'}">제목 + 내용 + 작성자</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>
<input type="hidden"> 부분에서 page의 값을 1로 지정한 것은 검색을 진행했을 때 무조건 1페이지를 보여주도록 하기 위함
그런데 실행했을 때 type 설정 부분이 이상했다..
<select class="custom-select" name="type" style="height:38px">
일단 style로 height를 지정해주었다..
잘 맞춰지긴 했다.
그런데 지금 발견한 더 이상한 점이 있다.
Gno가 아니라 Title, Title이 아니라 Writer이 항목 이름이어야 하는데..
바꿨다.
그리고 버튼에 따른 작업 처리도 해주었다.
<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>
clear을 누르면, 모든 검색 관련 내용이 사라지고 목록 1페이지로 이동함
search를 누르면 검색한 내용의 목록 중 1페이지로 이동함
[페이지 번호와 검색 조건 추가]
목록 페이지의 하단의 검색은 현재 page값만 처리하고 있기 때문에 type과 keyword를 추가해준다.
list.html
<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="@{/guestbook/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="@{/guestbook/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="@{/guestbook/list(page = ${result.end + 1}, type=${pageRequestDTO.type}, keyword = ${pageRequestDTO.keyword})}">Next</a>
</li>
</ul>
[조회 페이지로 이동하는 검색 처리]
특정 글의 번호를 클릭해서 이동하는 검색
=> type과 keyword 항목을 추가해서 처리 가능
list.html
<tr th:each="dto : ${result.dtoList}">
<th scope="row">
<a th:href="@{/guestbook/read(gno = ${dto.gno}, page= ${result.page}, type=${pageRequestDTO.type}, keyword = ${pageRequestDTO.keyword})}">
[[${dto.gno}]]
</a>
위처럼 하면 type과 keyword도 파라미터로 추가 전송됨
[조회 페이지 검색 처리]
기존 조회 페이지는 page값만 처리해서 다시 목록으로 돌아가는 링크를 앞서 처리한 것과 동일하게 type과 keyword를 추가해야 함
read.html
<a th:href="@{/guestbook/modify(gno = ${dto.gno}, page=${requestDTO.page}, type=${requestDTO.type}, keyword=${requestDTO.keyword})}">
<button type="button" class="btn btn-primary">Modify</button>
</a>
<a th:href="@{/guestbook/list(page=${requestDTO.page}, type=${requestDTO.type}, keyword=${requestDTO.keyword})}">
<button type="button" class="btn btn-info">List</button>
</a>
이렇게 하면 목록 페이지에서 특정 검색 조건으로 검색한 후 특정 글로 이동 후, 목록 버튼을 누르면 이전에 검색 조건으로 검색한 페이지로 돌아갈 수 있음
[수정 작업 후 이동 처리]
GuestbookController는 작업이 끝난 후에 redirect로 이동하는 경우가 있음
- 등록 처리: 1페이지로 이동
- 삭제 처리: 1페이지로 이동
- 수정 처리: 조회 페이지로 이동
수정은 조회 페이지로 이동하기 때문에 검색 조건을 유지해야 함
=> page, type, keyword 처리해야 함
modify.html
<form action="/guestbook/modify" method="post">
<!-- 페이지 번호 -->
<input type="hidden" name="page" th:value="${requestDTO.page}">
<input type="hidden" name="type" th:value="${requestDTO.type}">
<input type="hidden" name="keyword" th:value="${requestDTO.keyword}">
type, keyword 추가함
$(".listBtn").click(function () {
var page = $("input[name='page']");
var type = $("input[name='type']");
var keyword = $("input[name='keyword']");
actionForm.empty(); //form 태그의 모든 내용을 지움
actionForm.append(page); //목록 페이지 이동에 필요한 내용을 다시 추가
actionForm.append(type);
actionForm.append(keyword);
actionForm
.attr("action", "/guestbook/list")
.attr("method", "get");
actionForm.submit();
});
type과 keyword도 <form> 태그와 같이 전송하도록 수정함
GuestbookController 클래스
@PostMapping("/modify")
public String modify(GuestbookDTO dto, @ModelAttribute("requestDTO") PageRequestDTO requestDTO, RedirectAttributes redirectAttributes) {
log.info("post modify..................................................");
log.info("dto: " + dto);
service.modify(dto);
redirectAttributes.addAttribute("page", requestDTO.getPage());
redirectAttributes.addAttribute("type", requestDTO.getType());
redirectAttributes.addAttribute("keyword", requestDTO.getKeyword());
redirectAttributes.addAttribute("gno" ,dto.getGno());
return "redirect:/guestbook/read";
}
redirect 처리 될 때 검색 조건을 유지하도록 type과 keyword를 추가함