회원에 관한 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는 정말 사소한 실수로 인해 발생한 버그이다. 이런 사소한 실수는 찾기도 어렵고 검색하기도 어렵다.
꼭 까먹지말고 한번더 체크하자!!
'Projects > Personal project - 게시판 만들기' 카테고리의 다른 글
MockMVC - Multipart form data요청 테스트 (0) | 2023.06.10 |
---|---|
Mock test 단계에서 발생한 MockHttpServletResponse: body is empty (0) | 2023.06.08 |
파일 업로드를 위한 AWS S3 연결 도중 발생한 문제들과 해결방안 (0) | 2023.06.07 |
JPQL문에서 Enum 사용하기 (0) | 2023.05.30 |
UnexpectedTypeException과 DTO에서 Enum타입 사용 (1) | 2023.05.24 |