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 618786d..d0650a1 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/global/api/SuccessCode.java +++ b/src/main/java/hackerthon/likelion13th/canfly/global/api/SuccessCode.java @@ -42,6 +42,10 @@ public enum SuccessCode implements BaseCode { // 성공 MAJOR_UNIV_LIKE_SUCCESS(HttpStatus.OK, "MAJOR_UNIV_MARK_2001", "전공+대학 북마크 성공"), FIELD_LIKED_LIST_VIEW_SUCCESS(HttpStatus.OK, "FIELD_2006", "로그인 사용자가 북마크한 모든 계열명을 반환합니다."), FIELD_LIST_VIEW_SUCCESS(HttpStatus.OK, "FIELD_2007", "계열 전체 조회 완료."), + MAJOR_LIKED_LIST_VIEW_SUCCESS(HttpStatus.OK, "MAJOR_2006", "내 북마크 전공 전체 조회 완료"), + 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", "전공 기준 대학 목록 조회 완료"), // 내가 추가한 코드 TOKEN_PROCESS_SUCCESS(HttpStatus.OK, "TOKEN_2001", "코인(토큰) 사용이 완료되었습니다."); diff --git a/src/main/java/hackerthon/likelion13th/canfly/search/controller/FieldController.java b/src/main/java/hackerthon/likelion13th/canfly/search/controller/FieldController.java index 97624bd..2f6bae5 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/search/controller/FieldController.java +++ b/src/main/java/hackerthon/likelion13th/canfly/search/controller/FieldController.java @@ -6,7 +6,6 @@ import hackerthon.likelion13th.canfly.login.auth.mapper.CustomUserDetails; import hackerthon.likelion13th.canfly.login.service.UserService; import hackerthon.likelion13th.canfly.search.dto.FieldDto; -import hackerthon.likelion13th.canfly.search.repository.FieldBookmarkRepository; import hackerthon.likelion13th.canfly.search.service.FieldService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponses; @@ -19,14 +18,13 @@ import java.util.List; -@Tag(name = "계열 조회", description = "계열 관련 API") +@Tag(name = "계열 관련 컨트롤러", description = "계열 관련 API") @RestController @RequestMapping("/field") @RequiredArgsConstructor public class FieldController { private final UserService userService; private final FieldService fieldService; - private final FieldBookmarkRepository fieldBookmarkRepository; @Operation(summary = "내가 좋아요한 계열 전체", description = "로그인 사용자가 북마크한 모든 계열을 반환합니다.") @ApiResponses({ 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 7d3470a..3f87cf8 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/search/controller/FieldMarkController.java +++ b/src/main/java/hackerthon/likelion13th/canfly/search/controller/FieldMarkController.java @@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -@Tag(name = "계열 북마크", description = "계열 북마크 컨트롤러입니다") +@Tag(name = "계열 북마크 관련 컨트롤러", description = "계열 북마크 컨트롤러입니다") @RestController @RequestMapping("/field/{fieldId}/like") @RequiredArgsConstructor 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 481f633..2728102 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/search/controller/MajorController.java +++ b/src/main/java/hackerthon/likelion13th/canfly/search/controller/MajorController.java @@ -1,4 +1,57 @@ package hackerthon.likelion13th.canfly.search.controller; +import hackerthon.likelion13th.canfly.domain.user.User; +import hackerthon.likelion13th.canfly.global.api.ApiResponse; +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.MajorService; +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.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@Tag(name = "전공 관련 컨트롤러", description = "전공 관련 API") +@RestController +@RequestMapping("/major") +@RequiredArgsConstructor public class MajorController { + private final UserService userService; + private final MajorService majorService; + + @Operation(summary = "내가 좋아요한 전공 전체", description = "로그인 사용자가 북마크한 모든 전공을 반환합니다.") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses. + ApiResponse(responseCode = "MAJOR_2006", description = "내 북마크 전공 전체 조회 완료") + }) + @GetMapping("/like") + public ApiResponse> getMyLikedMajors( + @AuthenticationPrincipal CustomUserDetails customUserDetails + ) { + User user = userService.findUserByProviderId(customUserDetails.getUsername()); + List majors = majorService.getAllLikedMajors(user); + + return ApiResponse.onSuccess(SuccessCode.MAJOR_LIKED_LIST_VIEW_SUCCESS, majors); + } + + @Operation(summary = "전공 전체", description = "모든 전공을 반환합니다.") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses. + ApiResponse(responseCode = "MAJOR_2007", description = " 전체 조회 완료") + }) + @GetMapping("/all") + public ApiResponse> getMajors( + @AuthenticationPrincipal CustomUserDetails customUserDetails + ) { + List majors = majorService.getAllMajors(); + + return ApiResponse.onSuccess(SuccessCode.MAJOR_LIST_VIEW_SUCCESS, majors); + } } diff --git a/src/main/java/hackerthon/likelion13th/canfly/search/controller/MajorMarkController.java b/src/main/java/hackerthon/likelion13th/canfly/search/controller/MajorMarkController.java index bff548d..ee39951 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/search/controller/MajorMarkController.java +++ b/src/main/java/hackerthon/likelion13th/canfly/search/controller/MajorMarkController.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.UnivDto; import hackerthon.likelion13th.canfly.search.service.MajorService; 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 @@ -50,4 +50,17 @@ public ApiResponse toggleLikeWithUniv( majorService.toggleMajorUnivLike(majorId, univId, user); return ApiResponse.onSuccess(SuccessCode.MAJOR_UNIV_LIKE_SUCCESS, true); } + + @Operation(summary = "전공을 개설한 대학 목록", description = "전공(majorId)을 개설한 대학 목록을 반환합니다.") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses. + ApiResponse(responseCode = "MAJOR_UNIV_2007", description = "전공 기준 대학 목록 조회 완료") + }) + @GetMapping("/universities") + public ApiResponse> getUniversitiesByMajor( + @PathVariable Long majorId + ) { + List result = majorService.getUniversitiesByMajor(majorId); + return ApiResponse.onSuccess(SuccessCode.MAJOR_UNIV_LIST_BY_MAJOR_SUCCESS, result); + } } diff --git a/src/main/java/hackerthon/likelion13th/canfly/search/dto/MajorDto.java b/src/main/java/hackerthon/likelion13th/canfly/search/dto/MajorDto.java index 46ddaba..71a34aa 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/search/dto/MajorDto.java +++ b/src/main/java/hackerthon/likelion13th/canfly/search/dto/MajorDto.java @@ -1,4 +1,15 @@ package hackerthon.likelion13th.canfly.search.dto; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder public class MajorDto { + private Long id; // major_id + private String name; // major_name } diff --git a/src/main/java/hackerthon/likelion13th/canfly/search/dto/UnivDto.java b/src/main/java/hackerthon/likelion13th/canfly/search/dto/UnivDto.java new file mode 100644 index 0000000..ab9b592 --- /dev/null +++ b/src/main/java/hackerthon/likelion13th/canfly/search/dto/UnivDto.java @@ -0,0 +1,13 @@ +package hackerthon.likelion13th.canfly.search.dto; + +import lombok.*; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class UnivDto { + private Long id; + private String name; +} 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 6f65824..0ffe614 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/search/repository/MajorBookmarkRepository.java +++ b/src/main/java/hackerthon/likelion13th/canfly/search/repository/MajorBookmarkRepository.java @@ -4,10 +4,13 @@ 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.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; +import java.util.List; + public interface MajorBookmarkRepository extends JpaRepository { boolean existsByUserAndMajor(User user, Major major); @@ -36,4 +39,15 @@ INSERT INTO major_bookmark (uid, m_id, univ_id) void upsertMajorWithUniv(@org.springframework.data.repository.query.Param("userId") String userId, @org.springframework.data.repository.query.Param("majorId") Long majorId, @org.springframework.data.repository.query.Param("univId") Long univId); + + @Query(value = """ + SELECT m.m_id AS id, m.m_name AS name + FROM major_bookmark mb + JOIN major m ON mb.m_id = m.m_id + WHERE mb.uid = :userId + GROUP BY m.m_id, 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 findAllLikedMajors(@Param("userId") String userId); } 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 5b53957..6f2f65b 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/search/service/MajorService.java +++ b/src/main/java/hackerthon/likelion13th/canfly/search/service/MajorService.java @@ -5,6 +5,8 @@ import hackerthon.likelion13th.canfly.domain.user.User; import hackerthon.likelion13th.canfly.global.api.ErrorCode; 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.repository.MajorBookmarkRepository; import hackerthon.likelion13th.canfly.search.repository.MajorRepository; import hackerthon.likelion13th.canfly.university.repository.UniversityRepository; @@ -13,6 +15,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import java.util.List; + @Slf4j @Service @RequiredArgsConstructor @@ -51,4 +55,29 @@ public void toggleMajorUnivLike(Long majorId, Long univId, User user) { majorBookmarkRepository.upsertMajorWithUniv(user.getUid(), major.getId(), univ.getId()); } } + + public List getAllLikedMajors(User user) { + List rows = majorBookmarkRepository.findAllLikedMajors(user.getUid()); + return rows.stream() + .map(r -> new MajorDto(((Number) r[0]).longValue(), (String) r[1])) + .toList(); + } + + public List getAllMajors() { + List majors = majorRepository.findAll(); + + return majors.stream() + .map(m -> new MajorDto(m.getId(), m.getName())) + .toList(); + } + + public List getUniversitiesByMajor(Long majorId) { + List rows = universityRepository.findUniversitiesByMajorId(majorId); + return rows.stream() + .map(r -> new UnivDto( + ((Number) r[0]).longValue(), // univ_id + (String) r[1] // univ_name + )) + .toList(); + } } diff --git a/src/main/java/hackerthon/likelion13th/canfly/university/repository/UniversityRepository.java b/src/main/java/hackerthon/likelion13th/canfly/university/repository/UniversityRepository.java index 7a9a537..a3033ed 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/university/repository/UniversityRepository.java +++ b/src/main/java/hackerthon/likelion13th/canfly/university/repository/UniversityRepository.java @@ -1,10 +1,22 @@ package hackerthon.likelion13th.canfly.university.repository; import hackerthon.likelion13th.canfly.domain.university.University; +import io.lettuce.core.dynamic.annotation.Param; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import java.util.List; import java.util.Optional; public interface UniversityRepository extends JpaRepository { Optional findByName(String name); + + @Query(value = """ + SELECT DISTINCT u.univ_id AS id, u.univ_name AS name + FROM university_major um + JOIN university u ON u.univ_id = um.univ_id + WHERE um.m_id = :majorId + ORDER BY u.univ_name + """, nativeQuery = true) + List findUniversitiesByMajorId(@Param("majorId") Long majorId); }