[내일배움캠프 Spring 4기] 56일차 TIL - double과 int | 커스텀 어노테이션 Argument Resolver | 내 프로필 조회 기능 구현 | 프로필 수정 기능 구현 | 비밀번호 수정 기능 구현

서예진·2024년 3월 2일
0

오늘의 학습 키워드 💻

▸ 오늘의 코드카타
▸ double과 int
▸ 커스텀 어노테이션 Argument Resolver
▸ 내 프로필 조회 기능 구현
▸ 프로필 수정 기능 구현
▸ 비밀번호 수정 기능 구현


✅ 오늘의 코드카타

2024년 2월 26일 - [프로그래머스 - 자바(JAVA)] 30 : 의상 | 기능개발


✅ double과 int

  • 다음 두 코드의 출력값은 다르다.
double result = (int)Math.ceil((100-30)/30); System.out.println("결과: " + result); // 출력: 2.0
double result = (int)Math.ceil((100-30)/(double)30); System.out.println("결과: " + result); // 출력: 3.0
  • 내가 원하는 출력값은 3이었다.
  • 이를 위해서는 나눗셈을 수행할 때 소수로 나오도록 하기 위해 적어도 하나의 피연산자를 double 형태로 형변환해야 한다.
  • 따라서 위의 코드를 아래 코드로 수정해서 원하는 출력값을 얻을 수 있었다.

✅ 커스텀 어노테이션 Argument Resolver

  • 로그인된 유저를 받아오기 위해 UserDetailsImpl 대신해서 커스텀 어노테이션을 만들어서 받아오는 방법에 대해 알아보았다.

argumentResolver > UserInfoArgumentResolver

@Component
@RequiredArgsConstructor
public class UserInfoArgumentResolver implements HandlerMethodArgumentResolver {

    private final JwtUtil jwtUtil;
    private final UserRepository userRepository;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(UserInfo.class)
            && User.class.isAssignableFrom(parameter.getParameterType());
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
        NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);

        String tokenValue = jwtUtil.getJwtFromRequest(request);
        String token = jwtUtil.substringToken(tokenValue);

        String userInfo = jwtUtil.getUserInfoFromToken(token);

        return userRepository.userBy(userInfo);
    }
}
  • supportsParameter() 메서드
    - 이 메서드는 특정 매개변수가 이 Argument Resolver에 의해 해결될 수 있는지 여부를 결정
    - @UserInfo 어노테이션이 매개변수에 존재하고, 해당 매개변수의 타입이 User 클래스나 그 하위 클래스인 경우에만 이 Argument Resolver가 적용됨
  • resolveArgument() 메서드
    - 이 메서드는 실제로 매개변수를 해결하고 반환한다.
    - HttpServletRequest를 사용하여 현재 요청에서 JWT 토큰을 추출한다.
    - 추출한 JWT 토큰을 해독하여 사용자 정보를 가져온다.
    - 가져온 사용자 정보를 사용하여 UserRepository를 통해 실제 사용자 객체를 검색하고 반환한다.
  • 이러한 방식으로 UserInfoArgumentResolver 클래스는 @UserInfo 어노테이션이 붙은 매개변수에 대해 JWT 토큰을 해석하여 사용자 정보를 제공한다. 이를 통해 컨트롤러 메서드에서 편리하게 현재 사용자의 정보에 접근할 수 있게 된다.

argumentResolver > UserInfo

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserInfo {

}
  • 사용자 정의 어노테이션을 정의하는 부분
  • 여기서 @UserInfo 어노테이션은 컨트롤러 메서드의 매개변수에 사용됨
    - @Target(ElementType.PARAMETER): 이 어노테이션이 적용될 대상을 지정, 여기서는 메서드의 매개변수(Parameter)에만 적용됨
    - @Retention(RetentionPolicy.RUNTIME): 이 어노테이션 정보가 유지될 기간을 지정, 여기서는 런타임 시에도 유지되어야 하므로 RUNTIME으로 설정
  • 따라서 @UserInfo 어노테이션은 런타임 시 메서드의 매개변수에 적용되며, 이를 통해 해당 매개변수를 UserInfoArgumentResolver에서 해결할 때 식별할 수 있다.

커스텀 어노테이션 적용

  • 위에서 만든 커스텀 어노테이션을 다음과 같이 사용할 수 있다.
public ResponseEntity<ResponseDto<ProfileResponseDto>> getProfile(@UserInfo User user) {
  • @UserInfo를 통해 현재 로그인된 User를 가져올 수 있다.

✅ 내 프로필 조회 기능 구현

  • URL: /api/users

UserController

  • 로그인된 유저의 정보를 가져와야하기 때문에 @UserInfo 사용
  • 반환형식
  • 우선, 팔로워, 내가 작성한 댓글, 내 게시물은 다른 도메인의 repository를 주입받아와야하기 때문에 프로필 조회에 있어서 닉네임, 이메일, photo만 조회하게끔 만들었다.

ProfileResponseDto

UserSerivce

postman 결과


✅ 프로필 수정 기능 구현

UserController

@Transactional  
public ProfileResponseDto updateProfile(ProfileRequsetDto requsetDto, User user) {  
    user.update(requsetDto);  
    userRepository.update(user);  
    return user.profileResponseDto();  
}

User Service

@Transactional  
public ProfileResponseDto updateProfile(ProfileRequsetDto requsetDto, User user) {  
    user.update(requsetDto);  
    userRepository.update(user);  
    return user.profileResponseDto();  
}

ProfileRequestDto

@Getter  
public class ProfileRequsetDto {  
  
    private String nickname;  
    private String photo;  
}

User

public void update(ProfileRequsetDto requsetDto) {  
    this.nickname = requsetDto.getNickname();  
    this.photo = requsetDto.getPhoto();  
}  
  
public ProfileResponseDto profileResponseDto() {  
    return new ProfileResponseDto(nickname, email, photo);  
}

✅ 비밀번호 수정 기능 구현

  • 기존 비밀번호가 진짜 비밀번호가 맞는지 확인하기 위해 validatePassword 메서드 호출
  • 수정하고 인코딩 수행
  • User에서 update 처리
  • UserRepository update

UserController

@PostMapping("/api/users/change-password")  
@Operation(summary = "비밀번호 변경 API")  
public ResponseEntity<ResponseDto<ProfileResponseDto>> updatePassword(  
    @RequestBody @Valid ChangePasswordRequestDto requestDto, @UserInfo User user) {  
    return ResponseEntity.ok()  
        .body(ResponseDto.<ProfileResponseDto>builder()  
            .message("비밀번호 변경 성공")  
            .data(userService.updatePassword(requestDto, user))  
            .build());  
}

ChangePasswordRequestDto

@Getter  
public class ChangePasswordRequestDto {  
  
    @NotBlank(message = "현재 비밀번호를 입력하세요.")  
    private String existingPassword;  
    @NotBlank(message = "변경하고자 하는 비밀번호를 입력하세요.")  
    private String newPassword;  
  
}

UserService

@Transactional  
public ProfileResponseDto updatePassword(ChangePasswordRequestDto requestDto, User user) {  
    String existingPassword = requestDto.getExistingPassword();  
    String newPassword = requestDto.getNewPassword();  
      
    user.validatePassword(existingPassword, passwordEncoder);  
    user.updatePassword(passwordEncoder.encode(newPassword));  
      
    userRepository.update(user);  
      
    return user.profileResponseDto();  
}

User

public void updatePassword(String newPassword) {  
    this.password = newPassword;  
}
profile
안녕하세요

0개의 댓글