From d9aa4e39b2b2b16232b471a1712f6140941f00b8 Mon Sep 17 00:00:00 2001 From: MinJunKKang Date: Wed, 20 Aug 2025 21:43:56 +0900 Subject: [PATCH 1/5] =?UTF-8?q?=EB=B6=81=EB=A7=88=ED=81=AC,=20=EC=A0=84?= =?UTF-8?q?=EC=B2=B4=20=EC=A0=84=EA=B3=B5=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=20=EC=BD=94=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../search/controller/MajorController.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) 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); + } } From 414b3a7fb007db17a77b7a31ffc1fb9e2de91322 Mon Sep 17 00:00:00 2001 From: MinJunKKang Date: Wed, 20 Aug 2025 21:44:13 +0900 Subject: [PATCH 2/5] =?UTF-8?q?=ED=83=9C=EA=B7=B8=EB=AA=85=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../canfly/search/controller/FieldController.java | 4 +--- .../canfly/search/controller/FieldMarkController.java | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) 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 From 6f884992cfb0120a3522ffd63221a76cb838e524 Mon Sep 17 00:00:00 2001 From: MinJunKKang Date: Wed, 20 Aug 2025 21:44:52 +0900 Subject: [PATCH 3/5] =?UTF-8?q?=EC=A0=84=EA=B3=B5=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EB=94=94=ED=8B=B0=EC=98=A4,=20=EC=84=9C=EB=B9=84=EC=8A=A4,=20?= =?UTF-8?q?=EB=A0=88=ED=8F=AC=EC=A7=80=ED=86=A0=EB=A6=AC=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80=20(+=EC=84=B1=EA=B3=B5=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../canfly/global/api/SuccessCode.java | 2 ++ .../canfly/search/dto/MajorDto.java | 11 +++++++++++ .../repository/MajorBookmarkRepository.java | 14 ++++++++++++++ .../canfly/search/service/MajorService.java | 18 ++++++++++++++++++ 4 files changed, 45 insertions(+) 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..174e7df 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,8 @@ 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", "전공 전체 조회 완료."), // 내가 추가한 코드 TOKEN_PROCESS_SUCCESS(HttpStatus.OK, "TOKEN_2001", "코인(토큰) 사용이 완료되었습니다."); 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/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..7526d0b 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,7 @@ 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.repository.MajorBookmarkRepository; import hackerthon.likelion13th.canfly.search.repository.MajorRepository; import hackerthon.likelion13th.canfly.university.repository.UniversityRepository; @@ -13,6 +14,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import java.util.List; + @Slf4j @Service @RequiredArgsConstructor @@ -51,4 +54,19 @@ 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(); + } } From 288415497b42fc8aafe9f3797e9443bb55678ead Mon Sep 17 00:00:00 2001 From: MinJunKKang Date: Wed, 20 Aug 2025 22:26:52 +0900 Subject: [PATCH 4/5] =?UTF-8?q?=EC=A0=84=EA=B3=B5=20ID=20=EA=B8=B0?= =?UTF-8?q?=EB=B0=98=EC=9C=BC=EB=A1=9C=20=EB=8C=80=ED=95=99=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/MajorMarkController.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) 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); + } } From b7ee440c00ee19dd9ddf3e35ff87123dafb1c8a2 Mon Sep 17 00:00:00 2001 From: MinJunKKang Date: Wed, 20 Aug 2025 22:28:34 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=EC=A0=84=EA=B3=B5=20ID=20=EA=B8=B0?= =?UTF-8?q?=EB=B0=98=EC=9C=BC=EB=A1=9C=20=EB=8C=80=ED=95=99=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0=20(=EA=B5=AC?= =?UTF-8?q?=ED=98=84=EC=9D=84=20=EC=9C=84=ED=95=9C=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4,=20=EC=84=B1=EA=B3=B5=20=EC=BD=94=EB=93=9C,=20DTO,=20?= =?UTF-8?q?=EB=A0=88=ED=8F=AC=EC=A7=80=ED=86=A0=EB=A6=AC=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../likelion13th/canfly/global/api/SuccessCode.java | 2 ++ .../likelion13th/canfly/search/dto/UnivDto.java | 13 +++++++++++++ .../canfly/search/service/MajorService.java | 11 +++++++++++ .../university/repository/UniversityRepository.java | 12 ++++++++++++ 4 files changed, 38 insertions(+) create mode 100644 src/main/java/hackerthon/likelion13th/canfly/search/dto/UnivDto.java 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 174e7df..d0650a1 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/global/api/SuccessCode.java +++ b/src/main/java/hackerthon/likelion13th/canfly/global/api/SuccessCode.java @@ -44,6 +44,8 @@ public enum SuccessCode implements BaseCode { // 성공 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/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/service/MajorService.java b/src/main/java/hackerthon/likelion13th/canfly/search/service/MajorService.java index 7526d0b..6f2f65b 100644 --- a/src/main/java/hackerthon/likelion13th/canfly/search/service/MajorService.java +++ b/src/main/java/hackerthon/likelion13th/canfly/search/service/MajorService.java @@ -6,6 +6,7 @@ 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; @@ -69,4 +70,14 @@ public List getAllMajors() { .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); }