[코드로 배우는 스프링부트 웹 프로젝트] - 영화 리스트 생성(2) : 목록 페이지 생성

Jongwon·2023년 1월 19일
0

이전에 사용했던 PageRequestDTO와 PageResultDTO를 이용하여 목록 페이지를 생성하겠습니다.

MovieRepository에서 목록을 출력하기 위한 데이터를 받아오는 메서드는 이미 설계를 했었는데, [movie, movieImage, 평점, 리뷰수]라는 객체배열 타입의 Page를 반환합니다.
이 Object[] 내의 모든 요소들이 MovieDTO를 통해 전달되어야 하므로 MovieDTO에 평점과 리뷰수를 추가합니다.

MovieDTO

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MovieDTO {

    private Long mno;

    private String title;

    @Builder.Default
    private List<MovieImageDTO> imageDTOList = new ArrayList<>();

    private double avg;

    private int reviewCnt;

    private LocalDateTime regDate;
    private LocalDateTime modDate;
}

또한 regDate와 modDate를 전달할 수 있도록 추가하였습니다.



다음으로 entity 객체들을 DTO로 변환하는 작업이 필요합니다. 서비스에 default로 구현합니다.
MovieService

default MovieDTO entitiesToDTO(Movie movie, List<MovieImage> movieImages, Double avg, Long reviewCnt) {

    MovieDTO movieDTO = MovieDTO.builder()
            .mno(movie.getMno())
            .title(movie.getTitle())
            .regDate(movie.getRegDate())
            .modDate(movie.getModDate())
            .build();

    List<MovieImageDTO> movieImageDTOList = movieImages.stream().map(movieImage -> {
        return MovieImageDTO.builder()
                .imgName(movieImage.getImgName())
                .path(movieImage.getPath())
                .uuid(movieImage.getUuid())
                .build();
    }).collect(Collectors.toList());

    movieDTO.setImageDTOList(movieImageDTOList);
    movieDTO.setAvg(avg);
    movieDTO.setReviewCnt(reviewCnt.intValue());

    return movieDTO;
}


PageResult를 반환하는 서비스 계층 메서드도 생성하겠습니다.

MovieService

    PageResultDTO<MovieDTO, Object[]> getList(PageRequestDTO pageRequestDTO);

MovieServiceImpl

    @Override
    public PageResultDTO<MovieDTO, Object[]> getList(PageRequestDTO requestDTO) {
        Pageable pageable = requestDTO.getPageable(Sort.by("mno").descending());

        Page<Object[]> result = movieRepository.getListPage(pageable);

        Function<Object[], MovieDTO> fn = (arr -> entitiesToDTO(
                (Movie) arr[0],
                (List<MovieImage>) (Arrays.asList((MovieImage)arr[1])),
                (Double) arr[2],
                (Long) arr[3]
        ));

        return new PageResultDTO<>(result, fn);
    }

Controller에서 서비스의 결과를 받아 list 페이지에 반환합니다.

MovieController

    @GetMapping("/list")
    public void list(PageRequestDTO pageRequestDTO, Model model) {
        log.info("pageRequestDTO: ", pageRequestDTO);

        model.addAttribute("result", movieService.getList(pageRequestDTO));
    }

list 페이지는 이전에 했던 예제들과 비슷한 구조로 작성합니다.
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">Movie List Page
            <span>
                <a th:href="@{/movie/register}">
                    <button type="button" class="btn btn-outline-primary">REGISTER</button>
                </a>
            </span>
        </h1>

        <form action="/movie/list" method="get" id="searchForm">
            <input type="hidden" name="page" value="1">
        </form>

        <table class="table table striped">
            <thead>
            <tr>
                <th scope="col">#</th>
                <th scope="col">Title & Picture</th>
                <th scope="col">Review Count</th>
                <th scope="col">AVG Rating</th>
                <th scope="col">Regdate</th>
            </tr>
            </thead>
            <tbody>
            <tr th:each="dto : ${result.dtoList}">
                <th scope="row">
                    <a th:href="@{/movie/read(mno = ${dto.mno}, page=${result.page})}">
                        [[${dto.mno}]]
                    </a>
                </th>
                <td>
                    <img th:if="${dto.imageDTOList.size() > 0 && dto.imageDTOList[0].path != null}" th:src="|/display?fileName=${dto.imageDTOList[0].getThumbnailURL()}|">
                    [[${dto.title}]]
                </td>
                <td>
                    [[${dto.reviewCnt}]]
                </td>
                <td>
                    <b>
                        [[${dto.avg}]]
                    </b>
                </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="@{/movie/list(page=${result.start - 1})}" 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="@{/movie/list(page=${page})}">
                    [[${page}]]
                </a>
            </li>

            <li class="page-item" th:if="${result.next}">
                <a class="page-link" th:href="@{/movie/list(page=${result.end + 1})}">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">&times;</span>
                        </button>
                    </div>
                    <div class="modal-body">
                        <p>등록되었습니다.</p>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-secondary close" data-dismiss="modal">Close</button>
                    </div>
                </div>
            </div>
        </div>
        <script th:inline="javascript">
            var msg = [[${msg}]];

            console.log(msg);

            const $modal = $(".modal")

            if(msg) {
               $('.modal').show();
            }

            $(".close").on("click", () => {
                $modal.hide()
            });
        </script>
    </th:block>
</th:block>

등록 완료 후 목록 페이지로 돌아가면 모달창이 뜨는 부분까지 구현되어 있습니다. 다음 게시글에서는 조회 페이지 작성을 진행하겠습니다.

profile
Backend Engineer

0개의 댓글