Skip to content

Commit

Permalink
FIX: (#145) 판매점 도메인 인프라스트럭처 계층을 재정의한다
Browse files Browse the repository at this point in the history
  • Loading branch information
anxi01 committed Feb 20, 2025
1 parent 79c1272 commit cfc612f
Show file tree
Hide file tree
Showing 12 changed files with 459 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.zerozero.store.infrastructure.kakao.search.application;

import com.zerozero.store.exception.StoreErrorType;
import com.zerozero.store.exception.StoreException;
import com.zerozero.store.infrastructure.kakao.search.core.KakaoProperty;
import com.zerozero.store.infrastructure.kakao.search.request.KakaoSearchRequest;
import com.zerozero.store.infrastructure.kakao.search.response.KakaoSearchResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;

@Service
@RequiredArgsConstructor
@Log4j2
public class KakaoSearchService {

private final KakaoProperty kakaoProperty;
private static final String KAKAO_AUTHORIZATION_PREFIX = "KakaoAK ";

public KakaoSearchResponse search(KakaoSearchRequest kakaoSearchRequest) {
URI uri = UriComponentsBuilder.fromUriString(kakaoProperty.getKeywordUrl())
.queryParams(kakaoSearchRequest.createQueryParams())
.build()
.encode()
.toUri();

try {
return RestClient.create()
.get()
.uri(uri)
.headers(header -> {
header.set("Authorization", KAKAO_AUTHORIZATION_PREFIX + kakaoProperty.getRestApiKey());
header.setContentType(MediaType.APPLICATION_JSON);
})
.retrieve()
.body(KakaoSearchResponse.class);
} catch (Exception e) {
log.error("[KakaoSearchService] error", e);
throw new StoreException(StoreErrorType.KAKAO_SERVICE_UNAVAILABLE);
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.zerozero.store.infrastructure.kakao.search.application;

import com.zerozero.store.domain.response.StoreSearchResponse;
import com.zerozero.store.domain.service.StoreSearcher;
import com.zerozero.store.exception.StoreErrorType;
import com.zerozero.store.exception.StoreException;
import com.zerozero.store.infrastructure.kakao.search.request.KakaoSearchRequest;
import com.zerozero.store.infrastructure.kakao.search.response.KakaoSearchResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Log4j2
public class KakaoStoreSearcher implements StoreSearcher {

private final KakaoSearchService kakaoSearchService;
private static final Integer DEFAULT_RADIUS = 2000;

public List<StoreSearchResponse> search(String query) {
KakaoSearchResponse kakaoSearchResponse = kakaoSearchService.search(
KakaoSearchRequest.builder()
.query(query)
.build());

if (kakaoSearchResponse == null || kakaoSearchResponse.getMeta().getTotalCount() == 0) {
log.error("[KakaoStoreSearcher] Search response is null or empty");
throw new StoreException(StoreErrorType.NOT_EXIST_SEARCH_RESPONSE);
}

return Arrays.stream(kakaoSearchResponse.getDocuments())
.map(StoreSearchResponse::from)
.collect(Collectors.toList());
}

public List<StoreSearchResponse> searchByLocation(String query, double longitude, double latitude) {
KakaoSearchResponse kakaoSearchResponse = kakaoSearchService.search(
KakaoSearchRequest.builder()
.query(query)
.longitude(String.valueOf(longitude))
.latitude(String.valueOf(latitude))
.radius(DEFAULT_RADIUS)
.build());

if (kakaoSearchResponse == null || kakaoSearchResponse.getMeta().getTotalCount() == 0) {
log.error("[KakaoStoreSearcher] Location-based search response is null or empty");
throw new StoreException(StoreErrorType.NOT_EXIST_SEARCH_RESPONSE);
}

return Arrays.stream(kakaoSearchResponse.getDocuments())
.map(StoreSearchResponse::from)
.collect(Collectors.toList());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.zerozero.store.infrastructure.kakao.search.core;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum CategoryGroupCode {

MT1("대형마트"), CS2("편의점"), PS3("어린이집, 유치원"), SC4("학교"), AC5("학원"), PK6("주차장"), OL7("주유소, 충전소"),
SW8("지하철역"), BK9("은행"), CT1("문화시설"), AG2("중개업소"), PO3("공공기관"), AT4("관광명소"), AD5("숙박"), FD6("음식점"), CE7("카페"), HP8("병원"), PM9(
"약국");

private final String description;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.zerozero.store.infrastructure.kakao.search.core;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties("kakao")
@Getter
@Setter
public class KakaoProperty {

private String restApiKey;

private String keywordUrl;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.zerozero.store.infrastructure.kakao.search.request;

import com.zerozero.store.infrastructure.kakao.search.core.CategoryGroupCode;
import lombok.Builder;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

@Builder
public record KakaoSearchRequest(
String query,
CategoryGroupCode categoryGroupCode,
String longitude,
String latitude,
Integer radius,
String rect,
Integer page,
Integer size,
String sort
) {

public MultiValueMap<String, String> createQueryParams() {
LinkedMultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();

if (query != null && !query.isEmpty()) {
queryParams.add("query", query);
}
if (categoryGroupCode != null) {
queryParams.add("category_group_code", categoryGroupCode.name());
}
if (longitude != null && !longitude.isEmpty()) {
queryParams.add("x", longitude);
}
if (latitude != null && !latitude.isEmpty()) {
queryParams.add("y", latitude);
}
if (radius != null) {
queryParams.add("radius", String.valueOf(radius));
}
if (rect != null && !rect.isEmpty()) {
queryParams.add("rect", rect);
}
if (page != null) {
queryParams.add("page", String.valueOf(page));
}
if (size != null) {
queryParams.add("size", String.valueOf(size));
}
if (sort != null && !sort.isEmpty()) {
queryParams.add("sort", sort);
}

return queryParams;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.zerozero.store.infrastructure.kakao.search.response;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;

import java.util.UUID;

@Getter
@Setter
public class KakaoSearchResponse {

private Meta meta;

private Document[] documents;

@Getter
@Setter
public static class Meta {

@JsonProperty("total_count")
private Integer totalCount;

@JsonProperty("pageable_count")
private Integer pageableCount;

@JsonProperty("is_end")
private Boolean isEnd;

@JsonProperty("same_name")
private SameName sameName;

@Getter
@Setter
public static class SameName {

private String[] region;

private String keyword;

@JsonProperty("selected_region")
private String selectedRegion;
}
}

@Getter
@Setter
public static class Document {

private String id;

@JsonProperty("place_name")
private String placeName;

@JsonProperty("category_name")
private String categoryName;

@JsonProperty("category_group_code")
private String categoryGroupCode;

@JsonProperty("category_group_name")
private String categoryGroupName;

private String phone;

@JsonProperty("address_name")
private String addressName;

@JsonProperty("road_address_name")
private String roadAddressName;

private String x;

private String y;

@JsonProperty("place_url")
private String placeUrl;

private String distance;

private boolean status;

private UUID storeId;
}
}
63 changes: 63 additions & 0 deletions src/main/java/com/zerozero/store/infrastructure/mongodb/Store.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.zerozero.store.infrastructure.mongodb;

import com.zerozero.core.util.GeoJsonConverter;
import lombok.*;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.UUID;

@ToString
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "store")
public class Store {

private UUID storeId;

private String kakaoId;

private String name;

private String category;

private String phone;

private String address;

private String roadAddress;

private String longitude;

private String latitude;

private GeoJsonPoint location;

private String placeUrl;

private boolean status;

private UUID userId;

public static Store of(com.zerozero.store.domain.model.Store store) {
return Store.builder()
.storeId(store.getId())
.kakaoId(store.getKakaoId())
.name(store.getName())
.category(store.getCategory())
.phone(store.getPhone())
.address(store.getAddress().getAddress())
.roadAddress(store.getAddress().getRoadAddress())
.longitude(store.getGeoLocation().getLongitude())
.latitude(store.getGeoLocation().getLatitude())
.location(GeoJsonConverter.of(store.getGeoLocation().getLongitude(), store.getGeoLocation().getLatitude()))
.placeUrl(store.getPlaceUrl())
.status(true)
.userId(store.getUserId())
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.zerozero.store.infrastructure.mongodb;

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;

import java.util.List;
import java.util.UUID;

public interface StoreMongoRepository extends MongoRepository<Store, UUID> {

@Query("{ 'location': { $near: { $geometry: { type: 'Point', coordinates: [?0, ?1] }, $maxDistance: ?2 } } }")
List<Store> findStoresWithinCoordinatesRadius(double longitude, double latitude, double maxDistance);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.zerozero.store.infrastructure.rabbitmq;

import com.zerozero.core.infrastructure.rabbitmq.MessageConsumer;
import com.zerozero.store.domain.service.CreateStoreMongoUseCase;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;

@Component
@RequiredArgsConstructor
@Transactional
@Log4j2
public class CreateStoreMessageConsumer implements MessageConsumer<UUID> {

private final CreateStoreMongoUseCase createStoreMongoUseCase;

@Override
@RabbitListener(queues = "${create-store-queue.queue}")
public void consumeMessage(UUID storeId) {
createStoreMongoUseCase.execute(storeId);
}

}
Loading

0 comments on commit cfc612f

Please sign in to comment.