점프 투 스프링부트를 참고하여 학습,작성하였습니다.
1.서비스 구현
JPA Specification을 통해 JPA에서 동적 쿼리를 생성한다.
//검색
private Specification<Question> search(String kw) {
return new Specification<>() {
private static final long serialVersionUID = 1L;
@Override
public Predicate toPredicate(Root<Question> q, CriteriaQuery<?> query, CriteriaBuilder cb) {
query.distinct(true); // 중복을 제거
Join<Question, SiteUser> u1 = q.join("author", JoinType.LEFT);
Join<Question, Answer> a = q.join("answerList", JoinType.LEFT);
Join<Answer, SiteUser> u2 = a.join("author", JoinType.LEFT);
return cb.or(cb.like(q.get("subject"), "%" + kw + "%"), // 제목
cb.like(q.get("content"), "%" + kw + "%"), // 내용
cb.like(u1.get("username"), "%" + kw + "%"), // 질문 작성자
cb.like(a.get("content"), "%" + kw + "%"), // 답변 내용
cb.like(u2.get("username"), "%" + kw + "%")); // 답변 작성자
}
};
}
검색의 원래 SQL 쿼리다.
select
distinct q.id,
q.author_id,
q.content,
q.create_date,
q.modify_date,
q.subject
from question q
left outer join site_user u1 on q.author_id=u1.id
left outer join answer a on q.id=a.question_id
left outer join site_user u2 on a.author_id=u2.id
where
q.subject like '%글%'
or q.content like '%글%'
or u1.username like '%글%'
or a.content like '%글%'
or u2.username like '%글%'
2.질문 리포지터리 수정
Specification과 Pageable 객체를 매개변수로 받아서
findAll을 통해 Question 엔티티를 조회뒤
페이징하여 반환
Page<Question> findAll(Specification<Question> spec, Pageable pageable);
3.페이징 서비스수정
getlist 메소드에 kw로 검색값을 매개변수로 추가하고
Specification<Question> spec = search(kw);을 추가하여 findAll 메서드 호출할때 전달하였다.
//페이징
public Page<Question> getList(int page, String kw) {
List<Sort.Order> sorts = new ArrayList<>();
sorts.add(Sort.Order.desc("createDate"));
Pageable pageable = PageRequest.of(page, 10, Sort.by(sorts));
Specification<Question> spec = search(kw);
return this.questionRepository.findAll(spec,pageable);
}
4.컨트롤러 수정
서비스의 getlist를 수정했기때문에 컨트롤러에서도 getlist의 매개변수에 kw를 추가하고
뷰에 kw를 추가하여 보낸다.
@GetMapping("/list")
public String list(Model model, @RequestParam(value="page", defaultValue="0") int page,@RequestParam(value = "kw", defaultValue = "") String kw) {
Page<Question> paging = this.questionService.getList(page, kw);
model.addAttribute("paging", paging);
model.addAttribute("kw", kw);
return "question_list";
}
5.검색화면 제작
템플릿에 검색화면을 추가한다.
th:value="${kw}" 서버에서 전달된 검색어를 미리 입력 필드에 설정
<!--검색-->
<div class="row my-3">
<div class="col-6">
<a th:href="@{/question/create}" class="btn btn-primary">질문 등록하기</a>
</div>
<div class="col-6">
<div class="input-group">
<input type="text" id="search_kw" class="form-control" th:value="${kw}">
<button class="btn btn-outline-secondary" type="button" id="btn_search">찾기</button>
</div>
</div>
</div>
6.폼제작
searchForm
히든 입력 필드에 검색어, 페이지를 저장하여 제출한다.
이전에 요청했던 kw와 page의 값은 컨트롤러로부터 다시 전달받는다.
<form th:action="@{/question/list}" method="get" id="searchForm">
<input type="hidden" id="kw" name="kw" th:value="${kw}">
<input type="hidden" id="page" name="page" th:value="${paging.number}">
</form>
7.페이징
페이지 링크에 data-page속성으로 값을 읽도록 바꿨다.
<div th:if="${!paging.isEmpty()}">
<ul class="pagination justify-content-center">
<li class="page-item" th:classappend="${!paging.hasPrevious} ? 'disabled'">
<a class="page-link" href="javascript:void(0)" th:data-page="${paging.number-1}">
<span>이전</span>
</a>
</li>
<li th:each="page: ${#numbers.sequence(0, paging.totalPages-1)}"
th:if="${page >= paging.number-5 and page <= paging.number+5}"
th:classappend="${page == paging.number} ? 'active'" class="page-item">
<a th:text="${page}" class="page-link" href="javascript:void(0)" th:data-page="${page}"></a>
</li>
<li class="page-item" th:classappend="${!paging.hasNext} ? 'disabled'">
<a class="page-link" href="javascript:void(0)" th:data-page="${paging.number+1}">
<span>다음</span>
</a>
</li>
</ul>
</div>
8.자바스크립트 추가
page, kw 매개변수를 동시에 요청할 수 있는 자바스크립트를 추가한다.
<script layout:fragment="script" type='text/javascript'>
const page_elements = document.getElementsByClassName("page-link");
Array.from(page_elements).forEach(function(element) {
element.addEventListener('click', function() {
document.getElementById('page').value = this.dataset.page;
document.getElementById('searchForm').submit();
});
});
const btn_search = document.getElementById("btn_search");
btn_search.addEventListener('click', function() {
document.getElementById('kw').value = document.getElementById('search_kw').value;
document.getElementById('page').value = 0; // 검색버튼을 클릭할 경우 0페이지부터 조회한다.
document.getElementById('searchForm').submit();
});
</script>
'BackEnd > SpringBoot' 카테고리의 다른 글
[Spring Boot] REST API란? (0) | 2024.07.09 |
---|---|
[Spring Boot] 추천 기능 (0) | 2024.07.08 |
[Spring Boot] 수정, 삭제 (0) | 2024.07.08 |