Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
@@ -0,0 +1,16 @@
package com.movelog.domain.record.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class SearchKeywordReq {
@Schema( type = "String", example ="헬스", description="검색할 명사")
private String searchKeyword;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.movelog.domain.record.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class SearchKeywordRes {

@Schema( type = "int", example = "1", description="키워드 ID")
private Long keywordId;

@Schema( type = "String", example ="헬스", description="검색어가 포함된 명사")
private String noun;

@Schema( type = "String", example ="했어요", description="명사에 해당하는 동사")
private String verb;

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.movelog.domain.record.presentation;

import com.movelog.domain.record.dto.request.CreateRecordReq;
import com.movelog.domain.record.dto.request.SearchKeywordReq;
import com.movelog.domain.record.dto.response.RecentRecordImagesRes;
import com.movelog.domain.record.dto.response.SearchKeywordRes;
import com.movelog.domain.record.dto.response.TodayRecordStatus;
import com.movelog.domain.record.service.RecordService;
import com.movelog.global.config.security.token.UserPrincipal;
Expand Down Expand Up @@ -81,5 +83,23 @@ public ResponseEntity<?> retrieveRecentRecordImages(
}


@Operation(summary = "기록 내 명사 검색 API", description = "사용자가 생성한 기록 중 명사를 통해 동사-명사 쌍을 검색하는 API입니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "기록 내 명사 검색 성공",
content = @Content(mediaType = "application/json",
schema = @Schema(type = "array", implementation = SearchKeywordRes.class))),
@ApiResponse(responseCode = "400", description = "기록 내 명사 검색 실패",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class)))
})
@GetMapping("/search")
public ResponseEntity<?> searchKeyword(
@Parameter(description = "User의 토큰을 입력해주세요.", required = true) @AuthenticationPrincipal UserPrincipal userPrincipal,
@Parameter(description = "검색할 명사를 입력해주세요.", required = true) @RequestBody SearchKeywordReq searchKeywordReq
) {
List<SearchKeywordRes> result = recordService.searchKeyword(userPrincipal, searchKeywordReq);
return ResponseEntity.ok(ApiResponseUtil.success(result));
}



}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ public interface KeywordRepository extends JpaRepository<Keyword,Long> {
boolean existsByUserAndKeywordAndVerbType(User user, String noun, VerbType verbType);

Keyword findByUserAndKeywordAndVerbType(User user, String noun, VerbType verbType);

List<Keyword> findAllByUserAndKeywordContaining(User user, String keyword);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import com.movelog.domain.record.domain.Record;
import com.movelog.domain.record.domain.VerbType;
import com.movelog.domain.record.dto.request.CreateRecordReq;
import com.movelog.domain.record.dto.request.SearchKeywordReq;
import com.movelog.domain.record.dto.response.RecentRecordImagesRes;
import com.movelog.domain.record.dto.response.SearchKeywordRes;
import com.movelog.domain.record.dto.response.TodayRecordStatus;
import com.movelog.domain.record.repository.KeywordRepository;
import com.movelog.domain.record.repository.RecordRepository;
Expand All @@ -19,6 +21,7 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.text.Collator;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
Expand Down Expand Up @@ -131,6 +134,33 @@ public List<RecentRecordImagesRes> retrieveRecentRecordImages(UserPrincipal user

}


public List<SearchKeywordRes> searchKeyword(UserPrincipal userPrincipal, SearchKeywordReq searchKeywordReq) {
User user = validUserById(userPrincipal.getId());
// User user = validUserById(5L);
String keyword = searchKeywordReq.getSearchKeyword();
List<Keyword> keywords = keywordRepository.findAllByUserAndKeywordContaining(user, keyword);
keywords.forEach(k -> log.info("Keyword in DB: {}", k.getKeyword()));

// Collator 생성
Collator collator = Collator.getInstance(Locale.KOREA);

// Collator를 이용한 오름차순 정렬
List<SearchKeywordRes> sortedResults = keywords.stream()
.map(k -> SearchKeywordRes.builder()
.keywordId(k.getKeywordId())
.noun(k.getKeyword())
.verb(VerbType.getStringVerbType(k.getVerbType()))
.build())
.sorted((o1, o2) -> collator.compare(o1.getNoun(), o2.getNoun())) // Collator로 비교
.collect(Collectors.toList());

// 정렬된 명사 목록 출력
sortedResults.forEach(r -> log.info("Sorted Noun: {}", r.getNoun()));

return sortedResults;
}

private User validUserById(Long userId) {
Optional<User> userOptional = userRepository.findById(userId);
return userOptional.get();
Expand All @@ -153,5 +183,4 @@ private void validateCreateRecordReq(CreateRecordReq createRecordReq) {
throw new IllegalArgumentException("noun is required.");
}
}

}