From 2c0e2494e89d2a1283a23d1e363f6a89d45727eb Mon Sep 17 00:00:00 2001 From: seheonnn Date: Fri, 2 Aug 2024 16:15:35 +0900 Subject: [PATCH] =?UTF-8?q?=EF=B8=8Frefactor:=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=20=EB=B6=84=EB=A6=AC=20(#371)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 검색 api 북마크 여부 response 추가 * refactor: querydsl 검색 쿼리 수정 * refactor: hibernate batchSize 옵션 추가 * refactor: ddl-auto 옵션 변경 * refactor: OrganizationQueryService 분리 * refactor: PortfolioQueryService 분리 --- .../controller/OrganizationController.java | 12 +- .../response}/OrganizationGetResponse.java | 2 +- .../response/OrganizationSearchResponse.java | 6 +- .../service/OrganizationQueryService.java | 129 ++++++++++++++++++ .../service/OrganizationService.java | 102 ++------------ .../controller/PortfolioController.java | 5 +- .../service/PortfolioQueryService.java | 36 +++++ .../portfolio/service/PortfolioService.java | 19 +-- ...java => OrganizationQueryServiceTest.java} | 34 +++-- .../repository/OrganizationRepository.java | 3 +- .../OrganizationCustomRepository.java} | 6 +- .../OrganizationCustomRepositoryImpl.java} | 18 ++- .../querydsl/OrganizationSearchResponse.java | 25 ++++ .../OrganizationSearchCondition.java | 2 +- ...ava => PortfolioCustomRepositoryImpl.java} | 2 +- .../repository/PortfolioRepository.java | 2 +- .../src/main/resources/application-db.yml | 15 +- 17 files changed, 271 insertions(+), 147 deletions(-) rename api/src/main/java/com/sponus/sponusbe/domain/organization/{company/dto => dto/response}/OrganizationGetResponse.java (94%) create mode 100644 api/src/main/java/com/sponus/sponusbe/domain/organization/service/OrganizationQueryService.java create mode 100644 api/src/main/java/com/sponus/sponusbe/domain/portfolio/service/PortfolioQueryService.java rename api/src/test/java/com/sponus/sponusbe/domain/organization/{OrganizationServiceTest.java => OrganizationQueryServiceTest.java} (75%) rename core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/{OrganizationRepositoryCustom.java => querydsl/OrganizationCustomRepository.java} (53%) rename core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/{OrganizationRepositoryCustomImpl.java => querydsl/OrganizationCustomRepositoryImpl.java} (76%) create mode 100644 core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/querydsl/OrganizationSearchResponse.java rename core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/{ => querydsl}/conditions/OrganizationSearchCondition.java (79%) rename core/core-domain/src/main/java/com/sponus/coredomain/domain/portfolio/repository/{PortfolioRepositoryImpl.java => PortfolioCustomRepositoryImpl.java} (95%) diff --git a/api/src/main/java/com/sponus/sponusbe/domain/organization/controller/OrganizationController.java b/api/src/main/java/com/sponus/sponusbe/domain/organization/controller/OrganizationController.java index 475c6f0d..fedb5787 100644 --- a/api/src/main/java/com/sponus/sponusbe/domain/organization/controller/OrganizationController.java +++ b/api/src/main/java/com/sponus/sponusbe/domain/organization/controller/OrganizationController.java @@ -21,14 +21,15 @@ import com.sponus.coredomain.domain.organization.enums.OrganizationType; import com.sponus.coreinfrasecurity.annotation.AuthOrganization; import com.sponus.sponusbe.domain.organization.club.service.ClubService; -import com.sponus.sponusbe.domain.organization.company.dto.OrganizationGetResponse; import com.sponus.sponusbe.domain.organization.company.service.CompanyService; import com.sponus.sponusbe.domain.organization.dto.request.OrganizationCreateRequest; import com.sponus.sponusbe.domain.organization.dto.request.OrganizationSearchRequest; import com.sponus.sponusbe.domain.organization.dto.request.PageCondition; +import com.sponus.sponusbe.domain.organization.dto.response.OrganizationGetResponse; import com.sponus.sponusbe.domain.organization.dto.response.OrganizationImageUploadResponse; import com.sponus.sponusbe.domain.organization.dto.response.OrganizationSearchResponse; import com.sponus.sponusbe.domain.organization.dto.response.PageResponse; +import com.sponus.sponusbe.domain.organization.service.OrganizationQueryService; import com.sponus.sponusbe.domain.organization.service.OrganizationService; import jakarta.validation.Valid; @@ -39,6 +40,7 @@ @RequiredArgsConstructor public class OrganizationController { private final OrganizationService organizationService; + private final OrganizationQueryService organizationQueryService; private final ClubService clubService; private final CompanyService companyService; @@ -53,7 +55,7 @@ public ApiResponse> getOrganizations( @ModelAttribute @Valid PageCondition pageCondition, @ModelAttribute @Valid OrganizationType organizationType) { return ApiResponse.onSuccess( - organizationService.getOrganizations(authOrganization, pageCondition, organizationType)); + organizationQueryService.getOrganizations(authOrganization, pageCondition, organizationType)); } @GetMapping("/me") @@ -75,7 +77,7 @@ public ApiResponse uploadProfileImage( @GetMapping("/exists") public ApiResponse verifyName(@RequestParam String name) { - return ApiResponse.onSuccess(organizationService.verifyName(name)); + return ApiResponse.onSuccess(organizationQueryService.verifyName(name)); } @DeleteMapping("/{organizationId}") @@ -91,7 +93,7 @@ public ApiResponse> searchOrganization( @AuthOrganization Organization organization ) { return ApiResponse.onSuccess( - organizationService.searchOrganizations(pageCondition, keyword, organization.getId())); + organizationQueryService.searchOrganizations(pageCondition, keyword, organization)); } @DeleteMapping("/search") @@ -109,7 +111,7 @@ public ApiResponse createSearchHistory(@AuthOrganization Organization orga @GetMapping("/search/keywords") public ApiResponse> getSearchHistory(@AuthOrganization Organization organization) { - return ApiResponse.onSuccess(organizationService.getSearchHistory(organization.getId())); + return ApiResponse.onSuccess(organizationQueryService.getSearchHistory(organization.getId())); } @DeleteMapping("/search/keywords") diff --git a/api/src/main/java/com/sponus/sponusbe/domain/organization/company/dto/OrganizationGetResponse.java b/api/src/main/java/com/sponus/sponusbe/domain/organization/dto/response/OrganizationGetResponse.java similarity index 94% rename from api/src/main/java/com/sponus/sponusbe/domain/organization/company/dto/OrganizationGetResponse.java rename to api/src/main/java/com/sponus/sponusbe/domain/organization/dto/response/OrganizationGetResponse.java index bd0e02da..b147b1b4 100644 --- a/api/src/main/java/com/sponus/sponusbe/domain/organization/company/dto/OrganizationGetResponse.java +++ b/api/src/main/java/com/sponus/sponusbe/domain/organization/dto/response/OrganizationGetResponse.java @@ -1,4 +1,4 @@ -package com.sponus.sponusbe.domain.organization.company.dto; +package com.sponus.sponusbe.domain.organization.dto.response; import java.util.List; diff --git a/api/src/main/java/com/sponus/sponusbe/domain/organization/dto/response/OrganizationSearchResponse.java b/api/src/main/java/com/sponus/sponusbe/domain/organization/dto/response/OrganizationSearchResponse.java index 0cf35dbc..37aea99d 100644 --- a/api/src/main/java/com/sponus/sponusbe/domain/organization/dto/response/OrganizationSearchResponse.java +++ b/api/src/main/java/com/sponus/sponusbe/domain/organization/dto/response/OrganizationSearchResponse.java @@ -10,14 +10,16 @@ public record OrganizationSearchResponse( Long id, String name, String imageUrl, - OrganizationType organizationType + OrganizationType organizationType, + boolean isBookmarked ) { - public static OrganizationSearchResponse of(Organization organization) { + public static OrganizationSearchResponse of(Organization organization, boolean isBookmarked) { return OrganizationSearchResponse.builder() .id(organization.getId()) .name(organization.getName()) .imageUrl(organization.getImageUrl()) .organizationType(organization.getOrganizationType()) + .isBookmarked(isBookmarked) .build(); } } diff --git a/api/src/main/java/com/sponus/sponusbe/domain/organization/service/OrganizationQueryService.java b/api/src/main/java/com/sponus/sponusbe/domain/organization/service/OrganizationQueryService.java new file mode 100644 index 00000000..9ba6ff40 --- /dev/null +++ b/api/src/main/java/com/sponus/sponusbe/domain/organization/service/OrganizationQueryService.java @@ -0,0 +1,129 @@ +package com.sponus.sponusbe.domain.organization.service; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.support.PageableExecutionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.sponus.coredomain.domain.organization.Organization; +import com.sponus.coredomain.domain.organization.enums.OrganizationType; +import com.sponus.coredomain.domain.organization.enums.ProfileStatus; +import com.sponus.coredomain.domain.organization.repository.OrganizationRepository; +import com.sponus.coredomain.domain.organization.repository.querydsl.conditions.OrganizationSearchCondition; +import com.sponus.coreinfraredis.entity.SearchHistory; +import com.sponus.coreinfraredis.repository.SearchHistoryRepository; +import com.sponus.sponusbe.domain.organization.dto.request.PageCondition; +import com.sponus.sponusbe.domain.organization.dto.response.OrganizationGetResponse; +import com.sponus.sponusbe.domain.organization.dto.response.OrganizationSearchResponse; +import com.sponus.sponusbe.domain.organization.dto.response.PageResponse; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class OrganizationQueryService { + + private final OrganizationRepository organizationRepository; + private final SearchHistoryRepository searchHistoryRepository; + + public Boolean verifyName(String name) { + return organizationRepository.existsByName(name); + } + + public PageResponse getOrganizations( + Organization authOrganization, + PageCondition pageCondition, + OrganizationType organizationType) { + // TODO: FETCH JOIN으로 변경 + Set bookmarkedOrganizationIds = authOrganization.getBookmarks() + .stream() + .map(bookmark -> bookmark.getTarget().getId()) + .collect(Collectors.toSet()); + Pageable pageable = PageRequest.of(pageCondition.getPage() - 1, pageCondition.getSize()); + List organizations = organizationRepository.findOrganizations( + organizationType, pageable, authOrganization.getId()) + .stream() + .map(organization -> + OrganizationGetResponse.of(organization, bookmarkedOrganizationIds.contains(organization.getId()))) + .toList(); + + return PageResponse.of( + PageableExecutionUtils.getPage(organizations, pageable, + () -> organizationRepository.countByOrganizationType(organizationType))); + } + + public PageResponse searchOrganizations(PageCondition pageCondition, String keyword, + Organization authOrganization) { + + Set bookmarkedOrganizationIds = authOrganization.getBookmarks() + .stream() + .map(bookmark -> bookmark.getTarget().getId()) + .collect(Collectors.toSet()); + Pageable pageable = PageRequest.of(pageCondition.getPage() - 1, pageCondition.getSize()); + + List organizations = organizationRepository.findByNameContains( + keyword, pageable) + .stream() + .filter(organization -> organization.getProfileStatus().equals(ProfileStatus.ACTIVE)) + .filter(organization -> !organization.getId().equals(authOrganization.getId())) + .map(organization -> + OrganizationSearchResponse.of(organization, bookmarkedOrganizationIds.contains(organization.getId()))) + .toList(); + + return PageResponse.of( + PageableExecutionUtils.getPage(organizations, pageable, + () -> organizationRepository.countByNameContains(keyword))); + } + + public PageResponse searchOrganizationsV2( + PageCondition pageCondition, String keyword, + Organization authOrganization) { + + OrganizationSearchCondition condition = OrganizationSearchCondition.of(keyword, authOrganization.getId()); + Pageable pageable = PageRequest.of(pageCondition.getPage() - 1, pageCondition.getSize()); + + Page organizations = organizationRepository.searchOrganizationV2(condition, pageable); + + Set bookmarkedOrganizationIds = authOrganization.getBookmarks() + .stream() + .map(bookmark -> bookmark.getTarget().getId()) + .collect(Collectors.toSet()); + + return PageResponse.of(organizations.map(organization -> + OrganizationSearchResponse.of(organization, bookmarkedOrganizationIds.contains(organization.getId())))); + } + + public List getSearchHistory(Long organizationId) { + Set searchHistory = findSearchHistory(organizationId).getKeywords(); + + List searchHistoryList = new ArrayList<>(searchHistory); + searchHistoryList.removeIf(String::isEmpty); + + if (!searchHistoryList.isEmpty()) { + Collections.reverse(searchHistoryList); + } + + return searchHistoryList; + } + + private SearchHistory findSearchHistory(Long organizationId) { + return searchHistoryRepository.findById(organizationId).orElseGet(() -> { + SearchHistory newSearchHistory = SearchHistory.builder() + .organizationId(organizationId) + .build(); + return searchHistoryRepository.save(newSearchHistory); + }); + } + +} diff --git a/api/src/main/java/com/sponus/sponusbe/domain/organization/service/OrganizationService.java b/api/src/main/java/com/sponus/sponusbe/domain/organization/service/OrganizationService.java index c768ae53..bdc212c0 100644 --- a/api/src/main/java/com/sponus/sponusbe/domain/organization/service/OrganizationService.java +++ b/api/src/main/java/com/sponus/sponusbe/domain/organization/service/OrganizationService.java @@ -1,36 +1,20 @@ package com.sponus.sponusbe.domain.organization.service; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.support.PageableExecutionUtils; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; -import com.sponus.coredomain.domain.bookmark.repository.BookmarkRepository; import com.sponus.coredomain.domain.organization.Organization; import com.sponus.coredomain.domain.organization.club.Club; import com.sponus.coredomain.domain.organization.company.Company; import com.sponus.coredomain.domain.organization.enums.OrganizationType; -import com.sponus.coredomain.domain.organization.enums.ProfileStatus; import com.sponus.coredomain.domain.organization.repository.OrganizationRepository; -import com.sponus.coredomain.domain.organization.repository.conditions.OrganizationSearchCondition; import com.sponus.coreinfraredis.entity.SearchHistory; import com.sponus.coreinfraredis.repository.SearchHistoryRepository; import com.sponus.coreinfras3.S3Service; -import com.sponus.sponusbe.domain.organization.company.dto.OrganizationGetResponse; import com.sponus.sponusbe.domain.organization.dto.request.OrganizationCreateRequest; -import com.sponus.sponusbe.domain.organization.dto.request.PageCondition; import com.sponus.sponusbe.domain.organization.dto.response.OrganizationImageUploadResponse; -import com.sponus.sponusbe.domain.organization.dto.response.OrganizationSearchResponse; -import com.sponus.sponusbe.domain.organization.dto.response.PageResponse; import com.sponus.sponusbe.domain.organization.exception.OrganizationErrorCode; import com.sponus.sponusbe.domain.organization.exception.OrganizationException; @@ -42,8 +26,8 @@ @Transactional @RequiredArgsConstructor public class OrganizationService { + private final OrganizationRepository organizationRepository; - private final BookmarkRepository bookmarkRepository; private final S3Service s3Service; private final PasswordEncoder passwordEncoder; private final SearchHistoryRepository searchHistoryRepository; @@ -64,63 +48,11 @@ public OrganizationImageUploadResponse uploadProfileImage(Long organizationId, M return new OrganizationImageUploadResponse(imageUrl); } - public Boolean verifyName(String name) { - return organizationRepository.existsByName(name); - } - public void deleteOrganization(Long organizationId) { Organization organization = findOrganizationById(organizationId); organization.delete(); } - public PageResponse getOrganizations( - Organization authOrganization, - PageCondition pageCondition, - OrganizationType organizationType) { - // TODO: FETCH JOIN으로 변경 - Set bookmarkedOrganizationIds = bookmarkRepository.findByOrganization(authOrganization).stream() - .map((bookmark) -> bookmark.getTarget().getId()) - .collect(Collectors.toSet()); - Pageable pageable = PageRequest.of(pageCondition.getPage() - 1, pageCondition.getSize()); - List organizations = organizationRepository.findOrganizations( - organizationType, pageable, authOrganization.getId()) - .stream() - .map(organization -> - OrganizationGetResponse.of(organization, bookmarkedOrganizationIds.contains(organization.getId()))) - .toList(); - - return PageResponse.of( - PageableExecutionUtils.getPage(organizations, pageable, - () -> organizationRepository.countByOrganizationType(organizationType))); - } - - public PageResponse searchOrganizations(PageCondition pageCondition, String keyword, - Long organizationId) { - - Pageable pageable = PageRequest.of(pageCondition.getPage() - 1, pageCondition.getSize()); - List organizations = organizationRepository.findByNameContains( - keyword, pageable) - .stream() - .filter(organization -> organization.getProfileStatus().equals(ProfileStatus.ACTIVE)) - .filter(organization -> !organization.getId().equals(organizationId)) - .map(OrganizationSearchResponse::of) - .toList(); - - return PageResponse.of( - PageableExecutionUtils.getPage(organizations, pageable, - () -> organizationRepository.countByNameContains(keyword))); - } - - public PageResponse searchOrganizationsV2(PageCondition pageCondition, String keyword, - Long organizationId) { - - OrganizationSearchCondition condition = OrganizationSearchCondition.of(keyword, organizationId); - Pageable pageable = PageRequest.of(pageCondition.getPage() - 1, pageCondition.getSize()); - - return PageResponse.of(organizationRepository.searchOrganizationV2(condition, pageable) - .map(OrganizationSearchResponse::of)); - } - public void createSearchHistory(Long organizationId, String keyword) { SearchHistory searchHistory = findSearchHistory(organizationId); @@ -133,30 +65,7 @@ public void createSearchHistory(Long organizationId, String keyword) { searchHistoryRepository.save(searchHistory); } - public List getSearchHistory(Long organizationId) { - Set searchHistory = findSearchHistory(organizationId).getKeywords(); - - List searchHistoryList = new ArrayList<>(searchHistory); - searchHistoryList.removeIf(String::isEmpty); - - if (!searchHistoryList.isEmpty()) { - Collections.reverse(searchHistoryList); - } - - return searchHistoryList; - } - - public SearchHistory findSearchHistory(Long organizationId) { - return searchHistoryRepository.findById(organizationId).orElseGet(() -> { - SearchHistory newSearchHistory = SearchHistory.builder() - .organizationId(organizationId) - .build(); - return searchHistoryRepository.save(newSearchHistory); - }); - } - public void deleteSearchKeyword(Long organizationId, String keyword) { - // TODO 검색어 에러 처리 SearchHistory searchHistory = searchHistoryRepository.findById(organizationId) .orElseThrow(() -> new OrganizationException(OrganizationErrorCode.ORGANIZATION_ERROR)); searchHistory.getKeywords().remove(keyword); @@ -174,4 +83,13 @@ private Organization findOrganizationById(Long organizationId) { return organizationRepository.findById(organizationId) .orElseThrow(() -> new OrganizationException(OrganizationErrorCode.ORGANIZATION_NOT_FOUND)); } + + private SearchHistory findSearchHistory(Long organizationId) { + return searchHistoryRepository.findById(organizationId).orElseGet(() -> { + SearchHistory newSearchHistory = SearchHistory.builder() + .organizationId(organizationId) + .build(); + return searchHistoryRepository.save(newSearchHistory); + }); + } } diff --git a/api/src/main/java/com/sponus/sponusbe/domain/portfolio/controller/PortfolioController.java b/api/src/main/java/com/sponus/sponusbe/domain/portfolio/controller/PortfolioController.java index 49eaf92f..eba4f600 100644 --- a/api/src/main/java/com/sponus/sponusbe/domain/portfolio/controller/PortfolioController.java +++ b/api/src/main/java/com/sponus/sponusbe/domain/portfolio/controller/PortfolioController.java @@ -29,6 +29,7 @@ import com.sponus.sponusbe.domain.portfolio.dto.PortfolioGetResponse; import com.sponus.sponusbe.domain.portfolio.dto.PortfolioImageCreateResponse; import com.sponus.sponusbe.domain.portfolio.dto.PortfolioUpdateRequest; +import com.sponus.sponusbe.domain.portfolio.service.PortfolioQueryService; import com.sponus.sponusbe.domain.portfolio.service.PortfolioService; import jakarta.validation.Valid; @@ -42,7 +43,9 @@ @RequestMapping(PORTFOLIO_URI) @RestController public class PortfolioController { + private final PortfolioService portfolioService; + private final PortfolioQueryService portfolioQueryService; @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ApiResponse createPortfolio( @@ -57,7 +60,7 @@ public ApiResponse createPortfolio( @GetMapping public ApiResponse> getPortfolios(@PageableDefault() Pageable pageable, @ModelAttribute PortfolioSearchParam portfolioSearchParam) { - Page response = portfolioService.getPortfolios(portfolioSearchParam, pageable); + Page response = portfolioQueryService.getPortfolios(portfolioSearchParam, pageable); return ApiResponse.onSuccess(response); } diff --git a/api/src/main/java/com/sponus/sponusbe/domain/portfolio/service/PortfolioQueryService.java b/api/src/main/java/com/sponus/sponusbe/domain/portfolio/service/PortfolioQueryService.java new file mode 100644 index 00000000..62ff13bb --- /dev/null +++ b/api/src/main/java/com/sponus/sponusbe/domain/portfolio/service/PortfolioQueryService.java @@ -0,0 +1,36 @@ +package com.sponus.sponusbe.domain.portfolio.service; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.sponus.coredomain.domain.portfolio.Portfolio; +import com.sponus.coredomain.domain.portfolio.repository.PortfolioRepository; +import com.sponus.coredomain.domain.portfolio.repository.conditions.PortfolioSearchParam; +import com.sponus.sponusbe.domain.portfolio.dto.PortfolioGetResponse; +import com.sponus.sponusbe.domain.portfolio.dto.PortfolioImageGetResponse; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class PortfolioQueryService { + + private final PortfolioRepository portfolioRepository; + + public Page getPortfolios(PortfolioSearchParam portfolioSearchParam, Pageable pageable) { + Page queryResult = portfolioRepository.findAllByConditions(portfolioSearchParam, pageable); + return queryResult.map(portfolio -> { + List portfolioImageGetResponses = portfolio.getPortfolioImages().stream() + .map(image -> new PortfolioImageGetResponse(image.getId(), image.getUrl(), image.getOrder())) + .toList(); + return PortfolioGetResponse.from(portfolio, portfolioImageGetResponses); + }); + } +} diff --git a/api/src/main/java/com/sponus/sponusbe/domain/portfolio/service/PortfolioService.java b/api/src/main/java/com/sponus/sponusbe/domain/portfolio/service/PortfolioService.java index 86c6e386..84dafc1b 100644 --- a/api/src/main/java/com/sponus/sponusbe/domain/portfolio/service/PortfolioService.java +++ b/api/src/main/java/com/sponus/sponusbe/domain/portfolio/service/PortfolioService.java @@ -8,8 +8,6 @@ import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -19,14 +17,11 @@ import com.sponus.coredomain.domain.organization.repository.ClubRepository; import com.sponus.coredomain.domain.portfolio.Portfolio; import com.sponus.coredomain.domain.portfolio.PortfolioImage; -import com.sponus.coredomain.domain.portfolio.repository.PortfolioCustomRepository; import com.sponus.coredomain.domain.portfolio.repository.PortfolioRepository; -import com.sponus.coredomain.domain.portfolio.repository.conditions.PortfolioSearchParam; import com.sponus.coreinfras3.S3Service; import com.sponus.sponusbe.domain.organization.exception.OrganizationException; import com.sponus.sponusbe.domain.portfolio.dto.PortfolioCreateRequest; import com.sponus.sponusbe.domain.portfolio.dto.PortfolioCreateResponse; -import com.sponus.sponusbe.domain.portfolio.dto.PortfolioGetResponse; import com.sponus.sponusbe.domain.portfolio.dto.PortfolioImageCreateResponse; import com.sponus.sponusbe.domain.portfolio.dto.PortfolioImageGetResponse; import com.sponus.sponusbe.domain.portfolio.dto.PortfolioUpdateRequest; @@ -37,11 +32,11 @@ @Slf4j @RequiredArgsConstructor -@Transactional(readOnly = true) +@Transactional @Service public class PortfolioService { + private final PortfolioRepository portfolioRepository; - private final PortfolioCustomRepository portfolioCustomRepository; private final ClubRepository clubRepository; private final S3Service s3Service; @@ -99,16 +94,6 @@ public PortfolioCreateResponse createPortfolio( ); } - public Page getPortfolios(PortfolioSearchParam portfolioSearchParam, Pageable pageable) { - Page queryResult = portfolioCustomRepository.findAllByConditions(portfolioSearchParam, pageable); - return queryResult.map(portfolio -> { - List portfolioImageGetResponses = portfolio.getPortfolioImages().stream() - .map(image -> new PortfolioImageGetResponse(image.getId(), image.getUrl(), image.getOrder())) - .toList(); - return PortfolioGetResponse.from(portfolio, portfolioImageGetResponses); - }); - } - @Transactional public void deletePortfolio(long portfolioId, Organization authOrganization) { if (!authOrganization.isClub()) { diff --git a/api/src/test/java/com/sponus/sponusbe/domain/organization/OrganizationServiceTest.java b/api/src/test/java/com/sponus/sponusbe/domain/organization/OrganizationQueryServiceTest.java similarity index 75% rename from api/src/test/java/com/sponus/sponusbe/domain/organization/OrganizationServiceTest.java rename to api/src/test/java/com/sponus/sponusbe/domain/organization/OrganizationQueryServiceTest.java index 3105a52b..c6928255 100644 --- a/api/src/test/java/com/sponus/sponusbe/domain/organization/OrganizationServiceTest.java +++ b/api/src/test/java/com/sponus/sponusbe/domain/organization/OrganizationQueryServiceTest.java @@ -17,17 +17,17 @@ import com.sponus.sponusbe.domain.organization.dto.request.PageCondition; import com.sponus.sponusbe.domain.organization.dto.response.OrganizationSearchResponse; import com.sponus.sponusbe.domain.organization.dto.response.PageResponse; -import com.sponus.sponusbe.domain.organization.service.OrganizationService; +import com.sponus.sponusbe.domain.organization.service.OrganizationQueryService; import jakarta.persistence.EntityManager; @SpringBootTest @Transactional @ActiveProfiles("test") -class OrganizationServiceTest { +class OrganizationQueryServiceTest { @Autowired - OrganizationService organizationService; + OrganizationQueryService organizationQueryService; @Autowired EntityManager em; @@ -51,13 +51,21 @@ public void init() { @Test @DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD) - void searchV1() { + void searchOrganizationTestV1() { // given PageCondition pageCondition = new PageCondition(0, 10); + Organization authOrganization = Organization.builder() + .email("sponus_company_a@gmail.com") + .name("sponus_company") + .password("sponus_company1234#") + .organizationType(OrganizationType.COMPANY) + .profileStatus(ProfileStatus.ACTIVE) + .build(); + em.persist(authOrganization); // when - PageResponse searchOrganizations = organizationService.searchOrganizations( - pageCondition, "sponus", null); + PageResponse searchOrganizations = organizationQueryService.searchOrganizations( + pageCondition, "sponus", authOrganization); // then List expectedOrganizationNames = List.of( @@ -75,13 +83,21 @@ void searchV1() { @Test @DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD) - void searchV2() { + void searchOrganizationTestV2() { // given PageCondition pageCondition = new PageCondition(0, 10); + Organization authOrganization = Organization.builder() + .email("sponus_company_b@gmail.com") + .name("sponus_company") + .password("sponus_company1234#") + .organizationType(OrganizationType.COMPANY) + .profileStatus(ProfileStatus.ACTIVE) + .build(); + em.persist(authOrganization); // when - PageResponse searchOrganizations = organizationService.searchOrganizationsV2( - pageCondition, "sponus", null); + PageResponse searchOrganizations = organizationQueryService.searchOrganizationsV2( + pageCondition, "sponus", authOrganization); // then List expectedOrganizationNames = List.of( diff --git a/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/OrganizationRepository.java b/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/OrganizationRepository.java index a7284111..4662c4a5 100644 --- a/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/OrganizationRepository.java +++ b/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/OrganizationRepository.java @@ -10,8 +10,9 @@ import com.sponus.coredomain.domain.organization.Organization; import com.sponus.coredomain.domain.organization.enums.OrganizationType; +import com.sponus.coredomain.domain.organization.repository.querydsl.OrganizationCustomRepository; -public interface OrganizationRepository extends JpaRepository, OrganizationRepositoryCustom { +public interface OrganizationRepository extends JpaRepository, OrganizationCustomRepository { Optional findOrganizationByEmail(String email); diff --git a/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/OrganizationRepositoryCustom.java b/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/querydsl/OrganizationCustomRepository.java similarity index 53% rename from core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/OrganizationRepositoryCustom.java rename to core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/querydsl/OrganizationCustomRepository.java index 63a3f587..7b946878 100644 --- a/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/OrganizationRepositoryCustom.java +++ b/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/querydsl/OrganizationCustomRepository.java @@ -1,12 +1,12 @@ -package com.sponus.coredomain.domain.organization.repository; +package com.sponus.coredomain.domain.organization.repository.querydsl; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import com.sponus.coredomain.domain.organization.Organization; -import com.sponus.coredomain.domain.organization.repository.conditions.OrganizationSearchCondition; +import com.sponus.coredomain.domain.organization.repository.querydsl.conditions.OrganizationSearchCondition; -public interface OrganizationRepositoryCustom { +public interface OrganizationCustomRepository { Page searchOrganizationV2(OrganizationSearchCondition condition, Pageable pageable); } diff --git a/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/OrganizationRepositoryCustomImpl.java b/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/querydsl/OrganizationCustomRepositoryImpl.java similarity index 76% rename from core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/OrganizationRepositoryCustomImpl.java rename to core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/querydsl/OrganizationCustomRepositoryImpl.java index 49741cd9..cd82f1a2 100644 --- a/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/OrganizationRepositoryCustomImpl.java +++ b/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/querydsl/OrganizationCustomRepositoryImpl.java @@ -1,4 +1,4 @@ -package com.sponus.coredomain.domain.organization.repository; +package com.sponus.coredomain.domain.organization.repository.querydsl; import static com.sponus.coredomain.domain.organization.QOrganization.*; import static org.springframework.util.StringUtils.*; @@ -10,18 +10,19 @@ import org.springframework.data.support.PageableExecutionUtils; import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; import com.sponus.coredomain.domain.organization.Organization; import com.sponus.coredomain.domain.organization.enums.ProfileStatus; -import com.sponus.coredomain.domain.organization.repository.conditions.OrganizationSearchCondition; +import com.sponus.coredomain.domain.organization.repository.querydsl.conditions.OrganizationSearchCondition; import jakarta.persistence.EntityManager; -public class OrganizationRepositoryCustomImpl implements OrganizationRepositoryCustom { +public class OrganizationCustomRepositoryImpl implements OrganizationCustomRepository { private final JPAQueryFactory queryFactory; - public OrganizationRepositoryCustomImpl(EntityManager em) { + public OrganizationCustomRepositoryImpl(EntityManager em) { this.queryFactory = new JPAQueryFactory(em); } @@ -39,17 +40,14 @@ public Page searchOrganizationV2(OrganizationSearchCondition condi .limit(pageable.getPageSize()) .fetch(); - long count = queryFactory + JPAQuery countQuery = queryFactory .selectFrom(organization) .where( keywordContains(condition.keyword()), organizationIdNotEq(condition.organizationId()), isActive() - ) - .fetch() - .size(); - - return PageableExecutionUtils.getPage(content, pageable, () -> count); + ); + return PageableExecutionUtils.getPage(content, pageable, countQuery::fetchCount); } private BooleanExpression keywordContains(String keyword) { diff --git a/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/querydsl/OrganizationSearchResponse.java b/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/querydsl/OrganizationSearchResponse.java new file mode 100644 index 00000000..53e15003 --- /dev/null +++ b/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/querydsl/OrganizationSearchResponse.java @@ -0,0 +1,25 @@ +package com.sponus.coredomain.domain.organization.repository.querydsl; + +import com.sponus.coredomain.domain.organization.Organization; +import com.sponus.coredomain.domain.organization.enums.OrganizationType; + +import lombok.Builder; + +@Builder +public record OrganizationSearchResponse( + Long id, + String name, + String imageUrl, + OrganizationType organizationType, + boolean isBookmarked +) { + public static OrganizationSearchResponse of(Organization organization, boolean isBookmarked) { + return OrganizationSearchResponse.builder() + .id(organization.getId()) + .name(organization.getName()) + .imageUrl(organization.getImageUrl()) + .organizationType(organization.getOrganizationType()) + .isBookmarked(isBookmarked) + .build(); + } +} diff --git a/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/conditions/OrganizationSearchCondition.java b/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/querydsl/conditions/OrganizationSearchCondition.java similarity index 79% rename from core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/conditions/OrganizationSearchCondition.java rename to core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/querydsl/conditions/OrganizationSearchCondition.java index 90dc2ea3..33939a6c 100644 --- a/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/conditions/OrganizationSearchCondition.java +++ b/core/core-domain/src/main/java/com/sponus/coredomain/domain/organization/repository/querydsl/conditions/OrganizationSearchCondition.java @@ -1,4 +1,4 @@ -package com.sponus.coredomain.domain.organization.repository.conditions; +package com.sponus.coredomain.domain.organization.repository.querydsl.conditions; import lombok.Builder; diff --git a/core/core-domain/src/main/java/com/sponus/coredomain/domain/portfolio/repository/PortfolioRepositoryImpl.java b/core/core-domain/src/main/java/com/sponus/coredomain/domain/portfolio/repository/PortfolioCustomRepositoryImpl.java similarity index 95% rename from core/core-domain/src/main/java/com/sponus/coredomain/domain/portfolio/repository/PortfolioRepositoryImpl.java rename to core/core-domain/src/main/java/com/sponus/coredomain/domain/portfolio/repository/PortfolioCustomRepositoryImpl.java index 989383c5..d8f82c02 100644 --- a/core/core-domain/src/main/java/com/sponus/coredomain/domain/portfolio/repository/PortfolioRepositoryImpl.java +++ b/core/core-domain/src/main/java/com/sponus/coredomain/domain/portfolio/repository/PortfolioCustomRepositoryImpl.java @@ -17,7 +17,7 @@ import lombok.RequiredArgsConstructor; @RequiredArgsConstructor -public class PortfolioRepositoryImpl implements PortfolioCustomRepository { +public class PortfolioCustomRepositoryImpl implements PortfolioCustomRepository { private final JPAQueryFactory queryFactory; @Override diff --git a/core/core-domain/src/main/java/com/sponus/coredomain/domain/portfolio/repository/PortfolioRepository.java b/core/core-domain/src/main/java/com/sponus/coredomain/domain/portfolio/repository/PortfolioRepository.java index e94897c5..4cf2864b 100644 --- a/core/core-domain/src/main/java/com/sponus/coredomain/domain/portfolio/repository/PortfolioRepository.java +++ b/core/core-domain/src/main/java/com/sponus/coredomain/domain/portfolio/repository/PortfolioRepository.java @@ -4,5 +4,5 @@ import com.sponus.coredomain.domain.portfolio.Portfolio; -public interface PortfolioRepository extends JpaRepository { +public interface PortfolioRepository extends JpaRepository, PortfolioCustomRepository { } diff --git a/core/core-infra-db/src/main/resources/application-db.yml b/core/core-infra-db/src/main/resources/application-db.yml index 54624550..01a63297 100644 --- a/core/core-infra-db/src/main/resources/application-db.yml +++ b/core/core-infra-db/src/main/resources/application-db.yml @@ -9,9 +9,12 @@ spring: jpa: database: mysql hibernate: - ddl-auto: create + ddl-auto: create-drop open-in-view: false show-sql: true + properties: + hibernate: + default_batch_fetch_size: 100 --- spring.config.activate.on-profile: prod @@ -29,6 +32,9 @@ spring: ddl-auto: update open-in-view: false show-sql: true + properties: + hibernate: + default_batch_fetch_size: 100 --- spring.config.activate.on-profile: test @@ -42,8 +48,11 @@ spring: jpa: hibernate: ddl-auto: create-drop - open-in-view: false - show-sql: true + properties: + hibernate: + show_sql: true + format_sql: true + default_batch_fetch_size: 100 data: redis: