Project

프리온보딩 인턴십 백엔드 TIL #5

newny 2023. 11. 3. 03:21
반응형

⭐알게된 것

StringJoiner

exceptionHandler를 추가하며 메세지를 얻어올 때 사용할 메소드를 만들었다. 메세지가 여러개일 때 콤마를 구분자로하여 나열하여 반환해주는 메소드이다. 원래 코드는 boolean을 이용하여 첫번째 메세지라면 콤마를 붙이지 않는 형태로 하여 메소드를 만들었는데, 코드리뷰를 받으면서 코드를 더 간결하게 하고 가독성 있게 만들 수 있는 StringJoiner라는 클래스를  알게 되었다.
StringJoiner 사용 방법
  1. StringJoiner 객체를 생성할 때 구분자로 사용할 문자를 넣어 생성한다.
  2. 생성된 객체에 add 메소드를 이용하여 메세지를 구분자로 구분 할 단위로 넣는다.
private String getMessage(MethodArgumentNotValidException e) {

	StringJoiner joiner = new StringJoiner(", ");

	for (FieldError fieldError : e.getBindingResult().getFieldErrors()) {
    	String message = "[" + fieldError.getField() + "]은(는) " + fieldError.getDefaultMessage();
        joiner.add(message);
    }
    return joiner.toString();
}
 

EOF (End Of File)

"마지막 빈 줄"을 명시적으로 추가하는 것은 자바 언어와 관련이 있는 것이 아니다. 이러한 설명은 주로 스크립트 언어나 텍스트 파일을 처리하는 도구와 관련이 있다.
자바에서의 EOF는 파일 처리 스트림을 통해 자동으로 처리되며, 특별한 "마지막 빈 줄"을 명시적으로 추가할 필요가 없다. 자바에서는 EOF를 read() 메서드가 -1을 반환하는 방식으로 처리한다. 파일 처리 스트림을 사용하면 이러한 EOF 처리가 자동으로 이루어진다.
 

📒 오답 노트

# 처음 짠 코드

public User getAuthenticatedByLogin(LoginRequestDto loginRequestDto) {
	User user = userRepository.findByUsername(loginRequestDto.getUsername())
    		.orElseThrow(NotFoundUserException::new);
	String encryptedPassword = user.getPassword();

	if (!passwordEncoder.matches(loginRequestDto.getPassword(), encryptedPassword)) {
		throw new MismatchPasswordException();
    }
	return user;
}

@Transactional
public JwtResponse getLoginAuthorization(User user) {
	return TokenProvider.createJwt(user.getId(), secretKey, expiredMs);
}
위의 코드는 틀린 코드이다. Transaction의 아주 기본적인 개념을 무시하는 코드이다. 나의 생각으로는 getLoginAuthorization 메소드가 getAuthenticateByLogin 메소드를 사용하고 있기에 Transaction이 getLoginAuthorization메소드에서 발동되어야 한다고 생각했다.  @Transactional의 경우 DB와 직접 적으로 연관이 되어있는 서비스 메소드에 붙여야 함을 생각못하고 마음대로 해석하여 getLoginAuthorization 메소드에 붙였다. 그리하여 코드를 바꾸었다.
 
# 변경한 코드
@Transactional
public User getAuthenticatedByLogin(LoginRequestDto loginRequestDto) {
	User user = userRepository.findByUsername(loginRequestDto.getUsername())
    		.orElseThrow(NotFoundUserException::new);
	String encryptedPassword = user.getPassword();

	if (!passwordEncoder.matches(loginRequestDto.getPassword(), encryptedPassword)) {
		throw new MismatchPasswordException();
    }
    return user;
}

public JwtResponse getLoginAuthorization(User user) {
	return TokenProvider.createJwt(user.getId(), secretKey, expiredMs);
}
위의 코드도 틀린 코드이다.(ㅎㅎ) @Transactional 코드를 위의 메소드로 옮겼지만 아직도 틀렸다. 이유는 서비스 내의  한 로직을 담당하는 메소드가 접근제어자가 public 인 다른 메소드를 불러오는 형태로 되어있는것이 이유이다. public의 메소드는 각각의 로직을 담당하는데 다른 메소드를 불러서 사용하고 싶은 경우 사용되는 메소드의 접근제어자가 private 여야 한다.
하지만 @Transactional 어노테이션을 사용하려면 해당 메소드의 접근제어자가 public 또는 protected 여야 하기 때문에 (프록시 생성의 이유) public 접근제어자는 그대로 사용해야한다.
 
# 최종 변경된 코드
@Transactional(readOnly = true)
public User getAuthenticatedByLogin(LoginRequestDto loginRequestDto) {
	User user = userRepository.findByUsername(loginRequestDto.getUsername())
 			.orElseThrow(NotFoundUserException::new);
	String encryptedPassword = user.getPassword();

	if (!passwordEncoder.matches(loginRequestDto.getPassword(), encryptedPassword)) {  
		throw new MismatchPasswordException();
    }
	return user;
}

public JwtResponse getLoginAuthorization(User user) {
	return TokenProvider.createJwt(user.getId(), secretKey, expiredMs);
}
💡 결론
controller 단에서 각각의 메소드를 호출하는것으로 로직을 변경하였다. 그리하여 @Transaction을 사용할 수 있는 상태를 만들고(public) 서비스 내에서 또 다른 public 접근제어자를 갖는 서비스를 호출하지 않아도 되었다.
반응형