Projects/Personal project - 게시판 만들기

DB연동 도중 발견된 버그들(Enumerated, AuditingEntityListener, Optional 메서드)

마손리 2023. 5. 22. 21:59

회원에 관한 CRUD 서비스를 완성하고 회원을 등록했을때 발견된 버그이다.

 

위의 그림을 살펴보면 CREATED_AT, LAST_MODIFIED_AT, MEMBER_STATUS 컬럼이 비어있다.

 

JPA에서는 참조 타입에 입력값이 없는경우 null로, int와 같이 정수형 원시타입의 경우 0으로 채워져 저장된다. 

 

 

버그1 - MEMBER_STATUS에 열거형 데이터 적용

public class Member extends Auditable {
	...
    ...
    @Enumerated
    @Column(length = 20, nullable = false)
    private MemberStatus memberStatus = MemberStatus.MEMBER_ACTIVE;
    ...
    ...
    public enum MemberStatus{
        MEMBER_ACTIVE("활동중"),
        MEMBER_SLEEP("활동 중지"),
        MEMBER_QUIT("활동 정지");
        @Getter
        private String status;

        MemberStatus(String status) {
            this.status = status;
        }
    }
}

위와 같이  memberStatus에 관해 제대로 초기화 해주었는데도 버그가 발생했다. 

 

좀더 살펴보면 MemberStatus는 String으로 열거형이 정의되 있다. 

 

@Enumerated 에너테이션은 value라는 attribute가 있는데 여기서 숫자형 혹은 문자형인지 명시해 주어야한다.

(default는 숫자형이기 때문에 데이터베이스에서 숫자0으로 잘못 초기화된것이다.) 

 

@Enumerated(value = EnumType.STRING)

위와 같이 열거형 타입을 attribute로 정해주니 간단히 해결되었다.

 

 

버그2 - CREATED_AT과 LAST_MODIFIED_AT 초기화

두번째 버그도 사소한 실수때문에 생겨난 버그이다. 코드먼저 살펴보자면

 

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class Auditable {
    @CreatedDate
    @Column(name = "created_at", updatable = false)
    private LocalDateTime createdAt;

    @LastModifiedDate
    @Column(name = "LAST_MODIFIED_AT")
    private LocalDateTime modifiedAt;
}

@MappedSuperclass를 사용하여 엔티티에서 사용할 추상클래스를 정의 해준뒤 @EntityListeners를 이용하여AuditingEntityListener를 사용해준다 정의해 주었다.

 

아무리 살펴봐도 버그가 일어날 부분을 찾지 못했다...

 

계속해서 찾아본 결과... 코드상으론 문제가 없엇지만 중요한 에너테이션을 하나 까먹고있엇다...

 

@EnableJpaAuditing
@SpringBootApplication
public class BoardProjectApplication {
	public static void main(String[] args) {
		SpringApplication.run(BoardProjectApplication.class, args);
	}
}

해당 어플리케이션의 메인 클래스에 @EnableJpaAuditing을 추가하여 Jpa의 Auditing기능을 사용한다고 정의 해주어야 AuditingEntityListener를 사용할 수가 있다.

 

 

버그3 - Oauth2를 이용한 로그인 및 회원가입 버그

Spring Security의 Oauth2를 사용하는 로그인 기능을 넣고 인증처리가 완료되면 Oauth2를 이용해 받은 회원의 정보를 해당 어플리케이션의 서비스 계층으로 보내 회원가입을 진행시키게 코드를 작성해 주었다.

 

public class MemberService {
	...
    ...
    public Member oauth2CreateMember(Member member){
        member.setRoles(customAuthorityUtils.createRoles(member.getEmail()));

        Optional<Member> optionalMember = repository.findByEmail(member.getEmail());
        return optionalMember.orElse(repository.save(member)); // 에러 발생
    }

}

위와 같이 코드를 작성하여 인증을 마친 회원의 정보를 받아와 Optional 객체의 orElse()메서드와 람다식을 이용하여 DB에서 받아온 정보가 없다면 해당 회원을 가입시키려 하였다.

 

Oauth2 로그인을 처음 시도하면 정상적으로 잘 작동 하였지만 같은 사용자의 Oauth2 로그인을 두번째 시도하면 에러가 발생 했다.

 

orElse()메서드는 만약 데이터가 없다면 이름 그대로 람다식을 '실행' 만 시킨다. 하지만 작성된 코드는 Member 객체를 반환해야 한다. 

 

이때에는 orElseGet()메서드를 이용하여 optionalMember의 값이 null이라면 람다식을 실행한 뒤 반환된 값을 얻도록 해주어야 한다. 

 

 

변경된 식

return optionalMember.orElseGet(() -> optionalMember.orElse(repository.save(member)));

 

 

마무리

버그3의 경우는 Optional 객체에 대한 지식 부족으로 생겨난 버그이지만 버그1과 2는 정말 사소한 실수로 인해 발생한 버그이다. 이런 사소한 실수는 찾기도 어렵고 검색하기도 어렵다.

 

꼭 까먹지말고 한번더 체크하자!!