From 5a11bc43de2791d9e1534926821ddfd0567289a2 Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Sat, 24 Jan 2026 23:26:40 +0900 Subject: [PATCH 01/14] =?UTF-8?q?refactor:=20home=5Funiversity=EC=99=80=20?= =?UTF-8?q?university=5Finfo=5Ffor=5Fapply=EA=B0=80=20FK=20=EA=B4=80?= =?UTF-8?q?=EA=B3=84=EB=A5=BC=20=EA=B0=80=EC=A7=80=EB=8F=84=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../university/domain/HostUniversity.java | 5 ----- .../university/domain/UnivApplyInfo.java | 3 +++ ...3__move_home_university_fk_to_univ_apply_info.sql | 12 ++++++++++++ 3 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 src/main/resources/db/migration/V43__move_home_university_fk_to_univ_apply_info.sql diff --git a/src/main/java/com/example/solidconnection/university/domain/HostUniversity.java b/src/main/java/com/example/solidconnection/university/domain/HostUniversity.java index e36c2caa..3d817b45 100644 --- a/src/main/java/com/example/solidconnection/university/domain/HostUniversity.java +++ b/src/main/java/com/example/solidconnection/university/domain/HostUniversity.java @@ -8,9 +8,7 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.FetchType; import jakarta.persistence.ManyToOne; -import jakarta.persistence.Table; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; @@ -58,7 +56,4 @@ public class HostUniversity extends BaseEntity { @ManyToOne private Region region; - - @ManyToOne(fetch = FetchType.LAZY) - private HomeUniversity homeUniversity; } diff --git a/src/main/java/com/example/solidconnection/university/domain/UnivApplyInfo.java b/src/main/java/com/example/solidconnection/university/domain/UnivApplyInfo.java index e4c089c6..a727a74e 100644 --- a/src/main/java/com/example/solidconnection/university/domain/UnivApplyInfo.java +++ b/src/main/java/com/example/solidconnection/university/domain/UnivApplyInfo.java @@ -36,6 +36,9 @@ public class UnivApplyInfo extends BaseEntity { @Column(nullable = false, name = "term_id") private long termId; + @Column(name = "home_university_id") + private Long homeUniversityId; + @Column(nullable = false, length = 100) private String koreanName; diff --git a/src/main/resources/db/migration/V43__move_home_university_fk_to_univ_apply_info.sql b/src/main/resources/db/migration/V43__move_home_university_fk_to_univ_apply_info.sql new file mode 100644 index 00000000..36ba62a9 --- /dev/null +++ b/src/main/resources/db/migration/V43__move_home_university_fk_to_univ_apply_info.sql @@ -0,0 +1,12 @@ +ALTER TABLE host_university + DROP FOREIGN KEY fk_host_university_home_university; + +ALTER TABLE host_university + DROP COLUMN home_university_id; + +ALTER TABLE university_info_for_apply + ADD COLUMN home_university_id BIGINT NULL; + +ALTER TABLE university_info_for_apply + ADD CONSTRAINT fk_university_info_for_apply_home_university + FOREIGN KEY (home_university_id) REFERENCES home_university (id) ON DELETE NO ACTION; From ff30af83ff440ae185b0cc28a8852269896bf426 Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Sat, 24 Jan 2026 23:29:17 +0900 Subject: [PATCH 02/14] =?UTF-8?q?chore:=20FK=20=EB=B3=80=EA=B2=BD=EC=97=90?= =?UTF-8?q?=20=EB=94=B0=EB=A5=B8=20=EB=AA=A9=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/data.sql | 38 ++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 0f46eba1..ce4fca9c 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -50,100 +50,100 @@ VALUES ('test@test.email', 'yonso', 'https://github.com/nayonsoso.png', INSERT INTO home_university (id, name) VALUES (1, '인하대학교'); -INSERT INTO host_university(id, home_university_id, country_code, region_code, english_name, format_name, korean_name, +INSERT INTO host_university(id, country_code, region_code, english_name, format_name, korean_name, accommodation_url, english_course_url, homepage_url, details_for_local, logo_image_url, background_image_url) -VALUES (1, 1, 'US', 'AMERICAS', 'University of Guam', 'university_of_guam', '괌대학', +VALUES (1, 'US', 'AMERICAS', 'University of Guam', 'university_of_guam', '괌대학', 'https://www.uog.edu/life-at-uog/residence-halls/', 'https://www.uog.edu/admissions/course-schedule', 'https://www.uog.edu/admissions/international-students', NULL, 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/university_of_guam/logo.png', 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/university_of_guam/1.png'), - (2, 1, 'US', 'AMERICAS', 'University of Nevada, Las Vegas', 'university_of_nevada_las_vegas', '네바다주립대학 라스베이거스', + (2, 'US', 'AMERICAS', 'University of Nevada, Las Vegas', 'university_of_nevada_las_vegas', '네바다주립대학 라스베이거스', 'https://www.unlv.edu/housing', 'https://www.unlv.edu/engineering/academic-programs', 'https://www.unlv.edu/engineering/eip', NULL, 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/university_of_nevada_las_vegas/logo.png', 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/university_of_nevada_las_vegas/1.png'), - (3, 1, 'CA', 'AMERICAS', 'Memorial University of Newfoundland St. John''s', + (3, 'CA', 'AMERICAS', 'Memorial University of Newfoundland St. John''s', 'memorial_university_of_newfoundland_st_johns', '메모리얼 대학 세인트존스', 'https://www.mun.ca/residences/', 'https://www.mun.ca/regoff/registration-and-final-exams/course-offerings/', 'https://mun.ca/goabroad/visiting-students-inbound/', NULL, 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/memorial_university_of_newfoundland_st_johns/logo.png', 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/memorial_university_of_newfoundland_st_johns/1.png'), - (4, 1, 'AU', 'AMERICAS', 'University of Southern Queensland', 'university_of_southern_queensland', '서던퀸스랜드대학', + (4, 'AU', 'AMERICAS', 'University of Southern Queensland', 'university_of_southern_queensland', '서던퀸스랜드대학', 'https://www.unisq.edu.au/current-students/support/accommodation', 'https://www.unisq.edu.au/course/specification/current/', 'https://www.unisq.edu.au/international/partnerships/study-abroad-exchange', NULL, 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/university_of_southern_queensland/logo.png', 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/university_of_southern_queensland/1.png'), - (5, 1, 'AU', 'AMERICAS', 'University of Sydney', 'university_of_sydney', '시드니대학', + (5, 'AU', 'AMERICAS', 'University of Sydney', 'university_of_sydney', '시드니대학', 'https://www.sydney.edu.au/study/accommodation.html', 'www.sydney.edu.au/sydney-abroad-units', 'https://www.sydney.edu.au/', NULL, 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/university_of_sydney/logo.png', 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/university_of_sydney/1.png'), - (6, 1, 'AU', 'AMERICAS', 'Curtin University', 'curtin_university', '커틴대학', + (6, 'AU', 'AMERICAS', 'Curtin University', 'curtin_university', '커틴대학', 'https://www.curtin.edu.au/study/campus-life/accommodation/#perth', 'https://handbook.curtin.edu.au/', 'https://www.curtin.edu.au/', NULL, 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/curtin_university/logo.png', 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/curtin_university/1.png'), - (7, 1, 'DK', 'EUROPE', 'University of Southern Denmark', 'university_of_southern_denmark', '서던덴마크대학교', + (7, 'DK', 'EUROPE', 'University of Southern Denmark', 'university_of_southern_denmark', '서던덴마크대학교', 'https://www.sdu.dk/en/uddannelse/information_for_international_students/studenthousing', 'https://www.sdu.dk/en/uddannelse/exchange_programmes', 'https://www.sdu.dk/en', NULL, 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/university_of_southern_denmark/logo.png', 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/university_of_southern_denmark/1.png'), - (8, 1, 'DK', 'EUROPE', 'IT University of Copenhagen', 'it_university_of_copenhagen', '코펜하겐 IT대학', + (8, 'DK', 'EUROPE', 'IT University of Copenhagen', 'it_university_of_copenhagen', '코펜하겐 IT대학', 'https://en.itu.dk/Programmes/Student-Life/Practical-information-for-international-students', 'https://en.itu.dk/Programmes/Exchange-students/Become-an-exchange-student-at-ITU', 'https://en.itu.dk/programmes/exchange-students/become-an-exchange-student-at-itu', NULL, 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/it_university_of_copenhagen/logo.png', 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/it_university_of_copenhagen/1.png'), - (9, 1, 'DE', 'EUROPE', 'Neu-Ulm University of Applied Sciences', 'neu-ulm_university_of_applied_sciences', + (9, 'DE', 'EUROPE', 'Neu-Ulm University of Applied Sciences', 'neu-ulm_university_of_applied_sciences', '노이울름 대학', 'https://www.hnu.de/fileadmin/user_upload/5_Internationales/International_Incomings/Bewerbung/Housing_Broschure.pdf', 'https://www.hnu.de/en/international/international-exchange-students/courses-taught-in-english', 'https://www.hnu.de/en/international', NULL, 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/neu-ulm_university_of_applied_sciences/logo.png', 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/neu-ulm_university_of_applied_sciences/1.png'), - (10, 1, 'GB', 'EUROPE', 'University of Hull', 'university_of_hull', '헐대학', + (10, 'GB', 'EUROPE', 'University of Hull', 'university_of_hull', '헐대학', 'https://www.hull.ac.uk/Choose-Hull/Student-life/Accommodation/accommodation.aspx', 'https://universityofhull.app.box.com/s/mpvulz3yz0uijdt68rybce19nek0d8eh', 'https://www.hull.ac.uk/choose-hull/study-at-hull/need-to-know/key-dates', NULL, 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/university_of_hull/logo.png', 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/university_of_hull/1.png'), - (11, 1, 'AT', 'EUROPE', 'University of Graz', 'university_of_graz', '그라츠 대학', + (11, 'AT', 'EUROPE', 'University of Graz', 'university_of_graz', '그라츠 대학', 'https://orientation.uni-graz.at/de/planning-the-arrival/accommodation/', 'https://static.uni-graz.at/fileadmin/veranstaltungen/orientation/documents/incstud_application-courses.pdf', 'https://www.uni-graz.at/en/', NULL, 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/university_of_graz/logo.png', 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/university_of_graz/1.png'), - (12, 1, 'AT', 'EUROPE', 'Graz University of Technology', 'graz_university_of_technology', '그라츠공과대학', + (12, 'AT', 'EUROPE', 'Graz University of Technology', 'graz_university_of_technology', '그라츠공과대학', 'https://www.tugraz.at/en/studying-and-teaching/studying-internationally/incoming-students-exchange-at-tu-graz/your-stay-at-tu-graz/preparation#c75033', 'https://tugraz.at/go/search-courses', 'https://www.tugraz.at/en/home', NULL, 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/graz_university_of_technology/logo.png', 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/graz_university_of_technology/1.png'), - (13, 1, 'AT', 'EUROPE', 'Catholic Private University Linz', 'catholic_private_university_linz', '린츠 카톨릭 대학교', NULL, + (13, 'AT', 'EUROPE', 'Catholic Private University Linz', 'catholic_private_university_linz', '린츠 카톨릭 대학교', NULL, 'https://ku-linz.at/en/ku_international/incomings/kulis', 'https://ku-linz.at/en', NULL, 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/catholic_private_university_linz/logo.png', 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/catholic_private_university_linz/1.png'), - (14, 1, 'AT', 'EUROPE', 'University of Applied Sciences Technikum Wien', + (14, 'AT', 'EUROPE', 'University of Applied Sciences Technikum Wien', 'university_of_applied_sciences_technikum_wien', '빈 공과대학교', NULL, 'https://www.technikum-wien.at/en/international/student-mobility/', 'https://www.technikum-wien.at/international/studierendenmobilitaet-2/', NULL, 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/university_of_applied_sciences_technikum_wien/logo.png', 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/university_of_applied_sciences_technikum_wien/1.png'), - (15, 1, 'FR', 'EUROPE', 'IPSA', 'ipsa', 'IPSA', 'https://www.ipsa.fr/en/student-life/pratical-information/', NULL, + (15, 'FR', 'EUROPE', 'IPSA', 'ipsa', 'IPSA', 'https://www.ipsa.fr/en/student-life/pratical-information/', NULL, 'https://www.ipsa.fr/en/engineering-school/aeronautical-space', NULL, 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/ipsa/logo.png', 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/ipsa/1.png'), - (16, 1, 'JP', 'ASIA', 'Meiji University', 'meiji_university', '메이지대학', + (16, 'JP', 'ASIA', 'Meiji University', 'meiji_university', '메이지대학', 'https://www.meiji.ac.jp/cip/english/admissions/co7mm90000000461-att/co7mm900000004fa.pdf', NULL, 'https://www.meiji.ac.jp/cip/english/admissions/co7mm90000000461-att/co7mm900000004fa.pdf', NULL, 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/meiji_university/logo.png', 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/meiji_university/1.png'), - (17, 1, 'JP', 'ASIA', 'BAIKA Women''s University', 'baika_womens_university', '바이카여자대학', + (17, 'JP', 'ASIA', 'BAIKA Women''s University', 'baika_womens_university', '바이카여자대학', 'https://dormy-ac.com/page/baika/', NULL, 'https://www.baika.ac.jp/english/', NULL, 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/baika_womens_university/logo.png', 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/baika_womens_university/1.png'), - (18, 1, 'JP', 'ASIA', 'Bunkyo Gakuin University', 'bunkyo_gakuin_university', '분쿄가쿠인대학', NULL, NULL, + (18, 'JP', 'ASIA', 'Bunkyo Gakuin University', 'bunkyo_gakuin_university', '분쿄가쿠인대학', NULL, NULL, 'https://www.bgu.ac.jp/', NULL, 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/bunkyo_gakuin_university/logo.png', 'https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/bunkyo_gakuin_university/1.png'); From c38ae47675bec9dbed1b6ec57b33d72e03f89685 Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Sat, 31 Jan 2026 16:13:30 +0900 Subject: [PATCH 03/14] =?UTF-8?q?feat:=20=ED=8C=8C=EA=B2=AC=20=EB=8C=80?= =?UTF-8?q?=ED=95=99=20CRUD=20=EA=B4=80=EB=A0=A8=20ErrorCode=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - HOST_UNIVERSITY_HAS_REFERENCES : 파견 대학 삭제 시 해당 대학을 참조하는 UnivApplyInfo가 존재하는 경우 --- .../com/example/solidconnection/common/exception/ErrorCode.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/example/solidconnection/common/exception/ErrorCode.java b/src/main/java/com/example/solidconnection/common/exception/ErrorCode.java index d00ce52b..f0e06366 100644 --- a/src/main/java/com/example/solidconnection/common/exception/ErrorCode.java +++ b/src/main/java/com/example/solidconnection/common/exception/ErrorCode.java @@ -41,6 +41,8 @@ public enum ErrorCode { REGION_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "지역을 찾을 수 없습니다."), REGION_NOT_FOUND_BY_KOREAN_NAME(HttpStatus.NOT_FOUND.value(), "이름에 해당하는 지역을 찾을 수 없습니다."), REGION_ALREADY_EXISTS(HttpStatus.CONFLICT.value(), "이미 존재하는 지역입니다."), + HOST_UNIVERSITY_ALREADY_EXISTS(HttpStatus.CONFLICT.value(), "이미 존재하는 파견 대학입니다."), + HOST_UNIVERSITY_HAS_REFERENCES(HttpStatus.CONFLICT.value(), "해당 파견 대학을 참조하는 대학 지원 정보가 존재합니다."), COUNTRY_NOT_FOUND_BY_KOREAN_NAME(HttpStatus.NOT_FOUND.value(), "이름에 해당하는 국가를 찾을 수 없습니다."), GPA_SCORE_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "존재하지 않는 학점입니다."), LANGUAGE_TEST_SCORE_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "존재하지 않는 어학성적입니다."), From 9d206944498561c154e63f669ea335c30cc44d9c Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Sat, 31 Jan 2026 16:16:42 +0900 Subject: [PATCH 04/14] =?UTF-8?q?feat:=20=ED=8C=8C=EA=B2=AC=20=EB=8C=80?= =?UTF-8?q?=ED=95=99=20=EA=B4=80=EB=A0=A8=20=EC=A0=95=EB=B3=B4=EB=A5=BC=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../university/domain/HostUniversity.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/main/java/com/example/solidconnection/university/domain/HostUniversity.java b/src/main/java/com/example/solidconnection/university/domain/HostUniversity.java index 3d817b45..7ae461f6 100644 --- a/src/main/java/com/example/solidconnection/university/domain/HostUniversity.java +++ b/src/main/java/com/example/solidconnection/university/domain/HostUniversity.java @@ -56,4 +56,30 @@ public class HostUniversity extends BaseEntity { @ManyToOne private Region region; + + public void update( + String koreanName, + String englishName, + String formatName, + String homepageUrl, + String englishCourseUrl, + String accommodationUrl, + String logoImageUrl, + String backgroundImageUrl, + String detailsForLocal, + Country country, + Region region + ) { + this.koreanName = koreanName; + this.englishName = englishName; + this.formatName = formatName; + this.homepageUrl = homepageUrl; + this.englishCourseUrl = englishCourseUrl; + this.accommodationUrl = accommodationUrl; + this.logoImageUrl = logoImageUrl; + this.backgroundImageUrl = backgroundImageUrl; + this.detailsForLocal = detailsForLocal; + this.country = country; + this.region = region; + } } From e81b2a2eea1dcbb428827cf871491e9454baac90 Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Sat, 31 Jan 2026 16:18:44 +0900 Subject: [PATCH 05/14] =?UTF-8?q?feat:=20=EC=A1=B0=ED=9A=8C=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20Repository=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../university/repository/HostUniversityRepository.java | 3 +++ .../university/repository/UnivApplyInfoRepository.java | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/main/java/com/example/solidconnection/university/repository/HostUniversityRepository.java b/src/main/java/com/example/solidconnection/university/repository/HostUniversityRepository.java index 09a2ea39..97a9ef22 100644 --- a/src/main/java/com/example/solidconnection/university/repository/HostUniversityRepository.java +++ b/src/main/java/com/example/solidconnection/university/repository/HostUniversityRepository.java @@ -4,6 +4,7 @@ import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.university.domain.HostUniversity; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; public interface HostUniversityRepository extends JpaRepository { @@ -12,4 +13,6 @@ default HostUniversity getHostUniversityById(Long id) { return findById(id) .orElseThrow(() -> new CustomException(UNIVERSITY_NOT_FOUND)); } + + Optional findByKoreanName(String koreanName); } diff --git a/src/main/java/com/example/solidconnection/university/repository/UnivApplyInfoRepository.java b/src/main/java/com/example/solidconnection/university/repository/UnivApplyInfoRepository.java index 1cc25ee3..e0b71f8a 100644 --- a/src/main/java/com/example/solidconnection/university/repository/UnivApplyInfoRepository.java +++ b/src/main/java/com/example/solidconnection/university/repository/UnivApplyInfoRepository.java @@ -66,4 +66,6 @@ default UnivApplyInfo getUnivApplyInfoById(Long id) { WHERE uai.id IN :ids """) List findAllByIds(@Param("ids") List ids); + + boolean existsByUniversityId(Long universityId); } From 1bedd3d7d1f21abe61dfe1e134d81dc8f2f9bcb8 Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Sat, 31 Jan 2026 16:28:15 +0900 Subject: [PATCH 06/14] =?UTF-8?q?feat:=20=ED=8C=8C=EA=B2=AC=20=EB=8C=80?= =?UTF-8?q?=ED=95=99=20=EA=B2=80=EC=83=89=20=EA=B4=80=EB=A0=A8=20QueryDSL?= =?UTF-8?q?=EB=A1=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/HostUniversityRepository.java | 3 +- .../HostUniversityFilterRepository.java | 15 ++++ .../HostUniversityFilterRepositoryImpl.java | 88 +++++++++++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/example/solidconnection/university/repository/custom/HostUniversityFilterRepository.java create mode 100644 src/main/java/com/example/solidconnection/university/repository/custom/HostUniversityFilterRepositoryImpl.java diff --git a/src/main/java/com/example/solidconnection/university/repository/HostUniversityRepository.java b/src/main/java/com/example/solidconnection/university/repository/HostUniversityRepository.java index 97a9ef22..3fa80629 100644 --- a/src/main/java/com/example/solidconnection/university/repository/HostUniversityRepository.java +++ b/src/main/java/com/example/solidconnection/university/repository/HostUniversityRepository.java @@ -4,10 +4,11 @@ import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.university.domain.HostUniversity; +import com.example.solidconnection.university.repository.custom.HostUniversityFilterRepository; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; -public interface HostUniversityRepository extends JpaRepository { +public interface HostUniversityRepository extends JpaRepository, HostUniversityFilterRepository { default HostUniversity getHostUniversityById(Long id) { return findById(id) diff --git a/src/main/java/com/example/solidconnection/university/repository/custom/HostUniversityFilterRepository.java b/src/main/java/com/example/solidconnection/university/repository/custom/HostUniversityFilterRepository.java new file mode 100644 index 00000000..1e6cbc01 --- /dev/null +++ b/src/main/java/com/example/solidconnection/university/repository/custom/HostUniversityFilterRepository.java @@ -0,0 +1,15 @@ +package com.example.solidconnection.university.repository.custom; + +import com.example.solidconnection.university.domain.HostUniversity; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +public interface HostUniversityFilterRepository { + + Page findAllBySearchCondition( + String keyword, + String countryCode, + String regionCode, + Pageable pageable + ); +} diff --git a/src/main/java/com/example/solidconnection/university/repository/custom/HostUniversityFilterRepositoryImpl.java b/src/main/java/com/example/solidconnection/university/repository/custom/HostUniversityFilterRepositoryImpl.java new file mode 100644 index 00000000..e53ff4f2 --- /dev/null +++ b/src/main/java/com/example/solidconnection/university/repository/custom/HostUniversityFilterRepositoryImpl.java @@ -0,0 +1,88 @@ +package com.example.solidconnection.university.repository.custom; + +import com.example.solidconnection.location.country.domain.QCountry; +import com.example.solidconnection.location.region.domain.QRegion; +import com.example.solidconnection.university.domain.HostUniversity; +import com.example.solidconnection.university.domain.QHostUniversity; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQuery; +import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.persistence.EntityManager; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.support.PageableExecutionUtils; +import org.springframework.stereotype.Repository; + +@Repository +public class HostUniversityFilterRepositoryImpl implements HostUniversityFilterRepository { + + private final JPAQueryFactory queryFactory; + + @Autowired + public HostUniversityFilterRepositoryImpl(EntityManager em) { + this.queryFactory = new JPAQueryFactory(em); + } + + @Override + public Page findAllBySearchCondition( + String keyword, + String countryCode, + String regionCode, + Pageable pageable + ) { + QHostUniversity hostUniversity = QHostUniversity.hostUniversity; + QCountry country = QCountry.country; + QRegion region = QRegion.region; + + List content = queryFactory + .selectFrom(hostUniversity) + .leftJoin(hostUniversity.country, country).fetchJoin() + .leftJoin(hostUniversity.region, region).fetchJoin() + .where( + keywordContains(hostUniversity, keyword), + countryCodeEq(country, countryCode), + regionCodeEq(region, regionCode) + ) + .orderBy(hostUniversity.id.asc()) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); + + JPAQuery countQuery = queryFactory + .select(hostUniversity.count()) + .from(hostUniversity) + .leftJoin(hostUniversity.country, country) + .leftJoin(hostUniversity.region, region) + .where( + keywordContains(hostUniversity, keyword), + countryCodeEq(country, countryCode), + regionCodeEq(region, regionCode) + ); + + return PageableExecutionUtils.getPage(content, pageable, countQuery::fetchOne); + } + + private BooleanExpression keywordContains(QHostUniversity hostUniversity, String keyword) { + if (keyword == null || keyword.isBlank()) { + return null; + } + return hostUniversity.koreanName.contains(keyword) + .or(hostUniversity.englishName.containsIgnoreCase(keyword)); + } + + private BooleanExpression countryCodeEq(QCountry country, String countryCode) { + if (countryCode == null || countryCode.isBlank()) { + return null; + } + return country.code.eq(countryCode); + } + + private BooleanExpression regionCodeEq(QRegion region, String regionCode) { + if (regionCode == null || regionCode.isBlank()) { + return null; + } + return region.code.eq(regionCode); + } +} From 743791edbdb64adf95675acd6240d88c1c969f16 Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Sat, 31 Jan 2026 16:40:19 +0900 Subject: [PATCH 07/14] =?UTF-8?q?feat:=20=EC=96=B4=EB=93=9C=EB=AF=BC=20?= =?UTF-8?q?=ED=8C=8C=EA=B2=AC=20=EB=8C=80=ED=95=99=20CRUD=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20DTO=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/AdminHostUniversityCreateRequest.java | 46 +++++++++++++++++++ .../AdminHostUniversityDetailResponse.java | 40 ++++++++++++++++ .../dto/AdminHostUniversityListResponse.java | 33 +++++++++++++ .../dto/AdminHostUniversityResponse.java | 30 ++++++++++++ .../AdminHostUniversitySearchCondition.java | 9 ++++ .../dto/AdminHostUniversityUpdateRequest.java | 46 +++++++++++++++++++ 6 files changed, 204 insertions(+) create mode 100644 src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityCreateRequest.java create mode 100644 src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityDetailResponse.java create mode 100644 src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityListResponse.java create mode 100644 src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityResponse.java create mode 100644 src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversitySearchCondition.java create mode 100644 src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityUpdateRequest.java diff --git a/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityCreateRequest.java b/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityCreateRequest.java new file mode 100644 index 00000000..6b77061b --- /dev/null +++ b/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityCreateRequest.java @@ -0,0 +1,46 @@ +package com.example.solidconnection.admin.university.dto; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +public record AdminHostUniversityCreateRequest( + @NotBlank(message = "한글 대학명은 필수입니다") + @Size(max = 100, message = "한글 대학명은 100자 이하여야 합니다") + String koreanName, + + @NotBlank(message = "영문 대학명은 필수입니다") + @Size(max = 100, message = "영문 대학명은 100자 이하여야 합니다") + String englishName, + + @NotBlank(message = "표시 대학명은 필수입니다") + @Size(max = 100, message = "표시 대학명은 100자 이하여야 합니다") + String formatName, + + @Size(max = 500, message = "홈페이지 URL은 500자 이하여야 합니다") + String homepageUrl, + + @Size(max = 500, message = "영어 강좌 URL은 500자 이하여야 합니다") + String englishCourseUrl, + + @Size(max = 500, message = "숙소 URL은 500자 이하여야 합니다") + String accommodationUrl, + + @NotBlank(message = "로고 이미지 URL은 필수입니다") + @Size(max = 500, message = "로고 이미지 URL은 500자 이하여야 합니다") + String logoImageUrl, + + @NotBlank(message = "배경 이미지 URL은 필수입니다") + @Size(max = 500, message = "배경 이미지 URL은 500자 이하여야 합니다") + String backgroundImageUrl, + + @Size(max = 1000, message = "상세 정보는 1000자 이하여야 합니다") + String detailsForLocal, + + @NotBlank(message = "국가 코드는 필수입니다") + String countryCode, + + @NotBlank(message = "지역 코드는 필수입니다") + String regionCode +) { + +} diff --git a/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityDetailResponse.java b/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityDetailResponse.java new file mode 100644 index 00000000..1630f506 --- /dev/null +++ b/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityDetailResponse.java @@ -0,0 +1,40 @@ +package com.example.solidconnection.admin.university.dto; + +import com.example.solidconnection.university.domain.HostUniversity; + +public record AdminHostUniversityDetailResponse( + Long id, + String koreanName, + String englishName, + String formatName, + String homepageUrl, + String englishCourseUrl, + String accommodationUrl, + String logoImageUrl, + String backgroundImageUrl, + String detailsForLocal, + String countryCode, + String countryKoreanName, + String regionCode, + String regionKoreanName +) { + + public static AdminHostUniversityDetailResponse from(HostUniversity hostUniversity) { + return new AdminHostUniversityDetailResponse( + hostUniversity.getId(), + hostUniversity.getKoreanName(), + hostUniversity.getEnglishName(), + hostUniversity.getFormatName(), + hostUniversity.getHomepageUrl(), + hostUniversity.getEnglishCourseUrl(), + hostUniversity.getAccommodationUrl(), + hostUniversity.getLogoImageUrl(), + hostUniversity.getBackgroundImageUrl(), + hostUniversity.getDetailsForLocal(), + hostUniversity.getCountry() != null ? hostUniversity.getCountry().getCode() : null, + hostUniversity.getCountry() != null ? hostUniversity.getCountry().getKoreanName() : null, + hostUniversity.getRegion() != null ? hostUniversity.getRegion().getCode() : null, + hostUniversity.getRegion() != null ? hostUniversity.getRegion().getKoreanName() : null + ); + } +} diff --git a/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityListResponse.java b/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityListResponse.java new file mode 100644 index 00000000..84968859 --- /dev/null +++ b/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityListResponse.java @@ -0,0 +1,33 @@ +package com.example.solidconnection.admin.university.dto; + +import com.example.solidconnection.university.domain.HostUniversity; +import java.util.List; +import org.springframework.data.domain.Page; + +public record AdminHostUniversityListResponse( + List hostUniversities, + int page, + int size, + long totalElements, + int totalPages, + boolean hasNext, + boolean hasPrevious +) { + + public static AdminHostUniversityListResponse from(Page hostUniversityPage) { + List hostUniversities = hostUniversityPage.getContent() + .stream() + .map(AdminHostUniversityResponse::from) + .toList(); + + return new AdminHostUniversityListResponse( + hostUniversities, + hostUniversityPage.getNumber(), + hostUniversityPage.getSize(), + hostUniversityPage.getTotalElements(), + hostUniversityPage.getTotalPages(), + hostUniversityPage.hasNext(), + hostUniversityPage.hasPrevious() + ); + } +} diff --git a/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityResponse.java b/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityResponse.java new file mode 100644 index 00000000..12975c0a --- /dev/null +++ b/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityResponse.java @@ -0,0 +1,30 @@ +package com.example.solidconnection.admin.university.dto; + +import com.example.solidconnection.university.domain.HostUniversity; + +public record AdminHostUniversityResponse( + Long id, + String koreanName, + String englishName, + String formatName, + String logoImageUrl, + String countryCode, + String countryKoreanName, + String regionCode, + String regionKoreanName +) { + + public static AdminHostUniversityResponse from(HostUniversity hostUniversity) { + return new AdminHostUniversityResponse( + hostUniversity.getId(), + hostUniversity.getKoreanName(), + hostUniversity.getEnglishName(), + hostUniversity.getFormatName(), + hostUniversity.getLogoImageUrl(), + hostUniversity.getCountry() != null ? hostUniversity.getCountry().getCode() : null, + hostUniversity.getCountry() != null ? hostUniversity.getCountry().getKoreanName() : null, + hostUniversity.getRegion() != null ? hostUniversity.getRegion().getCode() : null, + hostUniversity.getRegion() != null ? hostUniversity.getRegion().getKoreanName() : null + ); + } +} diff --git a/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversitySearchCondition.java b/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversitySearchCondition.java new file mode 100644 index 00000000..cbf13ec5 --- /dev/null +++ b/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversitySearchCondition.java @@ -0,0 +1,9 @@ +package com.example.solidconnection.admin.university.dto; + +public record AdminHostUniversitySearchCondition( + String keyword, + String countryCode, + String regionCode +) { + +} diff --git a/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityUpdateRequest.java b/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityUpdateRequest.java new file mode 100644 index 00000000..cb2e64a7 --- /dev/null +++ b/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityUpdateRequest.java @@ -0,0 +1,46 @@ +package com.example.solidconnection.admin.university.dto; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +public record AdminHostUniversityUpdateRequest( + @NotBlank(message = "한글 대학명은 필수입니다") + @Size(max = 100, message = "한글 대학명은 100자 이하여야 합니다") + String koreanName, + + @NotBlank(message = "영문 대학명은 필수입니다") + @Size(max = 100, message = "영문 대학명은 100자 이하여야 합니다") + String englishName, + + @NotBlank(message = "표시 대학명은 필수입니다") + @Size(max = 100, message = "표시 대학명은 100자 이하여야 합니다") + String formatName, + + @Size(max = 500, message = "홈페이지 URL은 500자 이하여야 합니다") + String homepageUrl, + + @Size(max = 500, message = "영어 강좌 URL은 500자 이하여야 합니다") + String englishCourseUrl, + + @Size(max = 500, message = "숙소 URL은 500자 이하여야 합니다") + String accommodationUrl, + + @NotBlank(message = "로고 이미지 URL은 필수입니다") + @Size(max = 500, message = "로고 이미지 URL은 500자 이하여야 합니다") + String logoImageUrl, + + @NotBlank(message = "배경 이미지 URL은 필수입니다") + @Size(max = 500, message = "배경 이미지 URL은 500자 이하여야 합니다") + String backgroundImageUrl, + + @Size(max = 1000, message = "상세 정보는 1000자 이하여야 합니다") + String detailsForLocal, + + @NotBlank(message = "국가 코드는 필수입니다") + String countryCode, + + @NotBlank(message = "지역 코드는 필수입니다") + String regionCode +) { + +} From df5ab299c117f5f5eeb3a22abaaa56b6c3eee396 Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Sat, 31 Jan 2026 16:47:22 +0900 Subject: [PATCH 08/14] =?UTF-8?q?feat:=20country=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20ErrorCode=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/solidconnection/common/exception/ErrorCode.java | 1 + .../location/country/repository/CountryRepository.java | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/main/java/com/example/solidconnection/common/exception/ErrorCode.java b/src/main/java/com/example/solidconnection/common/exception/ErrorCode.java index f0e06366..83aeaf2a 100644 --- a/src/main/java/com/example/solidconnection/common/exception/ErrorCode.java +++ b/src/main/java/com/example/solidconnection/common/exception/ErrorCode.java @@ -43,6 +43,7 @@ public enum ErrorCode { REGION_ALREADY_EXISTS(HttpStatus.CONFLICT.value(), "이미 존재하는 지역입니다."), HOST_UNIVERSITY_ALREADY_EXISTS(HttpStatus.CONFLICT.value(), "이미 존재하는 파견 대학입니다."), HOST_UNIVERSITY_HAS_REFERENCES(HttpStatus.CONFLICT.value(), "해당 파견 대학을 참조하는 대학 지원 정보가 존재합니다."), + COUNTRY_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "국가를 찾을 수 없습니다."), COUNTRY_NOT_FOUND_BY_KOREAN_NAME(HttpStatus.NOT_FOUND.value(), "이름에 해당하는 국가를 찾을 수 없습니다."), GPA_SCORE_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "존재하지 않는 학점입니다."), LANGUAGE_TEST_SCORE_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "존재하지 않는 어학성적입니다."), diff --git a/src/main/java/com/example/solidconnection/location/country/repository/CountryRepository.java b/src/main/java/com/example/solidconnection/location/country/repository/CountryRepository.java index 8b997a2d..7aaf8ff5 100644 --- a/src/main/java/com/example/solidconnection/location/country/repository/CountryRepository.java +++ b/src/main/java/com/example/solidconnection/location/country/repository/CountryRepository.java @@ -2,12 +2,15 @@ import com.example.solidconnection.location.country.domain.Country; import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; public interface CountryRepository extends JpaRepository { + Optional findByCode(String code); + List findAllByKoreanNameIn(List koreanNames); @Query(""" From 5033c9851cabbc8abce5d8105926f03fc345be57 Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Sat, 31 Jan 2026 16:51:51 +0900 Subject: [PATCH 09/14] =?UTF-8?q?feat:=20=EC=96=B4=EB=93=9C=EB=AF=BC=20?= =?UTF-8?q?=ED=8C=8C=EA=B2=AC=20=EB=8C=80=ED=95=99=20CRUD=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/AdminHostUniversityService.java | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 src/main/java/com/example/solidconnection/admin/university/service/AdminHostUniversityService.java diff --git a/src/main/java/com/example/solidconnection/admin/university/service/AdminHostUniversityService.java b/src/main/java/com/example/solidconnection/admin/university/service/AdminHostUniversityService.java new file mode 100644 index 00000000..8798a86a --- /dev/null +++ b/src/main/java/com/example/solidconnection/admin/university/service/AdminHostUniversityService.java @@ -0,0 +1,152 @@ +package com.example.solidconnection.admin.university.service; + +import static com.example.solidconnection.common.exception.ErrorCode.COUNTRY_NOT_FOUND; +import static com.example.solidconnection.common.exception.ErrorCode.HOST_UNIVERSITY_ALREADY_EXISTS; +import static com.example.solidconnection.common.exception.ErrorCode.HOST_UNIVERSITY_HAS_REFERENCES; +import static com.example.solidconnection.common.exception.ErrorCode.REGION_NOT_FOUND; +import static com.example.solidconnection.common.exception.ErrorCode.UNIVERSITY_NOT_FOUND; + +import com.example.solidconnection.admin.university.dto.AdminHostUniversityCreateRequest; +import com.example.solidconnection.admin.university.dto.AdminHostUniversityDetailResponse; +import com.example.solidconnection.admin.university.dto.AdminHostUniversityListResponse; +import com.example.solidconnection.admin.university.dto.AdminHostUniversitySearchCondition; +import com.example.solidconnection.admin.university.dto.AdminHostUniversityUpdateRequest; +import com.example.solidconnection.common.exception.CustomException; +import com.example.solidconnection.location.country.domain.Country; +import com.example.solidconnection.location.country.repository.CountryRepository; +import com.example.solidconnection.location.region.domain.Region; +import com.example.solidconnection.location.region.repository.RegionRepository; +import com.example.solidconnection.university.domain.HostUniversity; +import com.example.solidconnection.university.repository.HostUniversityRepository; +import com.example.solidconnection.university.repository.UnivApplyInfoRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class AdminHostUniversityService { + + private final HostUniversityRepository hostUniversityRepository; + private final CountryRepository countryRepository; + private final RegionRepository regionRepository; + private final UnivApplyInfoRepository univApplyInfoRepository; + + @Transactional(readOnly = true) + public AdminHostUniversityListResponse getHostUniversities( + AdminHostUniversitySearchCondition condition, + Pageable pageable + ) { + Page hostUniversityPage = hostUniversityRepository.findAllBySearchCondition( + condition.keyword(), + condition.countryCode(), + condition.regionCode(), + pageable + ); + return AdminHostUniversityListResponse.from(hostUniversityPage); + } + + @Transactional(readOnly = true) + public AdminHostUniversityDetailResponse getHostUniversity(Long id) { + HostUniversity hostUniversity = hostUniversityRepository.findById(id) + .orElseThrow(() -> new CustomException(UNIVERSITY_NOT_FOUND)); + return AdminHostUniversityDetailResponse.from(hostUniversity); + } + + @Transactional + public AdminHostUniversityDetailResponse createHostUniversity(AdminHostUniversityCreateRequest request) { + validateKoreanNameNotExists(request.koreanName()); + + Country country = findCountryByCode(request.countryCode()); + Region region = findRegionByCode(request.regionCode()); + + HostUniversity hostUniversity = new HostUniversity( + null, + request.koreanName(), + request.englishName(), + request.formatName(), + request.homepageUrl(), + request.englishCourseUrl(), + request.accommodationUrl(), + request.logoImageUrl(), + request.backgroundImageUrl(), + request.detailsForLocal(), + country, + region + ); + + HostUniversity savedHostUniversity = hostUniversityRepository.save(hostUniversity); + return AdminHostUniversityDetailResponse.from(savedHostUniversity); + } + + private void validateKoreanNameNotExists(String koreanName) { + hostUniversityRepository.findByKoreanName(koreanName) + .ifPresent(existingUniversity -> { + throw new CustomException(HOST_UNIVERSITY_ALREADY_EXISTS); + }); + } + + @Transactional + public AdminHostUniversityDetailResponse updateHostUniversity(Long id, AdminHostUniversityUpdateRequest request) { + HostUniversity hostUniversity = hostUniversityRepository.findById(id) + .orElseThrow(() -> new CustomException(UNIVERSITY_NOT_FOUND)); + + validateKoreanNameNotDuplicated(request.koreanName(), id); + + Country country = findCountryByCode(request.countryCode()); + Region region = findRegionByCode(request.regionCode()); + + hostUniversity.update( + request.koreanName(), + request.englishName(), + request.formatName(), + request.homepageUrl(), + request.englishCourseUrl(), + request.accommodationUrl(), + request.logoImageUrl(), + request.backgroundImageUrl(), + request.detailsForLocal(), + country, + region + ); + + return AdminHostUniversityDetailResponse.from(hostUniversity); + } + + private void validateKoreanNameNotDuplicated(String koreanName, Long excludeId) { + hostUniversityRepository.findByKoreanName(koreanName) + .ifPresent(existingUniversity -> { + if (!existingUniversity.getId().equals(excludeId)) { + throw new CustomException(HOST_UNIVERSITY_ALREADY_EXISTS); + } + }); + } + + private Country findCountryByCode(String countryCode) { + return countryRepository.findByCode(countryCode) + .orElseThrow(() -> new CustomException(COUNTRY_NOT_FOUND)); + } + + private Region findRegionByCode(String regionCode) { + return regionRepository.findById(regionCode) + .orElseThrow(() -> new CustomException(REGION_NOT_FOUND)); + } + + @Transactional + public void deleteHostUniversity(Long id) { + HostUniversity hostUniversity = hostUniversityRepository.findById(id) + .orElseThrow(() -> new CustomException(UNIVERSITY_NOT_FOUND)); + + validateNoReferences(id); + + hostUniversityRepository.delete(hostUniversity); + } + + private void validateNoReferences(Long hostUniversityId) { + if (univApplyInfoRepository.existsByUniversityId(hostUniversityId)) { + throw new CustomException(HOST_UNIVERSITY_HAS_REFERENCES); + } + } +} From 9c4ad74e90c920ab5f5828e372da7d4ac3ea468c Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Sat, 31 Jan 2026 16:57:03 +0900 Subject: [PATCH 10/14] =?UTF-8?q?feat:=20=EC=96=B4=EB=93=9C=EB=AF=BC=20?= =?UTF-8?q?=ED=8C=8C=EA=B2=AC=20=EB=8C=80=ED=95=99=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdminHostUniversityController.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/main/java/com/example/solidconnection/admin/university/controller/AdminHostUniversityController.java diff --git a/src/main/java/com/example/solidconnection/admin/university/controller/AdminHostUniversityController.java b/src/main/java/com/example/solidconnection/admin/university/controller/AdminHostUniversityController.java new file mode 100644 index 00000000..e28a9116 --- /dev/null +++ b/src/main/java/com/example/solidconnection/admin/university/controller/AdminHostUniversityController.java @@ -0,0 +1,71 @@ +package com.example.solidconnection.admin.university.controller; + +import com.example.solidconnection.admin.university.dto.AdminHostUniversityCreateRequest; +import com.example.solidconnection.admin.university.dto.AdminHostUniversityDetailResponse; +import com.example.solidconnection.admin.university.dto.AdminHostUniversityListResponse; +import com.example.solidconnection.admin.university.dto.AdminHostUniversitySearchCondition; +import com.example.solidconnection.admin.university.dto.AdminHostUniversityUpdateRequest; +import com.example.solidconnection.admin.university.service.AdminHostUniversityService; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RequiredArgsConstructor +@RequestMapping("/admin/host-universities") +@RestController +public class AdminHostUniversityController { + + private final AdminHostUniversityService adminHostUniversityService; + + @GetMapping + public ResponseEntity getHostUniversities( + AdminHostUniversitySearchCondition condition, + @PageableDefault(size = 20) Pageable pageable + ) { + AdminHostUniversityListResponse response = adminHostUniversityService.getHostUniversities(condition, pageable); + return ResponseEntity.ok(response); + } + + @GetMapping("/{id}") + public ResponseEntity getHostUniversity( + @PathVariable Long id + ) { + AdminHostUniversityDetailResponse response = adminHostUniversityService.getHostUniversity(id); + return ResponseEntity.ok(response); + } + + @PostMapping + public ResponseEntity createHostUniversity( + @Valid @RequestBody AdminHostUniversityCreateRequest request + ) { + AdminHostUniversityDetailResponse response = adminHostUniversityService.createHostUniversity(request); + return ResponseEntity.ok(response); + } + + @PutMapping("/{id}") + public ResponseEntity updateHostUniversity( + @PathVariable Long id, + @Valid @RequestBody AdminHostUniversityUpdateRequest request + ) { + AdminHostUniversityDetailResponse response = adminHostUniversityService.updateHostUniversity(id, request); + return ResponseEntity.ok(response); + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteHostUniversity( + @PathVariable Long id + ) { + adminHostUniversityService.deleteHostUniversity(id); + return ResponseEntity.ok().build(); + } +} From e327a0884cb794f58a8c294a95d16619679c77e2 Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Sat, 31 Jan 2026 17:12:36 +0900 Subject: [PATCH 11/14] =?UTF-8?q?test:=20=EC=96=B4=EB=93=9C=EB=AF=BC=20?= =?UTF-8?q?=ED=8C=8C=EA=B2=AC=20=EB=8C=80=ED=95=99=20=EA=B4=80=EB=A6=AC=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdminHostUniversityServiceTest.java | 400 ++++++++++++++++++ 1 file changed, 400 insertions(+) create mode 100644 src/test/java/com/example/solidconnection/admin/service/AdminHostUniversityServiceTest.java diff --git a/src/test/java/com/example/solidconnection/admin/service/AdminHostUniversityServiceTest.java b/src/test/java/com/example/solidconnection/admin/service/AdminHostUniversityServiceTest.java new file mode 100644 index 00000000..06cfcf15 --- /dev/null +++ b/src/test/java/com/example/solidconnection/admin/service/AdminHostUniversityServiceTest.java @@ -0,0 +1,400 @@ +package com.example.solidconnection.admin.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +import com.example.solidconnection.admin.university.dto.AdminHostUniversityCreateRequest; +import com.example.solidconnection.admin.university.dto.AdminHostUniversityDetailResponse; +import com.example.solidconnection.admin.university.dto.AdminHostUniversityListResponse; +import com.example.solidconnection.admin.university.dto.AdminHostUniversitySearchCondition; +import com.example.solidconnection.admin.university.dto.AdminHostUniversityUpdateRequest; +import com.example.solidconnection.admin.university.service.AdminHostUniversityService; +import com.example.solidconnection.common.exception.CustomException; +import com.example.solidconnection.common.exception.ErrorCode; +import com.example.solidconnection.location.country.domain.Country; +import com.example.solidconnection.location.country.fixture.CountryFixture; +import com.example.solidconnection.location.region.domain.Region; +import com.example.solidconnection.location.region.fixture.RegionFixture; +import com.example.solidconnection.support.TestContainerSpringBootTest; +import com.example.solidconnection.university.domain.HostUniversity; +import com.example.solidconnection.university.fixture.UnivApplyInfoFixtureBuilder; +import com.example.solidconnection.university.fixture.UniversityFixture; +import com.example.solidconnection.university.repository.HostUniversityRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; + +@TestContainerSpringBootTest +@DisplayName("파견 대학 관리 서비스 테스트") +class AdminHostUniversityServiceTest { + + @Autowired + private AdminHostUniversityService adminHostUniversityService; + + @Autowired + private HostUniversityRepository hostUniversityRepository; + + @Autowired + private UniversityFixture universityFixture; + + @Autowired + private CountryFixture countryFixture; + + @Autowired + private RegionFixture regionFixture; + + @Autowired + private UnivApplyInfoFixtureBuilder univApplyInfoFixtureBuilder; + + @Nested + class 목록_조회 { + + @Test + void 대학이_없으면_빈_목록을_반환한다() { + // given + AdminHostUniversitySearchCondition condition = new AdminHostUniversitySearchCondition(null, null, null); + + // when + AdminHostUniversityListResponse response = adminHostUniversityService.getHostUniversities( + condition, PageRequest.of(0, 20)); + + // then + assertThat(response.hostUniversities()).isEmpty(); + assertThat(response.totalElements()).isZero(); + } + + @Test + void 키워드로_한글명을_검색한다() { + // given + universityFixture.괌_대학(); + HostUniversity target = universityFixture.메이지_대학(); + + AdminHostUniversitySearchCondition condition = new AdminHostUniversitySearchCondition("메이지", null, null); + + // when + AdminHostUniversityListResponse response = adminHostUniversityService.getHostUniversities( + condition, PageRequest.of(0, 20)); + + // then + assertThat(response.hostUniversities()).hasSize(1); + assertThat(response.hostUniversities().get(0).koreanName()).isEqualTo(target.getKoreanName()); + } + + @Test + void 키워드로_영문명을_검색한다() { + // given + universityFixture.괌_대학(); + HostUniversity target = universityFixture.메이지_대학(); + + AdminHostUniversitySearchCondition condition = new AdminHostUniversitySearchCondition("Meiji", null, null); + + // when + AdminHostUniversityListResponse response = adminHostUniversityService.getHostUniversities( + condition, PageRequest.of(0, 20)); + + // then + assertThat(response.hostUniversities()).hasSize(1); + assertThat(response.hostUniversities().get(0).englishName()).isEqualTo(target.getEnglishName()); + } + + @Test + void 국가_코드로_필터링한다() { + // given + universityFixture.괌_대학(); + universityFixture.네바다주립_대학_라스베이거스(); + universityFixture.메이지_대학(); + + Country usa = countryFixture.미국(); + AdminHostUniversitySearchCondition condition = new AdminHostUniversitySearchCondition(null, usa.getCode(), null); + + // when + AdminHostUniversityListResponse response = adminHostUniversityService.getHostUniversities( + condition, PageRequest.of(0, 20)); + + // then + assertThat(response.hostUniversities()).hasSize(2); + assertThat(response.hostUniversities()) + .extracting(r -> r.countryCode()) + .containsOnly(usa.getCode()); + } + + @Test + void 지역_코드로_필터링한다() { + // given + universityFixture.괌_대학(); + universityFixture.서던덴마크_대학(); + universityFixture.그라츠_대학(); + + Region europe = regionFixture.유럽(); + AdminHostUniversitySearchCondition condition = new AdminHostUniversitySearchCondition(null, null, europe.getCode()); + + // when + AdminHostUniversityListResponse response = adminHostUniversityService.getHostUniversities( + condition, PageRequest.of(0, 20)); + + // then + assertThat(response.hostUniversities()).hasSize(2); + assertThat(response.hostUniversities()) + .extracting(r -> r.regionCode()) + .containsOnly(europe.getCode()); + } + + @Test + void 페이징이_정상_작동한다() { + // given + universityFixture.괌_대학(); + universityFixture.네바다주립_대학_라스베이거스(); + universityFixture.메이지_대학(); + + AdminHostUniversitySearchCondition condition = new AdminHostUniversitySearchCondition(null, null, null); + + // when + AdminHostUniversityListResponse response = adminHostUniversityService.getHostUniversities( + condition, PageRequest.of(0, 2)); + + // then + assertThat(response.hostUniversities()).hasSize(2); + assertThat(response.totalElements()).isEqualTo(3); + assertThat(response.totalPages()).isEqualTo(2); + assertThat(response.hasNext()).isTrue(); + } + } + + @Nested + class 상세_조회 { + + @Test + void 존재하는_대학을_조회하면_성공한다() { + // given + HostUniversity university = universityFixture.괌_대학(); + + // when + AdminHostUniversityDetailResponse response = adminHostUniversityService.getHostUniversity(university.getId()); + + // then + assertThat(response.id()).isEqualTo(university.getId()); + assertThat(response.koreanName()).isEqualTo(university.getKoreanName()); + assertThat(response.englishName()).isEqualTo(university.getEnglishName()); + } + + @Test + void 존재하지_않는_대학을_조회하면_예외_응답을_반환한다() { + // when & then + assertThatCode(() -> adminHostUniversityService.getHostUniversity(999L)) + .isInstanceOf(CustomException.class) + .hasMessage(ErrorCode.UNIVERSITY_NOT_FOUND.getMessage()); + } + } + + @Nested + class 생성 { + + @Test + void 유효한_정보로_대학을_생성하면_성공한다() { + // given + Country country = countryFixture.미국(); + Region region = regionFixture.영미권(); + + AdminHostUniversityCreateRequest request = new AdminHostUniversityCreateRequest( + "테스트 대학", + "Test University", + "테스트 대학", + "https://homepage.com", + "https://english-course.com", + "https://accommodation.com", + "https://logo.com/image.png", + "https://background.com/image.png", + "상세 정보", + country.getCode(), + region.getCode() + ); + + // when + AdminHostUniversityDetailResponse response = adminHostUniversityService.createHostUniversity(request); + + // then + assertThat(response.koreanName()).isEqualTo(request.koreanName()); + assertThat(response.englishName()).isEqualTo(request.englishName()); + + HostUniversity savedUniversity = hostUniversityRepository.findById(response.id()).orElseThrow(); + assertThat(savedUniversity.getKoreanName()).isEqualTo(request.koreanName()); + } + + @Test + void 이미_존재하는_한글명으로_생성하면_예외_응답을_반환한다() { + // given + HostUniversity existing = universityFixture.괌_대학(); + Country country = countryFixture.미국(); + Region region = regionFixture.영미권(); + + AdminHostUniversityCreateRequest request = new AdminHostUniversityCreateRequest( + existing.getKoreanName(), + "New English Name", + "표시명", + null, null, null, + "https://logo.com/image.png", + "https://background.com/image.png", + null, + country.getCode(), + region.getCode() + ); + + // when & then + assertThatCode(() -> adminHostUniversityService.createHostUniversity(request)) + .isInstanceOf(CustomException.class) + .hasMessage(ErrorCode.HOST_UNIVERSITY_ALREADY_EXISTS.getMessage()); + } + } + + @Nested + class 수정 { + + @Test + void 유효한_정보로_대학을_수정하면_성공한다() { + // given + HostUniversity university = universityFixture.괌_대학(); + Country country = countryFixture.일본(); + Region region = regionFixture.아시아(); + + AdminHostUniversityUpdateRequest request = new AdminHostUniversityUpdateRequest( + "수정된 대학명", + "Updated University", + "수정된 표시명", + "https://new-homepage.com", + null, null, + "https://new-logo.com/image.png", + "https://new-background.com/image.png", + "수정된 상세 정보", + country.getCode(), + region.getCode() + ); + + // when + AdminHostUniversityDetailResponse response = adminHostUniversityService.updateHostUniversity( + university.getId(), request); + + // then + assertThat(response.koreanName()).isEqualTo(request.koreanName()); + assertThat(response.countryCode()).isEqualTo(country.getCode()); + + HostUniversity updatedUniversity = hostUniversityRepository.findById(university.getId()).orElseThrow(); + assertThat(updatedUniversity.getKoreanName()).isEqualTo(request.koreanName()); + } + + @Test + void 존재하지_않는_대학을_수정하면_예외_응답을_반환한다() { + // given + Country country = countryFixture.미국(); + Region region = regionFixture.영미권(); + + AdminHostUniversityUpdateRequest request = new AdminHostUniversityUpdateRequest( + "수정된 대학명", + "Updated University", + "수정된 표시명", + null, null, null, + "https://logo.com/image.png", + "https://background.com/image.png", + null, + country.getCode(), + region.getCode() + ); + + // when & then + assertThatCode(() -> adminHostUniversityService.updateHostUniversity(999L, request)) + .isInstanceOf(CustomException.class) + .hasMessage(ErrorCode.UNIVERSITY_NOT_FOUND.getMessage()); + } + + @Test + void 다른_대학의_한글명으로_수정하면_예외_응답을_반환한다() { + // given + HostUniversity university1 = universityFixture.괌_대학(); + HostUniversity university2 = universityFixture.메이지_대학(); + + AdminHostUniversityUpdateRequest request = new AdminHostUniversityUpdateRequest( + university2.getKoreanName(), + "Updated University", + "수정된 표시명", + null, null, null, + "https://logo.com/image.png", + "https://background.com/image.png", + null, + university1.getCountry().getCode(), + university1.getRegion().getCode() + ); + + // when & then + assertThatCode(() -> adminHostUniversityService.updateHostUniversity(university1.getId(), request)) + .isInstanceOf(CustomException.class) + .hasMessage(ErrorCode.HOST_UNIVERSITY_ALREADY_EXISTS.getMessage()); + } + + @Test + void 같은_대학의_한글명으로_수정하면_성공한다() { + // given + HostUniversity university = universityFixture.괌_대학(); + + AdminHostUniversityUpdateRequest request = new AdminHostUniversityUpdateRequest( + university.getKoreanName(), + "Updated English Name", + "수정된 표시명", + null, null, null, + "https://logo.com/image.png", + "https://background.com/image.png", + null, + university.getCountry().getCode(), + university.getRegion().getCode() + ); + + // when + AdminHostUniversityDetailResponse response = adminHostUniversityService.updateHostUniversity( + university.getId(), request); + + // then + assertThat(response.koreanName()).isEqualTo(university.getKoreanName()); + assertThat(response.englishName()).isEqualTo(request.englishName()); + } + } + + @Nested + class 삭제 { + + @Test + void 존재하는_대학을_삭제하면_성공한다() { + // given + HostUniversity university = universityFixture.괌_대학(); + + // when + adminHostUniversityService.deleteHostUniversity(university.getId()); + + // then + assertThat(hostUniversityRepository.findById(university.getId())).isEmpty(); + } + + @Test + void 존재하지_않는_대학을_삭제하면_예외_응답을_반환한다() { + // when & then + assertThatCode(() -> adminHostUniversityService.deleteHostUniversity(999L)) + .isInstanceOf(CustomException.class) + .hasMessage(ErrorCode.UNIVERSITY_NOT_FOUND.getMessage()); + } + + @Test + void 참조하는_대학_지원_정보가_있으면_예외_응답을_반환한다() { + // given + HostUniversity university = universityFixture.괌_대학(); + univApplyInfoFixtureBuilder.univApplyInfo() + .termId(1L) + .koreanName("괌 대학 지원 정보") + .university(university) + .create(); + + // when & then + assertThatCode(() -> adminHostUniversityService.deleteHostUniversity(university.getId())) + .isInstanceOf(CustomException.class) + .hasMessage(ErrorCode.HOST_UNIVERSITY_HAS_REFERENCES.getMessage()); + } + } +} From 4b112c4a51f8231f43a86067fd0bc186e40db2be Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Tue, 3 Feb 2026 21:32:26 +0900 Subject: [PATCH 12/14] =?UTF-8?q?refactor:=20=EC=97=94=EB=93=9C=ED=8F=AC?= =?UTF-8?q?=EC=9D=B8=ED=8A=B8=EC=9D=98=20path=20variable=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - id -> host-university-id --- .../AdminHostUniversityController.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/example/solidconnection/admin/university/controller/AdminHostUniversityController.java b/src/main/java/com/example/solidconnection/admin/university/controller/AdminHostUniversityController.java index e28a9116..fc66e8eb 100644 --- a/src/main/java/com/example/solidconnection/admin/university/controller/AdminHostUniversityController.java +++ b/src/main/java/com/example/solidconnection/admin/university/controller/AdminHostUniversityController.java @@ -36,11 +36,11 @@ public ResponseEntity getHostUniversities( return ResponseEntity.ok(response); } - @GetMapping("/{id}") + @GetMapping("/{host-university-id}") public ResponseEntity getHostUniversity( - @PathVariable Long id + @PathVariable("host-university-id") Long hostUniversityId ) { - AdminHostUniversityDetailResponse response = adminHostUniversityService.getHostUniversity(id); + AdminHostUniversityDetailResponse response = adminHostUniversityService.getHostUniversity(hostUniversityId); return ResponseEntity.ok(response); } @@ -52,20 +52,20 @@ public ResponseEntity createHostUniversity( return ResponseEntity.ok(response); } - @PutMapping("/{id}") + @PutMapping("/{host-university-id}") public ResponseEntity updateHostUniversity( - @PathVariable Long id, + @PathVariable("host-university-id") Long hostUniversityId, @Valid @RequestBody AdminHostUniversityUpdateRequest request ) { - AdminHostUniversityDetailResponse response = adminHostUniversityService.updateHostUniversity(id, request); + AdminHostUniversityDetailResponse response = adminHostUniversityService.updateHostUniversity(hostUniversityId, request); return ResponseEntity.ok(response); } - @DeleteMapping("/{id}") + @DeleteMapping("/{host-university-id}") public ResponseEntity deleteHostUniversity( - @PathVariable Long id + @PathVariable("host-university-id") Long hostUniversityId ) { - adminHostUniversityService.deleteHostUniversity(id); + adminHostUniversityService.deleteHostUniversity(hostUniversityId); return ResponseEntity.ok().build(); } } From 227925afb0bd11b3b2e7b5b3853a5d00c87db01f Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Tue, 3 Feb 2026 21:44:06 +0900 Subject: [PATCH 13/14] =?UTF-8?q?refactor:=20PageResponse=20=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdminHostUniversityController.java | 8 ++--- .../dto/AdminHostUniversityListResponse.java | 33 ------------------- .../service/AdminHostUniversityService.java | 6 ++-- 3 files changed, 7 insertions(+), 40 deletions(-) delete mode 100644 src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityListResponse.java diff --git a/src/main/java/com/example/solidconnection/admin/university/controller/AdminHostUniversityController.java b/src/main/java/com/example/solidconnection/admin/university/controller/AdminHostUniversityController.java index fc66e8eb..57035537 100644 --- a/src/main/java/com/example/solidconnection/admin/university/controller/AdminHostUniversityController.java +++ b/src/main/java/com/example/solidconnection/admin/university/controller/AdminHostUniversityController.java @@ -2,10 +2,11 @@ import com.example.solidconnection.admin.university.dto.AdminHostUniversityCreateRequest; import com.example.solidconnection.admin.university.dto.AdminHostUniversityDetailResponse; -import com.example.solidconnection.admin.university.dto.AdminHostUniversityListResponse; +import com.example.solidconnection.admin.university.dto.AdminHostUniversityResponse; import com.example.solidconnection.admin.university.dto.AdminHostUniversitySearchCondition; import com.example.solidconnection.admin.university.dto.AdminHostUniversityUpdateRequest; import com.example.solidconnection.admin.university.service.AdminHostUniversityService; +import com.example.solidconnection.common.response.PageResponse; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; @@ -28,12 +29,11 @@ public class AdminHostUniversityController { private final AdminHostUniversityService adminHostUniversityService; @GetMapping - public ResponseEntity getHostUniversities( + public ResponseEntity> getHostUniversities( AdminHostUniversitySearchCondition condition, @PageableDefault(size = 20) Pageable pageable ) { - AdminHostUniversityListResponse response = adminHostUniversityService.getHostUniversities(condition, pageable); - return ResponseEntity.ok(response); + return ResponseEntity.ok(PageResponse.of(adminHostUniversityService.getHostUniversities(condition, pageable))); } @GetMapping("/{host-university-id}") diff --git a/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityListResponse.java b/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityListResponse.java deleted file mode 100644 index 84968859..00000000 --- a/src/main/java/com/example/solidconnection/admin/university/dto/AdminHostUniversityListResponse.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.example.solidconnection.admin.university.dto; - -import com.example.solidconnection.university.domain.HostUniversity; -import java.util.List; -import org.springframework.data.domain.Page; - -public record AdminHostUniversityListResponse( - List hostUniversities, - int page, - int size, - long totalElements, - int totalPages, - boolean hasNext, - boolean hasPrevious -) { - - public static AdminHostUniversityListResponse from(Page hostUniversityPage) { - List hostUniversities = hostUniversityPage.getContent() - .stream() - .map(AdminHostUniversityResponse::from) - .toList(); - - return new AdminHostUniversityListResponse( - hostUniversities, - hostUniversityPage.getNumber(), - hostUniversityPage.getSize(), - hostUniversityPage.getTotalElements(), - hostUniversityPage.getTotalPages(), - hostUniversityPage.hasNext(), - hostUniversityPage.hasPrevious() - ); - } -} diff --git a/src/main/java/com/example/solidconnection/admin/university/service/AdminHostUniversityService.java b/src/main/java/com/example/solidconnection/admin/university/service/AdminHostUniversityService.java index 8798a86a..c03e9f52 100644 --- a/src/main/java/com/example/solidconnection/admin/university/service/AdminHostUniversityService.java +++ b/src/main/java/com/example/solidconnection/admin/university/service/AdminHostUniversityService.java @@ -8,7 +8,7 @@ import com.example.solidconnection.admin.university.dto.AdminHostUniversityCreateRequest; import com.example.solidconnection.admin.university.dto.AdminHostUniversityDetailResponse; -import com.example.solidconnection.admin.university.dto.AdminHostUniversityListResponse; +import com.example.solidconnection.admin.university.dto.AdminHostUniversityResponse; import com.example.solidconnection.admin.university.dto.AdminHostUniversitySearchCondition; import com.example.solidconnection.admin.university.dto.AdminHostUniversityUpdateRequest; import com.example.solidconnection.common.exception.CustomException; @@ -35,7 +35,7 @@ public class AdminHostUniversityService { private final UnivApplyInfoRepository univApplyInfoRepository; @Transactional(readOnly = true) - public AdminHostUniversityListResponse getHostUniversities( + public Page getHostUniversities( AdminHostUniversitySearchCondition condition, Pageable pageable ) { @@ -45,7 +45,7 @@ public AdminHostUniversityListResponse getHostUniversities( condition.regionCode(), pageable ); - return AdminHostUniversityListResponse.from(hostUniversityPage); + return hostUniversityPage.map(AdminHostUniversityResponse::from); } @Transactional(readOnly = true) From 138b3a053537d5c813cd93476d63bc4697ca0661 Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Tue, 3 Feb 2026 21:49:54 +0900 Subject: [PATCH 14/14] =?UTF-8?q?test:=20=EC=9D=91=EB=8B=B5=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=EC=97=90=20=EB=94=B0=EB=A5=B8=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdminHostUniversityServiceTest.java | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/test/java/com/example/solidconnection/admin/service/AdminHostUniversityServiceTest.java b/src/test/java/com/example/solidconnection/admin/service/AdminHostUniversityServiceTest.java index 06cfcf15..620f18a4 100644 --- a/src/test/java/com/example/solidconnection/admin/service/AdminHostUniversityServiceTest.java +++ b/src/test/java/com/example/solidconnection/admin/service/AdminHostUniversityServiceTest.java @@ -5,7 +5,7 @@ import com.example.solidconnection.admin.university.dto.AdminHostUniversityCreateRequest; import com.example.solidconnection.admin.university.dto.AdminHostUniversityDetailResponse; -import com.example.solidconnection.admin.university.dto.AdminHostUniversityListResponse; +import com.example.solidconnection.admin.university.dto.AdminHostUniversityResponse; import com.example.solidconnection.admin.university.dto.AdminHostUniversitySearchCondition; import com.example.solidconnection.admin.university.dto.AdminHostUniversityUpdateRequest; import com.example.solidconnection.admin.university.service.AdminHostUniversityService; @@ -24,6 +24,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @TestContainerSpringBootTest @@ -57,12 +58,12 @@ class 목록_조회 { AdminHostUniversitySearchCondition condition = new AdminHostUniversitySearchCondition(null, null, null); // when - AdminHostUniversityListResponse response = adminHostUniversityService.getHostUniversities( + Page response = adminHostUniversityService.getHostUniversities( condition, PageRequest.of(0, 20)); // then - assertThat(response.hostUniversities()).isEmpty(); - assertThat(response.totalElements()).isZero(); + assertThat(response.getContent()).isEmpty(); + assertThat(response.getTotalElements()).isZero(); } @Test @@ -74,12 +75,12 @@ class 목록_조회 { AdminHostUniversitySearchCondition condition = new AdminHostUniversitySearchCondition("메이지", null, null); // when - AdminHostUniversityListResponse response = adminHostUniversityService.getHostUniversities( + Page response = adminHostUniversityService.getHostUniversities( condition, PageRequest.of(0, 20)); // then - assertThat(response.hostUniversities()).hasSize(1); - assertThat(response.hostUniversities().get(0).koreanName()).isEqualTo(target.getKoreanName()); + assertThat(response.getContent()).hasSize(1); + assertThat(response.getContent().get(0).koreanName()).isEqualTo(target.getKoreanName()); } @Test @@ -91,12 +92,12 @@ class 목록_조회 { AdminHostUniversitySearchCondition condition = new AdminHostUniversitySearchCondition("Meiji", null, null); // when - AdminHostUniversityListResponse response = adminHostUniversityService.getHostUniversities( + Page response = adminHostUniversityService.getHostUniversities( condition, PageRequest.of(0, 20)); // then - assertThat(response.hostUniversities()).hasSize(1); - assertThat(response.hostUniversities().get(0).englishName()).isEqualTo(target.getEnglishName()); + assertThat(response.getContent()).hasSize(1); + assertThat(response.getContent().get(0).englishName()).isEqualTo(target.getEnglishName()); } @Test @@ -110,12 +111,12 @@ class 목록_조회 { AdminHostUniversitySearchCondition condition = new AdminHostUniversitySearchCondition(null, usa.getCode(), null); // when - AdminHostUniversityListResponse response = adminHostUniversityService.getHostUniversities( + Page response = adminHostUniversityService.getHostUniversities( condition, PageRequest.of(0, 20)); // then - assertThat(response.hostUniversities()).hasSize(2); - assertThat(response.hostUniversities()) + assertThat(response.getContent()).hasSize(2); + assertThat(response.getContent()) .extracting(r -> r.countryCode()) .containsOnly(usa.getCode()); } @@ -131,12 +132,12 @@ class 목록_조회 { AdminHostUniversitySearchCondition condition = new AdminHostUniversitySearchCondition(null, null, europe.getCode()); // when - AdminHostUniversityListResponse response = adminHostUniversityService.getHostUniversities( + Page response = adminHostUniversityService.getHostUniversities( condition, PageRequest.of(0, 20)); // then - assertThat(response.hostUniversities()).hasSize(2); - assertThat(response.hostUniversities()) + assertThat(response.getContent()).hasSize(2); + assertThat(response.getContent()) .extracting(r -> r.regionCode()) .containsOnly(europe.getCode()); } @@ -151,13 +152,13 @@ class 목록_조회 { AdminHostUniversitySearchCondition condition = new AdminHostUniversitySearchCondition(null, null, null); // when - AdminHostUniversityListResponse response = adminHostUniversityService.getHostUniversities( + Page response = adminHostUniversityService.getHostUniversities( condition, PageRequest.of(0, 2)); // then - assertThat(response.hostUniversities()).hasSize(2); - assertThat(response.totalElements()).isEqualTo(3); - assertThat(response.totalPages()).isEqualTo(2); + assertThat(response.getContent()).hasSize(2); + assertThat(response.getTotalElements()).isEqualTo(3); + assertThat(response.getTotalPages()).isEqualTo(2); assertThat(response.hasNext()).isTrue(); } }