[회원 목록 조회 기능 개선] 회원 목록 조회 API에 페이지네이션 기능을 추가하고, 검색 조건을 위한 DTO 및 관련 메서드를 구현하여 효율적인 데이터 조회를 지원. README.md에 DTO 네이밍 규칙을 추가하여 코드 일관성을 강화.
This commit is contained in:
28
README.md
28
README.md
@@ -353,7 +353,33 @@ public class Member extends BaseEntity {
|
||||
}
|
||||
```
|
||||
|
||||
### 11. 데이터베이스 스키마
|
||||
### 11. DTO 네이밍 규칙
|
||||
|
||||
#### 기본 원칙
|
||||
|
||||
- **API 계층**: `Dto` 접미사 유지
|
||||
- **Service 계층**: 역할에 따라 `Dto` 접미사 결정
|
||||
|
||||
#### 사용 예시
|
||||
|
||||
```java
|
||||
// API 계층 (Dto 유지)
|
||||
CreateMemberRequestDto, GetMemberResponseDto
|
||||
|
||||
// Service 계층 - 비즈니스 핵심 (Dto 유지)
|
||||
MemberDto
|
||||
|
||||
// Service 계층 - 내부 전달 (Dto 제거)
|
||||
MemberSearchCondition
|
||||
```
|
||||
|
||||
#### 핵심 규칙
|
||||
|
||||
- **API 노출**: `Dto` 유지
|
||||
- **비즈니스 핵심**: `Dto` 유지
|
||||
- **내부 전달**: `Dto` 제거
|
||||
|
||||
### 12. 데이터베이스 스키마
|
||||
|
||||
**데이터베이스 테이블 구조는 `ddl/schema_entity.sql`에 정의되어 있습니다.**
|
||||
|
||||
|
@@ -11,6 +11,11 @@ import com.bio.bio_backend.domain.base.member.dto.MemberDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.GetMemberResponseDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.CreateMemberRequestDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.CreateMemberResponseDto;
|
||||
|
||||
import com.bio.bio_backend.domain.base.member.dto.MemberSearchCondition;
|
||||
import com.bio.bio_backend.domain.base.member.dto.GetMembersRequestDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.GetMembersPagedRequestDto;
|
||||
import com.bio.bio_backend.global.dto.PagedResult;
|
||||
import com.bio.bio_backend.domain.base.member.service.MemberService;
|
||||
import com.bio.bio_backend.domain.base.member.mapper.MemberMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -26,7 +31,7 @@ import com.bio.bio_backend.global.utils.SecurityUtils;
|
||||
import com.bio.bio_backend.global.utils.JwtUtils;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -60,21 +65,33 @@ public class MemberController {
|
||||
@LogExecution("회원 목록 조회")
|
||||
@Operation(summary = "회원 목록 조회", description = "활성화된 모든 회원의 목록을 조회합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "회원 목록 조회 성공")
|
||||
@ApiResponse(responseCode = "200", description = "회원 목록 조회 성공"),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 파라미터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponseDto<List<GetMemberResponseDto>>> getMembers() {
|
||||
try {
|
||||
List<GetMemberResponseDto> members = memberService.selectMemberListForDisplay(new HashMap<>());
|
||||
ApiResponseDto<List<GetMemberResponseDto>> apiResponse = ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS, members);
|
||||
log.info("전체 회원 목록 조회 완료: {}명", members.size());
|
||||
|
||||
return ResponseEntity.ok(apiResponse);
|
||||
} catch (Exception e) {
|
||||
log.error("회원 목록 조회 중 오류 발생: {}", e.getMessage());
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(ApiResponseDto.fail(ApiResponseCode.COMMON_INTERNAL_SERVER_ERROR));
|
||||
}
|
||||
public ResponseEntity<ApiResponseDto<List<GetMemberResponseDto>>> getMembers(@ModelAttribute GetMembersRequestDto requestDto) {
|
||||
MemberSearchCondition condition = memberMapper.toSearchCondition(requestDto);
|
||||
List<GetMemberResponseDto> members = memberService.getMembers(condition);
|
||||
ApiResponseDto<List<GetMemberResponseDto>> apiResponse = ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS, members);
|
||||
log.info("회원 목록 조회 완료: {}명", members.size());
|
||||
|
||||
return ResponseEntity.ok(apiResponse);
|
||||
}
|
||||
|
||||
@LogExecution("회원 목록 조회 (페이지네이션)")
|
||||
@Operation(summary = "회원 목록 조회 (페이지네이션)", description = "페이지네이션을 적용한 회원 목록을 조회합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "회원 목록 조회 성공"),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 파라미터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@GetMapping("/paged")
|
||||
public ResponseEntity<ApiResponseDto<PagedResult<GetMemberResponseDto>>> getMembersPaged(@ModelAttribute GetMembersPagedRequestDto requestDto) {
|
||||
MemberSearchCondition condition = memberMapper.toSearchCondition(requestDto);
|
||||
PagedResult<GetMemberResponseDto> pagedMembers = memberService.getMembersPaged(condition, requestDto.getPage(), requestDto.getSize());
|
||||
ApiResponseDto<PagedResult<GetMemberResponseDto>> apiResponse = ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS, pagedMembers);
|
||||
log.info("페이지네이션된 회원 목록 조회 완료: 페이지={}, 크기={}, 전체={}명", requestDto.getPage(), requestDto.getSize(), pagedMembers.getTotalElements());
|
||||
|
||||
return ResponseEntity.ok(apiResponse);
|
||||
}
|
||||
|
||||
@LogExecution("로그아웃")
|
||||
@@ -84,18 +101,12 @@ public class MemberController {
|
||||
})
|
||||
@PostMapping("/logout")
|
||||
public ResponseEntity<ApiResponseDto<Void>> logout(HttpServletResponse response) {
|
||||
try {
|
||||
String userId = SecurityUtils.getCurrentUserId();
|
||||
memberService.deleteRefreshToken(userId);
|
||||
// 모든 토큰 쿠키 삭제
|
||||
jwtUtils.deleteAllTokenCookies(response);
|
||||
log.info("사용자 로그아웃 완료: {}", userId);
|
||||
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS));
|
||||
} catch (Exception e) {
|
||||
log.error("로그아웃 처리 중 오류 발생: {}", e.getMessage());
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(ApiResponseDto.fail(ApiResponseCode.COMMON_INTERNAL_SERVER_ERROR));
|
||||
}
|
||||
String userId = SecurityUtils.getCurrentUserId();
|
||||
memberService.deleteRefreshToken(userId);
|
||||
// 모든 토큰 쿠키 삭제
|
||||
jwtUtils.deleteAllTokenCookies(response);
|
||||
log.info("사용자 로그아웃 완료: {}", userId);
|
||||
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS));
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,25 @@
|
||||
package com.bio.bio_backend.domain.base.member.dto;
|
||||
|
||||
import com.bio.bio_backend.global.dto.BasePagedRequestDto;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 회원 목록 조회 요청용 DTO (검색 조건 + 페이지네이션 포함)
|
||||
* GET /members/paged
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class GetMembersPagedRequestDto extends BasePagedRequestDto {
|
||||
|
||||
private String userId;
|
||||
private String name;
|
||||
private String email;
|
||||
private String searchKeyword;
|
||||
private String createdDateFrom;
|
||||
private String createdDateTo;
|
||||
private String lastLoginFrom;
|
||||
private String lastLoginTo;
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package com.bio.bio_backend.domain.base.member.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 회원 목록 조회 요청용 DTO (검색 조건만 포함)
|
||||
* GET /members
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class GetMembersRequestDto {
|
||||
|
||||
private String userId;
|
||||
private String name;
|
||||
private String email;
|
||||
private String searchKeyword;
|
||||
private String createdDateFrom;
|
||||
private String createdDateTo;
|
||||
private String lastLoginFrom;
|
||||
private String lastLoginTo;
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
package com.bio.bio_backend.domain.base.member.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 회원 검색 조건
|
||||
*/
|
||||
@Builder
|
||||
@Getter
|
||||
@Setter
|
||||
public class MemberSearchCondition {
|
||||
|
||||
private String userId;
|
||||
private String name;
|
||||
private String email;
|
||||
private String searchKeyword;
|
||||
private String createdDateFrom;
|
||||
private String createdDateTo;
|
||||
private String lastLoginFrom;
|
||||
private String lastLoginTo;
|
||||
}
|
@@ -4,6 +4,9 @@ import com.bio.bio_backend.domain.base.member.dto.CreateMemberRequestDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.CreateMemberResponseDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.LoginResponseDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.MemberDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.MemberSearchCondition;
|
||||
import com.bio.bio_backend.domain.base.member.dto.GetMembersRequestDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.GetMembersPagedRequestDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.GetMemberResponseDto;
|
||||
import com.bio.bio_backend.domain.base.member.entity.Member;
|
||||
import com.bio.bio_backend.global.annotation.IgnoreBaseEntityMapping;
|
||||
@@ -68,4 +71,14 @@ public interface MemberMapper {
|
||||
* Member 엔티티 리스트를 GetMemberResponseDto 리스트로 변환 (민감한 정보 제외)
|
||||
*/
|
||||
List<GetMemberResponseDto> toGetMemberResponseDtoList(List<Member> members);
|
||||
|
||||
/**
|
||||
* GetMembersRequestDto를 MemberSearchCondition으로 변환
|
||||
*/
|
||||
MemberSearchCondition toSearchCondition(GetMembersRequestDto request);
|
||||
|
||||
/**
|
||||
* GetMembersPagedRequestDto를 MemberSearchCondition으로 변환
|
||||
*/
|
||||
MemberSearchCondition toSearchCondition(GetMembersPagedRequestDto request);
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
package com.bio.bio_backend.domain.base.member.repository;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@@ -14,4 +16,7 @@ public interface MemberRepository extends JpaRepository<Member, Long>, MemberRep
|
||||
|
||||
// 활성화된 회원 목록 조회
|
||||
List<Member> findByUseFlagTrue();
|
||||
|
||||
// 활성화된 회원 목록 조회 (페이지네이션)
|
||||
Page<Member> findByUseFlagTrue(Pageable pageable);
|
||||
}
|
@@ -1,6 +1,10 @@
|
||||
package com.bio.bio_backend.domain.base.member.repository;
|
||||
|
||||
import com.bio.bio_backend.domain.base.member.dto.MemberSearchCondition;
|
||||
import com.bio.bio_backend.domain.base.member.entity.Member;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface MemberRepositoryCustom {
|
||||
@@ -12,4 +16,21 @@ public interface MemberRepositoryCustom {
|
||||
* @return Optional<Member> 회원 정보 (없으면 empty)
|
||||
*/
|
||||
Optional<Member> findActiveMemberByUserId(String userId);
|
||||
|
||||
/**
|
||||
* QueryDSL을 사용한 회원 목록 조회 (검색 조건 + 페이징)
|
||||
*
|
||||
* @param condition 검색 조건
|
||||
* @param pageable 페이징 정보
|
||||
* @return Page<Member> 검색된 회원 목록
|
||||
*/
|
||||
Page<Member> findMembers(MemberSearchCondition condition, Pageable pageable);
|
||||
|
||||
/**
|
||||
* QueryDSL을 사용한 회원 목록 조회 (검색 조건)
|
||||
*
|
||||
* @param condition 검색 조건
|
||||
* @return List<Member> 검색된 회원 목록
|
||||
*/
|
||||
List<Member> findMembers(MemberSearchCondition condition);
|
||||
}
|
||||
|
@@ -1,11 +1,20 @@
|
||||
package com.bio.bio_backend.domain.base.member.repository;
|
||||
|
||||
import com.bio.bio_backend.domain.base.member.dto.MemberSearchCondition;
|
||||
import com.bio.bio_backend.domain.base.member.entity.Member;
|
||||
import com.bio.bio_backend.domain.base.member.entity.QMember;
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
@@ -30,4 +39,91 @@ public class MemberRepositoryImpl implements MemberRepositoryCustom {
|
||||
|
||||
return Optional.ofNullable(foundMember);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Member> findMembers(MemberSearchCondition condition, Pageable pageable) {
|
||||
BooleanBuilder builder = buildSearchConditions(condition);
|
||||
|
||||
List<Member> members = queryFactory
|
||||
.selectFrom(member)
|
||||
.where(builder)
|
||||
.orderBy(member.createdAt.desc())
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize())
|
||||
.fetch();
|
||||
|
||||
Long total = queryFactory
|
||||
.select(member.count())
|
||||
.from(member)
|
||||
.where(builder)
|
||||
.fetchOne();
|
||||
|
||||
return new PageImpl<>(members, pageable, total);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Member> findMembers(MemberSearchCondition condition) {
|
||||
return queryFactory
|
||||
.selectFrom(member)
|
||||
.where(buildSearchConditions(condition))
|
||||
.orderBy(member.createdAt.desc())
|
||||
.fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 검색 조건들을 조합하여 BooleanBuilder 생성
|
||||
*/
|
||||
private BooleanBuilder buildSearchConditions(MemberSearchCondition condition) {
|
||||
BooleanBuilder builder = new BooleanBuilder();
|
||||
|
||||
// 기본 조건: useFlag = true (활성화된 회원만 조회)
|
||||
builder.and(member.useFlag.eq(true));
|
||||
|
||||
// 사용자 ID (정확 일치)
|
||||
if (StringUtils.hasText(condition.getUserId())) {
|
||||
builder.and(member.userId.eq(condition.getUserId()));
|
||||
}
|
||||
|
||||
// 이름 (부분 일치)
|
||||
if (StringUtils.hasText(condition.getName())) {
|
||||
builder.and(member.name.containsIgnoreCase(condition.getName()));
|
||||
}
|
||||
|
||||
// 이메일 (부분 일치)
|
||||
if (StringUtils.hasText(condition.getEmail())) {
|
||||
builder.and(member.email.containsIgnoreCase(condition.getEmail()));
|
||||
}
|
||||
|
||||
// 통합 검색 키워드 (이름, 이메일, 사용자ID에서 검색)
|
||||
if (StringUtils.hasText(condition.getSearchKeyword())) {
|
||||
String keyword = condition.getSearchKeyword();
|
||||
builder.and(member.name.containsIgnoreCase(keyword)
|
||||
.or(member.email.containsIgnoreCase(keyword))
|
||||
.or(member.userId.containsIgnoreCase(keyword)));
|
||||
}
|
||||
|
||||
|
||||
// 생성일 범위
|
||||
if (StringUtils.hasText(condition.getCreatedDateFrom())) {
|
||||
LocalDate fromDate = LocalDate.parse(condition.getCreatedDateFrom(), DateTimeFormatter.ISO_LOCAL_DATE);
|
||||
builder.and(member.createdAt.goe(fromDate.atStartOfDay()));
|
||||
}
|
||||
if (StringUtils.hasText(condition.getCreatedDateTo())) {
|
||||
LocalDate toDate = LocalDate.parse(condition.getCreatedDateTo(), DateTimeFormatter.ISO_LOCAL_DATE);
|
||||
builder.and(member.createdAt.loe(toDate.atTime(23, 59, 59)));
|
||||
}
|
||||
|
||||
// 마지막 로그인 범위
|
||||
if (StringUtils.hasText(condition.getLastLoginFrom())) {
|
||||
LocalDate fromDate = LocalDate.parse(condition.getLastLoginFrom(), DateTimeFormatter.ISO_LOCAL_DATE);
|
||||
builder.and(member.lastLoginAt.goe(fromDate.atStartOfDay()));
|
||||
}
|
||||
if (StringUtils.hasText(condition.getLastLoginTo())) {
|
||||
LocalDate toDate = LocalDate.parse(condition.getLastLoginTo(), DateTimeFormatter.ISO_LOCAL_DATE);
|
||||
builder.and(member.lastLoginAt.loe(toDate.atTime(23, 59, 59)));
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -5,9 +5,10 @@ import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
import com.bio.bio_backend.domain.base.member.dto.MemberDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.GetMemberResponseDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.MemberSearchCondition;
|
||||
import com.bio.bio_backend.global.dto.PagedResult;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface MemberService extends UserDetailsService {
|
||||
|
||||
@@ -20,13 +21,20 @@ public interface MemberService extends UserDetailsService {
|
||||
void deleteRefreshToken(String id);
|
||||
|
||||
void updateMember(MemberDto member);
|
||||
|
||||
List<MemberDto> selectMemberList(Map<String, String> params);
|
||||
|
||||
/**
|
||||
* 회원 목록 조회 (민감한 정보 제외)
|
||||
* @param params 검색 파라미터
|
||||
* 검색 조건에 따른 회원 목록 조회
|
||||
* @param condition 검색 조건
|
||||
* @return GetMemberResponseDto 리스트
|
||||
*/
|
||||
List<GetMemberResponseDto> selectMemberListForDisplay(Map<String, String> params);
|
||||
List<GetMemberResponseDto> getMembers(MemberSearchCondition condition);
|
||||
|
||||
/**
|
||||
* 페이지네이션된 회원 목록 조회
|
||||
* @param condition 검색 조건
|
||||
* @param page 페이지 번호
|
||||
* @param size 페이지 크기
|
||||
* @return PagedResult<GetMemberResponseDto> 페이지네이션된 회원 목록
|
||||
*/
|
||||
PagedResult<GetMemberResponseDto> getMembersPaged(MemberSearchCondition condition, int page, int size);
|
||||
}
|
||||
|
@@ -2,6 +2,8 @@ package com.bio.bio_backend.domain.base.member.service;
|
||||
|
||||
import com.bio.bio_backend.domain.base.member.dto.MemberDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.GetMemberResponseDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.MemberSearchCondition;
|
||||
import com.bio.bio_backend.global.dto.PagedResult;
|
||||
import com.bio.bio_backend.domain.base.member.entity.Member;
|
||||
import com.bio.bio_backend.domain.base.member.mapper.MemberMapper;
|
||||
import com.bio.bio_backend.domain.base.member.repository.MemberRepository;
|
||||
@@ -13,12 +15,15 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@@ -89,18 +94,20 @@ public class MemberServiceImpl implements MemberService {
|
||||
member.setRefreshToken(null);
|
||||
memberRepository.save(member);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MemberDto> selectMemberList(Map<String, String> params) {
|
||||
List<Member> members = memberRepository.findByUseFlagTrue();
|
||||
|
||||
return memberMapper.toMemberDtoList(members);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GetMemberResponseDto> selectMemberListForDisplay(Map<String, String> params) {
|
||||
List<Member> members = memberRepository.findByUseFlagTrue();
|
||||
public List<GetMemberResponseDto> getMembers(MemberSearchCondition condition) {
|
||||
List<Member> members = memberRepository.findMembers(condition);
|
||||
|
||||
return memberMapper.toGetMemberResponseDtoList(members);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PagedResult<GetMemberResponseDto> getMembersPaged(MemberSearchCondition condition, int page, int size) {
|
||||
Pageable pageable = PageRequest.of(page, size);
|
||||
Page<Member> memberPage = memberRepository.findMembers(condition, pageable);
|
||||
List<GetMemberResponseDto> members = memberMapper.toGetMemberResponseDtoList(memberPage.getContent());
|
||||
|
||||
return PagedResult.of(memberPage, members);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,28 @@
|
||||
package com.bio.bio_backend.global.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.Max;
|
||||
|
||||
/**
|
||||
* 기본 페이징 요청 DTO
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BasePagedRequestDto {
|
||||
|
||||
@Min(value = 0, message = "페이지 번호는 0 이상이어야 합니다")
|
||||
@Builder.Default
|
||||
private int page = 0;
|
||||
|
||||
@Min(value = 1, message = "페이지 크기는 1 이상이어야 합니다")
|
||||
@Max(value = 100, message = "페이지 크기는 100 이하여야 합니다")
|
||||
@Builder.Default
|
||||
private int size = 10;
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
package com.bio.bio_backend.global.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* 기본 페이징 응답 DTO
|
||||
* 모든 페이징 응답에서 공통으로 사용되는 필드들을 포함
|
||||
*/
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
public class BasePagedResponseDto {
|
||||
|
||||
private int currentPage; // 현재 페이지
|
||||
private int totalPages; // 전체 페이지 수
|
||||
private long totalElements; // 전체 요소 수
|
||||
private int size; // 페이지 크기
|
||||
private boolean hasNext; // 다음 페이지 존재 여부
|
||||
private boolean hasPrevious; // 이전 페이지 존재 여부
|
||||
private boolean isFirst; // 첫 번째 페이지 여부
|
||||
private boolean isLast; // 마지막 페이지 여부
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
package com.bio.bio_backend.global.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.domain.Page;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 페이지네이션된 결과를 담는 제네릭 클래스
|
||||
* @param <T> 페이지네이션할 데이터의 타입
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class PagedResult<T> extends BasePagedResponseDto {
|
||||
|
||||
private List<T> content;
|
||||
|
||||
public static <T> PagedResult<T> of(Page<?> page, List<T> content) {
|
||||
PagedResult<T> result = new PagedResult<>();
|
||||
result.setContent(content);
|
||||
result.setCurrentPage(page.getNumber());
|
||||
result.setTotalPages(page.getTotalPages());
|
||||
result.setTotalElements(page.getTotalElements());
|
||||
result.setSize(page.getSize());
|
||||
result.setHasNext(page.hasNext());
|
||||
result.setHasPrevious(page.hasPrevious());
|
||||
result.setFirst(page.isFirst());
|
||||
result.setLast(page.isLast());
|
||||
return result;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user