Skip to content

Commit a991648

Browse files
committed
2 parents 23467fb + 697313b commit a991648

File tree

8 files changed

+324
-0
lines changed

8 files changed

+324
-0
lines changed

back/src/main/java/com/back/domain/member/member/controller/AdmMemberController.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.back.domain.member.member.controller;
22

3+
import com.back.domain.member.member.dto.MemberPagingResponse;
34
import com.back.domain.member.member.dto.MemberSearchResponse;
45
import com.back.domain.member.member.dto.MentorUpdateRequest;
56
import com.back.domain.member.member.dto.MenteeUpdateRequest;
@@ -21,6 +22,16 @@ public class AdmMemberController {
2122
private final Rq rq;
2223

2324

25+
@GetMapping
26+
@Operation(summary = "회원 목록 조회 (관리자) - 페이징, 페이지는 기본으로 10개씩 조회")
27+
@PreAuthorize("hasRole('ADMIN')")
28+
public RsData<MemberPagingResponse> getAllMembers(
29+
@RequestParam(defaultValue = "0") int page,
30+
@RequestParam(defaultValue = "10") int size) {
31+
MemberPagingResponse members = memberService.getAllMembersForAdmin(page, size);
32+
return new RsData<>("200-18", "회원 목록 조회 성공", members);
33+
}
34+
2435
@GetMapping("/{memberId}")
2536
@Operation(summary = "회원 상세 조회 (관리자)")
2637
@PreAuthorize("hasRole('ADMIN')")
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.back.domain.member.member.dto;
2+
3+
import com.back.domain.member.member.entity.Member;
4+
5+
import java.time.LocalDateTime;
6+
7+
public record MemberListResponse(
8+
Long id,
9+
String email,
10+
String name,
11+
String nickname,
12+
Member.Role role,
13+
Boolean isDeleted,
14+
LocalDateTime createdAt
15+
) {
16+
public static MemberListResponse from(Member member) {
17+
return new MemberListResponse(
18+
member.getId(),
19+
member.getEmail(),
20+
member.getName(),
21+
member.getNickname(),
22+
member.getRole(),
23+
member.getIsDeleted(),
24+
member.getCreateDate()
25+
);
26+
}
27+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.back.domain.member.member.dto;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import org.springframework.data.domain.Page;
5+
6+
import java.util.List;
7+
8+
public record MemberPagingResponse(
9+
@Schema(description = "회원 목록")
10+
List<MemberListResponse> members,
11+
@Schema(description = "현재 페이지 (0부터 시작)")
12+
int currentPage,
13+
@Schema(description = "총 페이지")
14+
int totalPage,
15+
@Schema(description = "총 개수")
16+
long totalElements,
17+
@Schema(description = "다음 페이지 존재 여부")
18+
boolean hasNext
19+
) {
20+
21+
public static MemberPagingResponse from(Page<MemberListResponse> page) {
22+
return new MemberPagingResponse(
23+
page.getContent(),
24+
page.getNumber(),
25+
page.getTotalPages(),
26+
page.getTotalElements(),
27+
page.hasNext()
28+
);
29+
}
30+
}

back/src/main/java/com/back/domain/member/member/repository/MemberRepository.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.back.domain.member.member.repository;
22

33
import com.back.domain.member.member.entity.Member;
4+
import org.springframework.data.domain.Page;
5+
import org.springframework.data.domain.Pageable;
46
import org.springframework.data.jpa.repository.JpaRepository;
57
import org.springframework.data.jpa.repository.Query;
68
import org.springframework.data.repository.query.Param;
@@ -27,4 +29,7 @@ public interface MemberRepository extends JpaRepository<Member, Long> {
2729

2830
@Query("SELECT m FROM Member m WHERE m.id = :id")
2931
Optional<Member> findByIdIncludingDeleted(@Param("id") Long id);
32+
33+
@Query("SELECT m FROM Member m ORDER BY m.createDate DESC")
34+
Page<Member> findAllIncludingDeleted(Pageable pageable);
3035
}

back/src/main/java/com/back/domain/member/member/service/MemberService.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
import com.back.domain.member.mentor.repository.MentorRepository;
1212
import com.back.global.exception.ServiceException;
1313
import lombok.RequiredArgsConstructor;
14+
import org.springframework.data.domain.Page;
15+
import org.springframework.data.domain.PageRequest;
16+
import org.springframework.data.domain.Pageable;
1417
import org.springframework.security.crypto.password.PasswordEncoder;
1518
import org.springframework.stereotype.Service;
1619
import org.springframework.transaction.annotation.Transactional;
@@ -276,6 +279,14 @@ public void updateMentor(Member currentUser, MentorUpdateRequest request) {
276279
}
277280

278281

282+
public MemberPagingResponse getAllMembersForAdmin(int page, int size) {
283+
Pageable pageable = PageRequest.of(page, size);
284+
Page<Member> members = memberRepository.findAllIncludingDeleted(pageable);
285+
286+
Page<MemberListResponse> memberPage = members.map(MemberListResponse::from);
287+
return MemberPagingResponse.from(memberPage);
288+
}
289+
279290
public MemberSearchResponse getMemberForAdmin(Long memberId) {
280291
Member member = memberRepository.findByIdIncludingDeleted(memberId)
281292
.orElseThrow(() -> new ServiceException("404-1", "존재하지 않는 회원입니다."));

back/src/main/java/com/back/global/globalExceptionHandler/GlobalExceptionHandler.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@
22

33
import com.back.global.exception.ServiceException;
44
import com.back.global.rsData.RsData;
5+
import io.sentry.Sentry;
56
import jakarta.validation.ConstraintViolationException;
67
import lombok.RequiredArgsConstructor;
8+
import lombok.extern.slf4j.Slf4j;
79
import org.springframework.http.ResponseEntity;
810
import org.springframework.http.converter.HttpMessageNotReadableException;
911
import org.springframework.security.authorization.AuthorizationDeniedException;
1012
import org.springframework.validation.FieldError;
1113
import org.springframework.web.bind.MethodArgumentNotValidException;
1214
import org.springframework.web.bind.MissingRequestHeaderException;
15+
import org.springframework.web.bind.MissingServletRequestParameterException;
1316
import org.springframework.web.bind.annotation.ExceptionHandler;
1417
import org.springframework.web.bind.annotation.ResponseStatus;
1518
import org.springframework.web.bind.annotation.RestControllerAdvice;
@@ -20,6 +23,7 @@
2023

2124
import static org.springframework.http.HttpStatus.*;
2225

26+
@Slf4j
2327
@RestControllerAdvice
2428
@RequiredArgsConstructor
2529
public class GlobalExceptionHandler {
@@ -106,6 +110,18 @@ public ResponseEntity<RsData<Void>> handle(MissingRequestHeaderException ex) {
106110
);
107111
}
108112

113+
@ExceptionHandler(MissingServletRequestParameterException.class)
114+
public ResponseEntity<RsData<Void>> handle(MissingServletRequestParameterException ex) {
115+
String message = String.format("필수 파라미터 '%s'(이)가 누락되었습니다.", ex.getParameterName());
116+
return new ResponseEntity<>(
117+
new RsData<>(
118+
"400-1",
119+
message
120+
),
121+
BAD_REQUEST
122+
);
123+
}
124+
109125
// @PreAuthorize 권한 에러
110126
@ExceptionHandler(AuthorizationDeniedException.class)
111127
public ResponseEntity<RsData<Void>> handle(AuthorizationDeniedException ex) {
@@ -131,4 +147,18 @@ public ResponseEntity<RsData<Void>> handle(ServiceException ex) {
131147
.getStatusCode()
132148
);
133149
}
150+
151+
@ExceptionHandler(Exception.class)
152+
public ResponseEntity<RsData<Void>> handle(Exception ex) {
153+
log.error("Unhandled exception occurred", ex);
154+
Sentry.captureException(ex);
155+
156+
return new ResponseEntity<>(
157+
new RsData<>(
158+
"500-1",
159+
"서버 오류가 발생했습니다."
160+
),
161+
INTERNAL_SERVER_ERROR
162+
);
163+
}
134164
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.back.global.initData;
2+
3+
import com.back.domain.member.member.entity.Member;
4+
import com.back.domain.member.member.repository.MemberRepository;
5+
import lombok.RequiredArgsConstructor;
6+
import lombok.extern.slf4j.Slf4j;
7+
import org.springframework.boot.ApplicationRunner;
8+
import org.springframework.context.annotation.Bean;
9+
import org.springframework.context.annotation.Profile;
10+
import org.springframework.security.crypto.password.PasswordEncoder;
11+
import org.springframework.stereotype.Component;
12+
13+
@Component
14+
@Profile("dev")
15+
@RequiredArgsConstructor
16+
@Slf4j
17+
public class AdminInitData {
18+
19+
private final MemberRepository memberRepository;
20+
private final PasswordEncoder passwordEncoder;
21+
22+
@Bean
23+
public ApplicationRunner initAdmin() {
24+
return args -> {
25+
if (memberRepository.findByEmail("[email protected]").isEmpty()) {
26+
Member admin = new Member(
27+
28+
passwordEncoder.encode("admin1234"),
29+
"관리자",
30+
"admin",
31+
Member.Role.ADMIN
32+
);
33+
memberRepository.save(admin);
34+
log.info("어드민 계정이 생성되었습니다. (email: [email protected], password: admin1234)");
35+
} else {
36+
log.info("어드민 계정이 이미 존재합니다.");
37+
}
38+
};
39+
}
40+
41+
}

0 commit comments

Comments
 (0)