diff --git a/LearnsMate/src/main/java/intbyte4/learnsmate/member/controller/MemberController.java b/LearnsMate/src/main/java/intbyte4/learnsmate/member/controller/MemberController.java index 37e414dc..f750c2fe 100644 --- a/LearnsMate/src/main/java/intbyte4/learnsmate/member/controller/MemberController.java +++ b/LearnsMate/src/main/java/intbyte4/learnsmate/member/controller/MemberController.java @@ -1,19 +1,18 @@ package intbyte4.learnsmate.member.controller; -import intbyte4.learnsmate.member.domain.dto.FindSingleStudentDTO; -import intbyte4.learnsmate.member.domain.dto.FindSingleTutorDTO; -import intbyte4.learnsmate.member.domain.dto.MemberFilterRequestDTO; +import intbyte4.learnsmate.member.domain.dto.*; import intbyte4.learnsmate.member.domain.vo.request.RequestEditMemberVO; import intbyte4.learnsmate.member.domain.vo.request.RequestFilterMembertVO; import intbyte4.learnsmate.member.domain.vo.response.ResponseFindStudentDetailVO; import intbyte4.learnsmate.member.domain.vo.response.ResponseFindTutorDetailVO; import intbyte4.learnsmate.member.mapper.MemberMapper; import intbyte4.learnsmate.member.domain.MemberType; -import intbyte4.learnsmate.member.domain.dto.MemberDTO; import intbyte4.learnsmate.member.domain.vo.request.RequestSaveMemberVO; import intbyte4.learnsmate.member.domain.vo.response.ResponseFindMemberVO; import intbyte4.learnsmate.member.service.MemberFacade; import intbyte4.learnsmate.member.service.MemberService; +import intbyte4.learnsmate.voc.domain.dto.VOCPageResponse; +import intbyte4.learnsmate.voc.domain.vo.response.ResponseFindVOCVO; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -36,30 +35,23 @@ public class MemberController { // 1. 모든 학생 조회(member_flag가 true인 사람 + member_type이 STUDENT) @GetMapping("/students") - public ResponseEntity> findAllStudent() { + public ResponseEntity> findAllStudent( + @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "15") int size) { - List memberDTOList = memberService.findAllMemberByMemberType(MemberType.STUDENT); - - // DTO 리스트를 VO 리스트로 변환 - List responseVOList = memberDTOList.stream() - .map(memberMapper::fromMemberDTOtoResponseFindMemberVO) - .collect(Collectors.toList()); - - return ResponseEntity.status(HttpStatus.OK).body(responseVOList); + MemberPageResponse response + = memberService.findAllMemberByMemberType(page, size, MemberType.STUDENT); + return ResponseEntity.ok(response); } // 1-2. 모든 강사 조회(member_flag가 true + member_type이 TUTOR) @GetMapping("/tutors") - public ResponseEntity> findAllTutor() { - - List memberDTOList = memberService.findAllMemberByMemberType(MemberType.TUTOR); + public ResponseEntity> findAllTutor( + @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "15") int size) { - // DTO 리스트를 VO 리스트로 변환 - List responseVOList = memberDTOList.stream() - .map(memberMapper::fromMemberDTOtoResponseFindMemberVO) - .collect(Collectors.toList()); + MemberPageResponse response + = memberService.findAllMemberByMemberType(page, size, MemberType.TUTOR); - return ResponseEntity.status(HttpStatus.OK).body(responseVOList); + return ResponseEntity.ok(response); } // 2-1. 학생 단건 조회(member flag가 true + member_type이 STUDENT) @@ -122,31 +114,35 @@ public ResponseEntity deleteMember(@PathVariable("membercode") Long memb @Operation(summary = "직원 - 학생 필터링 검색") @PostMapping("/filter/student") - public ResponseEntity> findStudentByFilter(@RequestBody RequestFilterMembertVO request) { + public ResponseEntity> findStudentByFilter( + @RequestBody RequestFilterMembertVO request, + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "15") int size) { MemberFilterRequestDTO dto = memberMapper.fromRequestFilterVOtoMemberFilterRequestDTO(request); - List memberDTOList = memberService.filterStudent(dto); + dto.setMemberType(MemberType.STUDENT); - return ResponseEntity.status(HttpStatus.OK) - .body(memberDTOList.stream() - .map(memberMapper::fromMemberDTOtoResponseFindMemberVO) - .collect(Collectors.toList())); + MemberPageResponse response = memberService.filterStudent(dto, page, size); + + return ResponseEntity.ok(response); } @Operation(summary = "직원 - 강사 필터링 검색") @PostMapping("/filter/tutor") - public ResponseEntity findTutorByFilter(@RequestBody RequestFilterMembertVO request) { + public ResponseEntity findTutorByFilter( + @RequestBody RequestFilterMembertVO request, + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "15") int size) { MemberFilterRequestDTO dto = memberMapper.fromRequestFilterVOtoMemberFilterRequestDTO(request); - List memberDTOList = memberService.filterTutor(dto); + dto.setMemberType(MemberType.TUTOR); + + MemberPageResponse response = memberService.filterTutor(dto, page, size); - return ResponseEntity.status(HttpStatus.OK) - .body(memberDTOList.stream() - .map(memberMapper::fromMemberDTOtoResponseFindMemberVO) - .collect(Collectors.toList())); + return ResponseEntity.ok(response); } } diff --git a/LearnsMate/src/main/java/intbyte4/learnsmate/member/domain/dto/MemberPageResponse.java b/LearnsMate/src/main/java/intbyte4/learnsmate/member/domain/dto/MemberPageResponse.java new file mode 100644 index 00000000..89e58696 --- /dev/null +++ b/LearnsMate/src/main/java/intbyte4/learnsmate/member/domain/dto/MemberPageResponse.java @@ -0,0 +1,17 @@ +package intbyte4.learnsmate.member.domain.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; + +@Getter +@AllArgsConstructor +public class MemberPageResponse { + + private List content; + private long totalElements; + private int totalPages; + private int currentPage; + private int size; +} diff --git a/LearnsMate/src/main/java/intbyte4/learnsmate/member/mapper/MemberMapper.java b/LearnsMate/src/main/java/intbyte4/learnsmate/member/mapper/MemberMapper.java index b8be7106..8ea0222e 100644 --- a/LearnsMate/src/main/java/intbyte4/learnsmate/member/mapper/MemberMapper.java +++ b/LearnsMate/src/main/java/intbyte4/learnsmate/member/mapper/MemberMapper.java @@ -2,6 +2,7 @@ import intbyte4.learnsmate.campaign.domain.vo.request.RequestEditCampaignStudentVO; import intbyte4.learnsmate.campaign.domain.vo.request.RequestFindCampaignStudentVO; +import intbyte4.learnsmate.member.domain.MemberType; import intbyte4.learnsmate.member.domain.dto.FindSingleStudentDTO; import intbyte4.learnsmate.member.domain.dto.FindSingleTutorDTO; import intbyte4.learnsmate.member.domain.dto.MemberDTO; @@ -17,6 +18,7 @@ import org.springframework.stereotype.Component; import java.time.LocalDateTime; +import java.util.List; @Component public class MemberMapper{ @@ -202,4 +204,22 @@ public MemberFilterRequestDTO fromRequestFilterVOtoMemberFilterRequestDTO(Reques .createdEndDate(request.getCreatedEndDate()) .build(); } + + public ResponseFindMemberVO fromMemberToResponseFindMemberVO(Member member) { + return ResponseFindMemberVO.builder() + .memberCode(member.getMemberCode()) + .memberType(member.getMemberType()) + .memberEmail(member.getMemberEmail()) + .memberPassword(member.getMemberPassword()) + .memberName(member.getMemberName()) + .memberAge(member.getMemberAge()) + .memberPhone(member.getMemberPhone()) + .memberAddress(member.getMemberAddress()) + .memberBirth(member.getMemberBirth()) + .memberFlag(member.getMemberFlag()) + .memberDormantStatus(member.getMemberDormantStatus()) + .createdAt(member.getCreatedAt()) + .updatedAt(member.getUpdatedAt()) + .build(); + } } diff --git a/LearnsMate/src/main/java/intbyte4/learnsmate/member/repository/MemberRepository.java b/LearnsMate/src/main/java/intbyte4/learnsmate/member/repository/MemberRepository.java index a1db2dff..217d6d25 100644 --- a/LearnsMate/src/main/java/intbyte4/learnsmate/member/repository/MemberRepository.java +++ b/LearnsMate/src/main/java/intbyte4/learnsmate/member/repository/MemberRepository.java @@ -3,16 +3,16 @@ import intbyte4.learnsmate.member.domain.MemberType; import intbyte4.learnsmate.member.domain.entity.Member; import org.springframework.context.annotation.Primary; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import java.util.List; - @Repository @Primary public interface MemberRepository extends JpaRepository, MemberRepositoryCustom { - List findByMemberFlagTrueAndMemberType(MemberType memberType); + Page findByMemberFlagTrueAndMemberType(MemberType memberType, PageRequest pageable); Member findByMemberFlagTrueAndMemberCodeAndMemberType(Long memberCode, MemberType memberType); } diff --git a/LearnsMate/src/main/java/intbyte4/learnsmate/member/repository/MemberRepositoryCustom.java b/LearnsMate/src/main/java/intbyte4/learnsmate/member/repository/MemberRepositoryCustom.java index a6e6eb9d..33ce70e6 100644 --- a/LearnsMate/src/main/java/intbyte4/learnsmate/member/repository/MemberRepositoryCustom.java +++ b/LearnsMate/src/main/java/intbyte4/learnsmate/member/repository/MemberRepositoryCustom.java @@ -2,9 +2,11 @@ import intbyte4.learnsmate.member.domain.entity.Member; import intbyte4.learnsmate.member.domain.dto.MemberFilterRequestDTO; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import java.util.List; public interface MemberRepositoryCustom { - List searchBy(MemberFilterRequestDTO request); + Page searchBy(MemberFilterRequestDTO request, Pageable pageable); } diff --git a/LearnsMate/src/main/java/intbyte4/learnsmate/member/repository/MemberRepositoryImpl.java b/LearnsMate/src/main/java/intbyte4/learnsmate/member/repository/MemberRepositoryImpl.java index 5a06e709..3bc42923 100644 --- a/LearnsMate/src/main/java/intbyte4/learnsmate/member/repository/MemberRepositoryImpl.java +++ b/LearnsMate/src/main/java/intbyte4/learnsmate/member/repository/MemberRepositoryImpl.java @@ -2,12 +2,16 @@ import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; import intbyte4.learnsmate.member.domain.MemberType; import intbyte4.learnsmate.member.domain.entity.Member; import intbyte4.learnsmate.member.domain.entity.QMember; import intbyte4.learnsmate.member.domain.dto.MemberFilterRequestDTO; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; import java.time.LocalDateTime; import java.util.List; @@ -18,26 +22,39 @@ public class MemberRepositoryImpl implements MemberRepositoryCustom { private final JPAQueryFactory queryFactory; @Override - public List searchBy(MemberFilterRequestDTO request) { + public Page searchBy(MemberFilterRequestDTO request, Pageable pageable) { QMember member = QMember.member; + // BooleanBuilder를 사용해 필터 조건 생성 BooleanBuilder builder = new BooleanBuilder() .and(eqMemberCode(request.getMemberCode())) .and(eqMemberType(request.getMemberType())) .and(likeEmail(request.getMemberEmail())) .and(likeName(request.getMemberName())) - .and(betweenAge(request.getMemberStartAge(), request.getMemberEndAge())) // 나이 범위 + .and(betweenAge(request.getMemberStartAge(), request.getMemberEndAge())) .and(likePhone(request.getMemberPhone())) .and(likeAddress(request.getMemberAddress())) - .and(eqMemberFlag(request.getMemberFlag())) // 멤버 플래그 - .and(eqMemberDormantFlag(request.getMemberDormantFlag())) // 휴면 멤버 플래그 - .and(betweenBirth(request.getBirthStartDate(), request.getBirthEndDate())) // 생년월일 범위 - .and(betweenCreatedAt(request.getCreatedStartDate(), request.getCreatedEndDate())); // 생성일 범위 + .and(eqMemberFlag(request.getMemberFlag())) + .and(eqMemberDormantFlag(request.getMemberDormantFlag())) + .and(betweenBirth(request.getBirthStartDate(), request.getBirthEndDate())) + .and(betweenCreatedAt(request.getCreatedStartDate(), request.getCreatedEndDate())); - return queryFactory + // Query 생성 + JPAQuery query = queryFactory .selectFrom(member) - .where(builder) + .where(builder); + + // 전체 데이터 수 조회 + long total = query.fetchCount(); + + // 페이징 적용 + List members = query + .offset(pageable.getOffset()) // 시작 위치 + .limit(pageable.getPageSize()) // 페이지 크기 .fetch(); + + // PageImpl 객체 생성 + return new PageImpl<>(members, pageable, total); } // memberCode 검색 조건 diff --git a/LearnsMate/src/main/java/intbyte4/learnsmate/member/service/MemberService.java b/LearnsMate/src/main/java/intbyte4/learnsmate/member/service/MemberService.java index 3f298c4f..760a0e86 100644 --- a/LearnsMate/src/main/java/intbyte4/learnsmate/member/service/MemberService.java +++ b/LearnsMate/src/main/java/intbyte4/learnsmate/member/service/MemberService.java @@ -3,6 +3,8 @@ import intbyte4.learnsmate.common.exception.CommonException; import intbyte4.learnsmate.common.exception.StatusEnum; import intbyte4.learnsmate.member.domain.dto.MemberFilterRequestDTO; +import intbyte4.learnsmate.member.domain.dto.MemberPageResponse; +import intbyte4.learnsmate.member.domain.vo.response.ResponseFindMemberVO; import intbyte4.learnsmate.member.mapper.MemberMapper; import intbyte4.learnsmate.member.domain.MemberType; import intbyte4.learnsmate.member.domain.dto.MemberDTO; @@ -11,6 +13,9 @@ import intbyte4.learnsmate.member.repository.MemberRepositoryCustom; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import java.time.LocalDateTime; @@ -25,7 +30,6 @@ public class MemberService { private final MemberRepository memberRepository; private final MemberMapper memberMapper; - private final MemberRepositoryCustom memberRepositoryCustom; public void saveMember(MemberDTO memberDTO) { LocalDateTime now = LocalDateTime.now(); @@ -34,16 +38,26 @@ public void saveMember(MemberDTO memberDTO) { memberRepository.save(member); } - public List findAllMemberByMemberType(MemberType memberType) { + public MemberPageResponse findAllMemberByMemberType(int page, int size, MemberType memberType) { - List allMember = memberRepository.findByMemberFlagTrueAndMemberType(memberType); + // Pageable 객체 생성 + PageRequest pageable = PageRequest.of(page, size); + // 페이징 처리된 데이터 조회 + Page memberPage = memberRepository.findByMemberFlagTrueAndMemberType(memberType, pageable); - List memberDTOList = new ArrayList<>(); - for (Member member : allMember) { - memberDTOList.add(memberMapper.fromMembertoMemberDTO(member)); - } + // Member -> ResponseFindMemberVO 변환 + List responseVOList = memberPage.getContent().stream() + .map(memberMapper::fromMemberToResponseFindMemberVO) + .collect(Collectors.toList()); - return memberDTOList; + // MemberPageResponse 반환 + return new MemberPageResponse<>( + responseVOList, + memberPage.getTotalElements(), + memberPage.getTotalPages(), + memberPage.getNumber(), + memberPage.getSize() + ); } public MemberDTO findByStudentCode(Long memberCode) { @@ -93,20 +107,48 @@ public MemberDTO findById(Long memberCode){ } // 학생 필터링하는 서비스 코드 - public List filterStudent(MemberFilterRequestDTO dto){ - List memberList = memberRepositoryCustom.searchBy(dto); + public MemberPageResponse filterStudent(MemberFilterRequestDTO dto, int page, int size){ + // Pageable 객체 생성 + Pageable pageable = PageRequest.of(page, size); + + // 필터 조건과 페이징 처리된 데이터 조회 + Page memberPage = memberRepository.searchBy(dto, pageable); - return memberList.stream() - .map(memberMapper::fromMembertoMemberDTO) + // DTO 리스트로 변환 + List memberVOList = memberPage.getContent().stream() + .map(memberMapper::fromMemberToResponseFindMemberVO) .collect(Collectors.toList()); + + // MemberPageResponse 생성 후 반환 + return new MemberPageResponse<>( + memberVOList, // 데이터 리스트 + memberPage.getTotalElements(), // 전체 데이터 수 + memberPage.getTotalPages(), // 전체 페이지 수 + memberPage.getNumber() + 1, // 현재 페이지 (0-based → 1-based) + memberPage.getSize() // 페이지 크기 + ); } // 강사 필터링하는 코드 -> 강사 필터링은 조건이 더 적음(멤버에 다 포함됨) - public List filterTutor(MemberFilterRequestDTO dto) { - List memberList = memberRepositoryCustom.searchBy(dto); + public MemberPageResponse filterTutor(MemberFilterRequestDTO dto, int page, int size){ + // Pageable 객체 생성 + Pageable pageable = PageRequest.of(page, size); + + // 필터 조건과 페이징 처리된 데이터 조회 + Page memberPage = memberRepository.searchBy(dto, pageable); - return memberList.stream() - .map(memberMapper::fromMembertoMemberDTO) + // DTO 리스트로 변환 + List memberVOList = memberPage.getContent().stream() + .map(memberMapper::fromMemberToResponseFindMemberVO) .collect(Collectors.toList()); + + // MemberPageResponse 생성 후 반환 + return new MemberPageResponse<>( + memberVOList, // 데이터 리스트 + memberPage.getTotalElements(), // 전체 데이터 수 + memberPage.getTotalPages(), // 전체 페이지 수 + memberPage.getNumber() + 1, // 현재 페이지 (0-based → 1-based) + memberPage.getSize() // 페이지 크기 + ); } }