[ 작업한 내용 ]
< 관리자: 사용자 전체 목록 조회 >
# AdminUserListResDTO
- UserListResDTO -> AdminUserListResDTO 네이밍 변경
- 사용자 고유번호, 아이디, 이메일, 권한, 가입날짜, 마지막 접속날짜, 상태 (id, username, email, role, joinDate, lastLoginDate, status)
* 필드는 그대로, 네이밍만 변경
@Getter
public class AdminUserListResDTO {
private long id;
private String username;
private String email;
private Role role;
private LocalDateTime joinDate;
private LocalDateTime lastLoginDate;
private UserStatus status;
public AdminUserListResDTO(User user) {
this.id = user.getId();
this.username = user.getUsername();
this.email = user.getEmail();
this.role = user.getRole();
this.joinDate = user.getJoinDate();
this.lastLoginDate = user.getLastLoginDate();
this.status = user.getStatus();
}
}
# AdminUserController
- GET /api/v1/admin/users 로 요청
- page, size, @AuthenticationPrincipal User user 파라미터
- Service 계층으로 page, size, user.getId()를 전달
- 클라이언트 측으로 성공 메시지와 반환 결과를 ApiResponse.seuccess()로 감싸서 응답
* 관리자 권한 확인을 위해 @AuthenticationPrincipal을 추가. 인증 객체는 커스텀한 User 엔티티로 생성.
@GetMapping()
public ResponseEntity<?> allListUsers(
@RequestParam(name = "page", defaultValue = "0") int page,
@RequestParam(name = "size", defaultValue = "10") int size,
@AuthenticationPrincipal User user) {
// 서비스로직
Page<AdminUserListResDTO> responseDTO = adminUserService.allListUsers(page, size, user.getId());
// 성공 메시지
String message = messageProvider.getMessage(UserSuccessCode.USER_LIST_FETCHED.getMessage());
// 응답
return ResponseEntity
.status(UserSuccessCode.USER_LIST_FETCHED.getHttpStatus())
.body(ApiResponse.success(
UserSuccessCode.USER_LIST_FETCHED,
message,
responseDTO));
}
# AdminUserService
- UserService에 통합으로 사용자, 관리자 기능이 작성되어 있는데 관리자 기능은 AdminUserService로 옮김.
- userRepository.findById(userId)로 유효한 사용자인지 조회를 하고 유효하지 않으면 UserErrorCode.USER_NOT_FOUND 예외를 발생.
- user.getRole() != Role.ROLE_ADMIN 로 권한을 체크한 후 관리자 권한이 아니라면 AuthErrorCode.AUTH_FORBIDDEN 예외를 발생.
- PageRequest.of(page, size)로 페이징 정보를 정의하고 Pageable형태로 저장.
- userRepository.findAll(pageable)로 사용자 정보를 정의한 페이징 설정으로 조회하여 Page<User> 형태로 저장.
- 클라이언트 측으로 반환을 할 때에는 User 엔티티 그대로 정보를 전달하면 안되서 Page<AdminUserListResDTO> 형태로 반환.
public Page<AdminUserListResDTO> allListUsers(int page, int size, Long userId) {
// 관리자 권환 조회 및 예외 처리
User user = userRepository.findById(userId)
.orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND));
if (user.getRole() != Role.ROLE_ADMIN) {
throw new BaseException(AuthErrorCode.AUTH_FORBIDDEN);
}
// 페이징 정의
Pageable pageable = PageRequest.of(page, size);
// Page형태로 사용자 조회
Page<User> result = userRepository.findAll(pageable);
// User -> AdminUserListResDTO로 맵핑
Page<AdminUserListResDTO> pageDTO = result.map(AdminUserListResDTO::new);
// 반환
return pageDTO;
}
# UserRepository
- 굳이 재정의할 필요가 없는 public findAll(Pageable pageable); 을 삭제
< 관리자: 회원 검색 >
# AdminUserSearchResDTO
- UserSearchResDTO -> AdminUserSearchResDTO 네이밍 변경
- 사용자 고유번호, 아이디, 이메일, 권한, 가입날짜, 마지막 접속날짜, 상태 (id, username, email, role, joinDate, lastLoginDate, status)
- ** 필드는 그대로, 네이밍만 변경
@Getter
public class AdminUserSearchResDTO {
private long id;
private String username;
private String email;
private Role role;
private LocalDateTime joinDate;
private LocalDateTime lastLoginDate;
private UserStatus status;
public AdminUserSearchResDTO(User user) {
this.id = user.getId();
this.username = user.getUsername();
this.email = user.getEmail();
this.role = user.getRole();
this.joinDate = user.getJoinDate();
this.lastLoginDate = user.getLastLoginDate();
this.status = user.getStatus();
}
}
# AdminUserController
- GET /api/v1/admin/users/search 로 요청
- type, keyword, page, size, @AuthenticationPrincipal User user 파라미터
- Service 계층으로 type, keyword, page, size, user.getId()를 전달
- 클라이언트 측으로 성공 메시지와 반환 결과를 ApiResponse.seuccess()로 감싸서 응답
* 관리자 권한 확인을 위해 @AuthenticationPrincipal을 추가. 인증 객체는 커스텀한 User 엔티티로 생성.
@GetMapping("search")
public ResponseEntity<?> searchUser(
@RequestParam("type") UserSearchType type,
@RequestParam("keyword") String keyword,
@RequestParam(value = "page", defaultValue = "0") int page,
@RequestParam(value = "size", defaultValue = "10") int size,
@AuthenticationPrincipal User user) {
// 서비스로직
Page<AdminUserSearchResDTO> responseDTO = adminUserService.searchUser(type, keyword, page, size, user.getId());
// 성공메시지
String message = messageProvider.getMessage(UserSuccessCode.USER_FETCHED.getMessage());
// 응답
return ResponseEntity
.status(UserSuccessCode.USER_ACCOUNT_DELETED.getHttpStatus())
.body(ApiResponse.success(
UserSuccessCode.USER_LIST_FETCHED,
message,
responseDTO));
}
# AdminUserService
- UserService에 통합으로 사용자, 관리자 기능이 작성되어 있는데 관리자 기능은 AdminUserService로 옮김.
- userRepository.findById(userId)로 유효한 사용자인지 조회를 하고 유효하지 않으면 UserErrorCode.USER_NOT_FOUND 예외를 발생.
- user.getRole() != Role.ROLE_ADMIN 로 권한을 체크한 후 관리자 권한이 아니라면 AuthErrorCode.AUTH_FORBIDDEN 예외를 발생.
- PageRequest.of(page, size)로 페이징 정보를 정의하고 Pageable형태로 저장.
- 타입별 Page형태로 사용자 검색 조회하기 위해 UserSearchType type, Page<User> result를 생성.
- switch문을 사용하여 type이 USERNAME, EMAIL 인지 case를 체크하여 각 메서드 실행.
- 클라이언트 측으로 반환을 할 때에는 User 엔티티 그대로 정보를 전달하면 안되서 Page<AdminUserSearchResDTO> 형태로 반환.
public Page<AdminUserSearchResDTO> searchUser(UserSearchType typeStr, String keyword, int page, int size, Long userId) {
// 관리자 권한 조회 및 예외 처리
User user = userRepository.findById(userId)
.orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND));
if (user.getRole() != Role.ROLE_ADMIN) {
throw new BaseException(AuthErrorCode.AUTH_FORBIDDEN);
}
// 페이징 정의
Pageable pageable = PageRequest.of(page, size);
// 타입별 Page형태로 사용자 검색 조회
UserSearchType type = typeStr;
Page<User> result;
switch(type) {
case USERNAME:
result = userRepository.findByUsernameContainingIgnoreCase(keyword, pageable);
break;
case EMAIL:
result = userRepository.findByEmailContainingIgnoreCase(keyword, pageable);
break;
default:
throw new IllegalArgumentException("올바른 타입을 선택해주세요 (USERNAME, EMAIL): " + type);
}
// User -> AdminUserSearchResDTO로 맵핑
Page<AdminUserSearchResDTO> pageDTO = result.map(AdminUserSearchResDTO::new);
// 반환
return pageDTO;
}
# UserRepository
- USERNAME 타입으로 검색시 페이징으로 조회하는 메서드 정의.
- EMAIL 타입으로 검색시 페이징으로 조회하는 메서드 정의.
- ** 주석만 수정
Page<User> findByUsernameContainingIgnoreCase(String username, Pageable pageable);
Page<User> findByEmailContainingIgnoreCase(String email, Pageable pageable);
< 관리자: 회원 권한 수정 >
# AdminUserRoleUpdateReqDTO
- UserRoleUpdateReqDTO -> AdminUserRoleUpdateReqDTO 네이밍 변경.
- 권한 (role)
@Getter
public class AdminUserRoleUpdateReqDTO {
private Role role;
}
# AdminUserRoleUpdateResDTO
- 사용자 고유번호, 아이디, 권한, 수정날짜 (id, username, role, updatedAt)
- User엔티티를 파라미터로 받는 생성자 함수 정의.
** 생성자함수 추가함.
@Getter
public class AdminUserRoleUpdatedResDTO {
private Long id;
private String username;
private Role role;
private LocalDateTime updatedAt;
public AdminUserRoleUpdatedResDTO(User user) {
this.id = user.getId();
this.username = user.getUsername();
this.role = user.getRole();
this.updatedAt = user.getUpdatedAt();
}
}
# AdminUserController
- PATCH /api/v1/admin/users/{userId}/role 로 요청
- userId, AdminUserRoleUpdateReqDTO requestDTO, @AuthenticationPrincipal User user 파라미터
- Service 계층으로 userId, requestDTO, user.getId()를 전달
- 클라이언트 측으로 성공 메시지와 반환 결과를 ApiResponse.seuccess()로 감싸서 응답
** 관리자 권한 확인을 위해 @AuthenticationPrincipal을 추가. 인증 객체는 커스텀한 User 엔티티로 생성.
@PatchMapping("/{userId}/role")
public ResponseEntity<?> updateUserRole(
@PathVariable("userId") Long userId,
@RequestBody AdminUserRoleUpdateReqDTO requestDTO,
@AuthenticationPrincipal User user) {
// 서비스로직
AdminUserRoleUpdatedResDTO responseDTO = adminUserService.updateUserRole(userId, requestDTO, user.getId());
// 성공메시지
String message = messageProvider.getMessage(UserSuccessCode.USER_ROLE_UPDATED.getMessage());
// 응답
return ResponseEntity
.status(UserSuccessCode.USER_ROLE_UPDATED.getHttpStatus())
.body(ApiResponse.success(
UserSuccessCode.USER_ROLE_UPDATED,
message,
responseDTO));
}
# AdminUserService
- UserService에 통합으로 사용자, 관리자 기능이 작성되어 있는데 관리자 기능은 AdminUserService로 옮김.
- 관리자 권한 확인을 위해 userRepository.findById(amdinUserId)로 유효한 사용자인지 조회를 하고 유효하지 않으면 UserErrorCode.USER_NOT_FOUND 예외를 발생.
- user.getRole() != Role.ROLE_ADMIN 로 권한을 체크한 후 관리자 권한이 아니라면 AuthErrorCode.AUTH_FORBIDDEN 예외를 발생.
- 권한 수정할 사용자의 유효성 체크를 위해 userRepository.findById(userId)로 조회하고 없다면 UserErrorCode.USER_NOT_FOUND, "userId: " + userId 예외를 발생.
- User 객체에 변경할 권한과 수정된 날짜를 저장 후 userRepository.save(user)를 사용하여 DB에 업데이트 해주기.
- 클라이언트 측으로 반환을 할 때에는 User 기반으로 AdminUserRoleUpdatedResDTO 객체를 생성하여 반환
@Transactional
public AdminUserRoleUpdatedResDTO updateUserRole(Long userId, AdminUserRoleUpdateReqDTO roleUpdateDTO, Long adminUserId) {
// 관리자 권한 조회 및 예외 처리
User userAdmin = userRepository.findById(adminUserId)
.orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND));
if (userAdmin.getRole() != Role.ROLE_ADMIN) {
throw new BaseException(AuthErrorCode.AUTH_FORBIDDEN);
}
// 사용자 정보 확인 및 예외 처리
User user = userRepository.findById(userId)
.orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND, "userId: " + userId));
// 권한 변경 및 저장
user.setRole(roleUpdateDTO.getRole());
user.setUpdatedAt(LocalDateTime.now());
userRepository.save(user);
// 반환
return new AdminUserRoleUpdatedResDTO(user);
}
# messages.properties
- 메시지 정리하면서 발생한 오탈자 수정.
success.user.role_updated=권한이 성공적으로 변경되었습니다.
< 관리자: 사용자 상태 수정 >
# AdminUserStatusUpdateReqDTO
- UserStatusUpdateReqDTO -> AdminUserStatusUpdateReqDTO 네이밍 변경.
- 상태 (status)
@Getter
public class AdminUserStatusUpdateReqDTO {
private UserStatus status;
}
# AdminUserStatusUpdateResDTO
- 사용자 고유번호, 아이디, 상태, 수정날짜 (id, username, status, updatedAt)
- User엔티티를 파라미터로 받는 생성자 함수 정의.
* 생성자함수 추가함.
@Getter
public class AdminUserStatusUpdateResDTO {
private Long id;
private String username;
private UserStatus status;
private LocalDateTime updatedAt;
public AdminUserStatusUpdateResDTO(User user) {
this.id = user.getId();
this.username = user.getUsername();
this.status = user.getStatus();
this.updatedAt = user.getUpdatedAt();
}
}
# AdminUserController
- PATCH /api/v1/admin/users/{userId}/status 로 요청
- userId, AdminUserStatusUpdateReqDTO requestDTO, @AuthenticationPrincipal User user 파라미터
- Service 계층으로 userId, requestDTO, user.getId()를 전달
- 클라이언트 측으로 성공 메시지와 반환 결과를 ApiResponse.seuccess()로 감싸서 응답
* 관리자 권한 확인을 위해 @AuthenticationPrincipal을 추가. 인증 객체는 커스텀한 User 엔티티로 생성.
@PatchMapping("/{userId}/status")
public ResponseEntity<?> updateUserStatus(
@PathVariable("userId") Long userId,
@RequestBody AdminUserStatusUpdateReqDTO requestDTO,
@AuthenticationPrincipal User user) {
// 서비스로직
AdminUserStatusUpdateResDTO responseDTO = adminUserService.updateUserStatus(userId, requestDTO, user.getId());
// 성공메시지
String message = messageProvider.getMessage(UserSuccessCode.USER_STATUS_UPDATED.getMessage());
// 응답
return ResponseEntity
.status(UserSuccessCode.USER_STATUS_UPDATED.getHttpStatus())
.body(ApiResponse.success(
UserSuccessCode.USER_STATUS_UPDATED,
message,
responseDTO));
}
# AdminUserService
- UserService에 통합으로 사용자, 관리자 기능이 작성되어 있는데 관리자 기능은 AdminUserService로 옮김.
- 관리자 권한 확인을 위해 userRepository.findById(amdinUserId)로 유효한 사용자인지 조회를 하고 유효하지 않
다면 UserErrorCode.USER_NOT_FOUND 예외를 발생.
- user.getRole() != Role.ROLE_ADMIN 로 권한을 체크한 후 관리자 권한이 아니라면 AuthErrorCode.AUTH_FORBIDDEN 예외를 발생.
- 상태 수정할 사용자의 유효성 체크를 위해 userRepository.findById(userId)로 조회하고 없다면 UserErrorCode.USER_NOT_FOUND, "userId: " + userId 예외를 발생.
- User 객체에 변경할 상태와 수정된 날짜를 저장 후 userRepository.save(user)를 사용하여 DB에 업데이트 해주기.
- 클라이언트 측으로 반환을 할 때에는 User 기반으로 AdminUserStatusUpdateResDTO 객체를 생성하여 반환
@Transactional
public AdminUserStatusUpdateResDTO updateUserStatus(Long userId, AdminUserStatusUpdateReqDTO requestDTO, Long adminUserId) {
// 관리자 권한 조회 및 예외 처리
User userAdmin = userRepository.findById(adminUserId)
.orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND));
if (userAdmin.getRole() != Role.ROLE_ADMIN) {
throw new BaseException(AuthErrorCode.AUTH_FORBIDDEN);
}
// 사용자 정보 확인 및 예외 처리
User user = userRepository.findById(userId)
.orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND, "userId: " + userId));
// 상태 변경 및 저장
user.setStatus(requestDTO.getStatus());
user.setUpdatedAt(LocalDateTime.now());
userRepository.save(user);
// 반환
return new AdminUserStatusUpdateResDTO(user);
}
# UserStatus enum
- enum에 주석 달아줌.
public enum UserStatus {
ACTIVE, // 활성화
INACTIVE, // 비활성화
SUSPENDED, // 정지
DELETED // 삭제된 상태
}
< 관리자: 회원 탈퇴 처리 >
# AdminUserDeleteResDTO
- UserDeleteResDTO -> AdminUserDeleteResDTO 네이밍 변경.
- 사용자 고유번호, 아이디, 이메일, 수정날짜, 상태 (id, username, email, updatedAt, status)
- User 엔티티를 파라미터로 받는 생성자 함수 정의.
** 생성자 함수 추가.
@Getter
public class AdminUserDeleteResDTO {
private Long id;
private String username;
private String email;
private LocalDateTime updatedAt;
private UserStatus status;
public AdminUserDeleteResDTO(User user) {
this.id = user.getId();
this.username = user.getUsername();
this.email = user.getEmail();
this.updatedAt = user.getUpdatedAt();
this.status = user.getStatus();
}
}
# AdminUserController
- PATCH /api/v1/admin/users/{userId}/deactivate 로 요청
- userId, @AuthenticationPrincipal User user 파라미터
- Service 계층으로 userId, user.getId()를 전달
- 클라이언트 측으로 성공 메시지와 반환 결과를 ApiResponse.seuccess()로 감싸서 응답
** 관리자 권한 확인을 위해 @AuthenticationPrincipal을 추가. 인증 객체는 커스텀한 User 엔티티로 생성.
@PatchMapping("/{userId}/deactivate")
public ResponseEntity<?> deleteUserAccount(
@PathVariable("userId") Long userId,
@AuthenticationPrincipal User user) {
// 서비스로직
AdminUserDeleteResDTO responseDTO = adminUserService.deleteUserAccount(userId, user.getId());
// 성공메시지
String message = messageProvider.getMessage(UserSuccessCode.USER_ACCOUNT_DELETED.getMessage());
// 응답
return ResponseEntity
.status(UserSuccessCode.USER_ACCOUNT_DELETED.getHttpStatus())
.body(ApiResponse.success(
UserSuccessCode.USER_ACCOUNT_DELETED,
message,
responseDTO));
}
# AdminUserService
- UserService에 통합으로 사용자, 관리자 기능이 작성되어 있는데 관리자 기능은 AdminUserService로 옮김.
- 관리자 권한 확인을 위해 userRepository.findById(amdinUserId)로 유효한 사용자인지 조회를 하고 유효하지 않으면 UserErrorCode.USER_NOT_FOUND 예외를 발생.
- user.getRole() != Role.ROLE_ADMIN 로 권한을 체크한 후 관리자 권한이 아니라면 AuthErrorCode.AUTH_FORBIDDEN 예외를 발생.
- 상태 수정할 사용자의 유효성 체크를 위해 userRepository.findById(userId)로 조회하고 없다면 UserErrorCode.USER_NOT_FOUND, "userId: " + userId 예외를 발생.
- 사용자 상태가 DELETED면 username과 email 뒤에 "_deleted_ + 삭제날짜"를 추가한 뒤, userRepository.save(user)를 사용해 DB에 저장한다. 상태가 DELETED가 아니리면 UserErrorCode.USER_STATUS_NOT_DELETED 예외를 발생시킨다.
- 클라이언트 측으로 반환을 할 때에는 User 기반으로 AdminUserDeleteResDTO 객체를 생성하여 반환
@Transactional
public AdminUserDeleteResDTO deleteUserAccount(Long userId, Long adminUserId) {
// 관리자 권한 조회 및 예외 처리
User userAdmin = userRepository.findById(adminUserId)
.orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND, "userId: " + userId));
if (userAdmin.getRole() != Role.ROLE_ADMIN) {
throw new BaseException(AuthErrorCode.AUTH_FORBIDDEN);
}
// 사용자 정보 확인 및 예외 처리
User user = userRepository.findById(userId)
.orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND));
// 사용자 상태가 DELETED 이면 username, email 수정 (_deleted_+삭제날짜)
if (user.getStatus() == UserStatus.DELETED) {
String today = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE); // e.g., 20250930
String userEmail = user.getEmail();
user.setUsername(user.getUsername() + "_deleted_" + today);
user.setEmail(userEmail.substring(0, userEmail.indexOf("@")) + "_deleted_" + today + "@deleted.local");
userRepository.save(user);
} else {
throw new BaseException(UserErrorCode.USER_STATUS_NOT_DELETED);
}
// 반환
return new AdminUserDeleteResDTO(user);
}