영화/리뷰 프로젝트 적용하기-(3)

33415 단어 MultipartMultipart

목록 처리와 평균 평점

  • 등록 처리가 완료 되었더라면 목록 페이지를 제작합니다.
  • 목록 페이지에는 영화의 제목과 이미지 평균 평점을 화면에 출력해야만 합니다.
  • 예제에서 사용했던 PageRequestDTO 와 PageResultDTO를 dto패키지에 추가해줍니다.

MovieService와 MovieServiceImpl

  • 영화와 평점 데이터는 이미 처리에 두었기 때문에 이를 이용하는 클래스를 수정해줍니다.
  • MoviRepository 인터페이스의 getListPage() 메서드는 Movie 객체와 MovieImage 객체 하나,double 값으로 나오는 영화의 평균 평점/Long 타입의 리뷰 개수를 Object[]로 반환해줍니다.

MovieDTO 수정

  • MovieServie의 getList()는 Movie,MovieImage,Double,Long을 Objecect[]배열을 리스트에 담은 형태 입니다.
  • 각 Object[]를 MovieDTO 하나의 객체로 처리해야만 합니다.
  • MovieDTO에는 Double 타입의 평점 평균과 리뷰의 개수를 처리하는 파라미터를 추가해줍니다.
@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 LocalDateTime regDate;  //리뷰 수 jpa의 count()
    
    private LocalDateTime modDate;
}

MovieServie의 엔티티 변환

  • MovieService에는 JPA를 통해서 나오는 엔티티 객체들과 Double,Long 등의 값을 MovieDTO로 변환하는 entityToDto()를 추가하고 컨트롤러가 호출할 때 사용할 getList()를 추가합니다.
  • 추가된 entityToDto는 다음과 같은 파라미터를 받습니다.
    -Movie 엔티티
    -List엔티티(리스트로 받은 이유는 조회 화면에서 여러개의 이미지를 처리하기 위해서 입니다.)
    -Double 타입의 평점 평균
    -Long 타입의 리뷰 개수
public interface MovieService {

    //등록처리
    Long register(MovieDTO movieDTO);
    //목록처리
    PageResultDTO<MovieDTO,Object[]> getList(PageRequestDTO pageRequestDTO);
    
    
    //생략
    
     //Entity -> DTO 변환
    default MovieDTO entityToDto(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 -> {
            MovieImageDTO movieImageDTO = MovieImageDTO.builder()
                    .imgName(movieImage.getImgName())
                    .path(movieImage.getPath())
                    .uuid(movieImage.getUuid())
                    .build();
            return movieImageDTO;
        }).collect(Collectors.toList());

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

        return movieDTO;
    }
  • MovieServiceImpl 클래스의 getList() 메서드를 구현해 줍니다.
 @Override
    public PageResultDTO<MovieDTO, Object[]> getList(PageRequestDTO pageRequestDTO) {

        Pageable pageable = pageRequestDTO.getPageable(Sort.by("mno").descending());

        Page<Object[]> result = movieRepository.getListPage(pageable);
        Function<Object[],MovieDTO> fn = (arr ->entityToDto(
                (Movie)arr[0],(List<MovieImage>) arr[1],(Double)arr[2],(Long) arr[3]));


        return new PageResultDTO<>(result,fn);

    }
  • 목록화면과 MovieController 처리
 @GetMapping("/list")
    public void list(PageRequestDTO pageRequestDTO, Model model){
        log.info("pageRequest : "+pageRequestDTO);
        
        model.addAttribute("result",movieService.getList(pageRequestDTO));
    }
  • template의 movie 폴더에는 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 th:action="@{/movie/list}" th: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</th>
                <th scope="col">Review Count</th>
                <th scope="col">AVG Rating</th>
                <th scope="col">RedDate</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()}|" ></td>
                        //문자열을 합치기 위해 '||'태그 삽입
                    <td><b>[[${dto.reviewCnt}]]</b></td>
                    <td><b>[[${dto.avg}]]</b></td>
                    <td>[[${#temporals.format(dto.regDate, 'yyyy/MM/dd')}]]</td>
                </tr>
            </tbody>
        </table>
        <script th:inline="javascript">

        </script>
        </th:block>
        </th:block>
        </html>
  • 영화 이미지는 imageDTOList의 크기가 0보다 크고 path 속성에 값이 있는 실제 이미지가 존재할 때만 <img>태그를 생성합니다.
  • 화며에 페이지를 출력하는 부분은 이전 예제들과 동일합니다.<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>
  • 화면에서는 페이지 번호가 출력되는 것을 볼 수 있고 실제 페이지의 이동도 가능합니다.

좋은 웹페이지 즐겨찾기