Skip to content

Commit

Permalink
ShortForm Video 조회 시, 전체 검색 조건(PetType, Area) 대응
Browse files Browse the repository at this point in the history
ShortForm Video 조회 시, 전체 검색 조건(PetType, Area) 대응
  • Loading branch information
xGreenNarae authored Nov 2, 2023
2 parents eb6a4ca + ce6b114 commit ffb92cf
Show file tree
Hide file tree
Showing 12 changed files with 182 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,4 @@ public enum PetType {
CAT,
ETC;

public String getKoreanName() {
return switch (this) {
case DOG -> "강아지";
case CAT -> "고양이";
case ETC -> "기타";
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,6 @@ public enum Province {
전남,
경북,
경남,
제주특별자치도
;
제주특별자치도;

public String getProvinceNameForUI() {
return switch (this) {
case 서울 -> "서울특별시";
case 부산 -> "부산광역시";
case 대구 -> "대구광역시";
case 인천 -> "인천광역시";
case 광주 -> "광주광역시";
case 대전 -> "대전광역시";
case 울산 -> "울산광역시";
case 세종특별자치시 -> "세종시";
case 경기 -> "경기도";
case 강원특별자치도 -> "강원도";
case 충북 -> "충청북도";
case 충남 -> "충청남도";
case 전북 -> "전라북도";
case 전남 -> "전라남도";
case 경북 -> "경상북도";
case 경남 -> "경상남도";
case 제주특별자치도 -> "제주도";
};
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
package com.daggle.animory.domain.shortform.controller;

import com.daggle.animory.common.Response;
import com.daggle.animory.domain.shortform.service.ShortFormService;
import com.daggle.animory.domain.shortform.dto.request.ShortFormSearchCondition;
import com.daggle.animory.domain.shortform.dto.response.CategoryShortFormPage;
import com.daggle.animory.domain.shortform.dto.response.HomeShortFormPage;
import com.daggle.animory.domain.shortform.service.PetVideoLikeService;
import javax.servlet.http.HttpServletRequest;
import com.daggle.animory.domain.shortform.service.ShortFormService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

@Validated
Expand All @@ -27,36 +22,42 @@ public class ShortFormController implements ShortFormControllerApi {

private final ShortFormService shortFormService;
private final PetVideoLikeService petVideoLikeService;

/**
* 다양한 검색 조건 변화에 대응할 수 있는 목적으로 사용할 숏폼 영상 조회 API 입니다.
*/
@Override
@GetMapping("/short-forms")
public Response<CategoryShortFormPage> getShortForms(
@ModelAttribute @Valid final ShortFormSearchCondition searchCondition,
@PageableDefault final Pageable pageable) {
@ModelAttribute @Valid final ShortFormSearchCondition searchCondition,
@PageableDefault final Pageable pageable) {
return Response.success(shortFormService.getCategoryShortFormPage(searchCondition, pageable));
}

/**
* 홈 화면에서 보여 줄 숏폼 영상들을 조회합니다.
* <p>
* 검색 조건이 담기지 않은 /short-forms API와 동작이 동일하지만,
* "서비스 첫 진입 시 홈 화면"에서 보여질 영상들의 기준이 달라질 수 있음을 고려하여 분리된 API를 유지합니다.
*/
@GetMapping("/short-forms/home")
public Response<HomeShortFormPage> getHomeShortForms(@PageableDefault final Pageable pageable) {
return Response.success(shortFormService.getHomeShortFormPage(pageable));
}

@PostMapping("/like/{petVideoId}")
public Response<Void> increasePetLikeCount(final HttpServletRequest httpServletRequest, @PathVariable final int petVideoId) {
String IPAddress = httpServletRequest.getRemoteAddr();
petVideoLikeService.updatePetVideoLikeCount(IPAddress, petVideoId);
public Response<Void> increasePetLikeCount(final HttpServletRequest httpServletRequest,
@PathVariable final int petVideoId) {
String ipAddress = httpServletRequest.getRemoteAddr();
petVideoLikeService.updatePetVideoLikeCount(ipAddress, petVideoId);
return Response.success();
}

@DeleteMapping("/like/{petVideoId}")
public Response<Void> deletePetLikeCount(final HttpServletRequest httpServletRequest, @PathVariable final int petVideoId) {
String IPAddress = httpServletRequest.getRemoteAddr();
petVideoLikeService.deletePetVideoLikeCount(IPAddress, petVideoId);
public Response<Void> deletePetLikeCount(final HttpServletRequest httpServletRequest,
@PathVariable final int petVideoId) {
String ipAddress = httpServletRequest.getRemoteAddr();
petVideoLikeService.deletePetVideoLikeCount(ipAddress, petVideoId);
return Response.success();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,12 @@
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import javax.servlet.http.HttpServletRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;

@Tag(
name = "숏폼 비디오 API",
Expand All @@ -37,21 +33,18 @@ public interface ShortFormControllerApi {
in = ParameterIn.QUERY,
name = "type",
description = "Pet 종류",
required = true,
schema = @Schema(implementation = PetType.class)
),
@Parameter(
in = ParameterIn.QUERY,
name = "area",
description = "지역",
required = true,
schema = @Schema(implementation = Province.class)
),
@Parameter(
in = ParameterIn.QUERY,
name = "page",
description = "페이지 번호",
required = true,
schema = @Schema(type = "integer", defaultValue = "1")
),
@Parameter(
Expand Down Expand Up @@ -92,7 +85,8 @@ Response<CategoryShortFormPage> getShortForms(@Parameter(hidden = true)
Response<HomeShortFormPage> getHomeShortForms(@Parameter(hidden = true) @PageableDefault Pageable pageable);

@PostMapping("/like/{petVideoId}")
Response<Void> increasePetLikeCount(final HttpServletRequest httpServletRequest, @PathVariable final int petVideoId) ;
Response<Void> increasePetLikeCount(final HttpServletRequest httpServletRequest,
@PathVariable final int petVideoId);

@DeleteMapping("/like/{petVideoId}")
Response<Void> deletePetLikeCount(final HttpServletRequest httpServletRequest, @PathVariable final int petVideoId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,13 @@

public record CategoryShortFormPage(

String categoryTitle,
List<ShortFormDto> shortForms,
boolean hasNext
) {

public static CategoryShortFormPage of(final String categoryTitle,
final List<PetVideo> petVideos,
public static CategoryShortFormPage of(final List<PetVideo> petVideos,
final boolean hasNext) {
return new CategoryShortFormPage(
categoryTitle,
petVideos.stream()
.map(ShortFormDto::of)
.toList(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,16 @@
package com.daggle.animory.domain.shortform.repository;

import com.daggle.animory.domain.pet.entity.PetType;
import com.daggle.animory.domain.pet.entity.PetVideo;
import com.daggle.animory.domain.shelter.entity.Province;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

public interface PetVideoRepository extends JpaRepository<PetVideo, Integer> {
public interface PetVideoJpaRepository extends JpaRepository<PetVideo, Integer>, JpaSpecificationExecutor<PetVideo> {

@Query("""
select pv.id
from PetVideo pv
left join pv.pet p
left join p.shelter s
where s.address.province = :province
and p.type = :petType
order by pv.likeCount desc
""")
Slice<Integer> findSliceOfIds(PetType petType, Province province, Pageable pageable);

@Query("""
select pv.id
Expand All @@ -38,5 +27,7 @@ public interface PetVideoRepository extends JpaRepository<PetVideo, Integer> {
where pv.id in :petVideoIds
order by pv.likeCount desc
""")
// WARN: 서비스 전체에 short form video가 하나도 없다면, in 절이 비게 되어서 SQL에러가 발생합니다.
List<PetVideo> findAllByPetVideoIdIn(List<Integer> petVideoIds);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.daggle.animory.domain.shortform.repository;

import com.daggle.animory.domain.pet.entity.PetType;
import com.daggle.animory.domain.pet.entity.PetVideo;
import com.daggle.animory.domain.shelter.entity.Province;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.SliceImpl;
import org.springframework.stereotype.Repository;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import java.util.ArrayList;
import java.util.List;

@Repository
public class PetVideoJpqlRepository {
@PersistenceContext
private EntityManager em;

public Slice<Integer> findPetVideoIdsBy(PetType petType, Province province, Pageable pageable) {
String jpql = """
select pv.id
from PetVideo pv
left join pv.pet p
left join p.shelter s
""";
String where = "";
List<String> conditions = new ArrayList<>();
String order = " order by pv.likeCount desc";

if (petType != null) {
conditions.add("p.type = :petType");
}
if (province != null) {
conditions.add("s.address.province = :province");
}

if (!conditions.isEmpty()) {
where = " where " + String.join(" and ", conditions);
}

jpql += where + order;

TypedQuery<Integer> query = em.createQuery(jpql, Integer.class);

if (petType != null) {
query.setParameter("petType", petType);
}
if (province != null) {
query.setParameter("province", province);
}

int overLimit = pageable.getPageSize() + 1;
int offset = (int) pageable.getOffset();

List<Integer> petVideoIds = query.setFirstResult(offset)
.setMaxResults(overLimit)
.getResultList();

boolean hasNext = petVideoIds.size() == overLimit;

if (hasNext) {
petVideoIds.remove(petVideoIds.size() - 1);
}

return new SliceImpl<>(petVideoIds, pageable, hasNext);
}

public List<PetVideo> findAllByIds(final List<Integer> petVideoIds) {
if (petVideoIds.isEmpty()) return new ArrayList<>(); // in 절이 비어있으면 쿼리 에러.

String jpql = """
select pv
from PetVideo pv
left join fetch pv.pet p
left join fetch p.shelter s
where pv.id in :petVideoIds
order by pv.likeCount desc
""";

return em.createQuery(jpql, PetVideo.class)
.setParameter("petVideoIds", petVideoIds)
.getResultList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import com.daggle.animory.domain.shortform.exception.AlreadyLikedPetVideo;
import com.daggle.animory.domain.shortform.exception.NotLikedPetVideo;
import com.daggle.animory.domain.shortform.exception.ShortFormNotFound;
import com.daggle.animory.domain.shortform.repository.PetVideoJpaRepository;
import com.daggle.animory.domain.shortform.repository.PetVideoLikeRepository;
import com.daggle.animory.domain.shortform.repository.PetVideoRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -15,28 +15,28 @@
@Transactional
@RequiredArgsConstructor
public class PetVideoLikeService {
final PetVideoRepository petVideoRepository;
final PetVideoJpaRepository petVideoJpaRepository;
final PetVideoLikeRepository petVideoLikeRepository;

public void updatePetVideoLikeCount(final String IPAddress, final int petVideoId) {
validatePetVideoLikeDuplication(IPAddress, petVideoId);

final PetVideo petVideo = petVideoRepository.findById(petVideoId)
.orElseThrow(ShortFormNotFound::new);
final PetVideo petVideo = petVideoJpaRepository.findById(petVideoId)
.orElseThrow(ShortFormNotFound::new);

petVideo.updateLikeCount();

petVideoLikeRepository.save(PetVideoLike.builder()
.ipAddress(IPAddress)
.petVideo(petVideo)
.build());
.ipAddress(IPAddress)
.petVideo(petVideo)
.build());
}

public void deletePetVideoLikeCount(final String IPAddress, final int petVideoId) {
validatePetVideoLikeDelete(IPAddress, petVideoId);

final PetVideo petVideo = petVideoRepository.findById(petVideoId)
.orElseThrow(ShortFormNotFound::new);
final PetVideo petVideo = petVideoJpaRepository.findById(petVideoId)
.orElseThrow(ShortFormNotFound::new);

petVideo.deleteLikeCount();

Expand Down
Loading

0 comments on commit ffb92cf

Please sign in to comment.