diff --git a/src/main/java/corecord/dev/domain/analysis/entity/Ability.java b/src/main/java/corecord/dev/domain/analysis/entity/Ability.java index 5417aff..cb9b161 100644 --- a/src/main/java/corecord/dev/domain/analysis/entity/Ability.java +++ b/src/main/java/corecord/dev/domain/analysis/entity/Ability.java @@ -32,7 +32,7 @@ public class Ability extends BaseEntity { @JoinColumn(name = "user_id", nullable = false) private User user; - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "analysis_id", nullable = false) private Analysis analysis; diff --git a/src/main/java/corecord/dev/domain/analysis/entity/Analysis.java b/src/main/java/corecord/dev/domain/analysis/entity/Analysis.java index f0caf34..540437d 100644 --- a/src/main/java/corecord/dev/domain/analysis/entity/Analysis.java +++ b/src/main/java/corecord/dev/domain/analysis/entity/Analysis.java @@ -7,6 +7,7 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.BatchSize; import java.util.List; @@ -29,6 +30,7 @@ public class Analysis extends BaseEntity { @JoinColumn(name = "record_id", nullable = false) private Record record; + @BatchSize(size = 3) @OneToMany(mappedBy = "analysis", cascade = CascadeType.ALL, fetch = FetchType.LAZY) private List abilityList; } diff --git a/src/main/java/corecord/dev/domain/folder/repository/FolderRepository.java b/src/main/java/corecord/dev/domain/folder/repository/FolderRepository.java index c18e9b5..90c9607 100644 --- a/src/main/java/corecord/dev/domain/folder/repository/FolderRepository.java +++ b/src/main/java/corecord/dev/domain/folder/repository/FolderRepository.java @@ -9,6 +9,7 @@ import org.springframework.stereotype.Repository; import java.util.List; +import java.util.Optional; @Repository public interface FolderRepository extends JpaRepository { @@ -19,5 +20,12 @@ public interface FolderRepository extends JpaRepository { "ORDER BY f.createdAt desc ") List findFolderDtoList(@Param(value = "user") User user); + @Query("SELECT f " + + "FROM Folder f " + + "WHERE f.title = :title AND f.user = :user ") + Optional findFolderByTitle( + @Param(value = "title") String title, + @Param(value = "user") User user); + boolean existsByTitle(String title); } diff --git a/src/main/java/corecord/dev/domain/record/constant/RecordSuccessStatus.java b/src/main/java/corecord/dev/domain/record/constant/RecordSuccessStatus.java index 710d93b..6046ace 100644 --- a/src/main/java/corecord/dev/domain/record/constant/RecordSuccessStatus.java +++ b/src/main/java/corecord/dev/domain/record/constant/RecordSuccessStatus.java @@ -12,7 +12,9 @@ public enum RecordSuccessStatus implements BaseSuccessStatus { MEMO_RECORD_CREATE_SUCCESS(HttpStatus.CREATED, "S404", "메모 경험 기록이 성공적으로 완료되었습니다."), MEMO_RECORD_DETAIL_GET_SUCCESS(HttpStatus.OK, "S401", "메모 경험 기록 세부 조회가 성공적으로 완료되었습니다."), MEMO_RECORD_TMP_CREATE_SUCCESS(HttpStatus.OK, "S403", "메모 경험 기록 임시 저장이 성공적으로 완료되었습니다."), - MEMO_RECORD_TMP_GET_SUCCESS(HttpStatus.OK, "S402", "메모 경험 기록 임시 저장 내역 조회가 성공적으로 완료되었습니다.") + MEMO_RECORD_TMP_GET_SUCCESS(HttpStatus.OK, "S402", "메모 경험 기록 임시 저장 내역 조회가 성공적으로 완료되었습니다."), + RECORD_LIST_GET_SUCCESS(HttpStatus.OK, "S602", "폴더별 경험 기록 리스트 조회가 성공적으로 완료되었습니다."), + KEYWORD_RECORD_LIST_GET_SUCCESS(HttpStatus.OK, "S503", "역량 키워드별 경험 기록 리스트 조회가 성공적으로 완료되었습니다.") ; private final HttpStatus httpStatus; diff --git a/src/main/java/corecord/dev/domain/record/controller/RecordController.java b/src/main/java/corecord/dev/domain/record/controller/RecordController.java index 1022e11..3dc91b0 100644 --- a/src/main/java/corecord/dev/domain/record/controller/RecordController.java +++ b/src/main/java/corecord/dev/domain/record/controller/RecordController.java @@ -51,4 +51,22 @@ public ResponseEntity> getTmpMemoRe return ApiResponse.success(RecordSuccessStatus.MEMO_RECORD_TMP_GET_SUCCESS, recordResponse); } + @GetMapping("") + public ResponseEntity> getRecordListByFolder( + @UserId Long userId, + @RequestParam(name = "folder", defaultValue = "all") String folder + ) { + RecordResponse.RecordListDto recordResponse = recordService.getRecordList(userId, folder); + return ApiResponse.success(RecordSuccessStatus.RECORD_LIST_GET_SUCCESS, recordResponse); + } + + @GetMapping("/keyword") + public ResponseEntity> getRecordListByKeyword( + @UserId Long userId, + @RequestParam(name = "keyword") String keyword + ) { + RecordResponse.KeywordRecordListDto recordResponse = recordService.getKeywordRecordList(userId, keyword); + return ApiResponse.success(RecordSuccessStatus.KEYWORD_RECORD_LIST_GET_SUCCESS, recordResponse); + } + } diff --git a/src/main/java/corecord/dev/domain/record/converter/RecordConverter.java b/src/main/java/corecord/dev/domain/record/converter/RecordConverter.java index 472b89b..c770d9a 100644 --- a/src/main/java/corecord/dev/domain/record/converter/RecordConverter.java +++ b/src/main/java/corecord/dev/domain/record/converter/RecordConverter.java @@ -1,11 +1,15 @@ package corecord.dev.domain.record.converter; +import corecord.dev.domain.analysis.constant.Keyword; +import corecord.dev.domain.analysis.entity.Ability; import corecord.dev.domain.folder.entity.Folder; import corecord.dev.domain.record.constant.RecordType; import corecord.dev.domain.record.dto.response.RecordResponse; import corecord.dev.domain.record.entity.Record; import corecord.dev.domain.user.entity.User; +import java.util.List; + public class RecordConverter { public static Record toMemoRecordEntity(String title, String content, User user, Folder folder) { return Record.builder() @@ -42,4 +46,53 @@ public static RecordResponse.TmpMemoRecordDto toNotExistingTmpMemoRecordDto() { .content(null) .build(); } + + public static RecordResponse.RecordDto toRecordDto(Record record) { + List keywordList = record.getAnalysis().getAbilityList().stream() + .map(Ability::getKeyword) + .map(Keyword::getValue) + .toList(); + + return RecordResponse.RecordDto.builder() + .analysisId(record.getAnalysis().getAnalysisId()) + .folder(record.getFolder().getTitle()) + .title(record.getTitle()) + .keywordList(keywordList) + .createdAt(record.getCreatedAtFormatted()) + .build(); + } + + public static RecordResponse.RecordListDto toRecordListDto(String folder, List recordList) { + List recordDtoList = recordList.stream() + .map(RecordConverter::toRecordDto) + .toList(); + + return RecordResponse.RecordListDto.builder() + .folder(folder) + .recordDtoList(recordDtoList) + .build(); + } + + public static RecordResponse.KeywordRecordDto toKeywordRecordDto(Record record) { + String content = record.getContent(); + String truncatedContent = content.length() > 30 ? content.substring(0, 30) : content; + + return RecordResponse.KeywordRecordDto.builder() + .analysisId(record.getAnalysis().getAnalysisId()) + .folder(record.getFolder().getTitle()) + .title(record.getTitle()) + .content(truncatedContent) + .createdAt(record.getCreatedAtFormatted()) + .build(); + } + + public static RecordResponse.KeywordRecordListDto toKeywordRecordListDto(List recordList) { + List keywordRecordDtoList = recordList.stream() + .map(RecordConverter::toKeywordRecordDto) + .toList(); + + return RecordResponse.KeywordRecordListDto.builder() + .recordDtoList(keywordRecordDtoList) + .build(); + } } diff --git a/src/main/java/corecord/dev/domain/record/dto/response/RecordResponse.java b/src/main/java/corecord/dev/domain/record/dto/response/RecordResponse.java index 3d6ec9a..c1b6e0c 100644 --- a/src/main/java/corecord/dev/domain/record/dto/response/RecordResponse.java +++ b/src/main/java/corecord/dev/domain/record/dto/response/RecordResponse.java @@ -5,6 +5,8 @@ import lombok.Data; import lombok.Getter; +import java.util.List; + public class RecordResponse { @Builder @Getter @@ -27,4 +29,45 @@ public static class TmpMemoRecordDto { private String title; private String content; } + + @Builder + @Getter + @AllArgsConstructor + @Data + public static class RecordDto { + private Long analysisId; + private String folder; + private String title; + private List keywordList; + private String createdAt; + } + + @Builder + @Getter + @AllArgsConstructor + @Data + public static class RecordListDto { + private String folder; + private List recordDtoList; + } + + @Builder + @Getter + @AllArgsConstructor + @Data + public static class KeywordRecordDto { + private Long analysisId; + private String folder; + private String title; + private String content; + private String createdAt; + } + + @Builder + @Getter + @AllArgsConstructor + @Data + public static class KeywordRecordListDto { + private List recordDtoList; + } } diff --git a/src/main/java/corecord/dev/domain/record/entity/Record.java b/src/main/java/corecord/dev/domain/record/entity/Record.java index ed7ebea..370f3f3 100644 --- a/src/main/java/corecord/dev/domain/record/entity/Record.java +++ b/src/main/java/corecord/dev/domain/record/entity/Record.java @@ -40,11 +40,11 @@ public class Record extends BaseEntity { @JoinColumn(name = "chat_room_id", nullable = true) private ChatRoom chatRoom; - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "folder_id", nullable = true) private Folder folder; - @OneToOne(mappedBy = "record", cascade = CascadeType.ALL, orphanRemoval = true) + @OneToOne(mappedBy = "record", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) private Analysis analysis; public void updateContent(String content) { diff --git a/src/main/java/corecord/dev/domain/record/repository/RecordRepository.java b/src/main/java/corecord/dev/domain/record/repository/RecordRepository.java index 108a752..bf266d1 100644 --- a/src/main/java/corecord/dev/domain/record/repository/RecordRepository.java +++ b/src/main/java/corecord/dev/domain/record/repository/RecordRepository.java @@ -1,9 +1,50 @@ package corecord.dev.domain.record.repository; +import corecord.dev.domain.analysis.constant.Keyword; +import corecord.dev.domain.folder.entity.Folder; import corecord.dev.domain.record.entity.Record; +import corecord.dev.domain.user.entity.User; 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; +import java.util.List; + @Repository public interface RecordRepository extends JpaRepository { + + @Query("SELECT r " + + "FROM Record r " + + "JOIN FETCH r.analysis a " + + "JOIN FETCH r.folder f " + + "JOIN FETCH a.abilityList al " + + "WHERE r.user = :user " + + "AND r.folder is not null AND r.folder = :folder "+ // 임시 저장 기록 제외 + "ORDER BY r.createdAt desc ") // 최근 생성 순 정렬 + List findRecordsByFolder( + @Param(value = "folder") Folder folder, + @Param(value = "user") User user); + + @Query("SELECT r FROM Record r " + + "JOIN FETCH r.analysis a " + + "JOIN FETCH r.folder f " + + "JOIN FETCH a.abilityList al " + + "WHERE r.user = :user " + + "AND r.folder is not null " + // 임시 저장 기록 제외 + "ORDER BY r.createdAt DESC") // 최근 생성 순 정렬 + List findRecords(@Param(value = "user") User user); + + + @Query("SELECT r FROM Ability a " + + "JOIN a.analysis an " + + "JOIN an.record r " + + "JOIN FETCH r.folder f " + + "WHERE a.user = :user " + + "AND a.keyword = :keyword " + + "AND r.folder is not null " + // 임시 저장 기록 제외 + "ORDER BY r.createdAt DESC") // 최근 생성 순 정렬 + List findRecordByKeyword( + @Param(value = "keyword")Keyword keyword, + @Param(value = "user") User user); } diff --git a/src/main/java/corecord/dev/domain/record/service/RecordService.java b/src/main/java/corecord/dev/domain/record/service/RecordService.java index dd559d0..0e87782 100644 --- a/src/main/java/corecord/dev/domain/record/service/RecordService.java +++ b/src/main/java/corecord/dev/domain/record/service/RecordService.java @@ -2,6 +2,9 @@ import corecord.dev.common.exception.GeneralException; import corecord.dev.common.status.ErrorStatus; +import corecord.dev.domain.analysis.constant.Keyword; +import corecord.dev.domain.analysis.exception.enums.AnalysisErrorStatus; +import corecord.dev.domain.analysis.exception.model.AnalysisException; import corecord.dev.domain.analysis.service.AnalysisService; import corecord.dev.domain.folder.entity.Folder; import corecord.dev.domain.folder.exception.enums.FolderErrorStatus; @@ -21,6 +24,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; + @Service @Slf4j @RequiredArgsConstructor @@ -118,6 +123,43 @@ public RecordResponse.TmpMemoRecordDto getTmpMemoRecord(Long userId) { return RecordConverter.toExistingTmpMemoRecordDto(tmpMemoRecord); } + /* + * 폴더별 경험 기록 리스트를 반환합니다. folder의 default value는 'all'입니다. + * @param userId, folderName + * @return + */ + @Transactional(readOnly = true) + public RecordResponse.RecordListDto getRecordList(Long userId, String folderName) { + User user = findUserById(userId); + List recordList; + + // 임시 저장 기록 제외 Record List 최신 생성 순 조회 + if (folderName.equals("all")) { + recordList = getRecordList(user); + } else { + Folder folder = findFolderByTitle(user, folderName); + recordList = getRecordListByFolder(user, folder); + } + + return RecordConverter.toRecordListDto(folderName, recordList); + } + + /* + * keyword를 받아 해당 키워드를 가진 역량 분석 정보와 경험 기록 정보를 반환 + * @param userId, keywordValue + * @return + */ + @Transactional(readOnly = true) + public RecordResponse.KeywordRecordListDto getKeywordRecordList(Long userId, String keywordValue) { + User user = findUserById(userId); + + // 해당 keyword를 가진 ability 객체 조회 후 맵핑된 Record 객체 리스트 조회 + Keyword keyword = getKeyword(keywordValue); + List recordList = getRecordListByKeyword(user, keyword); + + return RecordConverter.toKeywordRecordListDto(recordList); + } + private void validHasUserTmpMemo(User user) { if (user.getTmpMemo() != null) throw new RecordException(RecordErrorStatus.ALREADY_TMP_MEMO); @@ -143,6 +185,11 @@ private Folder findFolderById(Long folderId) { .orElseThrow(() -> new FolderException(FolderErrorStatus.FOLDER_NOT_FOUND)); } + private Folder findFolderByTitle(User user, String title) { + return folderRepository.findFolderByTitle(title, user) + .orElseThrow(() -> new FolderException(FolderErrorStatus.FOLDER_NOT_FOUND)); + } + private User findUserById(Long userId) { return userRepository.findById(userId) .orElseThrow(() -> new GeneralException(ErrorStatus.UNAUTHORIZED)); @@ -152,4 +199,23 @@ private Record findRecordById(Long recordId) { return recordRepository.findById(recordId) .orElseThrow(() -> new RecordException(RecordErrorStatus.RECORD_NOT_FOUND)); } + + private List getRecordListByFolder(User user, Folder folder) { + return recordRepository.findRecordsByFolder(folder, user); + } + + private List getRecordList(User user) { + return recordRepository.findRecords(user); + } + + private List getRecordListByKeyword(User user, Keyword keyword) { + return recordRepository.findRecordByKeyword(keyword, user); + } + + private Keyword getKeyword(String keywordValue) { + Keyword keyword = Keyword.getName(keywordValue); + if (keyword == null) + throw new AnalysisException(AnalysisErrorStatus.INVALID_KEYWORD); + return keyword; + } }