최근 조회한 상품 호출 API 개발 로그
정기 회의를 진행하다 디자이너 팀원분이신 명현님께서 임시로 짜놓으신 마이페이지 와이어프레임을 보니 '최근 본 상품'이라는 버튼이 있었다. 기존에 협의된 기능은 아니었지만 관련 레퍼런스(쇼핑몰 서비스 등)을 참고하였을 때 필요한 기능인듯하여 추가해보았다고 하셨다. 나도 해당 기능이 우리 서비스에 있어 유익한 기능이라는 생각이 들었고 개발에 들어갔다.
단일 상품 조회 API(ItemController)
우선 상품(게시글)을 조회했을 때 해당 상품을 조회했다는 기록을 남길 무언가가 필요했다. 방법에 대해 고민하던 와중 쿠키의 존재가 떠올랐다. 쿠키라면 생성도 어렵지 않을 뿐더러 일정 시간이 지났을 때 만료되게끔 설정할 수도 있었다. 더불어 특정 상품을 조회했다는 기록자체는 클라이언트 측에 저장되어도 보안이나 특별한 문제가 발생되지 않는 데이터이기에 이번 API 개발에 적합하다 판단되어 쿠키를 적용시켜보기로 하였다.
/* 단일 상품 조회(DetailPage) */
@ApiOperation(value = "단일 상품 조회 메소드")
@GetMapping("items/detail/{itemId}")
public ResponseEntity<?> getItem(@AuthenticationPrincipal UserDetails userDetails, @PathVariable Long itemId,
HttpServletResponse httpServletResponse) {
Cookie cookie = new Cookie("itemId" + itemId, Long.toString(itemId)); /* itemId로 신규 쿠키 생성(cookie name은 중복불가 */
cookie.setPath("/");
cookie.setMaxAge(24 * 60 * 60); /* 쿠키 만료 기한은 하루 */
httpServletResponse.addCookie(cookie); /* response로 쿠키를 담아 보냄 */
ItemResponseDto itemResponseDto = itemService.getItem(userDetails, itemId);
itemService.addViewCnt(itemId);
return ResponseEntity.ok().body(itemResponseDto);
}
상품을 조회할 때 쿠키가 생성, Response 때 함께 내보내게끔 만들었다.
상품 조회 기록을 너무 길게 가지고 있는 것도 좋지 않다고 판단되어(최근 조회한 상품이 너무 많아질 수 있다고 생각되어)만료 기한은 하루로만 설정해주었다.
이때 쿠키 관련 코드를 작성하며 헤매었던 부분은 바로 쿠키의 이름을 설정해주는 부분이었다.
이번 API를 개발하며 나는 상품을 조회했다는 기록을 여러개 저장할 필요가 있었다. 예를 들어 1번 상품과 2번 상품을 조회하였다고 할 경우, 2개의 상품을 조회했다는 내용과 해당 상품들을 구분할 수 있는 정보를 온전히 저장해줄 필요가 있었다. 이때, 내가 간과했던 부분은 바로 쿠키의 이름은 중복될 수 없다는 부분이었다.
처음에는 큰 고민 없이 쿠키의 이름을 ItemId라고 설정해주었는데 쿠키를 받아오는건 잘 작동되었지만, 1번 상품을 조회하고 2번 상품으로 넘어가자 1번 상품을 조회했을 때 데이터가 사라지는 문제가 발생되었다. 처음에는 원인을 파악하지 못하고 단순 페이지가 이동될 때 기존 쿠키를 기억하지 못하고 소멸시키는 것인가하여 코드를 계속해서 뜯어보게 되었다.
그러다 타 웹 서비스에서는 어떻게 쿠키를 사용하고 있나 확인하던 중 네이버에서 해답을 얻을 수 있었다. 단 한 개의 쿠키도 중복되는 이름을 갖고 있지 않는다는 것이었다. 쿠키는 고유한 이름이 있어야했다.
그래서 나도 상품을 조회할 때 마다 해당 Item의 Id에 매칭되는 고유한 쿠키의 이름이 생성되게끔 설정해주었고 문제를 해결할 수 있었다.
내가 조회한 상품 API(ItemController)
/* 마이페이지 - 내가 조회한 상품 */
@ApiOperation(value = "마이페이지 - 내가 조회한 상품 호출 메소드")
@GetMapping("items/mypage/list")
public ResponseEntity<?> getItemList(HttpServletRequest httpServletRequest) {
return ResponseEntity.ok().body(itemService.getItemList(httpServletRequest));
}
getItemList Method(ItemService)
/* 마이페이지 - 내가 조회한 상품 리스트 호출 */
public List<ItemMainResponseDto> getItemList(HttpServletRequest httpServletRequest){
List<ItemMainResponseDto> itemMainResponseDtoList = new ArrayList<>();
int lastData = 0; /* lastData가 필요없는 메소드이기에 임시값 부여 */
Cookie[] cookieList = httpServletRequest.getCookies();
if (cookieList != null) {
for (Cookie cookie : cookieList) {
if (cookie.getName().startsWith("itemId")) {
Item item = itemRepository.findById(Long.parseLong(cookie.getValue())).orElseThrow(
()-> new IllegalArgumentException("유효하지 않은 요청입니다.")
);
itemMainResponseDtoList.add(
buildItemMainResponseDto(lastData, item)
);
}
}
}
return itemMainResponseDtoList;
}
/* 공통작업 - 메인 및 마이 페이지용 ResponseDto build */
private ItemMainResponseDto buildItemMainResponseDto(int lastData, Item item) {
boolean isLastData = false;
if(item.getId() == lastData){
isLastData = true;
}
/* 해당 item의 이미지 호출 */
List<Image> imageList = imageRepository.findAllByItemId(item.getId());
List<String> imgUrlList = new ArrayList<>();
for (Image image : imageList) {
System.out.println();
imgUrlList.add(image.getImgUrl());
}
return ItemMainResponseDto.builder()
.id(item.getId())
.title(item.getTitle())
.petCategory(item.getPetCategory())
.itemCategory(item.getItemCategory())
.itemImgs(imgUrlList)
.location(item.getLocation())
.zzimCnt(item.getZzimCnt())
.viewCnt(item.getViewCnt())
.sellingPrice(item.getSellingPrice())
.IsComplete(item.isComplete())
.time(TimeUtil.convertLocaldatetimeToTime(item.getCreatedAt()))
.lastData(isLastData)
.build();
}
쿠키가 존재할 경우, 쿠키의 name 및 value에 해당 상품의 Id값이 저장되어 있기에 이를 바탕으로 상품의 기본 정보를 build해서 response시켜주는 API를 만들어줄 수 있었다.
'✍️개발로그' 카테고리의 다른 글
실전프로젝트 6주차(평균 가격 호출 메서드 리팩터링 feat.Spring Cache + Scheduler) (1) | 2022.09.26 |
---|---|
실전프로젝트 5주차(Query 메서드 리팩터링 feat.QueryDSL) (0) | 2022.09.23 |
20220909_실전 프로젝트 14일차(Swagger 도입) (0) | 2022.09.09 |
220830_실전프로젝트 8일차(feat.Item 수정부분 트러블슈팅🚀) (0) | 2022.09.03 |
220829_실전프로젝트 4일차 (0) | 2022.08.29 |