profile 수정 관련 작성 CRUD
1. User 엔티티 업데이트
최근 사용한 비밀번호 목록을 저장하는 필드를 User 엔티티에 추가합니다.
package com.sparta.realestatefeed.entity;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Getter
@Setter
@NoArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String userName;
@Column(nullable = false)
private String password;
@Column(nullable = false)
private String email;
private String nickName;
private String info;
@ElementCollection
@CollectionTable(name = "user_previous_passwords", joinColumns = @JoinColumn(name = "user_id"))
@Column(name = "previous_password")
private List<String> previousPasswords = new ArrayList<>();
}
2. ProfileService 클래스
비밀번호 변경 시 최근 사용한 비밀번호를 previousPasswords 필드에 저장하고, 최근 세 개의 비밀번호와 중복되지 않도록 합니다.
package com.sparta.realestatefeed.service;
import com.sparta.realestatefeed.dto.ProfileRequestDto;
import com.sparta.realestatefeed.dto.ProfileResponseDto;
import com.sparta.realestatefeed.entity.User;
import com.sparta.realestatefeed.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor
public class ProfileService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public ProfileResponseDto getUserProfile(String userName) {
User user = userRepository.findByUserName(userName).orElseThrow(
() -> new IllegalArgumentException("User not found")
);
return new ProfileResponseDto(user.getUserName(), user.getNickName(), user.getEmail(), user.getInfo());
}
public ProfileResponseDto updateUserProfile(String userName, ProfileRequestDto profileRequestDto) {
User user = userRepository.findByUserName(userName).orElseThrow(
() -> new IllegalArgumentException("User not found")
);
user.setNickName(profileRequestDto.getNickName());
user.setInfo(profileRequestDto.getInfo());
userRepository.save(user);
return new ProfileResponseDto(user.getUserName(), user.getNickName(), user.getEmail(), user.getInfo());
}
public User updateUserPassword(String userName, String currentPassword, String newPassword) {
User user = userRepository.findByUserName(userName).orElseThrow(
() -> new IllegalArgumentException("User not found")
);
if (!passwordEncoder.matches(currentPassword, user.getPassword())) {
throw new IllegalArgumentException("Current password is incorrect");
}
List<String> previousPasswords = user.getPreviousPasswords();
if (previousPasswords.stream().anyMatch(password -> passwordEncoder.matches(newPassword, password))) {
throw new IllegalArgumentException("New password must be different from the last three passwords");
}
// Add the current password to the list of previous passwords
previousPasswords.add(0, user.getPassword());
if (previousPasswords.size() > 3) {
previousPasswords.remove(3);
}
// Update the user's password
user.setPassword(passwordEncoder.encode(newPassword));
userRepository.save(user);
return user;
}
}
3. ProfileController 클래스
컨트롤러에서 서비스 메서드를 호출하여 클라이언트 요청을 처리합니다.
package com.sparta.realestatefeed.controller;
import com.sparta.realestatefeed.dto.CommonDto;
import com.sparta.realestatefeed.dto.ProfileRequestDto;
import com.sparta.realestatefeed.dto.ProfileResponseDto;
import com.sparta.realestatefeed.security.UserDetailsImpl;
import com.sparta.realestatefeed.service.ProfileService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
@RequestMapping("/api/profiles")
@Validated
public class ProfileController {
private final ProfileService profileService;
public ProfileController(ProfileService profileService) {
this.profileService = profileService;
}
@GetMapping("/")
public ResponseEntity<?> getUserProfile(@AuthenticationPrincipal UserDetailsImpl userDetails) {
String userName = userDetails.getUser().getUserName();
ProfileResponseDto responseDto = profileService.getUserProfile(userName);
CommonDto<ProfileResponseDto> response = new CommonDto<>(HttpStatus.OK.value(), "회원 조회", responseDto);
return ResponseEntity.status(HttpStatus.OK).body(response);
}
@PutMapping("/")
public ResponseEntity<?> updateUserProfile(@AuthenticationPrincipal UserDetailsImpl userDetails, @RequestBody ProfileRequestDto profileRequestDto) {
String userName = userDetails.getUser().getUserName();
ProfileResponseDto responseDto = profileService.updateUserProfile(userName, profileRequestDto);
CommonDto<ProfileResponseDto> response = new CommonDto<>(HttpStatus.OK.value(), "회원 조회", responseDto);
return ResponseEntity.status(HttpStatus.OK).body(response);
}
@PutMapping("/password")
public ResponseEntity<?> updateUserPassword(@AuthenticationPrincipal UserDetailsImpl userDetails, @RequestBody Map<String, String> passwordRequest) {
String userName = userDetails.getUser().getUserName();
String currentPassword = passwordRequest.get("currentPassword");
String newPassword = passwordRequest.get("newPassword");
try {
User user = profileService.updateUserPassword(userName, currentPassword, newPassword);
return ResponseEntity.ok().body("Password updated successfully");
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}
}
4. ProfileRequestDto와 ProfileResponseDto 클래스
프로필 수정 및 조회에 필요한 DTO 클래스입니다.
package com.sparta.realestatefeed.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class ProfileRequestDto {
private String nickName;
private String info;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class ProfileResponseDto {
private String userName;
private String nickName;
private String email;
private String info;
}