[From Hello To QueryDSL] Add Search (4/12)

By | 2020년 3월 12일
Table of Contents

Add Search

검색조건을 추가합니다. 일단, 검색조건이 하나일때 얼마나 쉽게 검색조건을 추가할 수 있는지 알려드립니다.

개발환경

  • Spring Boot 2.1.x
  • Gradle 4.10.2

프로젝트는 이전 글에서 작성된 프로젝트에 파일을 추가 또는 수정하는 방식으로 진행됩니다. 이전 글을 따라 하지 않은 경우, 먼저 이전 글대로 프로젝트를 구성하시기 바랍니다.

파일추가

없음

파일수정

아래 findByTitle() 메소드 하나 추가하는 것으로 쿼리 생성이 끝납니다.

findByTitle 이라는 메소드명으로 변수명이 title 인 변수를 찾아 where 절에 추가하는 방식입니다.

src/main/java/kr/co/episode/example/domain/posts/PostsPagingRepository.java

// ......
public interface PostsPagingRepository extends JpaRepository<Posts, Long> {

    @Query(value = "SELECT p FROM Posts p ORDER BY p.id DESC")
    Page<Posts> findAllDesc(Pageable pageable);

    Page<Posts> findByTitle(Pageable pageable, String title);
}
// ......

Pageable 의 기본적인 정렬순서는 id 순차정렬이라, 정렬순서를 변경하는 코드를 추가합니다.

src/main/java/kr/co/episode/example/service/posts/PostsPagingService.java

// ......
@RequiredArgsConstructor
@Service
public class PostsPagingService {

    private final PostsPagingRepository postsPagingRepository;

    // ......

    @Transactional(readOnly = true)
    public Page<PostsListResponseDto> findAllDesc(Pageable pageable, String title) {
        Page<Posts> posts;
        if ("".equals(title)) {
            posts = postsPagingRepository.findAllDesc(pageable);
        } else {
            // 정렬순서 변경
            Pageable p = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), Sort.by("id").descending());
            posts = postsPagingRepository.findByTitle(p, title);
        }
        List<PostsListResponseDto> results = posts.getContent().stream()
                .map(PostsListResponseDto::new)
                .collect(Collectors.toList());
        long totalCount = posts.getTotalElements();

        return new PageImpl<>(results, pageable, totalCount);
    }
}
// ......

src/main/java/kr/co/episode/example/web/IndexController.java

@RequiredArgsConstructor
@Controller
public class IndexController {

    private final PostsService postsService;
    private final PostsPagingService postsPagingService;

    @GetMapping("/")
    public String index(Model model, @PageableDefault Pageable pageable,
                        @RequestParam(value = "title", required = false, defaultValue = "") String title) {
        //model.addAttribute("posts", postsService.findAllDesc());

        pageable = PageRequest.of(pageable.getPageNumber(), 3);
        //model.addAttribute("posts", postsPagingService.findAllDesc(pageable));
        model.addAttribute("posts", postsPagingService.findAllDesc(pageable, title));
        model.addAttribute("title", title);

        return "index";
    }

    // ......
}

src/main/resources/templates/index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>게시판</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
    <style>
        .container p { display: inline }
    </style>
</head>
<body class="container">

<h1>스프링 부트 게시판</h1>

<div class="col-md-12">
    <div class="row">
        <div class="col-md-6">
            <a href="/posts/save" role="button" class="btn" btn-primary>글 등록</a>
        </div>
    </div>
</div>

<div style="height: 80px;">

</div>

<table class="table">
    <tr>
        <th>글 번호</th>
        <th>글쓴이</th>
        <th>글 제목</th>
        <th>최종수정</th>
    </tr>
    <tr th:each="posts: ${posts}">
        <td th:text="${posts.id}"></td>
        <td>
            <a th:href="${posts.link}" th:text="${posts.author}" />
        </td>
        <td>
            <a th:href="${posts.link}" th:text="${posts.title}" />
        </td>
        <td th:text="${posts.modifiedDate}"></td>
    </tr>
</table>

<div class="col-md-12">
    <div class="col-md-4">
        <form name="frm">
            <input type="hidden" name="page" value="0">
            <div class="form-group">
                <label for="title">제목</label>
                <input type="text" class="form-control" id="title" placeholder="제목을 입력하세요." name="title" th:value="${title}" />
            </div>
        </form>

        <button type="button" class="btn btn-primary" id="btn-search">검색</button>
    </div>
</div>

<nav style="text-align: center;">
    <ul class="pagination"
        th:with="start=${T(Math).floor(posts.number/10)*10},
                    last=(${start + 9 < posts.totalPages-1 ? start + 9 : posts.totalPages-1})">
        <li>
            <a th:onclick="|javascript:gotoPage(0)|" aria-label="First">
                <span aria-hidden="true">First</span>
            </a>
        </li>

        <li th:class="${posts.first} ? 'disabled'">
            <a th:onclick="|javascript:gotoPage(${posts.number-1})|" aria-label="Previous">
                <span aria-hidden="true"><</span>
            </a>
        </li>

        <li th:each="page: ${#numbers.sequence(start, last)}" th:class="${page == posts.number} ? 'active'">
            <a th:text="${page+1}" th:onclick="|javascript:gotoPage(${page})|" ></a>
        </li>

        <li th:class="${posts.last} ? 'disabled'">
            <a th:onclick="|javascript:gotoPage(${posts.number+1})|" aria-label="Next">
                <span aria-hidden="true">></span>
            </a>
        </li>

        <li>
            <a th:onclick="|javascript:gotoPage(${posts.totalPages-1})|" aria-label="Last">
                <span aria-hidden="true">Last</span>
            </a>
        </li>
    </ul>
</nav>

<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>

<script src="/js/app/index.js"></script>
<script>
    function gotoPage(pg) {
        document.frm.page.value = pg;
        document.frm.submit();
    }
</script>
</body>
</html>

답글 남기기