diff --git a/src/main/java/fouragrant/scentasy/biz/chat/controller/ChatController.java b/src/main/java/fouragrant/scentasy/biz/chat/controller/ChatController.java index 15c97ba..fb5a51c 100644 --- a/src/main/java/fouragrant/scentasy/biz/chat/controller/ChatController.java +++ b/src/main/java/fouragrant/scentasy/biz/chat/controller/ChatController.java @@ -1,10 +1,11 @@ package fouragrant.scentasy.biz.chat.controller; -import fouragrant.scentasy.biz.chat.domain.Chat; import fouragrant.scentasy.biz.chat.dto.ChatListResDto; import fouragrant.scentasy.biz.chat.dto.ChatReqDto; import fouragrant.scentasy.biz.chat.dto.ChatResDto; +import fouragrant.scentasy.biz.chat.dto.ChatSessionListResDto; import fouragrant.scentasy.biz.chat.service.ChatService; +import fouragrant.scentasy.biz.member.CustomUserDetails; import fouragrant.scentasy.common.Response; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -12,14 +13,13 @@ import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; -import java.sql.Date; -import java.time.LocalDate; import java.util.List; +import java.util.UUID; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -46,47 +46,62 @@ public class ChatController { @Parameters({ @Parameter(name = "memberId", description = "멤버의 ID, path variable") }) - @PostMapping("/{memberId}") + @PostMapping("/{sessionId}") public ResponseEntity chat(@RequestBody ChatReqDto chatReqDto, - @PathVariable Long memberId) { - ChatResDto chatResDto = chatService.processChat(chatReqDto, memberId); + @AuthenticationPrincipal CustomUserDetails userDetails, + @PathVariable String sessionId) { + Long memberId = userDetails.getMemberId(); + ChatResDto chatResDto = chatService.processChat(chatReqDto, memberId, sessionId); return ResponseEntity.ok(Response.createSuccess("0000", chatResDto)); } - @Operation(summary = "멤버별 채팅 날짜 리스트 조회", description = "멤버별 채팅 내역이 있는 날짜 조회를 위한 메소드") - @ApiResponse(responseCode = "0000", description = "Successful retrieve chat dates", + @Operation(summary = "새로운 채팅 생성", description = "새로운 채팅 세션을 생성하는 메소드") + @ApiResponse(responseCode = "0000", description = "Successful new chat session creation", content = @Content( mediaType = "application/json" ) ) - @Parameters({ - @Parameter(name = "memberId", description = "멤버의 ID, path variable") - }) - @GetMapping("/dates/{memberId}") - public ResponseEntity>> getChatDatesByMemberId(@PathVariable Long memberId) { - List chatDates = chatService.getChatDatesByMemberId(memberId); - return ResponseEntity.ok(Response.createSuccess("0000", chatDates)); + @PostMapping("/new-session") + public ResponseEntity> createNewChatSession(@AuthenticationPrincipal CustomUserDetails userDetails) { + String sessionId = chatService.generateNewChatSessionId(userDetails.getMemberId()); + return ResponseEntity.ok(Response.createSuccess("0000", sessionId)); } - @Operation(summary = "멤버별 날짜별 채팅 내역 조회", description = "멤버별 날짜별 채팅 내역 조회를 위한 메소드") - @ApiResponse(responseCode = "0000", description = "Successful retrieve chat lists", + @Operation(summary = "세션 ID로 채팅 기록 조회", description = "세션 ID를 통해 해당 채팅의 전체 기록을 조회하는 메소드") + @ApiResponse(responseCode = "0000", description = "Successful retrieve chat history by session ID", content = @Content( mediaType = "application/json", schema = @Schema(implementation = ChatListResDto.class) ) ) @Parameters({ - @Parameter(name = "memberId", description = "멤버의 ID, path variable"), - @Parameter(name = "date", description = "날,, path variable") + @Parameter(name = "sessionId", description = "세션 ID, path variable") }) - @GetMapping("/{memberId}/{date}") - public ResponseEntity>> getChatsByMemberIdAndDate(@PathVariable Long memberId, - @PathVariable String date) { - LocalDate parsedDate = LocalDate.parse(date); - List chats = chatService.getChatsByMemberIdAndDate(memberId, parsedDate); + @GetMapping("/sessions/{sessionId}") + public ResponseEntity>> getChatsBySessionId( + @PathVariable String sessionId, + @AuthenticationPrincipal CustomUserDetails userDetails) { + Long memberId = userDetails.getMemberId(); + + // 해당 멤버 ID와 세션 ID에 대한 채팅 기록을 조회 + List chats = chatService.getChatsBySessionIdAndMemberId(sessionId, memberId); return ResponseEntity.ok(Response.createSuccess("0000", chats)); } + @Operation(summary = "멤버의 채팅 세션 ID 조회", description = "멤버의 채팅 기록이 있는 모든 세션 ID를 조회하는 메소드") + @ApiResponse(responseCode = "0000", description = "Successful retrieve chat sessions by member ID", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ChatSessionListResDto.class) + ) + ) + @GetMapping("/sessions") + public ResponseEntity>> getChatSessionsByMemberId( + @AuthenticationPrincipal CustomUserDetails userDetails) { + Long memberId = userDetails.getMemberId(); + List sessions = chatService.getChatSessionsByMemberId(memberId); + return ResponseEntity.ok(Response.createSuccess("0000", sessions)); + } } diff --git a/src/main/java/fouragrant/scentasy/biz/chat/domain/Chat.java b/src/main/java/fouragrant/scentasy/biz/chat/domain/Chat.java index 75ee8ec..4f26f96 100644 --- a/src/main/java/fouragrant/scentasy/biz/chat/domain/Chat.java +++ b/src/main/java/fouragrant/scentasy/biz/chat/domain/Chat.java @@ -45,6 +45,9 @@ public class Chat extends BaseTimeEntity { /* -------------------------------------------- */ /* ------------ Information Column ------------ */ /* -------------------------------------------- */ + @Column(nullable = false) + private String sessionId; + @Column(name = "input") private String input; @@ -54,7 +57,6 @@ public class Chat extends BaseTimeEntity { @CreatedDate @Column(updatable = false) private LocalDateTime createdAt; - /* -------------------------------------------- */ /* -------------- Relation Column ------------- */ /* -------------------------------------------- */ @@ -62,5 +64,4 @@ public class Chat extends BaseTimeEntity { @JsonBackReference @JoinColumn(name = "member_id", nullable = false) private Member member; - } diff --git a/src/main/java/fouragrant/scentasy/biz/chat/dto/ChatReqDto.java b/src/main/java/fouragrant/scentasy/biz/chat/dto/ChatReqDto.java index f7ff36a..232c99a 100644 --- a/src/main/java/fouragrant/scentasy/biz/chat/dto/ChatReqDto.java +++ b/src/main/java/fouragrant/scentasy/biz/chat/dto/ChatReqDto.java @@ -7,7 +7,6 @@ @Builder public record ChatReqDto( String input, - ExtraInfoReqDto extraInfo -) { - + ExtraInfoReqDto extraInfo, + String sessionId) { } diff --git a/src/main/java/fouragrant/scentasy/biz/chat/dto/ChatResDto.java b/src/main/java/fouragrant/scentasy/biz/chat/dto/ChatResDto.java index 244daab..58f6455 100644 --- a/src/main/java/fouragrant/scentasy/biz/chat/dto/ChatResDto.java +++ b/src/main/java/fouragrant/scentasy/biz/chat/dto/ChatResDto.java @@ -1,6 +1,7 @@ package fouragrant.scentasy.biz.chat.dto; public record ChatResDto( - String response + String response, + String sessionId ) { } diff --git a/src/main/java/fouragrant/scentasy/biz/chat/dto/ChatSessionListResDto.java b/src/main/java/fouragrant/scentasy/biz/chat/dto/ChatSessionListResDto.java new file mode 100644 index 0000000..382c35b --- /dev/null +++ b/src/main/java/fouragrant/scentasy/biz/chat/dto/ChatSessionListResDto.java @@ -0,0 +1,9 @@ +package fouragrant.scentasy.biz.chat.dto; + +import lombok.Builder; + +@Builder +public record ChatSessionListResDto( + String sessionId +) { +} diff --git a/src/main/java/fouragrant/scentasy/biz/chat/repository/ChatRepository.java b/src/main/java/fouragrant/scentasy/biz/chat/repository/ChatRepository.java index e77dee3..30faa44 100644 --- a/src/main/java/fouragrant/scentasy/biz/chat/repository/ChatRepository.java +++ b/src/main/java/fouragrant/scentasy/biz/chat/repository/ChatRepository.java @@ -1,24 +1,19 @@ package fouragrant.scentasy.biz.chat.repository; import fouragrant.scentasy.biz.chat.domain.Chat; -import fouragrant.scentasy.biz.chat.dto.ChatListResDto; -import java.time.LocalDate; -import java.time.LocalDateTime; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @Repository public interface ChatRepository extends JpaRepository { - @Query("SELECT DISTINCT FUNCTION('DATE', c.createdAt) FROM chat c WHERE c.member.id = :memberId") - List findDistinctChatDatesByMemberId(@Param("memberId") Long memberId); + List findChatsBySessionIdAndMemberId(String sessionId, Long memberId); - @Query("SELECT c FROM chat c WHERE c.member.id = :memberId AND c.createdAt BETWEEN :startOfDay AND :endOfDay") - List findChatsByMemberIdAndDate(@Param("memberId") Long memberId, - @Param("startOfDay") LocalDateTime startOfDay, - @Param("endOfDay") LocalDateTime endOfDay); + @Query("SELECT DISTINCT c.sessionId FROM chat c WHERE c.member.id = :memberId") + List findDistinctSessionIdsByMemberId(Long memberId); + + long countByMemberId(Long memberId); } diff --git a/src/main/java/fouragrant/scentasy/biz/chat/service/ChatService.java b/src/main/java/fouragrant/scentasy/biz/chat/service/ChatService.java index 0541b0b..bf29a82 100644 --- a/src/main/java/fouragrant/scentasy/biz/chat/service/ChatService.java +++ b/src/main/java/fouragrant/scentasy/biz/chat/service/ChatService.java @@ -6,19 +6,15 @@ import fouragrant.scentasy.biz.chat.dto.ChatListResDto; import fouragrant.scentasy.biz.chat.dto.ChatReqDto; import fouragrant.scentasy.biz.chat.dto.ChatResDto; +import fouragrant.scentasy.biz.chat.dto.ChatSessionListResDto; import fouragrant.scentasy.biz.chat.repository.ChatRepository; import fouragrant.scentasy.biz.member.domain.ExtraInfo; import fouragrant.scentasy.biz.member.domain.Member; -import fouragrant.scentasy.biz.member.dto.ExtraInfoReqDto; import fouragrant.scentasy.biz.member.repository.MemberRepository; import jakarta.transaction.Transactional; -import java.sql.Date; -import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.LocalTime; import java.util.List; import java.util.stream.Collectors; -import lombok.AllArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import lombok.extern.slf4j.Slf4j; @@ -47,7 +43,7 @@ public ChatService(ChatRepository chatRepository, MemberRepository memberReposit } @Transactional - public ChatResDto processChat(ChatReqDto chatReqDto, Long memberId) { + public ChatResDto processChat(ChatReqDto chatReqDto, Long memberId, String sessionId) { Member member = findMemberById(memberId); ExtraInfo extraInfo = member.getExtraInfo(); @@ -58,7 +54,7 @@ public ChatResDto processChat(ChatReqDto chatReqDto, Long memberId) { } assert extraInfo != null; - ChatReqDto requestWithExtraInfo = new ChatReqDto(chatReqDto.input(), extraInfo.toDto()); + ChatReqDto requestWithExtraInfo = new ChatReqDto(chatReqDto.input(), extraInfo.toDto(), sessionId); log.info("{}", requestWithExtraInfo); String response = communicateWithFlask(requestWithExtraInfo); @@ -66,12 +62,13 @@ public ChatResDto processChat(ChatReqDto chatReqDto, Long memberId) { .input(chatReqDto.input()) .response(response) .member(member) + .sessionId(sessionId) .createdAt(LocalDateTime.now()) .build(); chatRepository.save(chat); - return new ChatResDto(response); + return new ChatResDto(response, sessionId); } private String communicateWithFlask(ChatReqDto chatReqDto) { @@ -106,16 +103,9 @@ private Member findMemberById(Long memberId) { .orElseThrow(() -> new IllegalArgumentException("Member not found with ID: " + memberId)); } - public List getChatDatesByMemberId(Long memberId) { - return chatRepository.findDistinctChatDatesByMemberId(memberId); - } - @Transactional - public List getChatsByMemberIdAndDate(Long memberId, LocalDate date) { - LocalDateTime startOfDay = date.atStartOfDay(); - LocalDateTime endOfDay = date.atTime(LocalTime.MAX); - - return chatRepository.findChatsByMemberIdAndDate(memberId, startOfDay, endOfDay).stream() + public List getChatsBySessionIdAndMemberId(String sessionId, Long memberId) { + return chatRepository.findChatsBySessionIdAndMemberId(sessionId, memberId).stream() .map(chat -> ChatListResDto.builder() .chatId(chat.getId()) .createdAt(chat.getCreatedAt()) @@ -125,6 +115,21 @@ public List getChatsByMemberIdAndDate(Long memberId, LocalDate d .collect(Collectors.toList()); } + @Transactional + public List getChatSessionsByMemberId(Long memberId) { + return chatRepository.findDistinctSessionIdsByMemberId(memberId).stream() + .map(sessionId -> ChatSessionListResDto.builder() + .sessionId(sessionId) + .build()) + .collect(Collectors.toList()); + } - + @Transactional + public String generateNewChatSessionId(Long memberId) { + Member member = memberRepository.findById(memberId) + .orElseThrow(() -> new IllegalArgumentException("Member not found with ID: " + memberId)); + String nickname = member.getExtraInfo().getNickname(); + long nextId = chatRepository.countByMemberId(memberId) + 1; + return "chat_" + nextId + "_" + nickname; + } } diff --git a/src/main/java/fouragrant/scentasy/biz/perfume/controller/PerfumeController.java b/src/main/java/fouragrant/scentasy/biz/perfume/controller/PerfumeController.java index d67d6f1..18aa7fa 100644 --- a/src/main/java/fouragrant/scentasy/biz/perfume/controller/PerfumeController.java +++ b/src/main/java/fouragrant/scentasy/biz/perfume/controller/PerfumeController.java @@ -42,11 +42,10 @@ public class PerfumeController { schema = @Schema(implementation = PerfumeRecipeResDto.class) ) ) - @PostMapping("/recipe") - public ResponseEntity createRecipe(@AuthenticationPrincipal CustomUserDetails userDetails) { + @PostMapping("/recipe/{sessionId}") + public ResponseEntity createRecipe(@AuthenticationPrincipal CustomUserDetails userDetails, String sessionId) { Long memberId = userDetails.getMemberId(); - PerfumeRecipeResDto perfumeRecipeResDto = perfumeRecipeService.processRecipe(memberId); - + PerfumeRecipeResDto perfumeRecipeResDto = perfumeRecipeService.processRecipe(memberId, sessionId); return ResponseEntity.ok(Response.createSuccess("0000", perfumeRecipeResDto)); } diff --git a/src/main/java/fouragrant/scentasy/biz/perfume/service/PerfumeRecipeService.java b/src/main/java/fouragrant/scentasy/biz/perfume/service/PerfumeRecipeService.java index 16387d1..089c1fb 100644 --- a/src/main/java/fouragrant/scentasy/biz/perfume/service/PerfumeRecipeService.java +++ b/src/main/java/fouragrant/scentasy/biz/perfume/service/PerfumeRecipeService.java @@ -43,11 +43,11 @@ public PerfumeRecipeService(PerfumeRepository perfumeRepository, MemberRepositor } @Transactional - public PerfumeRecipeResDto processRecipe(Long memberId) { + public PerfumeRecipeResDto processRecipe(Long memberId, String sessionId) { Member member = findMemberById(memberId); // Flask와 통신하여 JSON 응답을 받아옴 - FlaskResponse responseData = communicateWithFlask(); + FlaskResponse responseData = communicateWithFlask(sessionId); String title = responseData.getTitle(); String description = responseData.getDescription(); String recipeArray = responseData.getPredictedNotes(); @@ -75,14 +75,14 @@ public PerfumeRecipeResDto processRecipe(Long memberId) { return new PerfumeRecipeResDto(perfume.getPerfumeId(), perfume.getCreatedAt(), title, description, noteDescriptions, accords); } - private FlaskResponse communicateWithFlask() { + private FlaskResponse communicateWithFlask(String sessionId) { RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); // 요청 본문 생성 - PerfumeRecipeReqDto perfumeRecipeReqDto = new PerfumeRecipeReqDto("default_session"); + PerfumeRecipeReqDto perfumeRecipeReqDto = new PerfumeRecipeReqDto(sessionId); HttpEntity entity = new HttpEntity<>(perfumeRecipeReqDto, headers); try { @@ -138,5 +138,4 @@ private List mapRecipeArrayToNotes(String recipeArray) { return notes; } - } diff --git a/src/main/java/fouragrant/scentasy/biz/perfume/service/PerfumeService.java b/src/main/java/fouragrant/scentasy/biz/perfume/service/PerfumeService.java index 5219099..20e0ff9 100644 --- a/src/main/java/fouragrant/scentasy/biz/perfume/service/PerfumeService.java +++ b/src/main/java/fouragrant/scentasy/biz/perfume/service/PerfumeService.java @@ -2,11 +2,8 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import fouragrant.scentasy.biz.member.CustomUserDetails; -import fouragrant.scentasy.biz.member.domain.Member; import fouragrant.scentasy.biz.member.service.MemberService; import fouragrant.scentasy.biz.perfume.domain.Perfume; -import fouragrant.scentasy.biz.perfume.dto.PerfumeDto; import fouragrant.scentasy.biz.perfume.repository.PerfumeRepository; import fouragrant.scentasy.common.exception.CommonException; import fouragrant.scentasy.common.exception.ErrorCode; diff --git a/src/main/java/fouragrant/scentasy/config/SwaggerConfig.java b/src/main/java/fouragrant/scentasy/config/SwaggerConfig.java index df23feb..9dc9df7 100644 --- a/src/main/java/fouragrant/scentasy/config/SwaggerConfig.java +++ b/src/main/java/fouragrant/scentasy/config/SwaggerConfig.java @@ -19,7 +19,7 @@ public class SwaggerConfig { @Bean public OpenAPI customOpenAPI() { return new OpenAPI() - .addServersItem(new Server().url("http://43.201.210.211:8080").description("Dev Server")) + .addServersItem(new Server().url("http://43.202.191.111:8080").description("Dev Server")) .addServersItem(new Server().url("http://localhost:8080").description("Local Server")); } } diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 57f8a0c..fdbadd5 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -8,15 +8,15 @@ spring: jpa: hibernate: - ddl-auto: create-drop - # show-sql: true + ddl-auto: create + #show-sql: true properties: hibernate: format_sql: true dialect: org.hibernate.dialect.MariaDBDialect datasource: - url: ${DB_URL} + url: jdbc:mariadb://localhost:3306/scentasy username: ${DB_USR} password: ${DB_PASSWORD} driver-class-name: org.mariadb.jdbc.Driver