[USER] 닉네임 자동 생성 및 프로필 편집 기능 구현#45
Conversation
Summary by CodeRabbit
Walkthrough이 변경 사항은 사용자 이름( Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Frontend
participant UsersApiController
participant UserService
participant UsersRepository
User->>Frontend: 닉네임 입력 및 중복 확인 버튼 클릭
Frontend->>UsersApiController: GET /api/check-displayname?displayName=xxx (with token)
UsersApiController->>UserService: checkDisplayName(currentUserId, displayName)
UserService->>UsersRepository: existsByDisplayName(displayName)
UsersRepository-->>UserService: true/false
UserService-->>UsersApiController: { available: true/false, message: ... }
UsersApiController-->>Frontend: JSON 응답 반환
Frontend-->>User: 중복 결과 메시지 및 입력 상태 반영
sequenceDiagram
participant User
participant Frontend
participant UsersController
participant UserService
participant UsersRepository
User->>Frontend: 프로필 수정 폼 제출
Frontend->>UsersController: POST /profile/edit
UsersController->>UserService: updateUserProfile(userId, userProfileEditDTO)
UserService->>UsersRepository: existsByDisplayName(newDisplayName)
alt 중복 O & 본인 아님
UserService-->>UsersController: Exception 발생
UsersController-->>Frontend: 에러 메시지 및 입력값 복구
else 중복 X 또는 본인
UserService->>UsersRepository: save(user)
UsersController-->>Frontend: 성공 리다이렉트
end
Possibly related PRs
Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
|
@CodeRabbit review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (10)
src/main/java/io/github/petty/users/util/DisplayNameGenerator.java (1)
14-14: Random 인스턴스의 스레드 안전성을 개선할 수 있습니다.현재
Random인스턴스가 인스턴스 필드로 선언되어 있어 멀티스레드 환경에서 성능 저하가 발생할 수 있습니다.더 나은 성능을 위해
ThreadLocalRandom을 사용하는 것을 권장합니다:-import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; -private final Random random = new Random();그리고 사용 부분에서:
-String adjective = ADJECTIVES[random.nextInt(ADJECTIVES.length)]; -String animal = ANIMALS[random.nextInt(ANIMALS.length)]; -String number = String.format("%03d", random.nextInt(1000)); +String adjective = ADJECTIVES[ThreadLocalRandom.current().nextInt(ADJECTIVES.length)]; +String animal = ANIMALS[ThreadLocalRandom.current().nextInt(ANIMALS.length)]; +String number = String.format("%03d", ThreadLocalRandom.current().nextInt(1000));src/main/java/io/github/petty/users/oauth2/CustomOAuth2UserService.java (1)
99-112: 이메일 폴백 로직의 보안성을 검토해주세요.이메일 주소에서
@앞부분을 사용자 이름으로 사용하는 폴백 로직이 있습니다. 이는 예측 가능한 패턴을 만들 수 있어 보안상 고려가 필요합니다.더 안전한 폴백 전략을 고려해보세요:
} else { - user.setName(email.split("@")[0]); + user.setName("User_" + UUID.randomUUID().toString().substring(0, 8)); }또는 기본값을 설정하되 사용자가 나중에 수정할 수 있도록 유도하는 방식도 고려할 수 있습니다.
src/main/java/io/github/petty/users/controller/UsersApiController.java (1)
107-128: 닉네임 중복 체크 API 구현이 적절합니다.API 설계와 보안 처리가 잘 되어 있습니다:
- 인증된 사용자만 접근 가능
- 현재 사용자 ID를 통한 자신의 닉네임 제외 로직
- 적절한 HTTP 상태 코드 반환
다만 몇 가지 개선사항을 제안합니다:
입력 검증과 에러 처리를 강화할 수 있습니다:
@GetMapping("/check-displayname") public ResponseEntity<Map<String, Object>> checkDisplayName( - @RequestParam String displayName) { + @RequestParam @NotBlank(message = "닉네임을 입력해주세요") String displayName) { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth == null || !auth.isAuthenticated() || auth instanceof AnonymousAuthenticationToken) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } + try { // 현재 사용자 ID 가져오기 UUID currentUserId = userService.getCurrentUserId(auth.getPrincipal()); // 한 번의 서비스 호출로 모든 정보 가져오기 Map<String, Object> result = userService.checkDisplayName(currentUserId, displayName); Map<String, Object> response = new HashMap<>(); response.put("available", result.get("available")); response.put("message", result.get("message")); return ResponseEntity.ok(response); + } catch (Exception e) { + Map<String, Object> errorResponse = new HashMap<>(); + errorResponse.put("available", false); + errorResponse.put("message", "서버 오류가 발생했습니다."); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); + } }src/main/java/io/github/petty/users/service/EmailService.java (1)
60-75: HTML 구조 개선이 필요합니다.이메일 콘텐츠가 개선되었지만, 접근성과 보안 측면에서 몇 가지 개선사항을 제안합니다:
-<div style='display:block;margin-bottom:20px;text-decoration:none;color:#000000;width:5.5rem;font-weight:bold' target='_blank'> +<div style='display:block;margin-bottom:20px;color:#000000;font-weight:bold'> <h2 style='color:#f39c12'>Petty</h2> </div>추가로 이메일 템플릿을 별도 파일로 분리하는 것을 고려해보세요:
// resources/templates/email-verification.html 파일 생성 후 private String loadEmailTemplate(String code) { // 템플릿 엔진 사용하여 코드 바인딩 return templateEngine.process("email-verification", Map.of("verificationCode", code)); }src/main/java/io/github/petty/users/controller/UsersController.java (1)
94-112: 프로필 업데이트 에러 핸들링이 크게 개선되었습니다.사용자 경험 향상을 위한 여러 개선사항이 적용되었습니다:
- 입력값 유지 로직으로 재입력 불편함 해소
- 명확한 에러 메시지 제공
- 프로필 편집 페이지로 다시 리다이렉트하여 수정 가능
예외 처리를 더 세분화하여 구체적인 에러 메시지를 제공할 수 있습니다:
} catch (Exception e) { - // 모든 에러를 하나로 처리 - String errorMessage = e.getMessage(); - if (errorMessage == null || errorMessage.trim().isEmpty()) { - errorMessage = "프로필 수정 중 오류가 발생했습니다."; - } + String errorMessage; + if (e instanceof IllegalArgumentException) { + errorMessage = e.getMessage(); // 닉네임 중복 등 비즈니스 로직 오류 + } else if (e instanceof DataAccessException) { + errorMessage = "데이터베이스 오류가 발생했습니다."; + } else { + errorMessage = "프로필 수정 중 오류가 발생했습니다."; + log.error("프로필 업데이트 중 예상치 못한 오류", e); // 디버깅용 로그 + } redirectAttributes.addFlashAttribute("errorMessage", errorMessage); redirectAttributes.addFlashAttribute("userProfile", userProfileEditDTO); return "redirect:/profile/edit"; }src/main/resources/templates/profile_edit.html (4)
6-143: CSS 스타일링이 크게 개선되었습니다.사용자 인터페이스가 훨씬 직관적이고 사용하기 쉬워졌습니다:
- 입력 상태별 시각적 피드백 (valid/invalid 클래스)
- 일관된 색상 체계와 브랜딩
- 반응형 디자인 고려
CSS를 별도 파일로 분리하여 유지보수성을 높이는 것을 고려해보세요:
- <style> - /* 모든 CSS 코드 */ - </style> + <link rel="stylesheet" th:href="@{/css/profile-edit.css}">
203-243: 사용자 프로필 로드 로직이 견고합니다.토큰 만료 시 자동 갱신을 포함한 인증 처리가 잘 구현되어 있습니다.
에러 처리를 더 세분화할 수 있습니다:
} catch (error) { - console.error('프로필 정보 조회 실패:', error); - redirectToLogin(); + console.error('프로필 정보 조회 실패:', error); + if (error.name === 'TypeError' && !navigator.onLine) { + alert('네트워크 연결을 확인해주세요.'); + } else { + alert('프로필 정보를 불러올 수 없습니다.'); + } + redirectToLogin(); }
306-366: 닉네임 중복 체크 로직이 잘 구현되었습니다.실시간 중복 체크와 토큰 갱신 처리가 포함된 견고한 구현입니다.
중복된 토큰 갱신 로직을 공통 함수로 추출할 수 있습니다:
+ // 공통 API 호출 함수 (토큰 갱신 포함) + async function apiCall(url, options = {}) { + let response = await fetch(url, options); + + if (response.status === 401) { + const refreshResponse = await fetch('/api/auth/refresh', { method: 'POST' }); + if (refreshResponse.ok) { + response = await fetch(url, options); + } else { + redirectToLogin(); + return null; + } + } + return response; + } // 닉네임 중복 확인에서 사용 - const response = await fetch(`/api/check-displayname?displayName=${encodeURIComponent(displayName)}`); - - if (response.ok) { - const data = await response.json(); - handleDisplayNameCheckResult(data); - } else if (response.status === 401) { - // 토큰 갱신 로직... - } + const response = await apiCall(`/api/check-displayname?displayName=${encodeURIComponent(displayName)}`); + if (response && response.ok) { + const data = await response.json(); + handleDisplayNameCheckResult(data); + }
404-440: 폼 검증과 제출 로직이 안전하게 구현되었습니다.모든 필드의 검증 상태를 확인하고 제출 버튼 활성화를 제어하는 로직이 잘 구현되어 있습니다.
초기 검증 수행 부분을 더 간결하게 작성할 수 있습니다:
- // 페이지 로드 시 초기 검증 수행 - if (nameInput.value.trim()) { - nameInput.dispatchEvent(new Event('input')); - } - if (displayNameInput.value.trim()) { - displayNameInput.dispatchEvent(new Event('input')); - } - if (phoneInput.value.trim()) { - phoneInput.dispatchEvent(new Event('input')); - } + // 페이지 로드 시 초기 검증 수행 + [nameInput, displayNameInput, phoneInput].forEach(input => { + if (input.value.trim()) { + input.dispatchEvent(new Event('input')); + } + });src/main/java/io/github/petty/users/service/UserService.java (1)
66-72: 닉네임 중복 검사 로직을 개선해주세요.현재 구현은 기본적으로 올바르지만 예외 처리 방식을 개선할 수 있습니다:
RuntimeException대신 더 구체적인 예외 타입 사용을 고려해보세요- 현재 닉네임과 새 닉네임이 같은 경우를 올바르게 처리하고 있습니다
더 구체적인 예외 처리를 위해 다음과 같이 개선할 수 있습니다:
- throw new RuntimeException("이미 사용 중인 닉네임입니다."); + throw new IllegalArgumentException("이미 사용 중인 닉네임입니다.");또는 비즈니스 로직에 특화된 커스텀 예외를 정의하는 것을 고려해보세요.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
src/main/java/io/github/petty/users/controller/UsersApiController.java(3 hunks)src/main/java/io/github/petty/users/controller/UsersController.java(2 hunks)src/main/java/io/github/petty/users/dto/JoinDTO.java(1 hunks)src/main/java/io/github/petty/users/dto/UserProfileEditDTO.java(1 hunks)src/main/java/io/github/petty/users/entity/Users.java(1 hunks)src/main/java/io/github/petty/users/oauth2/CustomOAuth2UserService.java(3 hunks)src/main/java/io/github/petty/users/repository/UsersRepository.java(1 hunks)src/main/java/io/github/petty/users/service/EmailService.java(3 hunks)src/main/java/io/github/petty/users/service/JoinService.java(3 hunks)src/main/java/io/github/petty/users/service/UserService.java(3 hunks)src/main/java/io/github/petty/users/util/DisplayNameGenerator.java(1 hunks)src/main/resources/templates/join.html(1 hunks)src/main/resources/templates/profile_edit.html(2 hunks)
🔇 Additional comments (29)
src/main/java/io/github/petty/users/repository/UsersRepository.java (1)
13-13: 닉네임 중복 체크를 위한 메서드 추가가 적절합니다.Spring Data JPA 명명 규칙을 올바르게 따르고 있으며, 닉네임 유일성 검증 기능에 필요한 메서드입니다.
src/main/java/io/github/petty/users/dto/JoinDTO.java (1)
13-13: 실명과 닉네임을 구분하는 리팩터링이 잘 적용되었습니다.필드명을
displayName에서name으로 변경하여 사용자의 실제 이름을 나타내도록 명확히 했습니다. 닉네임은 시스템에서 자동 생성되므로 회원가입 시에는 실명만 입력받는 것이 적절합니다.src/main/resources/templates/join.html (1)
253-254: 백엔드 DTO 변경에 맞춰 템플릿 바인딩이 올바르게 업데이트되었습니다.
th:field="*{name}"과th:errors="*{name}"으로 변경하여 JoinDTO의 필드명 변경사항과 일치시켰습니다.src/main/java/io/github/petty/users/dto/UserProfileEditDTO.java (1)
13-15: 실명과 닉네임을 명확히 구분한 DTO 구조가 훌륭합니다.
name(실명)과displayName(닉네임)을 분리하여 관리할 수 있도록 구조를 개선했고, 한국어 주석을 통해 각 필드의 용도를 명확히 했습니다. 프로필 편집 기능에서 두 필드를 독립적으로 관리할 수 있게 되었습니다.src/main/java/io/github/petty/users/service/JoinService.java (3)
7-7: DisplayNameGenerator 의존성 주입이 적절하게 구현되었습니다.새로운 유틸리티 컴포넌트가 올바르게 주입되어 유니크한 닉네임 생성 기능을 지원합니다.
Also applies to: 18-18
23-23: 사용자 이름과 닉네임 분리가 올바르게 구현되었습니다.DTO에서
name필드를 사용하여 실제 이름을 저장하도록 변경된 것이 적절합니다. 이는 닉네임과 실명을 분리하는 전체적인 리팩터링과 일치합니다.Also applies to: 35-35
40-41: 자동 닉네임 생성 로직이 적절히 통합되었습니다.
DisplayNameGenerator를 사용하여 유니크한 닉네임을 자동 생성하는 로직이 깔끔하게 구현되었습니다. 사용자 가입 시 중복 없는 닉네임이 보장됩니다.src/main/java/io/github/petty/users/util/DisplayNameGenerator.java (3)
29-46: 유니크 닉네임 생성 로직이 견고하게 구현되었습니다.50회 재시도 로직과 UUID 폴백 메커니즘이 잘 설계되어 있어 유니크성을 보장하면서도 무한루프를 방지합니다. 데이터베이스 조회를 통한 중복 체크도 적절합니다.
17-26: 한국어 형용사와 동물 이름 배열이 적절하게 정의되었습니다.사용자 친화적인 한국어 닉네임 생성을 위한 단어 선택이 적절하며, 반려동물 테마와 잘 어울립니다.
49-55: 닉네임 형식 생성이 일관성 있게 구현되었습니다.'형용사 + 동물 + 3자리 숫자' 형식으로 생성하는 로직이 명확하고 예측 가능한 패턴을 제공합니다. String.format을 사용한 숫자 포맷팅도 적절합니다.
src/main/java/io/github/petty/users/entity/Users.java (3)
27-28: 실제 이름을 위한 name 필드가 적절하게 정의되었습니다.사용자의 실명 또는 소셜 로그인 제공자의 이름을 저장하는 필드로서 적절한 제약조건(non-null, 길이 50)이 설정되었습니다.
30-31: 닉네임을 위한 displayName 필드가 올바르게 구현되었습니다.자동 생성되는 유니크 닉네임을 위한 필드로서
unique = true제약조건이 적절하게 설정되어 중복을 방지합니다. 주석도 명확하게 작성되었습니다.
27-31:Details
❓ Verification inconclusive
데이터베이스 마이그레이션 계획을 확인해주세요.
기존
displayName필드를name과displayName으로 분리하는 변경사항은 기존 데이터에 영향을 줄 수 있습니다.데이터베이스 마이그레이션 전략이 준비되어 있는지 확인하기 위해 다음 스크립트를 실행해보세요:
🏁 Script executed:
#!/bin/bash # 데이터베이스 마이그레이션 파일 확인 fd -e sql . | head -10 echo "--- Liquibase/Flyway 마이그레이션 파일 확인 ---" fd "migration\|changelog" . echo "--- application.yml DDL 설정 확인 ---" rg -A 3 -B 3 "ddl-auto\|hibernate\.ddl"Length of output: 258
데이터베이스 마이그레이션 준비 여부 확인 필요
스크립트 실행 결과 리포지토리 내에 아래 항목이 전혀 발견되지 않았습니다.
기존displayName필드를name과displayName으로 분리하는 변경은 기존 데이터를 손상시킬 수 있으므로, 아래 사항들을 직접 점검해 주세요:
.sql마이그레이션 스크립트 파일 유무 확인- Liquibase/Flyway용 changelog·migration 파일 위치 확인
application.yml또는application.properties내ddl-auto/hibernate.ddl-auto설정 검토- 기존 데이터 마이그레이션 전략(기본값 설정, 데이터 복사·이동 로직 등) 수립 여부 확인
src/main/java/io/github/petty/users/oauth2/CustomOAuth2UserService.java (3)
6-6: DisplayNameGenerator 의존성이 적절하게 추가되었습니다.OAuth2 사용자 생성 시에도 일관된 유니크 닉네임 생성을 위해 동일한 컴포넌트를 사용하는 것이 좋은 설계입니다.
Also applies to: 25-25
92-94: 자동 닉네임 생성이 OAuth2 플로우에 잘 통합되었습니다.소셜 로그인 사용자도 동일한 유니크 닉네임 생성 로직을 사용하여 일관성을 유지합니다. 주석도 명확하게 작성되었습니다.
97-112: OAuth2 제공자별 이름 처리 로직이 올바르게 구현되었습니다.GitHub와 Kakao 각각의 속성 구조에 맞게 사용자 이름을 추출하여
name필드에 설정하는 로직이 적절합니다. 각 제공자에서 데이터가 없을 경우의 폴백 로직도 잘 구현되어 있습니다.src/main/java/io/github/petty/users/controller/UsersApiController.java (1)
33-38: 의존성 주입 구조가 올바르게 구현되었습니다.생성자 주입 패턴을 사용하여 UserService를 안전하게 주입하고 있으며, 불변성을 보장하는 좋은 구조입니다.
src/main/java/io/github/petty/users/service/EmailService.java (4)
39-39: 예외 처리 개선이 적절합니다.
UnsupportedEncodingException을 추가하여 인코딩 관련 오류를 포함한 더 포괄적인 예외 처리가 구현되었습니다.Also applies to: 50-50
54-54: 발신자 정보 개선이 좋습니다."Petty Team"이라는 표시 이름을 추가하여 사용자에게 더 친숙하고 전문적인 이메일 발신자 정보를 제공하고 있습니다.
56-56: 이메일 제목이 더 간결해졌습니다."Petty 인증 코드"로 간소화된 제목이 사용자에게 더 명확하고 직관적입니다.
81-81: 로그 메시지 개선이 적절합니다.인증 코드 값을 로그에서 제거하여 보안을 강화한 것이 좋은 개선사항입니다.
src/main/java/io/github/petty/users/controller/UsersController.java (1)
68-81: 프로필 로드 시 예외 처리가 잘 구현되었습니다.try-catch 블록을 추가하여 프로필 정보 조회 실패 시 사용자에게 적절한 피드백을 제공하고 안전하게 홈페이지로 리다이렉트하는 로직이 좋습니다.
src/main/resources/templates/profile_edit.html (2)
150-187: HTML 구조가 잘 구성되었습니다.폼 구조와 사용자 피드백 영역이 체계적으로 구성되어 있습니다:
- 로딩 상태 표시
- 에러/성공 메시지 영역
- 입력 그룹과 검증 메시지 배치
386-401: 전화번호 검증 로직이 적절합니다.한국 휴대폰 번호 패턴에 맞는 정규식을 사용하여 올바른 검증이 이루어지고 있습니다.
src/main/java/io/github/petty/users/service/UserService.java (5)
12-13: import 문 추가가 적절합니다.새로 추가된
checkDisplayName메서드에서 사용하는 HashMap과 Map 인터페이스를 위한 import 문이 정확하게 추가되었습니다.
57-57: DTO 생성자 변경이 올바르게 적용되었습니다.
name과displayName을 분리한 새로운 엔티티 구조에 맞게UserProfileEditDTO생성자가 정확하게 수정되었습니다. 사용자의 실제 이름과 닉네임을 구분하여 반환하는 로직이 적절합니다.
74-74: name 필드 설정이 적절하게 추가되었습니다.사용자의 실제 이름(
name)과 닉네임(displayName)을 분리한 새로운 구조에 맞게name필드 설정이 올바르게 추가되었습니다.
81-99: 닉네임 유효성 검사 메서드가 잘 구현되었습니다.
checkDisplayName메서드의 로직이 올바릅니다:
- 현재 사용자의 닉네임인 경우를 적절히 처리
- 사용 가능 여부와 메시지를 명확하게 반환
- API 응답에 적합한 Map 구조 사용
메서드의 책임이 명확하고 재사용 가능한 구조입니다.
101-105: 헬퍼 메서드가 적절하게 구현되었습니다.
isCurrentUserDisplayName메서드가 null 처리를 포함하여 안전하게 구현되었습니다. 사용자가 존재하지 않는 경우를 적절히 처리하고 있으며, 닉네임 비교 로직도 정확합니다.
|
|
이번 PR은 사용자 ID 관리, 프로필 기능 및 사용자 경험 측면에서 상당한 개선을 이룬 포괄적이고 완성도 높은 작업으로 판단됩니다.
총평하자면, 이번 변경 사항들은 플랫폼 기능과 사용자 경험을 의미있게 향상시킬 것으로 기대됩니다. 수고하셨습니다. |
📜 PR 내용 요약
displayName)을 자동으로 생성하는 기능을 구현했습니다.name) 필드를 추가하고 닉네임(displayName)과 분리했습니다.⚒️ 작업 및 변경 내용(상세하게)
1. 로그인/가입 시 자동 닉네임 생성 기능 구현
DisplayNameGenerator유틸리티 클래스 추가:UsersRepository.existsByDisplayName메서드를 통해 확인하고, 중복 시 최대 50회까지 재시도합니다.username,password,name,phone으로 변경했습니다 (JoinDTO에서displayName필드를 제거하고name필드를 추가).JoinService.joinProcess메서드에서DisplayNameGenerator를 주입받아 사용자의displayName을 자동으로 생성하여 저장하도록 로직을 추가했습니다. 사용자가 입력한name과phone도 함께 저장합니다.CustomOAuth2UserService에DisplayNameGenerator를 주입받도록 수정했습니다.saveOrUpdate메서드에서 소셜 로그인 성공 시DisplayNameGenerator를 사용하여 사용자의displayName을 자동으로 생성하여 저장하도록 로직을 추가했습니다.name필드에 설정하도록 변경했습니다. 기존에는 이 정보가displayName으로 설정되었습니다.Users엔티티 및UsersRepository수정:Users엔티티에 사용자의 실제 이름 또는 소셜 제공자 이름에 해당하는name필드를 추가했습니다.displayName필드는 닉네임으로 사용되며,unique = true속성을 추가하여 중복을 허용하지 않도록 변경했습니다.UsersRepository에Boolean existsByDisplayName(String displayName);메서드를 추가했습니다.2. 이메일 인증 메일 구조 개선
EmailService.sendEmail메서드 수정:krpetty54@gmail.com과 함께 "Petty Team"이라는 표시 이름을 사용하여 설정하도록 변경했습니다.sendVerificationCode메서드에서 이메일 전송 실패 시MessagingException뿐만 아니라UnsupportedEncodingException도 함께 처리하도록 예외 처리를 보강했습니다.3. 프로필 수정 기능 완성
UserProfileEditDTO에name필드를 추가하고displayName필드를 닉네임으로 명시하도록 수정했습니다.UserService에 사용자 ID(UUID)로 프로필 정보 (name,displayName,phone)를 조회하는getUserById메서드를 추가했습니다.UserService에 프로필 정보 (name,displayName,phone)를 받아 사용자 엔티티를 업데이트하는updateUserProfile메서드를 추가했습니다.updateUserProfile메서드 내에서 수정하려는 닉네임(newDisplayName)이 현재 사용자의 닉네임과 다를 경우에만usersRepository.existsByDisplayName를 호출하여 중복 검사를 수행하고, 중복 시 예외를 발생시키도록 로직을 추가했습니다.UserService에 특정 닉네임의 사용 가능 여부를 확인하는checkDisplayName메서드를 추가했습니다. 이 메서드는 해당 닉네임이 이미 존재하는지 확인하되, 현재 사용자의 닉네임인 경우는 사용 가능한 것으로 처리하는isCurrentUserDisplayName헬퍼 메서드를 활용합니다. 결과는available상태와 메시지를 담은 Map 형태로 반환합니다.UsersApiController에/api/users/check-displaynameGET 엔드포인트를 추가하여 클라이언트에서 닉네임 중복 검사를 요청할 수 있도록 했습니다. 이 API는 인증된 사용자만 호출할 수 있습니다.UsersController의/profile/editGET 엔드포인트에서 인증 상태를 확인하고,userService.getUserById를 통해 현재 사용자의 프로필 정보를 불러와userProfile모델 속성으로profile_edit.html뷰에 전달하도록 수정했습니다. 프로필 정보를 가져오는 중 오류 발생 시 예외를 처리합니다.UsersController의/profile/updatePOST 엔드포인트에서@ModelAttribute로 받은UserProfileEditDTO객체를userService.updateUserProfile메서드에 전달하여 프로필 업데이트를 수행하도록 수정했습니다.RedirectAttributes에 담아 메인 페이지 또는 프로필 수정 페이지로 리다이렉트하도록 했습니다. 실패 시 입력값을 유지하기 위해userProfileEditDTO를 플래시 속성으로 추가했습니다.profile_edit.html뷰에 이름, 닉네임, 전화번호 입력 필드와 저장 버튼을 구현하고 디자인을 개선했습니다./api/users/check-displaynameAPI를 호출하여 닉네임 중복 여부를 실시간으로 확인하고 사용자에게 피드백을 제공하는 클라이언트 측 JavaScript 로직을 추가했습니다. 페이지 로드 시 초기 유효성 검사를 수행합니다.📚 기타 참고 사항
displayName)과 사용자의 실제 이름 또는 제공자 이름인name필드가 목적에 맞게 분리되어 사용됩니다.