Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,17 @@
import com.example.solidconnection.common.resolver.AuthorizedUser;
import com.example.solidconnection.university.dto.IsLikeResponse;
import com.example.solidconnection.university.dto.UnivApplyInfoDetailResponse;
import com.example.solidconnection.university.dto.UnivApplyInfoFilterSearchRequest;
import com.example.solidconnection.university.dto.UnivApplyInfoPreviewResponse;
import com.example.solidconnection.university.dto.UnivApplyInfoPreviewResponses;
import com.example.solidconnection.university.dto.UnivApplyInfoRecommendsResponse;
import com.example.solidconnection.university.service.LikedUnivApplyInfoService;
import com.example.solidconnection.university.service.UnivApplyInfoQueryService;
import com.example.solidconnection.university.service.UnivApplyInfoRecommendService;
import jakarta.validation.Valid;
import java.util.List;
import lombok.RequiredArgsConstructor;
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.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
Expand Down Expand Up @@ -87,14 +84,6 @@ public ResponseEntity<UnivApplyInfoDetailResponse> getUnivApplyInfoDetails(
return ResponseEntity.ok(univApplyInfoDetailResponse);
}

@GetMapping("/search/filter")
public ResponseEntity<UnivApplyInfoPreviewResponses> searchUnivApplyInfoByFilter(
@Valid @ModelAttribute UnivApplyInfoFilterSearchRequest request
) {
UnivApplyInfoPreviewResponses response = univApplyInfoQueryService.searchUnivApplyInfoByFilter(request);
return ResponseEntity.ok(response);
}

@GetMapping("/search/text")
public ResponseEntity<UnivApplyInfoPreviewResponses> searchUnivApplyInfoByText(
@RequestParam(required = false) String value
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,19 @@ public record UnivApplyInfoPreviewResponse(
long id,
String term,
String koreanName,
String homeUniversityName,
String region,
String country,
String logoImageUrl,
String backgroundImageUrl,
int studentCapacity,
List<LanguageRequirementResponse> languageRequirements) {

public static UnivApplyInfoPreviewResponse from(UnivApplyInfo univApplyInfo, String termName) {
public static UnivApplyInfoPreviewResponse of(
UnivApplyInfo univApplyInfo,
String termName,
String homeUniversityName
) {
List<LanguageRequirementResponse> languageRequirementResponses = new ArrayList<>(
univApplyInfo.getLanguageRequirements().stream()
.map(LanguageRequirementResponse::from)
Expand All @@ -27,6 +32,7 @@ public static UnivApplyInfoPreviewResponse from(UnivApplyInfo univApplyInfo, Str
univApplyInfo.getId(),
termName,
univApplyInfo.getKoreanName(),
homeUniversityName,
univApplyInfo.getUniversity().getRegion().getKoreanName(),
univApplyInfo.getUniversity().getCountry().getKoreanName(),
univApplyInfo.getUniversity().getLogoImageUrl(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.solidconnection.university.repository;

import com.example.solidconnection.university.domain.HomeUniversity;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;

public interface HomeUniversityRepository extends JpaRepository<HomeUniversity, Long> {

List<HomeUniversity> findAllByIdIn(List<Long> ids);
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
package com.example.solidconnection.university.repository.custom;

import com.example.solidconnection.university.domain.LanguageTestType;
import com.example.solidconnection.university.domain.UnivApplyInfo;
import java.util.List;

public interface UnivApplyInfoFilterRepository {

List<UnivApplyInfo> findAllByRegionCodeAndKeywordsAndTermId(String regionCode, List<String> keywords, Long term);

List<UnivApplyInfo> findAllByFilter(LanguageTestType testType, String testScore, Long termId, List<String> countryKoreanNames);

List<UnivApplyInfo> findAllByText(String text, Long termId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.example.solidconnection.location.country.domain.QCountry;
import com.example.solidconnection.location.region.domain.QRegion;
import com.example.solidconnection.university.domain.LanguageTestType;
import com.example.solidconnection.university.domain.QLanguageRequirement;
import com.example.solidconnection.university.domain.QUnivApplyInfo;
import com.example.solidconnection.university.domain.QHostUniversity;
Expand Down Expand Up @@ -74,75 +73,13 @@ private BooleanExpression createKeywordCondition(StringPath namePath, List<Strin
.orElse(Expressions.FALSE);
}

@Override
public List<UnivApplyInfo> findAllByFilter(
LanguageTestType testType, String testScore, Long termId, List<String> countryCodes
) {
QHostUniversity university = QHostUniversity.hostUniversity;
QUnivApplyInfo univApplyInfo = QUnivApplyInfo.univApplyInfo;
QCountry country = QCountry.country;
QLanguageRequirement languageRequirement = QLanguageRequirement.languageRequirement;

List<UnivApplyInfo> filteredUnivApplyInfo = queryFactory.selectFrom(univApplyInfo)
.join(univApplyInfo.university, university)
.join(university.country, country)
.join(univApplyInfo.languageRequirements, languageRequirement)
.fetchJoin()
.where(
languageTestTypeEq(languageRequirement, testType),
termIdEq(univApplyInfo, termId),
countryCodesIn(country, countryCodes)
)
.distinct()
.fetch();

if (testScore == null || testScore.isBlank()) {
return filteredUnivApplyInfo;
}

/*
* 시험 유형에 따라 성적 비교 방식이 다르다.
* 입력된 점수가 대학에서 요구하는 최소 점수보다 높은지를 '쿼리로' 비교하기엔 쿼리가 지나치게 복잡해진다.
* 따라서 이 부분만 자바 코드로 필터링한다.
* */
return filteredUnivApplyInfo.stream()
.filter(uai -> isGivenScoreOverMinPassScore(uai, testType, testScore))
.toList();
}

private BooleanExpression languageTestTypeEq(
QLanguageRequirement languageRequirement, LanguageTestType givenTestType
) {
if (givenTestType == null) {
return null;
}
return languageRequirement.languageTestType.eq(givenTestType);
}

private BooleanExpression termIdEq(QUnivApplyInfo univApplyInfo, Long givenTermId) {
if (givenTermId == null) {
return null;
}
return univApplyInfo.termId.eq(givenTermId);
}

private BooleanExpression countryCodesIn(QCountry country, List<String> givenCountryCodes) {
if (givenCountryCodes == null || givenCountryCodes.isEmpty()) {
return null;
}
return country.code.in(givenCountryCodes);
}

private boolean isGivenScoreOverMinPassScore(
UnivApplyInfo univApplyInfo, LanguageTestType givenTestType, String givenTestScore
) {
return univApplyInfo.getLanguageRequirements().stream()
.filter(languageRequirement -> languageRequirement.getLanguageTestType().equals(givenTestType))
.findFirst()
.map(requirement -> givenTestType.compare(givenTestScore, requirement.getMinScore()))
.orElse(-1) >= 0;
}

@Override
public List<UnivApplyInfo> findAllByText(String text, Long termId) {
QUnivApplyInfo univApplyInfo = QUnivApplyInfo.univApplyInfo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@
import com.example.solidconnection.common.exception.CustomException;
import com.example.solidconnection.term.domain.Term;
import com.example.solidconnection.term.repository.TermRepository;
import com.example.solidconnection.university.domain.HomeUniversity;
import com.example.solidconnection.university.domain.LikedUnivApplyInfo;
import com.example.solidconnection.university.domain.UnivApplyInfo;
import com.example.solidconnection.university.dto.IsLikeResponse;
import com.example.solidconnection.university.dto.UnivApplyInfoPreviewResponse;
import com.example.solidconnection.university.repository.HomeUniversityRepository;
import com.example.solidconnection.university.repository.LikedUnivApplyInfoRepository;
import com.example.solidconnection.university.repository.UnivApplyInfoRepository;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -27,6 +30,7 @@
public class LikedUnivApplyInfoService {

private final UnivApplyInfoRepository univApplyInfoRepository;
private final HomeUniversityRepository homeUniversityRepository;
private final LikedUnivApplyInfoRepository likedUnivApplyInfoRepository;
private final TermRepository termRepository;

Expand All @@ -42,15 +46,29 @@ public List<UnivApplyInfoPreviewResponse> getLikedUnivApplyInfos(long siteUserId

Map<Long, String> termMap = termRepository.findAllById(termIds).stream()
.collect(Collectors.toMap(Term::getId, Term::getName));
Map<Long, HomeUniversity> homeUniversityMap = getHomeUniversityMap(univApplyInfos);

return univApplyInfos.stream()
.map(univApplyInfo -> {
String termName = termMap.getOrDefault(univApplyInfo.getTermId(), "Unknown");
return UnivApplyInfoPreviewResponse.from(univApplyInfo, termName);
HomeUniversity homeUniversity = homeUniversityMap.get(univApplyInfo.getHomeUniversityId());
String homeUniversityName = homeUniversity != null ? homeUniversity.getName() : null;
return UnivApplyInfoPreviewResponse.of(univApplyInfo, termName, homeUniversityName);
})
.toList();
}

private Map<Long, HomeUniversity> getHomeUniversityMap(List<UnivApplyInfo> univApplyInfos) {
List<Long> homeUniversityIds = univApplyInfos.stream()
.map(UnivApplyInfo::getHomeUniversityId)
.filter(Objects::nonNull)
.distinct()
.toList();

return homeUniversityRepository.findAllByIdIn(homeUniversityIds).stream()
.collect(Collectors.toMap(HomeUniversity::getId, Function.identity()));
}

/*
* 대학교를 '좋아요' 한다.
* */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,19 @@
import com.example.solidconnection.common.exception.CustomException;
import com.example.solidconnection.term.domain.Term;
import com.example.solidconnection.term.repository.TermRepository;
import com.example.solidconnection.university.domain.UnivApplyInfo;
import com.example.solidconnection.university.domain.HomeUniversity;
import com.example.solidconnection.university.domain.HostUniversity;
import com.example.solidconnection.university.domain.UnivApplyInfo;
import com.example.solidconnection.university.dto.UnivApplyInfoDetailResponse;
import com.example.solidconnection.university.dto.UnivApplyInfoFilterSearchRequest;
import com.example.solidconnection.university.dto.UnivApplyInfoPreviewResponse;
import com.example.solidconnection.university.dto.UnivApplyInfoPreviewResponses;
import com.example.solidconnection.university.repository.HomeUniversityRepository;
import com.example.solidconnection.university.repository.UnivApplyInfoRepository;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -24,6 +29,7 @@
public class UnivApplyInfoQueryService {

private final UnivApplyInfoRepository univApplyInfoRepository;
private final HomeUniversityRepository homeUniversityRepository;
private final TermRepository termRepository;

/*
Expand All @@ -43,34 +49,32 @@ public UnivApplyInfoDetailResponse getUnivApplyInfoDetail(Long univApplyInfoId)
}

@Transactional(readOnly = true)
public UnivApplyInfoPreviewResponses searchUnivApplyInfoByFilter(UnivApplyInfoFilterSearchRequest request) {
@ThunderingHerdCaching(key = "univApplyInfoTextSearch:{0}", cacheManager = "customCacheManager", ttlSec = 86400)
public UnivApplyInfoPreviewResponses searchUnivApplyInfoByText(String text) {
Term term = termRepository.findByIsCurrentTrue()
.orElseThrow(() -> new CustomException(CURRENT_TERM_NOT_FOUND));

List<UnivApplyInfoPreviewResponse> responses = univApplyInfoRepository
.findAllByFilter(request.languageTestType(), request.testScore(), term.getId(), request.countryCode())
.stream()
.map(univApplyInfo -> UnivApplyInfoPreviewResponse.from(
univApplyInfo,
term.getName()
))
List<UnivApplyInfo> univApplyInfos = univApplyInfoRepository.findAllByText(text, term.getId());
Map<Long, HomeUniversity> homeUniversityMap = getHomeUniversityMap(univApplyInfos);

List<UnivApplyInfoPreviewResponse> responses = univApplyInfos.stream()
.map(univApplyInfo -> {
HomeUniversity homeUniversity = homeUniversityMap.get(univApplyInfo.getHomeUniversityId());
String homeUniversityName = homeUniversity != null ? homeUniversity.getName() : null;
return UnivApplyInfoPreviewResponse.of(univApplyInfo, term.getName(), homeUniversityName);
})
.toList();
return new UnivApplyInfoPreviewResponses(responses);
}

@Transactional(readOnly = true)
@ThunderingHerdCaching(key = "univApplyInfoTextSearch:{0}", cacheManager = "customCacheManager", ttlSec = 86400)
public UnivApplyInfoPreviewResponses searchUnivApplyInfoByText(String text) {
Term term = termRepository.findByIsCurrentTrue()
.orElseThrow(() -> new CustomException(CURRENT_TERM_NOT_FOUND));

List<UnivApplyInfoPreviewResponse> responses = univApplyInfoRepository.findAllByText(text, term.getId())
.stream()
.map(univApplyInfo -> UnivApplyInfoPreviewResponse.from(
univApplyInfo,
term.getName()
))
private Map<Long, HomeUniversity> getHomeUniversityMap(List<UnivApplyInfo> univApplyInfos) {
List<Long> homeUniversityIds = univApplyInfos.stream()
.map(UnivApplyInfo::getHomeUniversityId)
.filter(Objects::nonNull)
.distinct()
.toList();
return new UnivApplyInfoPreviewResponses(responses);

return homeUniversityRepository.findAllByIdIn(homeUniversityIds).stream()
.collect(Collectors.toMap(HomeUniversity::getId, Function.identity()));
}
}
Loading
Loading