diff --git a/src/main/java/hackerthon/likelion13th/canfly/global/api/SuccessCode.java b/src/main/java/hackerthon/likelion13th/canfly/global/api/SuccessCode.java index d0650a1..dee7e53 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/global/api/SuccessCode.java +++ b/src/main/java/hackerthon/likelion13th/canfly/global/api/SuccessCode.java @@ -46,6 +46,8 @@ public enum SuccessCode implements BaseCode { // 성공 MAJOR_LIST_VIEW_SUCCESS(HttpStatus.OK, "MAJOR_2007", "전공 전체 조회 완료."), MAJOR_UNIV_LIKED_LIST_VIEW_SUCCESS(HttpStatus.OK, "MAJOR_UNIV_2006", "전공별 대학-전공 북마크 조회 완료"), MAJOR_UNIV_LIST_BY_MAJOR_SUCCESS(HttpStatus.OK, "MAJOR_UNIV_2007", "전공 기준 대학 목록 조회 완료"), + FIELD_MAJOR_LIST_BY_FIELD_SUCCESS(HttpStatus.OK, "FIELD_MAJOR_2007", "계열 기준 전공 목록 조회 완료"), + MAJOR_UNIV_BOOKMARK_LIST_SUCCESS(HttpStatus.OK, "UNIV_MAJOR_2008", "전공+대학 북마크 목록 조회 완료"), // 내가 추가한 코드 TOKEN_PROCESS_SUCCESS(HttpStatus.OK, "TOKEN_2001", "코인(토큰) 사용이 완료되었습니다."); diff --git a/src/main/java/hackerthon/likelion13th/canfly/search/controller/FieldMarkController.java b/src/main/java/hackerthon/likelion13th/canfly/search/controller/FieldMarkController.java index 3f87cf8..4160ffb 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/search/controller/FieldMarkController.java +++ b/src/main/java/hackerthon/likelion13th/canfly/search/controller/FieldMarkController.java @@ -5,16 +5,16 @@ import hackerthon.likelion13th.canfly.global.api.SuccessCode; import hackerthon.likelion13th.canfly.login.auth.mapper.CustomUserDetails; import hackerthon.likelion13th.canfly.login.service.UserService; +import hackerthon.likelion13th.canfly.search.dto.MajorDto; import hackerthon.likelion13th.canfly.search.service.FieldService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import java.util.List; @Tag(name = "계열 북마크 관련 컨트롤러", description = "계열 북마크 컨트롤러입니다") @RestController @@ -38,4 +38,18 @@ public ApiResponse toggleLike( return ApiResponse.onSuccess(SuccessCode.FIELD_LIKE_SUCCESS, true); } + + @Operation(summary = "계열에 포함된 전공 목록", + description = "계열(fieldId)에 속한 전공(major) 목록을 반환합니다.") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses. + ApiResponse(responseCode = "FIELD_MAJOR_2007", description = "계열 기준 전공 목록 조회 완료") + }) + @GetMapping("/majors") + public ApiResponse> getMajorsByField( + @PathVariable Long fieldId + ) { + List result = fieldService.getMajorsByField(fieldId); + return ApiResponse.onSuccess(SuccessCode.FIELD_MAJOR_LIST_BY_FIELD_SUCCESS, result); + } } diff --git a/src/main/java/hackerthon/likelion13th/canfly/search/controller/MajorController.java b/src/main/java/hackerthon/likelion13th/canfly/search/controller/MajorController.java index 2728102..93e3fe1 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/search/controller/MajorController.java +++ b/src/main/java/hackerthon/likelion13th/canfly/search/controller/MajorController.java @@ -6,6 +6,7 @@ import hackerthon.likelion13th.canfly.login.auth.mapper.CustomUserDetails; import hackerthon.likelion13th.canfly.login.service.UserService; import hackerthon.likelion13th.canfly.search.dto.MajorDto; +import hackerthon.likelion13th.canfly.search.dto.UnivMajorTupleDto; import hackerthon.likelion13th.canfly.search.service.MajorService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponses; @@ -54,4 +55,19 @@ public ApiResponse> getMajors( return ApiResponse.onSuccess(SuccessCode.MAJOR_LIST_VIEW_SUCCESS, majors); } + + @Operation(summary = "전공+대학 북마크 전체", + description = "로그인 사용자의 전공+대학 북마크 목록을 반환합니다. (univ_id IS NOT NULL)") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses. + ApiResponse(responseCode = "MAJOR_UNIV_BOOKMARK_2008", description = "전공+대학 북마크 목록 조회 완료") + }) + @GetMapping("/univ/list") + public ApiResponse> getLikedMajorUnivList( + @AuthenticationPrincipal CustomUserDetails customUserDetails + ) { + User user = userService.findUserByProviderId(customUserDetails.getUsername()); + List result = majorService.getAllBookmarkedMajorUnivPairs(user); + return ApiResponse.onSuccess(SuccessCode.MAJOR_UNIV_BOOKMARK_LIST_SUCCESS, result); + } } diff --git a/src/main/java/hackerthon/likelion13th/canfly/search/dto/UnivMajorTupleDto.java b/src/main/java/hackerthon/likelion13th/canfly/search/dto/UnivMajorTupleDto.java new file mode 100644 index 0000000..c12af35 --- /dev/null +++ b/src/main/java/hackerthon/likelion13th/canfly/search/dto/UnivMajorTupleDto.java @@ -0,0 +1,17 @@ +package hackerthon.likelion13th.canfly.search.dto; + + +import lombok.*; + +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class UnivMajorTupleDto { + private Long majorId; + private Long univId; + private List name; +} \ No newline at end of file diff --git a/src/main/java/hackerthon/likelion13th/canfly/search/repository/FieldBookmarkRepository.java b/src/main/java/hackerthon/likelion13th/canfly/search/repository/FieldBookmarkRepository.java index 52c33c1..3a8d9de 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/search/repository/FieldBookmarkRepository.java +++ b/src/main/java/hackerthon/likelion13th/canfly/search/repository/FieldBookmarkRepository.java @@ -3,7 +3,7 @@ import hackerthon.likelion13th.canfly.domain.field.Field; import hackerthon.likelion13th.canfly.domain.field.FieldBookmark; import hackerthon.likelion13th.canfly.domain.user.User; -import io.lettuce.core.dynamic.annotation.Param; +import org.springframework.data.repository.query.Param; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; diff --git a/src/main/java/hackerthon/likelion13th/canfly/search/repository/MajorBookmarkRepository.java b/src/main/java/hackerthon/likelion13th/canfly/search/repository/MajorBookmarkRepository.java index 0ffe614..1c2dea7 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/search/repository/MajorBookmarkRepository.java +++ b/src/main/java/hackerthon/likelion13th/canfly/search/repository/MajorBookmarkRepository.java @@ -4,7 +4,7 @@ import hackerthon.likelion13th.canfly.domain.major.MajorBookmark; import hackerthon.likelion13th.canfly.domain.university.University; import hackerthon.likelion13th.canfly.domain.user.User; -import io.lettuce.core.dynamic.annotation.Param; +import org.springframework.data.repository.query.Param; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -50,4 +50,22 @@ ORDER BY COALESCE(MAX(mb.created_at), '1000-01-01 00:00:00') DESC, MAX(mb.mb_id) DESC """, nativeQuery = true) List findAllLikedMajors(@Param("userId") String userId); + + @Query(value = """ + SELECT mb.m_id AS majorId, + mb.univ_id AS univId, + u.univ_name AS universityName, + m.m_name AS majorName, + MAX(mb.created_at) AS lastCreatedAt, -- 정렬용 + MAX(mb.mb_id) AS lastMbId -- 보조 정렬 + FROM major_bookmark mb + JOIN university u ON u.univ_id = mb.univ_id + JOIN major m ON m.m_id = mb.m_id + WHERE mb.uid = :userId + AND mb.univ_id IS NOT NULL + GROUP BY mb.m_id, mb.univ_id, u.univ_name, m.m_name + ORDER BY COALESCE(MAX(mb.created_at), '1000-01-01 00:00:00') DESC, + MAX(mb.mb_id) DESC + """, nativeQuery = true) + List findAllBookmarkedMajorUnivPairs(@Param("userId") String userId); } diff --git a/src/main/java/hackerthon/likelion13th/canfly/search/repository/MajorRepository.java b/src/main/java/hackerthon/likelion13th/canfly/search/repository/MajorRepository.java index bf942a1..34c27e7 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/search/repository/MajorRepository.java +++ b/src/main/java/hackerthon/likelion13th/canfly/search/repository/MajorRepository.java @@ -2,9 +2,20 @@ import hackerthon.likelion13th.canfly.domain.major.Major; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import io.lettuce.core.dynamic.annotation.Param; +import java.util.List; import java.util.Optional; public interface MajorRepository extends JpaRepository { Optional findByCode(Integer code); // m_code == majorSeq + + @Query(value = """ + SELECT m.m_id AS id, m.m_name AS name + FROM major m + WHERE m.f_id = :fieldId + ORDER BY m.m_name + """, nativeQuery = true) + List findMajorsByFieldId(@Param("fieldId") Long fieldId); } \ No newline at end of file diff --git a/src/main/java/hackerthon/likelion13th/canfly/search/service/FieldService.java b/src/main/java/hackerthon/likelion13th/canfly/search/service/FieldService.java index fe46a73..8eba769 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/search/service/FieldService.java +++ b/src/main/java/hackerthon/likelion13th/canfly/search/service/FieldService.java @@ -5,8 +5,10 @@ import hackerthon.likelion13th.canfly.global.api.ErrorCode; import hackerthon.likelion13th.canfly.global.exception.GeneralException; import hackerthon.likelion13th.canfly.search.dto.FieldDto; +import hackerthon.likelion13th.canfly.search.dto.MajorDto; import hackerthon.likelion13th.canfly.search.repository.FieldBookmarkRepository; import hackerthon.likelion13th.canfly.search.repository.FieldRepository; +import hackerthon.likelion13th.canfly.search.repository.MajorRepository; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -20,6 +22,7 @@ public class FieldService { private final FieldBookmarkRepository fieldBookmarkRepository; private final FieldRepository fieldRepository; + private final MajorRepository majorRepository; @Transactional public Field toggleFieldLike(Long fieldId, User user) { @@ -55,4 +58,14 @@ public List getAllFields() { .map(f -> new FieldDto(f.getId(), f.getName())) .toList(); } + + public List getMajorsByField(Long fieldId) { + List rows = majorRepository.findMajorsByFieldId(fieldId); + return rows.stream() + .map(r -> new MajorDto( + ((Number) r[0]).longValue(), // m_id + (String) r[1] // m_name + )) + .toList(); + } } diff --git a/src/main/java/hackerthon/likelion13th/canfly/search/service/MajorService.java b/src/main/java/hackerthon/likelion13th/canfly/search/service/MajorService.java index 6f2f65b..c725403 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/search/service/MajorService.java +++ b/src/main/java/hackerthon/likelion13th/canfly/search/service/MajorService.java @@ -7,6 +7,7 @@ import hackerthon.likelion13th.canfly.global.exception.GeneralException; import hackerthon.likelion13th.canfly.search.dto.MajorDto; import hackerthon.likelion13th.canfly.search.dto.UnivDto; +import hackerthon.likelion13th.canfly.search.dto.UnivMajorTupleDto; import hackerthon.likelion13th.canfly.search.repository.MajorBookmarkRepository; import hackerthon.likelion13th.canfly.search.repository.MajorRepository; import hackerthon.likelion13th.canfly.university.repository.UniversityRepository; @@ -80,4 +81,21 @@ public List getUniversitiesByMajor(Long majorId) { )) .toList(); } + + public List getAllBookmarkedMajorUnivPairs(User user) { + List rows = majorBookmarkRepository.findAllBookmarkedMajorUnivPairs(user.getUid()); + return rows.stream() + .map(r -> { + Long mId = ((Number) r[0]).longValue(); + Long univId = ((Number) r[1]).longValue(); + String univName = (String) r[2]; + String majorName= (String) r[3]; + return UnivMajorTupleDto.builder() + .majorId(mId) + .univId(univId) + .name(List.of(univName, majorName)) + .build(); + }) + .toList(); + } }