Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public class ApplicationQueryService {
* 다른 지원자들의 성적을 조회한다.
* - 유저가 다른 지원자들을 볼 수 있는지 검증한다.
* - 지역과 키워드를 통해 대학을 필터링한다.
* - 지역은 영어 대문자로 받는다 e.g. ASIA
* - 1지망, 2지망 지원자들을 조회한다.
* */
@Transactional(readOnly = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ public record SignUpRequest(
@Schema(description = "카카오 인증 토큰", example = "kakaoToken123")
String kakaoOauthToken,

@ArraySchema(schema = @Schema(description = "관심 지역 목록", example = "[\"아시아\", \"유럽\"]"))
@ArraySchema(schema = @Schema(description = "관심 지역 목록", example = "아시아권"))
List<String> interestedRegions,

@ArraySchema(schema = @Schema(description = "관심 국가 목록", example = "[\"일본\", \"독일\"]"))
@ArraySchema(schema = @Schema(description = "관심 국가 목록", example = "일본"))
List<String> interestedCountries,

@Schema(description = "지원 준비 단계", example = "CONSIDERING")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
"/", "/index.html", "/favicon.ico",
"/file/profile/pre",
"/auth/kakao", "/auth/sign-up", "/auth/reissue",
"/university/detail/**", "/university/search/**", "/home",
"/university/detail/**", "/university/search/**", "/university/recommends",
"/swagger-ui/**", "/v3/api-docs/**"
)
.permitAll()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,10 @@ public ResponseEntity<Object> handleJwtException(JwtException ex) {
.body(errorResponse);
}


@ExceptionHandler(Exception.class)
public ResponseEntity<Object> handleOtherException(Exception ex) {
String errorMessage = ex.getMessage();
log.error("알 수 없는 예외 발생 : {}", errorMessage);
log.error("서버 내부 예외 발생 : {}", errorMessage);
ErrorResponse errorResponse = new ErrorResponse(NOT_DEFINED_ERROR, errorMessage);
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
import jakarta.persistence.OneToMany;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.HashSet;
import java.util.Set;

@Getter
@EqualsAndHashCode(of = "id")
@AllArgsConstructor(access = AccessLevel.PUBLIC)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
Expand Down Expand Up @@ -71,10 +73,10 @@ public class UniversityInfoForApply {
@Column(length = 500)
private String details;

@OneToMany(mappedBy = "universityInfoForApply", fetch = FetchType.LAZY)
@OneToMany(mappedBy = "universityInfoForApply", fetch = FetchType.EAGER)
private Set<LanguageRequirement> languageRequirements = new HashSet<>();

@ManyToOne(fetch = FetchType.LAZY)
@ManyToOne(fetch = FetchType.EAGER)
private University university;

public void addLanguageRequirements(LanguageRequirement languageRequirements) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ public interface UniversityFilterRepository {

List<University> findByRegionCodeAndKeywords(String regionCode, List<String> keywords);

List<UniversityInfoForApply> findByRegionCodeAndKeywordsAndLanguageTestTypeAndTestScore(
String regionCode, List<String> keywords, LanguageTestType testType, String testScore);
List<UniversityInfoForApply> findByRegionCodeAndKeywordsAndLanguageTestTypeAndTestScoreAndTerm(
String regionCode, List<String> keywords, LanguageTestType testType, String testScore, String term);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.example.solidconnection.entity.QCountry;
import com.example.solidconnection.entity.QRegion;
import com.example.solidconnection.type.LanguageTestType;
import com.example.solidconnection.university.domain.QLanguageRequirement;
import com.example.solidconnection.university.domain.QUniversity;
import com.example.solidconnection.university.domain.QUniversityInfoForApply;
import com.example.solidconnection.university.domain.University;
Expand Down Expand Up @@ -68,26 +67,25 @@ private BooleanExpression createKeywordCondition(StringPath namePath, List<Strin
}

@Override
public List<UniversityInfoForApply> findByRegionCodeAndKeywordsAndLanguageTestTypeAndTestScore(
String regionCode, List<String> keywords, LanguageTestType testType, String testScore) {
public List<UniversityInfoForApply> findByRegionCodeAndKeywordsAndLanguageTestTypeAndTestScoreAndTerm(
String regionCode, List<String> keywords, LanguageTestType testType, String testScore, String term) {

QUniversity university = QUniversity.university;
QCountry country = QCountry.country;
QRegion region = QRegion.region;
QUniversityInfoForApply universityInfoForApply = QUniversityInfoForApply.universityInfoForApply;
QLanguageRequirement languageRequirement = QLanguageRequirement.languageRequirement;

List<UniversityInfoForApply> filteredUniversityInfoForApply = queryFactory
.selectFrom(universityInfoForApply)
.join(universityInfoForApply.university, university)
.join(university.country, country)
.join(country.region, region)
.join(universityInfoForApply.languageRequirements, languageRequirement)
.join(university.region, region)
.where(regionCodeEq(region, regionCode)
.and(countryOrUniversityContainsKeyword(country, university, keywords)))
.and(countryOrUniversityContainsKeyword(country, university, keywords))
.and(universityInfoForApply.term.eq(term)))
.fetch();

if(testType == null || testScore == null || testScore.isEmpty()) {
if(testScore == null || testScore.isEmpty()) {
if(testType != null) {
return filteredUniversityInfoForApply.stream()
.filter(uifa -> uifa.getLanguageRequirements().stream()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.example.solidconnection.university.service;

import com.example.solidconnection.repositories.CountryRepository;
import com.example.solidconnection.university.domain.UniversityInfoForApply;
import com.example.solidconnection.university.repository.UniversityInfoForApplyRepository;
import jakarta.annotation.PostConstruct;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import java.util.List;
Expand All @@ -24,17 +26,18 @@ public class GeneralRecommendUniversities {
@Getter
private final List<UniversityInfoForApply> recommendUniversities;
private final UniversityInfoForApplyRepository universityInfoForApplyRepository;
private final CountryRepository countryRepository;
private final List<String> candidates = List.of(
"오스트라바 대학", "RMIT멜버른공과대학(A형)", "알브슈타트 지그마링엔 대학",
"뉴저지시티대학(A형)", "도요대학", "템플대학(A형)", "빈 공과대학교",
"리스본대학 공과대학", "바덴뷔르템베르크 산학협력대학", "긴다이대학", "네바다주립대학 라스베이거스(B형)", "릴 가톨릭 대학",
"그라츠공과대학", "그라츠 대학", "코펜하겐 IT대학", "메이지대학", "분쿄가쿠인대학"
"그라츠공과대학", "그라츠 대학", "코펜하겐 IT대학", "메이지대학", "분쿄가쿠인대학", "린츠 카톨릭 대학교"
);

@Value("${university.term}")
public String term;

@PostConstruct
@EventListener(ApplicationReadyEvent.class)
public void init() {
int i = 0;
while (recommendUniversities.size() < RECOMMEND_UNIVERSITY_NUM && i < candidates.size()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class UniversityRecommendService {
private final UniversityInfoForApplyRepository universityInfoForApplyRepository;
private final GeneralRecommendUniversities generalRecommendUniversities;
private final SiteUserRepository siteUserRepository;

@Value("${university.term}")
public String term;

Expand All @@ -39,16 +40,16 @@ public UniversityRecommendsResponse getPersonalRecommends(String email) {
// 맞춤 추천 대학교를 불러온다.
List<UniversityInfoForApply> personalRecommends = universityInfoForApplyRepository
.findUniversityInfoForAppliesBySiteUsersInterestedCountryOrRegionAndTerm(siteUser, term);
List<UniversityInfoForApply> shuffledList
List<UniversityInfoForApply> trimmedRecommendUniversities
= personalRecommends.subList(0, Math.min(RECOMMEND_UNIVERSITY_NUM, personalRecommends.size()));
Collections.shuffle(personalRecommends);
Collections.shuffle(trimmedRecommendUniversities);

// 맞춤 추천 대학교의 수가 6개보다 적다면, 일반 추천 대학교를 부족한 수 만큼 불러온다.
if (shuffledList.size() < 6) {
shuffledList.addAll(getGeneralRecommendsExcludingSelected(shuffledList));
if (trimmedRecommendUniversities.size() < RECOMMEND_UNIVERSITY_NUM) {
trimmedRecommendUniversities.addAll(getGeneralRecommendsExcludingSelected(trimmedRecommendUniversities));
}

return new UniversityRecommendsResponse(shuffledList.stream()
return new UniversityRecommendsResponse(trimmedRecommendUniversities.stream()
.map(UniversityInfoForApplyPreviewResponse::from)
.toList());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,15 @@ public UniversityDetailResponse getUniversityDetail(Long universityInfoForApplyI
/*
* 대학교 검색 결과를 불러온다.
* - 권역, 키워드, 언어 시험 종류, 언어 시험 점수를 조건으로 검색하여 결과를 반환한다.
* - 권역은 영어 대문자로 받는다 e.g. ASIA
* - 키워드는 국가명 또는 대학명에 포함되는 것이 조건이다.
* - 언어 시험 점수는 합격 최소 점수보다 높은 것이 조건이다.
* */
@Transactional(readOnly = true)
public List<UniversityInfoForApplyPreviewResponse> searchUniversity(
String regionCode, List<String> keywords, LanguageTestType testType, String testScore) {
return universityFilterRepository
.findByRegionCodeAndKeywordsAndLanguageTestTypeAndTestScore(regionCode, keywords, testType, testScore)
.findByRegionCodeAndKeywordsAndLanguageTestTypeAndTestScoreAndTerm(regionCode, keywords, testType, testScore, term)
.stream()
.map(UniversityInfoForApplyPreviewResponse::from)
.toList();
Expand Down
43 changes: 42 additions & 1 deletion src/main/resources/data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -221,4 +221,45 @@ VALUES ('2024-1', 1, 2, 1, 'IRRELEVANT', 'HOME_UNIVERSITY_PAYMENT', '파견대
'여학생만 신청가능', NULL, NULL,
'기숙사 없음, 계약된 외부 기숙사 사용-“Maison de Claire Ibaraki” 62,300엔/월, 2식 포함, 계약시 66,000엔 청구 (2023년 6월기준)', NULL),
('2024-1', 20, 2, 3, 'ONE_YEAR', 'HOME_UNIVERSITY_PAYMENT', NULL, NULL, NULL, NULL,
'기숙사 보유, off campus, 식사 미제공, 45,000~50,000엔/월', NULL);
'기숙사 보유, off campus, 식사 미제공, 45,000~50,000엔/월', NULL);

INSERT INTO language_requirement(language_test_type, min_score, university_info_for_apply_id)
VALUES
('TOEFL_IBT', '80', 1),
('IELTS', '6.5', 1),
('TOEFL_IBT', '80', 2),
('IELTS', '6.5', 2),
('TOEFL_IBT', '79', 3),
('IELTS', '6.0', 3),
('TOEFL_IBT', '88', 4),
('IELTS', '6.5', 4),
('TOEFL_IBT', '88', 5),
('IELTS', '6.5', 5),
('TOEFL_IBT', '85', 6),
('IELTS', '6.5', 6),
('TOEFL_IBT', '85', 7),
('IELTS', '6.5', 7),
('TOEFL_IBT', '80', 8),
('IELTS', '6.0', 8),
('TOEFL_IBT', '83', 9),
('IELTS', '6.5', 9),
('TOEFL_IBT', '87', 10),
('IELTS', '6.5', 10),
('TOEFL_IBT', '90', 11),
('IELTS', '6.5', 11),
('TOEFL_IBT', '85', 12),
('IELTS', '6.5', 12),
('TOEFL_IBT', '82', 13),
('IELTS', '6.0', 13),
('TOEFL_IBT', '85', 14),
('IELTS', '6.5', 14),
('TOEFL_IBT', '90', 15),
('IELTS', '7.0', 15),
('TOEFL_IBT', '85', 16),
('IELTS', '6.5', 16),
('DELF', 'B2', 17),
('DALF', 'C1', 17),
('JLPT', 'N2', 18),
('JLPT', 'N1', 19),
('TOEFL_IBT', '85', 20),
('IELTS', '6.5', 20);
Loading