[Spring][쇼핑몰 프로젝트][52] 메인페이지 평점 순 상품 노출(서버처리)
프로젝트 Github : https://github.com/sjinjin7/Blog_Project
프로젝트 포스팅 색인(index) : https://kimvampa.tistory.com/188
목표
메인 페이지 평점 높은 상품 노출
메인 페이지에 평점이 높은 순서의 상품이 노출되도록 하는 것이 목표입니다.
순서
1. 개요
2. DTO 클래스
3. Mapper
4. Service
5. Controller
1. 개요
메인페이지에 평점이 높은 상품 노출을 구현하고자 합니다. 한 화면에 4개의 상품이 노출될 것이며 슬라이드 형식으로 넘기기 버튼을 클릭하면 다음 4개가 노출되도록 만들어 줄 것입니다.
노출 시킬 정보는 '상품 이미지', '상품 이름', '상풍 카테고리', '상품 평점'입니다.
전체적인 흐름은 DB로부터 필요로 한 상품의 정보를 평점이 높은 순으로 총 8개의 상품 정보를 검색할 것입니다. 검색된 결과 데이터를 main.jsp로 전달하고, main.jsp에서는 전달받은 상품 데이터를 통해서 슬라이드 형식으로 4개씩 노출되도록 만들어 줄 것입니다.
상품 노출 틀을 슬라이드 형식으로 한다고 했는데, 이전 포스팅에서 사용했던 slick 라이브러리를 그대로 활용해서 만들어 보도록 하겠습니다.
2. DTO 클래스
노출시킬 상품 정보를 계층 간에 데이터를 주고받을 수 있도록 그릇 역할을 해줄 DTO 클래스를 생성해 주겠습니다. com.vam.model 패키지에 SelectDTO 클래스를 생성합니다.
이 클래스에 담을 정보는 '상품 아이디', '상품 이름', '카테고리 이름', '평점', '이미지 정보'입니다. 따라서 아래와 같이 변수를 선언했습니다.
/* 상품 id */
private int bookId;
/* 상품 이름 */
private String bookName;
/* 카테고리 이름 */
private String cateName;
private double ratingAvg;
/* 상품 이미지 */
private List<AttachImageVO> imageList;
선언한 변수의 getter/setter/toString 메서드를 추가해주었습니다.
3. Mapper
평점이 높은 순으로 8개의 상품 정보를 검색하는 Mapper 메서드를 작성해주겠습니다.
BookMapper 인터페이스
com.vam.mapper 패키지의 BookMapper 인터페이스에 아래의 메서드 선언부를 추가해줍니다.
- SelectDTO타입의 객체는 한 가지의 상품 정보만 담을 수 있기 때문에 여러 개의 상품 정보를 담을 수 있도록 List 타입을 반환 타입으로 지정했습니다.
- SelectDTO 객체에 이미지 정보(imageList)는 Service 단계에서 넣어 줄 것입니다. (이미지 정보를 검색하는 Mapper 메서드는 기존에 작성해 둔 것을 그대로 사용할 것입니다.)
/* 평줌순 상품 정보 */
public List<SelectDTO> likeSelect();
BookMapper.xml
src/main/resources/com/vam/mapper 경로에 있는 BookMapper.xml 파일에 앞서 선언한 메서드가 실행할 쿼리문을 작성해줍니다.
■ MySQL
MySQL의 경우 limit과 order by 키워드를 사용하여 아래와 같이 작성했습니다.
<select id="likeSelect" resultType="com.vam.model.SelectDTO">
select bookId, bookName, ratingAvg, (select cateName from vam_bcate where vam_book.cateCode = vam_bcate.cateCode) as cateName
from vam_book
order by ratingAvg desc limit 8
</select>
■ Oracle
MySQL의 경우 limit 키워드를 통해 편하게 쿼리문을 작성했지만, Oracle의 경우는 해당 기능이 없기 때문에 rownum 키워드를 사용해야 합니다. 따라서 아래와 같은 쿼리문을 작성하면 된다고 생각할 수 있습니다.
select rownum as rn, bookId, bookName, ratingAvg, (select cateName from vam_bcate where vam_book.cateCode = vam_bcate.cateCode) as cateName
from vam_book
where rn < 9
order by ratingAvg desc ;
하지만 위의 쿼리의 경우 제의도와 다른 결과가 나타납니다. 저의 의도는 평점을 기준으로 역순으로 8개의 데이터를 가지고 오는 것입니다. 제 의도대로 되려면 위의 쿼리문에서 order by가 where 보다 우선순위를 가져야 하지만, 실제 실행될 때 where가 우선순위를 실행 우선순위를 가지기 때문에 의도와 전혀 다른 결과를 가져오게 됩니다.
이를 해결하기 위해서 먼저 평점 기준으로 역순으로 배열된 테이블을 만들어내고 이 테이블에서 8개의 행만 가져오도록 아래와 같이 명령문을 작성할 수 있을 것입니다.
select * from
(select rownum as rn, bookId, bookName, ratingAvg, (select cateName from vam_bcate where vam_book.cateCode = vam_bcate.cateCode) as cateName
from vam_book
order by ratingAvg desc)
where rn < 9 ;
따라서 BookMapper.xml 파일에 아래의 코드를 추가해줍니다.
<select id="likeSelect" resultType="com.vam.model.SelectDTO">
select * from
(select rownum as rn, bookId, bookName, ratingAvg, (select cateName from vam_bcate where vam_book.cateCode = vam_bcate.cateCode) as cateName
from vam_book
order by ratingAvg desc nulls last)
<![CDATA[
where rn < 9
]]>
</select>
※ order by 뒤 "nulls last"
우리가 만들어준 vam_book의 ratingAvg에는 기본값을 따로 주지 않았기 때문에 값을 부여하지 않았다면 null값이 들어가게 됩니다. 정렬을 했을 때 만약 null값이 포함이 되어 있다면 정렬된 값보다 null값이 앞에 배치된 결과를 반환받게 됩니다. null값이 있을 경우 null값을 앞에 배치할지 뒤에 배치할지를 "nulls last", "nulls first" 키워드를 통해서 조정할 수 있습니다. (OracleDB에 직접 명령문을 실행해서 각각 결과가 어떻게 달라지는지 직접 확인해보신다면 이해가 편하실 거 같습니다.)
4. Service
우리가 작성할 Service 메서드는 메인 페이지에 노출시킬 상품 정보를 앞서 작성한 Mapper 메서드를 호출하여 List타입의 객체로 가져오고, List 객체의 각 요소에 담긴 SelectDTO 객체에 해당 상품의 이미지 정보 또한 추가해주는 작업을 해줄 것입니다.
BookService 인터페이스
com.vam.service 패키지의 BookService 인터페이스에 아래의 메서드 선언부를 추가해줍니다.
/* 평줌순 상품 정보 */
public List<SelectDTO> likeSelect();
BookServiceImpl.java
인터페이스에서 선언한 메서드를 오버라이딩 해줍니다.
구현부에는 먼저 메인 페이지에 노출시킬 상품 정보를 반환해주는 likeSelect Mapper 메서드를 호출해주고 반환받은 객체를 변수에 저장해줍니다.
List<SelectDTO> list = bookMapper.likeSelect();
반환받은 List 객체에 담긴 각 SelectDTO 객체에 해당 이미지 정보를 추가해주는 코드를 작성해줍니다.
List<SelectDTO> list = bookMapper.likeSelect();
list.forEach(dto -> {
int bookId = dto.getBookId();
List<AttachImageVO> imageList = attachMapper.getAttachList(bookId);
dto.setImageList(imageList);
});
이미지 정보도 담긴 List 객체를 반환해줍니다.
List<SelectDTO> list = bookMapper.likeSelect();
list.forEach(dto -> {
int bookId = dto.getBookId();
List<AttachImageVO> imageList = attachMapper.getAttachList(bookId);
dto.setImageList(imageList);
});
return list;
5. Controller
메인 페이지를 반환해주는 매핑 메서드(mainPageGET) 구현부에 우리가 앞서 만들어준 Service 메서드를 호출하여 '메인 페이지'에 노출시킬 정보가 담긴 List 객체를 반환받고 이 객체를 Model클래스의 addAttribute 메서드를 호출하여 뷰로 전달해주는 코드를 작성합니다.
model.addAttribute("ls", bookService.likeSelect());
REFERENCE
DATE
- 2020.02.08