From 5a11bc43de2791d9e1534926821ddfd0567289a2 Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Sat, 24 Jan 2026 23:26:40 +0900 Subject: [PATCH 1/4] =?UTF-8?q?refactor:=20home=5Funiversity=EC=99=80=20un?= =?UTF-8?q?iversity=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 2/4] =?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 2a996dd4bf1c0d571c94701c33cae4d21b733dcc Mon Sep 17 00:00:00 2001 From: seonghyeok Date: Sun, 1 Feb 2026 15:22:17 +0900 Subject: [PATCH 3/4] =?UTF-8?q?feat:=20WebSocket=20=EB=A1=9C=EA=B9=85=20?= =?UTF-8?q?=EC=9D=B8=ED=84=B0=EC=85=89=ED=84=B0=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat/config/StompWebSocketConfig.java | 9 +++- .../config/WebSocketLoggingInterceptor.java | 53 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/example/solidconnection/chat/config/WebSocketLoggingInterceptor.java diff --git a/src/main/java/com/example/solidconnection/chat/config/StompWebSocketConfig.java b/src/main/java/com/example/solidconnection/chat/config/StompWebSocketConfig.java index 51259a0e..c7631172 100644 --- a/src/main/java/com/example/solidconnection/chat/config/StompWebSocketConfig.java +++ b/src/main/java/com/example/solidconnection/chat/config/StompWebSocketConfig.java @@ -5,6 +5,7 @@ import com.example.solidconnection.chat.config.StompProperties.OutboundProperties; import com.example.solidconnection.security.config.CorsProperties; import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.simp.config.ChannelRegistration; @@ -24,6 +25,7 @@ public class StompWebSocketConfig implements WebSocketMessageBrokerConfigurer { private final CorsProperties corsProperties; private final WebSocketHandshakeInterceptor webSocketHandshakeInterceptor; private final CustomHandshakeHandler customHandshakeHandler; + private final Optional webSocketLoggingInterceptor; @Override public void registerStompEndpoints(StompEndpointRegistry registry) { @@ -39,7 +41,12 @@ public void registerStompEndpoints(StompEndpointRegistry registry) { @Override public void configureClientInboundChannel(ChannelRegistration registration) { InboundProperties inboundProperties = stompProperties.threadPool().inbound(); - registration.interceptors(stompHandler).taskExecutor().corePoolSize(inboundProperties.corePoolSize()).maxPoolSize(inboundProperties.maxPoolSize()).queueCapacity(inboundProperties.queueCapacity()); + webSocketLoggingInterceptor.ifPresent(registration::interceptors); + registration.interceptors(stompHandler) + .taskExecutor() + .corePoolSize(inboundProperties.corePoolSize()) + .maxPoolSize(inboundProperties.maxPoolSize()) + .queueCapacity(inboundProperties.queueCapacity()); } @Override diff --git a/src/main/java/com/example/solidconnection/chat/config/WebSocketLoggingInterceptor.java b/src/main/java/com/example/solidconnection/chat/config/WebSocketLoggingInterceptor.java new file mode 100644 index 00000000..f7abcec0 --- /dev/null +++ b/src/main/java/com/example/solidconnection/chat/config/WebSocketLoggingInterceptor.java @@ -0,0 +1,53 @@ +package com.example.solidconnection.chat.config; + +import com.example.solidconnection.security.authentication.TokenAuthentication; +import com.example.solidconnection.security.userdetails.SiteUserDetails; +import java.security.Principal; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Profile; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.simp.stomp.StompCommand; +import org.springframework.messaging.simp.stomp.StompHeaderAccessor; +import org.springframework.messaging.support.ChannelInterceptor; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@Profile("dev") +public class WebSocketLoggingInterceptor implements ChannelInterceptor { + + @Override + public Message preSend(Message message, MessageChannel channel) { + StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message); + StompCommand command = accessor.getCommand(); + + if (command != null) { + Long userId = extractUserId(accessor); + String destination = accessor.getDestination(); + logStompMessage(command, destination, userId); + } + + return message; + } + + private void logStompMessage(StompCommand command, String destination, Long userId) { + switch (command) { + case CONNECT -> log.info("[WEBSOCKET] CONNECT userId = {}", userId); + case SUBSCRIBE -> log.info("[WEBSOCKET] SUBSCRIBE {} userId = {}", destination, userId); + case SEND -> log.info("[WEBSOCKET] SEND {} userId = {}", destination, userId); + case DISCONNECT -> log.info("[WEBSOCKET] DISCONNECT userId = {}", userId); + default -> { + } + } + } + + private Long extractUserId(StompHeaderAccessor accessor) { + Principal user = accessor.getUser(); + if (user instanceof TokenAuthentication tokenAuth) { + SiteUserDetails details = (SiteUserDetails) tokenAuth.getPrincipal(); + return details.getSiteUser().getId(); + } + return null; + } +} From 8b15a6052d87c86457b9c58aae15fac4173a2e31 Mon Sep 17 00:00:00 2001 From: seonghyeok cho <65901319+whqtker@users.noreply.github.com> Date: Tue, 3 Feb 2026 03:08:31 +0000 Subject: [PATCH 4/4] =?UTF-8?q?refactor:=20Principal=20=EB=AA=85=EC=8B=9C?= =?UTF-8?q?=EC=A0=81=20=ED=98=95=20=EB=B3=80=ED=99=98=20=EB=8C=80=EC=8B=A0?= =?UTF-8?q?=20null=20=EC=B2=B4=ED=81=AC=ED=95=98=EC=97=AC=20=ED=98=95=20?= =?UTF-8?q?=EB=B3=80=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat/config/WebSocketLoggingInterceptor.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/solidconnection/chat/config/WebSocketLoggingInterceptor.java b/src/main/java/com/example/solidconnection/chat/config/WebSocketLoggingInterceptor.java index f7abcec0..ea137ade 100644 --- a/src/main/java/com/example/solidconnection/chat/config/WebSocketLoggingInterceptor.java +++ b/src/main/java/com/example/solidconnection/chat/config/WebSocketLoggingInterceptor.java @@ -45,8 +45,10 @@ private void logStompMessage(StompCommand command, String destination, Long user private Long extractUserId(StompHeaderAccessor accessor) { Principal user = accessor.getUser(); if (user instanceof TokenAuthentication tokenAuth) { - SiteUserDetails details = (SiteUserDetails) tokenAuth.getPrincipal(); - return details.getSiteUser().getId(); + Object principal = tokenAuth.getPrincipal(); + if (principal instanceof SiteUserDetails details) { + return details.getSiteUser().getId(); + } } return null; }