From a1b6b5781feacf55c5bfc6c796d774c047a6b666 Mon Sep 17 00:00:00 2001 From: Dom1046 Date: Thu, 2 Jan 2025 00:09:33 +0900 Subject: [PATCH 1/4] =?UTF-8?q?[refactor]=20redis=20publish=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/chat/redis/RedisPublisher.java | 22 ++++++++ .../domain/chat/redis/RedisSubscriber.java | 10 ++-- .../chat/service/ChatMessageService.java | 4 +- .../mallangs/global/config/RedisConfig.java | 56 +++++++++++++------ 4 files changed, 70 insertions(+), 22 deletions(-) create mode 100644 src/main/java/com/mallangs/domain/chat/redis/RedisPublisher.java diff --git a/src/main/java/com/mallangs/domain/chat/redis/RedisPublisher.java b/src/main/java/com/mallangs/domain/chat/redis/RedisPublisher.java new file mode 100644 index 00000000..22b2e240 --- /dev/null +++ b/src/main/java/com/mallangs/domain/chat/redis/RedisPublisher.java @@ -0,0 +1,22 @@ +package com.mallangs.domain.chat.redis; + +import com.mallangs.domain.chat.dto.response.ChatMessageResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +@Log4j2 +@Component +@RequiredArgsConstructor +public class RedisPublisher { + + private final RedisTemplate redisTemplate; + //레디스함 채널명 + private static final String CHAT_CHANNEL = "chat_channel"; + + //레디스함으로 메세지 송신 + public void publish(ChatMessageResponse message) { + redisTemplate.convertAndSend(CHAT_CHANNEL, message); + } +} diff --git a/src/main/java/com/mallangs/domain/chat/redis/RedisSubscriber.java b/src/main/java/com/mallangs/domain/chat/redis/RedisSubscriber.java index b8bdace5..d43dcc40 100644 --- a/src/main/java/com/mallangs/domain/chat/redis/RedisSubscriber.java +++ b/src/main/java/com/mallangs/domain/chat/redis/RedisSubscriber.java @@ -19,26 +19,26 @@ public class RedisSubscriber implements MessageListener { private final SimpMessageSendingOperations messagingTemplate; private final RedisTemplate redisTemplate; - //Stomp로 송신 + //stomp (레디스 거치지 않고) 바로 메세지 전송 public void sendMessage(ChatMessageResponse publishMessage) { try { - log.info("레디스 펍섭의 publishMessage: {}", publishMessage); messagingTemplate.convertAndSend("/sub/chat/room/" + publishMessage.getChatRoomId(), publishMessage); } catch (Exception e) { log.error("Exception {}", e.getMessage()); } } - //redis로 송수신 + //publish Redis 메세지 수신 @Override public void onMessage(Message message, byte[] pattern) { try { + //레디스 역직렬화 String publishMessage = (String) redisTemplate.getStringSerializer().deserialize(message.getBody()); - ChatMessageResponse chatMessage = objectMapper.readValue(publishMessage, ChatMessageResponse.class); + //stomp 이용해서 구독자들에게 메세지 송신 messagingTemplate.convertAndSend("/sub/chat/room/" + chatMessage.getChatRoomId(), chatMessage); } catch (Exception e) { - log.error(e.getMessage()); + log.error("publish 레디스 메세지 -> stomp 메세지로 송신 실패 :{}", e.getMessage()); } } } diff --git a/src/main/java/com/mallangs/domain/chat/service/ChatMessageService.java b/src/main/java/com/mallangs/domain/chat/service/ChatMessageService.java index 4c223aa2..742b44da 100644 --- a/src/main/java/com/mallangs/domain/chat/service/ChatMessageService.java +++ b/src/main/java/com/mallangs/domain/chat/service/ChatMessageService.java @@ -8,6 +8,7 @@ import com.mallangs.domain.chat.entity.ChatMessage; import com.mallangs.domain.chat.entity.ChatRoom; import com.mallangs.domain.chat.entity.ParticipatedRoom; +import com.mallangs.domain.chat.redis.RedisPublisher; import com.mallangs.domain.chat.redis.RedisSubscriber; import com.mallangs.domain.chat.repository.ChatMessageRepository; import com.mallangs.domain.chat.repository.ParticipatedRoomRepository; @@ -41,6 +42,7 @@ public class ChatMessageService { private final ChatMessageRepository chatMessageRepository; private final ParticipatedRoomRepository participatedRoomRepository; + private final RedisPublisher redisPublisher; private final RedisSubscriber redisSubscriber; private final MemberRepository memberRepository; @@ -79,7 +81,7 @@ public ChatMessageSuccessResponse sendMessage(ChatMessageRequest chatMessageRequ log.info("마지막 메세지 보낼 채팅 정보: {}", chatMessageResponse.toString()); //redis로 채팅 보내기 - redisSubscriber.sendMessage(chatMessageResponse); + redisPublisher.publish(chatMessageResponse); return new ChatMessageSuccessResponse(savedChatMessage.getSender().getUserId().getValue()); } catch (Exception e) { throw new MallangsCustomException(ErrorCode.FAILED_CREATE_CHAT_MESSAGE); diff --git a/src/main/java/com/mallangs/global/config/RedisConfig.java b/src/main/java/com/mallangs/global/config/RedisConfig.java index f1c21f98..0168bceb 100644 --- a/src/main/java/com/mallangs/global/config/RedisConfig.java +++ b/src/main/java/com/mallangs/global/config/RedisConfig.java @@ -1,11 +1,14 @@ package com.mallangs.global.config; +import com.fasterxml.jackson.databind.ObjectMapper; import com.mallangs.domain.chat.redis.RedisSubscriber; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.listener.ChannelTopic; import org.springframework.data.redis.listener.RedisMessageListenerContainer; @@ -18,45 +21,66 @@ @Log4j2 public class RedisConfig { + @Value("${spring.data.redis.port}") + private int redisPort; + + @Value("${spring.data.redis.host}") + private String redisHost; + @Bean - public ChannelTopic topicPattern() { + public RedisConnectionFactory redisConnectionFactory() { + return new LettuceConnectionFactory(redisHost, redisPort); + } - return new ChannelTopic("chatRoom"); + @Bean + //Redis 채널명 + public ChannelTopic topicPattern() { + return new ChannelTopic("chat_channel"); } //클라이언트로 부터 메세지 수신 @Bean + //Redis 메세지 구독을 담당 public RedisMessageListenerContainer redisMessageListener(RedisConnectionFactory connectionFactory - , MessageListenerAdapter listenerAdapter, ChannelTopic channelTopic) { + ,MessageListenerAdapter listenerAdapter) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); - container.setConnectionFactory(connectionFactory); - container.addMessageListener(listenerAdapter, channelTopic); + container.setConnectionFactory(connectionFactory); //연결될 레디스 서버 주소, 포트 설정(매핑) + container.addMessageListener(listenerAdapter, topicPattern()); //연결될 레디스 채널명, 리스너 설정(매핑) return container; } - //클라이언트로 부터 메세지 수신 + @Bean + /** + <메세지의 흐름> + * messageService -> redisMessageListener -> listenerAdapter -> onMessage + : onMessage 실제 메세지 처리 로직 실행 (Stomp 메세지 전송) + + * listenerAdapter : message 랩핑 + onMessage 향해 메세지 전달역할 + */ public MessageListenerAdapter listenerAdapter(RedisSubscriber subscriber) { - return new MessageListenerAdapter(subscriber, "sendMessage"); + return new MessageListenerAdapter(subscriber, "onMessage"); } - // RedisConnectionFactory은 spring redis api에서 자동으로 빈 생성 @Bean(name = "redisTemplate") - public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { + //Redis 직렬화 방식 GenericJackson2 변경 + public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory + ,ObjectMapper objectMapper) { RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); // GenericJackson2JsonRedisSerializer 설정 - GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); + GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer(objectMapper); - // Key Serializer 설정 - StringRedisSerializer - template.setKeySerializer(new StringRedisSerializer()); - template.setHashKeySerializer(new StringRedisSerializer()); + // Key Serializer 설정 + StringRedisSerializer stringSerializer = new StringRedisSerializer(); + template.setKeySerializer(stringSerializer); + template.setHashKeySerializer(stringSerializer); // Value Serializer 설정 - template.setValueSerializer(jackson2JsonRedisSerializer); - template.setHashValueSerializer(jackson2JsonRedisSerializer); + template.setValueSerializer(serializer); + template.setHashValueSerializer(serializer); - template.afterPropertiesSet(); + template.afterPropertiesSet(); // 설정 완료 후 초기화 return template; } } From ccc076e04e7f1d147b2a777c3a827f3ce853c1a0 Mon Sep 17 00:00:00 2001 From: Dom1046 Date: Thu, 2 Jan 2025 17:39:20 +0900 Subject: [PATCH 2/4] =?UTF-8?q?[fix]=20AI=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20token=20=EA=B2=80=EC=A6=9Dx?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + .../domain/ai/AIPromptController.java | 21 ++-------------- .../article/service/ArticleService.java | 24 ++++++++++++++++--- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/build.gradle b/build.gradle index d4ef58b9..e447c5f8 100644 --- a/build.gradle +++ b/build.gradle @@ -109,6 +109,7 @@ dependencies { //AI prompt // implementation 'org.springframework.ai:spring-ai-vertex-ai-gemini-spring-boot-starter:1.0.0-SNAPSHOT' implementation 'com.google.cloud:google-cloud-vertexai:1.15.0' + implementation 'org.springframework.ai:spring-ai-vertex-ai-gemini' //jackson 날짜변환 위한 의존성, json 의존성 implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' diff --git a/src/main/java/com/mallangs/domain/ai/AIPromptController.java b/src/main/java/com/mallangs/domain/ai/AIPromptController.java index cb16a45f..a0e29040 100644 --- a/src/main/java/com/mallangs/domain/ai/AIPromptController.java +++ b/src/main/java/com/mallangs/domain/ai/AIPromptController.java @@ -14,7 +14,6 @@ import com.mallangs.domain.article.service.ArticleService; import com.mallangs.domain.board.dto.response.SightingListResponse; import com.mallangs.domain.board.service.BoardService; -import com.mallangs.domain.member.entity.Member; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import lombok.RequiredArgsConstructor; @@ -22,7 +21,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -59,25 +57,10 @@ public class AIPromptController { public ResponseEntity> getArticleByArticleIdByAI( @Parameter(description = "조회할 글타래 ID", required = true) @PathVariable Long articleId) { - String memberRole; - Long memberId; - - Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - - if (principal instanceof Member member) { - memberRole = member.getMemberRole().name(); - memberId = member.getMemberId(); - } else { - memberRole = "ROLE_GUEST"; - memberId = -1L; - } - log.info("role: {} memberId: {}", memberRole, memberId); - //단전조회, 실종글타래 조회 - ArticleResponse articleResponse = articleService.getArticleById(articleId, memberRole, - memberId); + ArticleResponse articleResponse = articleService.getLostArticleById(articleId); - //질문 제작 + //질문제작 StringBuilder question = new StringBuilder(); // JSON 형식에 대한 예시 설명 diff --git a/src/main/java/com/mallangs/domain/article/service/ArticleService.java b/src/main/java/com/mallangs/domain/article/service/ArticleService.java index d87cdb52..54e79523 100644 --- a/src/main/java/com/mallangs/domain/article/service/ArticleService.java +++ b/src/main/java/com/mallangs/domain/article/service/ArticleService.java @@ -41,13 +41,13 @@ public ArticleResponse createArticle(ArticleCreateRequest articleCreateRequest, .orElseThrow(() -> new MallangsCustomException(ErrorCode.MEMBER_NOT_FOUND)); // 팩토리 매니저를 통해 적절한 팩토리 선택 -> 팩토리의 역할: - log.info("articleCreateRequest: {}",articleCreateRequest.toString()); - log.info("articleCreateRequest 설명: {}",articleCreateRequest.getArticleType().getDescription()); + log.info("articleCreateRequest: {}", articleCreateRequest.toString()); + log.info("articleCreateRequest 설명: {}", articleCreateRequest.getArticleType().getDescription()); ArticleFactory factory = factoryManager.getFactory( articleCreateRequest.getArticleType().getDescription()); // 팩토리에서 article 생성 - Article article = factory.createArticle(foundMember, articleCreateRequest); + Article article = factory.createArticle(foundMember, articleCreateRequest); article.hideInMap(); // published 상태 아니면 map hidden Article savedArticle = articleRepository.save(article); @@ -147,6 +147,24 @@ public ArticleResponse getArticleById(Long articleId, String userRole, Long memb throw new MallangsCustomException(ErrorCode.ARTICLE_NOT_FOUND); } + // 실종 글타래 단건 조회 (수정본) + // 사용자는 map visiblie 인 경우 + public ArticleResponse getLostArticleById(Long articleId) { + Article foundArticle = articleRepository.findById(articleId) + .orElseThrow(() -> new MallangsCustomException(ErrorCode.ARTICLE_NOT_FOUND)); + + try { + // ArticleResponse 로 반환 통일되게 팩토리메서드 작성 필요 + ArticleFactory factory = factoryManager.getFactory( + foundArticle.getArticleType().getDescription()); + log.info("factory. : {}", factory); + + return factory.createResponse(foundArticle); + } catch (Exception e) { + throw new MallangsCustomException(ErrorCode.ARTICLE_NOT_FOUND); + } + } + // 목격제보 글타래 전체조회 public List getSightArticleByLostId(Long LostArticleId) { List
articles = articleRepository.findSightingArticles(LostArticleId); From 03f18738d1afd6cb72ea4483d18e4b6783678367 Mon Sep 17 00:00:00 2001 From: Dom1046 Date: Thu, 2 Jan 2025 17:46:37 +0900 Subject: [PATCH 3/4] =?UTF-8?q?=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle b/build.gradle index e447c5f8..d4ef58b9 100644 --- a/build.gradle +++ b/build.gradle @@ -109,7 +109,6 @@ dependencies { //AI prompt // implementation 'org.springframework.ai:spring-ai-vertex-ai-gemini-spring-boot-starter:1.0.0-SNAPSHOT' implementation 'com.google.cloud:google-cloud-vertexai:1.15.0' - implementation 'org.springframework.ai:spring-ai-vertex-ai-gemini' //jackson 날짜변환 위한 의존성, json 의존성 implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' From cfa4f62e9c51fb8da238a88148c4c82e5afe3d53 Mon Sep 17 00:00:00 2001 From: Dom1046 Date: Fri, 3 Jan 2025 03:35:08 +0900 Subject: [PATCH 4/4] =?UTF-8?q?[add]=20=EC=A7=80=EB=8F=84=20=EA=B8=80?= =?UTF-8?q?=ED=83=80=EB=9E=98=20user=ED=83=80=EC=9E=85=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80,=20=ED=9A=8C=EC=9B=90=20memberId=EB=A1=9C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/response/MapBoundsResponse.java | 9 +- .../repository/JdbcLocationRepository.java | 32 +++- .../repository/LocationRepository.java | 3 + .../article/service/LocationService.java | 146 ++++++++++-------- .../controller/MemberUserController.java | 22 +++ .../member/repository/MemberRepository.java | 6 + .../member/service/MemberUserService.java | 26 +++- .../mallangs/global/jwt/filter/JWTFilter.java | 1 + 8 files changed, 174 insertions(+), 71 deletions(-) diff --git a/src/main/java/com/mallangs/domain/article/dto/response/MapBoundsResponse.java b/src/main/java/com/mallangs/domain/article/dto/response/MapBoundsResponse.java index b6b7b5ec..552f03a1 100644 --- a/src/main/java/com/mallangs/domain/article/dto/response/MapBoundsResponse.java +++ b/src/main/java/com/mallangs/domain/article/dto/response/MapBoundsResponse.java @@ -20,5 +20,12 @@ public class MapBoundsResponse { private double longitude; private String description; - + + public MapBoundsResponse(Long articleId, String type, double latitude, double longitude, String description) { + this.articleId = articleId; + this.type = type; + this.latitude = latitude; + this.longitude = longitude; + this.description = description; + } } diff --git a/src/main/java/com/mallangs/domain/article/repository/JdbcLocationRepository.java b/src/main/java/com/mallangs/domain/article/repository/JdbcLocationRepository.java index 876e9d15..faf7bd93 100644 --- a/src/main/java/com/mallangs/domain/article/repository/JdbcLocationRepository.java +++ b/src/main/java/com/mallangs/domain/article/repository/JdbcLocationRepository.java @@ -76,7 +76,7 @@ public List findArticlesInBoundsByType(double southWestLat, ); } - // 장소 / 사용자 등록 위치 + // 장소 @Override public List findPlaceArticlesInBoundsByType(double southWestLat, double southWestLon, double northEastLat, double northEastLon, boolean isPublicData) { @@ -143,4 +143,34 @@ public List findPlaceArticlesInBoundsByCategory(double southW ); } + //사용자 등록 위치 + @Override + public List findUserInBoundsByCategory(double southWestLat, + double southWestLon, double northEastLat, double northEastLon) { + + String query = String.format( + "SELECT m.member_id, ST_X(a.point) AS longitude, " + + "ST_Y(a.point) AS latitude, a.region_3depth_h_name " + + "FROM address a " + + "JOIN member m ON m.member_id = a.member_id " + + "WHERE MBRContains(ST_GeomFromText('POLYGON((%f %f, %f %f, %f %f, %f %f, %f %f))', 4326), a.point) ", + southWestLat, southWestLon, + southWestLat, northEastLon, + northEastLat, northEastLon, + northEastLat, southWestLon, + southWestLat, southWestLon); + + log.info(query); + + return jdbcTemplate.query(query, (rs, rowNum) -> + new MapBoundsResponse( + rs.getLong("member_id"), + "user", + rs.getDouble("latitude"), // geography의 x 값 + rs.getDouble("longitude"), // geography의 y 값 + rs.getString("region_3depth_h_name") + ) + ); + } + } diff --git a/src/main/java/com/mallangs/domain/article/repository/LocationRepository.java b/src/main/java/com/mallangs/domain/article/repository/LocationRepository.java index cb9b67c5..a88f9965 100644 --- a/src/main/java/com/mallangs/domain/article/repository/LocationRepository.java +++ b/src/main/java/com/mallangs/domain/article/repository/LocationRepository.java @@ -18,4 +18,7 @@ List findPlaceArticlesInBoundsByCategory(double southWestLat, double southWestLon, double northEastLat, double northEastLon, String placeCategory, boolean isPublicData); + List findUserInBoundsByCategory(double southWestLat, + double southWestLon, double northEastLat, double northEastLon); + } diff --git a/src/main/java/com/mallangs/domain/article/service/LocationService.java b/src/main/java/com/mallangs/domain/article/service/LocationService.java index 3509d43f..9cf20e94 100644 --- a/src/main/java/com/mallangs/domain/article/service/LocationService.java +++ b/src/main/java/com/mallangs/domain/article/service/LocationService.java @@ -2,8 +2,12 @@ import com.mallangs.domain.article.dto.response.MapBoundsResponse; import com.mallangs.domain.article.repository.LocationRepository; + import java.util.List; import java.util.Objects; + +import com.mallangs.domain.member.repository.AddressRepository; +import com.mallangs.domain.member.repository.MemberRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -13,74 +17,82 @@ @RequiredArgsConstructor public class LocationService { - private final LocationRepository locationRepository; - - // 지도 조회 시 지도 표시, 글상태 체크 - // 사용자 지도, 목록 조회 시 표시, 발생만 반환 - // 관리자 목록 형태 조회 시 다 볼 수 있음 - - // 전체 조회 - public List findArticlesInBounds(double southWestLat, double southWestLon, - double northEastLat, double northEastLon) { - // 위도, 경도 순서로 전달해야 하므로, 순서를 바꿔서 호출 - log.info("findArticlesInBounds"); - log.info(String.valueOf(southWestLat)); - log.info(String.valueOf(southWestLon)); - log.info(String.valueOf(northEastLat)); - log.info(String.valueOf(northEastLon)); - - return locationRepository.findArticlesInBounds(southWestLat, southWestLon, northEastLat, - northEastLon); - } - - // 대분류 기준 조회 - public List findArticlesInBoundsByType(double southWestLat, - double southWestLon, - double northEastLat, double northEastLon, String type) { - - log.info("findArticlesInBounds"); - log.info(String.valueOf(southWestLat)); - log.info(String.valueOf(southWestLon)); - log.info(String.valueOf(northEastLat)); - log.info(String.valueOf(northEastLon)); - - // 장소 public, user 구분 - if (Objects.equals(type, "place") || Objects.equals(type, "user")) { - boolean isPublicData = Objects.equals(type, "place"); // place 면 true - - return locationRepository.findPlaceArticlesInBoundsByType(southWestLat, - southWestLon, northEastLat, northEastLon, isPublicData); + private final LocationRepository locationRepository; + + // 지도 조회 시 지도 표시, 글상태 체크 + // 사용자 지도, 목록 조회 시 표시, 발생만 반환 + // 관리자 목록 형태 조회 시 다 볼 수 있음 + // 전체 조회 + public List findArticlesInBounds(double southWestLat, double southWestLon, + double northEastLat, double northEastLon) { + // 위도, 경도 순서로 전달해야 하므로, 순서를 바꿔서 호출 + log.info("findArticlesInBounds"); + log.info(String.valueOf(southWestLat)); + log.info(String.valueOf(southWestLon)); + log.info(String.valueOf(northEastLat)); + log.info(String.valueOf(northEastLon)); + + return locationRepository.findArticlesInBounds(southWestLat, southWestLon, northEastLat, + northEastLon); } - // 실종, 구조 - return locationRepository.findArticlesInBoundsByType( - southWestLat, southWestLon, - northEastLat, northEastLon, - type); - } - - // 장소 소분류 기준 조회 - public List findPlaceArticlesInBoundsByCategory( - double southWestLat, double southWestLon, - double northEastLat, double northEastLon, - String articleType, String placeCategory) { - - log.info("findArticlesInBounds"); - log.info(String.valueOf(southWestLat)); - log.info(String.valueOf(southWestLon)); - log.info(String.valueOf(northEastLat)); - log.info(String.valueOf(northEastLon)); - - boolean isPublicData; - - isPublicData = articleType.equalsIgnoreCase("place"); - // true 면 공공 데이터 검색 - // false 면 사용자 등록 정보 검색 - - return locationRepository.findPlaceArticlesInBoundsByCategory( - southWestLat, southWestLon, - northEastLat, northEastLon, - placeCategory, isPublicData); - } + // 대분류 기준 조회 + public List findArticlesInBoundsByType(double southWestLat, + double southWestLon, + double northEastLat, double northEastLon, String type) { + + log.info("findArticlesInBounds"); + log.info(String.valueOf(southWestLat)); + log.info(String.valueOf(southWestLon)); + log.info(String.valueOf(northEastLat)); + log.info(String.valueOf(northEastLon)); + + try { + // 장소 public, user 구분 + if (Objects.equals(type, "place")) { + boolean isPublicData = Objects.equals(type, "place"); // place 면 true + + return locationRepository.findPlaceArticlesInBoundsByType(southWestLat, + southWestLon, northEastLat, northEastLon, isPublicData); + } else if (Objects.equals(type, "user")) { + return locationRepository.findUserInBoundsByCategory(southWestLat, + southWestLon, northEastLat, northEastLon); + } + + // 실종, 구조 + return locationRepository.findArticlesInBoundsByType( + southWestLat, southWestLon, + northEastLat, northEastLon, + type); + + } catch (Exception e) { + log.error("대분류에서 실패하였습니다. {}", e.getMessage()); + throw e; + } + } + + // 장소 소분류 기준 조회 + public List findPlaceArticlesInBoundsByCategory( + double southWestLat, double southWestLon, + double northEastLat, double northEastLon, + String articleType, String placeCategory) { + + log.info("findArticlesInBounds"); + log.info(String.valueOf(southWestLat)); + log.info(String.valueOf(southWestLon)); + log.info(String.valueOf(northEastLat)); + log.info(String.valueOf(northEastLon)); + + boolean isPublicData; + + isPublicData = articleType.equalsIgnoreCase("place"); + // true 면 공공 데이터 검색 + // false 면 사용자 등록 정보 검색 + + return locationRepository.findPlaceArticlesInBoundsByCategory( + southWestLat, southWestLon, + northEastLat, northEastLon, + placeCategory, isPublicData); + } } diff --git a/src/main/java/com/mallangs/domain/member/controller/MemberUserController.java b/src/main/java/com/mallangs/domain/member/controller/MemberUserController.java index 86cd0171..e304f1b3 100644 --- a/src/main/java/com/mallangs/domain/member/controller/MemberUserController.java +++ b/src/main/java/com/mallangs/domain/member/controller/MemberUserController.java @@ -80,6 +80,28 @@ public ResponseEntity create(@Validated @RequestBody Memb return ResponseEntity.status(HttpStatus.CREATED).body(memberUserService.create(memberCreateRequest)); } + @GetMapping("/member-id/{memberId}") + @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") + @Operation(summary = "회원 프로필 조회", description = "회원 프로필 조회 요청 API") + @ApiResponses({ + @ApiResponse(responseCode = "201", description = "회원 조회 성공"), + @ApiResponse(responseCode = "404", description = "회원을 찾을 수 없습니다."), + @ApiResponse(responseCode = "406", description = "차단된 계정입니다.") + }) + public ResponseEntity get(@PathVariable("memberId") Long memberId) { + return ResponseEntity.status(HttpStatus.CREATED).body(memberUserService.get(memberId)); + } + @GetMapping("/other/member-id/{memberId}") + @Operation(summary = "(타인)회원 프로필 조회", description = "(타인)회원 프로필 조회 요청 API") + @ApiResponses({ + @ApiResponse(responseCode = "201", description = "회원 조회 성공"), + @ApiResponse(responseCode = "404", description = "회원을 찾을 수 없습니다."), + @ApiResponse(responseCode = "406", description = "차단된 계정입니다.") + }) + public ResponseEntity getByOther(@PathVariable("memberId") Long memberId) { + return ResponseEntity.status(HttpStatus.CREATED).body(memberUserService.getByOther(memberId)); + } + @GetMapping("") @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") @Operation(summary = "회원 프로필 조회", description = "회원 프로필 조회 요청 API") diff --git a/src/main/java/com/mallangs/domain/member/repository/MemberRepository.java b/src/main/java/com/mallangs/domain/member/repository/MemberRepository.java index d6850417..05962e47 100644 --- a/src/main/java/com/mallangs/domain/member/repository/MemberRepository.java +++ b/src/main/java/com/mallangs/domain/member/repository/MemberRepository.java @@ -45,6 +45,12 @@ public interface MemberRepository extends JpaRepository { " WHERE m.userId =:userId ") Optional findByUserId(@Param("userId") UserId userId); + //단일 회원조회 - 회원프로필 조회 + @Query("SELECT DISTINCT m FROM Member m LEFT JOIN FETCH m.addresses" + + " LEFT JOIN m.pets " + + "WHERE m.memberId =:memberId") + Optional findByUserIdForProfile(@Param("memberId") Long memberId); + //단일 회원조회 - 회원프로필 조회 @Query("SELECT DISTINCT m FROM Member m LEFT JOIN FETCH m.addresses" + " LEFT JOIN m.pets " + diff --git a/src/main/java/com/mallangs/domain/member/service/MemberUserService.java b/src/main/java/com/mallangs/domain/member/service/MemberUserService.java index 2e573740..5179b5a2 100644 --- a/src/main/java/com/mallangs/domain/member/service/MemberUserService.java +++ b/src/main/java/com/mallangs/domain/member/service/MemberUserService.java @@ -68,7 +68,29 @@ public MemberRegisterRequest create(MemberCreateRequest memberCreateRequest) { } } - //회원조회 + //회원조회 -memberId + public MemberGetResponse get(Long memberId) { + Member foundMember = memberRepository.findByUserIdForProfile(memberId) + .orElseThrow(() -> new MallangsCustomException(ErrorCode.MEMBER_NOT_FOUND)); + if (foundMember.getIsActive().equals(false)) { + throw new MallangsCustomException(ErrorCode.BANNED_MEMBER); + } + return new MemberGetResponse(foundMember); + } + + //회원조회(타인) -memberId + public MemberGetByOtherResponse getByOther(Long memberId) { + Member foundMember = memberRepository.findByUserIdForProfile(memberId) + .orElseThrow(() -> new MallangsCustomException(ErrorCode.MEMBER_NOT_FOUND)); + + if (foundMember.getIsActive().equals(false)) { + throw new MallangsCustomException(ErrorCode.BANNED_MEMBER); + } + + return new MemberGetByOtherResponse(foundMember); + } + + //회원조회 -userId public MemberGetResponse get(String userId) { Member foundMember = memberRepository.findByUserIdForProfile(new UserId(userId)) .orElseThrow(() -> new MallangsCustomException(ErrorCode.MEMBER_NOT_FOUND)); @@ -78,7 +100,7 @@ public MemberGetResponse get(String userId) { return new MemberGetResponse(foundMember); } - //회원조회(타인) + //회원조회(타인) -userId public MemberGetByOtherResponse getByOther(String userId) { Member foundMember = memberRepository.findByUserIdForProfile(new UserId(userId)) .orElseThrow(() -> new MallangsCustomException(ErrorCode.MEMBER_NOT_FOUND)); diff --git a/src/main/java/com/mallangs/global/jwt/filter/JWTFilter.java b/src/main/java/com/mallangs/global/jwt/filter/JWTFilter.java index e6a70136..37aa9108 100644 --- a/src/main/java/com/mallangs/global/jwt/filter/JWTFilter.java +++ b/src/main/java/com/mallangs/global/jwt/filter/JWTFilter.java @@ -117,6 +117,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse //회원 uri.contains("/api/v1/member/other/") || + uri.contains("/api/v1/member/other/member-id") || //반려동물 ("GET".equals(method) && uri.startsWith("/api/v1/pets/nearby"))) {