Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/search place by tag #15

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import org.prography.kagongsillok.auth.domain.dto.LoginMemberInfo;
import org.prography.kagongsillok.auth.infrastructure.JwtAuthTokenProvider;
import org.prography.kagongsillok.common.resolver.dto.LoginMemberDto;
import org.prography.kagongsillok.common.resolver.exception.AccessTokenAuthenticationException;
import org.prography.kagongsillok.member.domain.Role;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
Expand All @@ -32,7 +31,6 @@ public Object resolveArgument(final MethodParameter parameter, final ModelAndVie
HttpServletRequest httpServletRequest = (HttpServletRequest) webRequest.getNativeRequest();

String accessToken = getAccessToken(httpServletRequest.getHeader("authorization"));

final LoginMemberInfo loginMemberInfo = jwtAuthTokenProvider.getLoginMemberByAccessToken(accessToken);
final Long memberId = loginMemberInfo.getMemberId();
final Role role = loginMemberInfo.getRole();
Expand All @@ -41,9 +39,6 @@ public Object resolveArgument(final MethodParameter parameter, final ModelAndVie
}

private String getAccessToken(String accessTokenHeader) {
if (accessTokenHeader == null) {
throw new AccessTokenAuthenticationException();
}
return accessTokenHeader.split(" ")[1];
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ public static <T> boolean isEmpty(final List<T> list) {
}

public static <T> String joiningToString(final List<T> list, final String delimiter) {
if (list.size() < 1) {
return null;
}
return list.stream()
.map(Object::toString)
.collect(Collectors.joining(delimiter));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.prography.kagongsillok.image.application.exception;

import java.util.List;
import org.prography.kagongsillok.common.exception.NotFoundException;
import org.prography.kagongsillok.common.utils.CustomListUtils;
import org.prography.kagongsillok.common.utils.CustomStringUtils;

public final class NotFoundImageException extends NotFoundException {

public NotFoundImageException(final List<Long> imageIds) {
super(String.format("존재하지 않는 이미지 id가 포함되어 있습니다. imageIds = %s",
CustomListUtils.joiningToString(imageIds, ",")));
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package org.prography.kagongsillok.image.infrastructure;

import java.util.List;
import java.util.Map;
import org.prography.kagongsillok.image.domain.Image;

public interface ImageRepositoryCustom {

Map<Long, Image> findByIdInToMap(List<Long> imageIds);
boolean isExistIdIn(final List<Long> imageIds);

}
Original file line number Diff line number Diff line change
@@ -1,37 +1,38 @@
package org.prography.kagongsillok.image.infrastructure;

import static org.prography.kagongsillok.image.domain.QImage.image;
import static org.prography.kagongsillok.member.domain.QMember.member;

import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.prography.kagongsillok.image.domain.Image;
import org.springframework.stereotype.Repository;

@Repository
@RequiredArgsConstructor
public class ImageRepositoryImpl implements ImageRepositoryCustom{
public class ImageRepositoryImpl implements ImageRepositoryCustom {

private final JPAQueryFactory queryFactory;

@Override
public Map<Long, Image> findByIdInToMap(final List<Long> imageIds) {

final List<Image> images = queryFactory
public boolean isExistIdIn(final List<Long> imageIds) {
List<Long> existImageIds = queryFactory
.selectFrom(image)
.where(
idIn(imageIds),
isNotDeleted()
)
.fetch();

return images
.fetch()
.stream()
.collect(Collectors.toMap(Image::getId, Function.identity()));
.map(i -> i.getId())
.collect(Collectors.toList());

return imageIds.stream()
.map(imageId -> existImageIds.contains(imageId))
.collect(Collectors.toList())
.contains(Boolean.FALSE);
}

private BooleanExpression idIn(final List<Long> ids) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@

public interface MemberRepositoryCustom {

Map<Long, Member> findByIdIn(final List<Long> memberIds);

Map<Long, Member> findByIdIn(List<Long> memberIds);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package org.prography.kagongsillok.member.infrastructure;

import static org.prography.kagongsillok.member.domain.QMember.member;
import static org.prography.kagongsillok.review.domain.QReviewTag.reviewTag;

import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.prography.kagongsillok.member.domain.Member;
Expand All @@ -19,17 +21,14 @@ public class MemberRepositoryImpl implements MemberRepositoryCustom {

@Override
public Map<Long, Member> findByIdIn(final List<Long> memberIds) {
final List<Member> members = queryFactory
return queryFactory
.selectFrom(member)
.where(
idIn(memberIds),
isNotDeleted()
)
.fetch();

return members
.stream()
.collect(Collectors.toMap(Member::getId, m -> m));
.collect(Collectors.toMap(Member::getId, Function.identity()));
}

private BooleanExpression idIn(final List<Long> ids) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package org.prography.kagongsillok.place.application;

import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.prography.kagongsillok.common.utils.CustomListUtils;
import org.prography.kagongsillok.image.application.exception.NotFoundImageException;
import org.prography.kagongsillok.image.domain.ImageRepository;
import org.prography.kagongsillok.place.application.dto.PlaceCreateCommand;
import org.prography.kagongsillok.place.application.dto.PlaceDto;
import org.prography.kagongsillok.place.application.dto.PlaceLocationAroundSearchCondition;
Expand All @@ -11,6 +13,9 @@
import org.prography.kagongsillok.place.domain.Location;
import org.prography.kagongsillok.place.domain.Place;
import org.prography.kagongsillok.place.domain.PlaceRepository;
import org.prography.kagongsillok.review.domain.Review;
import org.prography.kagongsillok.review.domain.ReviewRepository;
import org.prography.kagongsillok.review.domain.ReviewTag;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -20,9 +25,12 @@
public class PlaceService {

private final PlaceRepository placeRepository;
private final ReviewRepository reviewRepository;
private final ImageRepository imageRepository;

@Transactional
public PlaceDto createPlace(final PlaceCreateCommand placeCreateCommand) {
checkExistImage(placeCreateCommand.getImageIds());
final Place savedPlace = placeRepository.save(placeCreateCommand.toEntity());

return PlaceDto.from(savedPlace);
Expand All @@ -38,26 +46,38 @@ public PlaceDto getPlace(final Long id) {
return PlaceDto.from(place);
}

public PlaceDto getPlaceWithTags(final Long placeId) {
final Place place = placeRepository.findById(placeId)
.orElseThrow(() -> new NotFoundPlaceException(placeId));
if (place.getIsDeleted()) {
throw new NotFoundPlaceException(placeId);
}
final List<Review> reviews = reviewRepository.findAllByPlaceId(placeId);

return PlaceDto.of(place, getReviewTagsRelatedToPlace(reviews));
}

public List<PlaceDto> searchPlacesLocationAround(final PlaceLocationAroundSearchCondition searchCondition) {
final List<Place> places = placeRepository.findByLocationAround(
Location.of(searchCondition.getLatitude(), searchCondition.getLongitude()),
searchCondition.getLatitudeBound(),
searchCondition.getLongitudeBound()
);

return CustomListUtils.mapTo(places, PlaceDto::from);
return getPlaceDtos(places);
}

public List<PlaceDto> searchPlacesByName(final String name) {
final List<Place> places = placeRepository.findByNameContains(name);

return CustomListUtils.mapTo(places, PlaceDto::from);
return getPlaceDtos(places);
}

@Transactional
public PlaceDto updatePlace(final Long id, final PlaceUpdateCommand updateCommand) {
final Place place = placeRepository.findById(id)
.orElseThrow(() -> new NotFoundPlaceException(id));
checkExistImage(updateCommand.getImageIds());

final Place target = updateCommand.toEntity();
place.update(target);
Expand All @@ -72,4 +92,52 @@ public void deletePlace(final Long id) {

place.delete();
}

public List<PlaceDto> searchPlacesByTags(final List<Long> reviewTagIds) {
final List<Review> reviews = reviewRepository.findByReviewTagIds(reviewTagIds);
final List<Long> placeIds = reviews.stream()
.map(review -> review.getPlaceId())
.collect(Collectors.toSet())
.stream()
.toList();
final List<Place> places = placeRepository.findByIdIn(placeIds);

return createPlaceDtos(places, reviews);
}

private List<PlaceDto> getPlaceDtos(final List<Place> places) {
final List<Long> placeIds = places.stream()
.map(place -> place.getId())
.collect(Collectors.toList());
final List<Review> reviews = reviewRepository.findByPlaceIds(placeIds);

return createPlaceDtos(places, reviews);
}

private List<PlaceDto> createPlaceDtos(final List<Place> places, final List<Review> reviews) {
return places.stream()
.map(place -> {
List<Review> relatedReviews = reviews.stream()
.filter(review -> review.getPlaceId().equals(place.getId()))
.collect(Collectors.toList());
return PlaceDto.of(place, getReviewTagsRelatedToPlace(relatedReviews));
})
.collect(Collectors.toList());
}

private List<ReviewTag> getReviewTagsRelatedToPlace(final List<Review> reviews) {
return reviews.stream()
.flatMap(review -> review.getTagMappings()
.getValues()
.stream()
.map(reviewTagMapping -> reviewTagMapping.getReviewTag())
)
.collect(Collectors.toList());
}

private void checkExistImage(final List<Long> imageIds) {
if (imageRepository.isExistIdIn(imageIds)) {
throw new NotFoundImageException(imageIds);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.prography.kagongsillok.place.domain.BusinessHour;
import org.prography.kagongsillok.place.domain.Link;
import org.prography.kagongsillok.place.domain.Place;
import org.prography.kagongsillok.review.domain.ReviewTag;

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
Expand All @@ -24,6 +25,7 @@ public class PlaceDto {
private String phone;
private List<LinkDto> links;
private List<BusinessHourDto> businessHours;
private List<ReviewTag> reviewTags;

@Builder
public PlaceDto(
Expand All @@ -35,7 +37,8 @@ public PlaceDto(
final List<Long> imageIds,
final String phone,
final List<LinkDto> links,
final List<BusinessHourDto> businessHours
final List<BusinessHourDto> businessHours,
final List<ReviewTag> reviewTags
) {
this.id = id;
this.name = name;
Expand All @@ -46,6 +49,7 @@ public PlaceDto(
this.phone = phone;
this.links = links;
this.businessHours = businessHours;
this.reviewTags = reviewTags;
}

public static PlaceDto from(final Place place) {
Expand All @@ -62,6 +66,21 @@ public static PlaceDto from(final Place place) {
.build();
}

public static PlaceDto of(final Place place, final List<ReviewTag> reviewTags) {
return PlaceDto.builder()
.id(place.getId())
.name(place.getName())
.address(place.getAddress())
.latitude(place.getLatitude())
.longitude(place.getLongitude())
.imageIds(place.getImageIds())
.phone(place.getPhone())
.links(CustomListUtils.mapTo(place.getLinks().getValues(), LinkDto::from))
.businessHours(CustomListUtils.mapTo(place.getBusinessHours().getValues(), BusinessHourDto::from))
.reviewTags(reviewTags)
.build();
}

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public static class LinkDto {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -29,6 +30,12 @@ public ResponseEntity<CommonResponse<PlaceResponse>> getPlace(@PathVariable("id"
return CommonResponse.success(PlaceResponse.from(placeDto));
}

@GetMapping("/with-tags/{placeId}")
public ResponseEntity<CommonResponse<PlaceResponse>> getPlaceWithTags(@PathVariable("placeId") final Long placeId) {
final PlaceDto placeDto = placeService.getPlaceWithTags(placeId);
return CommonResponse.success(PlaceResponse.from(placeDto));
}

@GetMapping("/around")
public ResponseEntity<CommonResponse<PlaceListResponse>> searchAroundPlace(
@ModelAttribute final PlaceLocationAroundSearchRequest request
Expand All @@ -44,4 +51,13 @@ public ResponseEntity<CommonResponse<PlaceListResponse>> searchTitle(@RequestPar

return CommonResponse.success(PlaceListResponse.of(placeDtos));
}

@GetMapping("/tags")
public ResponseEntity<CommonResponse<PlaceListResponse>> searchTaggedPlace(
@RequestParam final List<Long> tagIds
) {
final List<PlaceDto> placeDtos = placeService.searchPlacesByTags(tagIds);

return CommonResponse.success(PlaceListResponse.of(placeDtos));
}
}
Loading
Loading