코드 그라데이션

shop 구현 (11) 메인 페이지 만들기 본문

Spring/SpringShop

shop 구현 (11) 메인 페이지 만들기

완벽한 장면 2023. 7. 19. 11:44

메인 페이지 만들기

ItemController

기존에는 메인으로만 돌아가는 역할을 했다면, 지금은 무언가를 연결해서 보여주는 로직으로 변모

@Controller
@RequiredArgsConstructor
public class MainController {

  private final ItemService itemService;

  @GetMapping(value = "/")
  public String main(ItemSearchDto itemSearchDto, Optional<Integer> page, Model model) {
    Pageable pageable = PageRequest.of(page.isPresent() ? page.get() : 0, 5);

    if (itemSearchDto.getSearchQuery() == null) {
      itemSearchDto.setSearchQuery("");
    }
    Page<MainItemDto> items = itemService.getMainItemPage(itemSearchDto, pageable);

    System.out.println(items.getNumber() + "!!!!!");
    System.out.println(items.getTotalPages() + "#####");

    model.addAttribute("items", items);
    model.addAttribute("itemSearchDto", itemSearchDto);
    model.addAttribute("maxPage", 5);
    return "main";
  }

--> 메인에서 보여줄 아이템도 페이징 처리를 해서 특정한 개수만큼만 들고 온 다음 화면에 보여줄 것이고 화면에 보여줄 것이니까 모델이 필요하다. 

 

화면에 보여줄 때 아이템 정보 전달할 Dto도 생성 Item을 그대로 들고다니진 않음.

@Getter
@Setter
public class MainItemDto {

  private Long id;
  private String itemNm;
  private String itemDetail;
  private String imgUrl;
  private Integer price;

  @QueryProjection // 쿼리dsl 결과 조회 시 MainItemDto 객체로 바로 오도록 활용.
  public MainItemDto(Long id, String itemNm, String itemDetail, String imgUrl, Integer price) {
    this.id = id;
    this.itemNm = itemNm;
    this.itemDetail = itemDetail;
    this.imgUrl = imgUrl;
    this.price = price;
  }
}

Projection은 SQL에서 select * from 처럼 전부를 가지고 오는 게 아니라

일부만 가지고 올 때 쓴다. select id, itemNm from ~ 등...

이 두 개를 하나로 묶어서 그 객체째로 받는 것.

 

여기선   private Long id;
  private String itemNm;
  private String itemDetail;
  private String imgUrl;
  private Integer price; 이 다섯개를 하나로 묶어서, 각각 받는 것이 아니라 하나의 객체에 쿼리dsl이 매핑한 다음에 리턴을 준다는 뜻.

 

그 코드가 바로 여기

ItemRepositoryCustomImpl

  @Override
  public Page<MainItemDto> getMainItemPage(ItemSearchDto itemSearchDto, Pageable pageable) {
    QItem item = QItem.item;
    QItemImg itemImg = QItemImg.itemImg;

    // QMainItemDto @QueryProjection을 허용하면 DTO로 바로 조회 가능
    QueryResults<MainItemDto> results = queryFactory.select(new QMainItemDto(item.id, item.itemNm, item.itemDetail
        , itemImg.imgUrl, item.price))
    // join 내부조인 .repImgYn.eq("Y") 대표이미지만 가져온다.
        .from(itemImg).join(itemImg.item, item).where(itemImg.repImgYn.eq("Y"))
        .where(itemNmLike(itemSearchDto.getSearchQuery()))
        .orderBy(item.id.desc()).offset(pageable.getOffset()).limit(pageable.getPageSize()).fetchResults();
    List<MainItemDto> content = results.getResults();
    long total = results.getTotal();
    return new PageImpl<>(content, pageable, total);
  }

QMainItemDto(item.id, item.itemNm, item.itemDetail, itemImg.imgUrl, item.price) 이 다섯개를

MainItemDto라는 이름으로 객체에 담아줘.

그래서 result가 MainItemDto.

 

이게 아니었으면 이 다섯개를 리스트로 받거나 배열로 받아서 하나씩 쪼개서 다시 dto 객체를 만들고 세팅해주는 지리한 과정을 일일이 했어야 한다.

 


ItemService

@Transactional(readOnly = true)
  public Page<MainItemDto> getMainItemPage(ItemSearchDto itemSearchDto, Pageable pageable) {
    return itemRepository.getMainItemPage(itemSearchDto, pageable);
  }

 

사실 클래스 위에 어노테이션으로 @Transactional이 붙어 있는데, true라는 다른 값이기 때문에 쓴 건데, 이걸 쓰면 급진적 성능향상을 기대할 수 있음.

readOnly가 true면 읽기 전용이라 조회만 할 거니까 snapshot을 기억해두지 않아도 된다.

 

728x90
Comments