728x90
320x100
📌 회원 정보 수정 항목
- name // 필수 값
- password //필수 값
- website
- bio
- phone
- gender
⚡️ UserController
세션에서 user를 가져와서 model로 보낸다.
@GetMapping("/user/{id}/update")
public String update(@PathVariable("id") Long id, @AuthenticationPrincipal PrincipalDetails principalDetails, Model model){
model.addAttribute("principal", principalDetails.getUser());
return "views/user/update";
}
➡️ html에서 thymeleaf를 이용해 ${principal.username} 이런 식으로 사용 가능하다.
⚡️ UserApiController
package yerong.InstagramCloneCoding.web.api;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.parameters.P;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RestController;
import yerong.InstagramCloneCoding.config.auth.PrincipalDetails;
import yerong.InstagramCloneCoding.domain.user.User;
import yerong.InstagramCloneCoding.handler.exception.CustomValidationApiException;
import yerong.InstagramCloneCoding.handler.exception.CustomValidationException;
import yerong.InstagramCloneCoding.service.UserService;
import yerong.InstagramCloneCoding.service.impl.UserServiceImpl;
import yerong.InstagramCloneCoding.web.dto.CMRespDto;
import yerong.InstagramCloneCoding.web.dto.user.UserUpdateDto;
import java.util.HashMap;
import java.util.Map;
@RequiredArgsConstructor
@RestController
public class UserApiController {
private final UserService userService;
@PutMapping("/api/user/{id}")
public ResponseEntity<CMRespDto<?>> update(
@PathVariable("id")Long id,
@Valid UserUpdateDto userUpdateDto,
BindingResult bindingResult,
@AuthenticationPrincipal PrincipalDetails principalDetails){
if(bindingResult.hasErrors()){
Map<String, String> errorMap = new HashMap<>();
for(FieldError error : bindingResult.getFieldErrors()){
errorMap.put(error.getField(), error.getDefaultMessage());
}
throw new CustomValidationApiException("유효성 검사 실패", errorMap);
}
else{
User userEntity = userService.update(id, userUpdateDto);
principalDetails.setUser(userEntity);
return new ResponseEntity<CMRespDto<?>>(new CMRespDto<>(1, "회원 수정 완료", userEntity), HttpStatus.OK);
}
}
}
- 필요한 부분만 Dto로 받아온다.
- @Valid 는 검증하려는 Dto 앞에 둔다.
- BindingResult 는 @Valid 뒤에 둔다(순서 중요)
- CMRespDto로 errorMessage와 errorMap을 리턴함
- 상태 코드도 반환하기 위해서 ResponseEntity 사용!
- CustomValidationApiException 예외 처리 따로 만들어서 (CMRespDto 방식 사용) 처리
⚡️ UserUpdateDto
package yerong.InstagramCloneCoding.web.dto.user;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;
import yerong.InstagramCloneCoding.domain.user.User;
@Getter
@Setter
public class UserUpdateDto {
@NotBlank
private String name; //필수로 받을 것
@NotBlank
private String password; //필수로 받을 것
private String website;
private String bio;
private String phone;
private String gender;
public User toEntity(){
return User.builder()
.name(name)
.password(password)
.website(website)
.bio(bio)
.phone(phone)
.gender(gender)
.build();
}
}
- name // 필수 값
- password //필수 값
⚡️ UserService
package yerong.InstagramCloneCoding.service.impl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import yerong.InstagramCloneCoding.domain.user.User;
import yerong.InstagramCloneCoding.handler.exception.CustomValidationApiException;
import yerong.InstagramCloneCoding.repository.UserRepository;
import yerong.InstagramCloneCoding.service.UserService;
import yerong.InstagramCloneCoding.web.dto.user.UserUpdateDto;
import java.util.function.Supplier;
@Service
@RequiredArgsConstructor
@Slf4j
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
@Override
@Transactional
public User findById(Long id){
return userRepository.findById(id).orElseThrow(() -> new CustomValidationApiException("찾을 수 없는 Id 입니다."));
}
@Override
@Transactional
public User update(Long id, UserUpdateDto userUpdateDto)
{
User user = userRepository.findById(id).orElseThrow(() -> new CustomValidationApiException("찾을 수 없는 Id 입니다."));
user.updateName(userUpdateDto.getName());
String rawPassword = userUpdateDto.getPassword();
String encPassword = bCryptPasswordEncoder.encode(rawPassword);
user.updatePassword(encPassword);
user.updateBio(userUpdateDto.getBio());
user.updateWebsite(userUpdateDto.getWebsite());
user.updatePhone(userUpdateDto.getPhone());
user.updateGender(userUpdateDto.getGender());
log.info("userUpdateDto.gender" , userUpdateDto.getGender());
return user;
}
}
- userRepository.findById(id)는 Optional로 반환되기 때문에 null일 때 처리를 해줘야 한다
- 만약 null이라면 CustomValidationApiException을 호출하여 찾을 수 없는 Id라는 메시지를 날린다.(errorMap은 전달하지 않아도 됨)
- 찾았다면 엔티티에 구현해둔 수정 가능한 필드들을 수정하는 함수를 호출한다.
- password는 encode 해서 저장해야 함
⚡️ CustomValidationApiException
package yerong.InstagramCloneCoding.handler.exception;
import java.util.Map;
public class CustomValidationApiException extends RuntimeException{
private Map<String, String> errorMap;
public CustomValidationApiException(String message){
super(message);
}
public CustomValidationApiException(String message, Map<String, String> errorMap){
super(message);
this.errorMap = errorMap;
}
public Map<String, String> getErrorMap(){
return errorMap;
}
}
- CMRespDto 방식으로 사용
- 메시지만 넘길 수도 있고, 메시지와 에러맵 두가지를 넘길 수도 있음
PREV
NEXT
728x90
반응형
'프로젝트 > 인스타그램 클론 코딩' 카테고리의 다른 글
[인스타그램 클론 코딩][Spring boot] 7. 프로필 페이지 (2) | 2024.02.20 |
---|---|
[인스타그램 클론 코딩][Spring boot] 6. 구독하기 (0) | 2024.02.19 |
[인스타그램 클론 코딩][Spring boot] 4. 로그인 구현 (1) | 2024.02.18 |
[인스타그램 클론 코딩][Spring boot] 3. 회원 가입 구현 (2) | 2024.02.17 |
[인스타그램 클론 코딩][Spring boot] 2. Security 설정 (0) | 2024.02.16 |