728x90

들어가며,


간단한 SNS 모델링을 통해 MySQL의 기능들을 사용해 볼 계획입니다.

아래 기술들을 활용해 Layered 구조로 작성했습니다.

 

Java 17

Spring Boot 3.x

MySQL 8.x

 

회원정보 등록을 구현


회원정보

  • 아이디
  • 닉네임 -*닉네임 최대 길이는 10자.
  • 이메일
  • 생년월일
// 파라미터를 RegisterMemberCommand로 받는다.
//val member = Member of(registerMemberCommand)
//memberRepository.save(member)

 

public record RegisterMemberCommand(
        String email,
        String nickname,
        LocalDate birthdate ) {
}
Java Spring Framework에서 Record는 Java 16부터 도입된 새로운 기능 중 하나입니다. Record는 불변(Immutable) 데이터를 표현하기 위한 간편한 방법을 제공합니다. Record를 사용하면 클래스를 정의할 때 간결하게 필드를 선언하고, 불변성과 자동으로 생성되는 메서드를 얻을 수 있습니다.

 

AS-IS

@Getter
public class Member {

    private final Long id;
    private final String nickname;
    private final String email;
    private final LocalDate birthdate;
    private final LocalDate createdAt; // 로그를 위해 생성시간 추가

    //nickname.length() <= 10
    private static final Long MAX_NICKNAME_LENGTH = 10L;
    @Builder
    public Member(Long id, String nickname, String email, LocalDate birthdate, LocalDate createdAt) {
        this.id = id;
        this.nickname = Objects.requireNonNull(nickname);
        this.email =  Objects.requireNonNull(email);
        this.birthdate = birthdate;
        this.createdAt = createdAt == null ? LocalDate.now() : createdAt;

        if (nickname.length() > MAX_NICKNAME_LENGTH) {
            throw new IllegalArgumentException("nickname length must be less than " + MAX_NICKNAME_LENGTH);
        }

 

이 엔터티 코드는 불변하는 필드값을 빌더 패턴을 통해 객체를 생성할 수 있습니다.
그러나 현재 코드는 생성자 내에 객체 생성과 유효성 검사를 동시에 수행하고 있어, SRP를 위반하고 있습니다.

 

TO-BE

    @Builder
    public Member(Long id, String nickname, String email, LocalDate birthdate, LocalDate createdAt) {
        this.id = id;
        this.email =  Objects.requireNonNull(email);
        this.birthdate = birthdate;

        validateNickname(nickname);
        this.nickname = nickname;
        this.createdAt = createdAt == null ? LocalDate.now() : createdAt;
//
//        if (nickname.length() > MAX_NICKNAME_LENGTH) {
//            throw new IllegalArgumentException("nickname length must be less than " + MAX_NICKNAME_LENGTH);
//        }

    }
    void validateNickname(String nickname) {
        if (nickname == null || nickname.length() > MAX_NICKNAME_LENGTH) {
            throw new IllegalArgumentException("Invalid nickname");
        }
    }

 

따라서 validateNickname 메서드를 통해 유효성 검사를 분리해, 각 메서드 또는 클래스가 하나의 책임을 갖도록 수정되어야 합니다.

 

@Service
@RequiredArgsConstructor
public class MemberWriteService {

    private final MemberRepository memberRepository;
	// member 객체 생성한다.
    public void createMember(RegisterMemberCommand command) {

        var member = Member.builder()
                .nickname(command.nickname())
                .email(command.email())
                .birthdate(command.birthdate())
                .build();
		// member 객체를 Repository에 저장한다.
        memberRepository.save(member);
    }

 

서비스 계층에서는 비즈니스 로직을 수행합니다. 

1. 회원정보 생성
우선 생성 단계에서는 Command 명령 객체를 통한 createMember 메서드를 정의합니다.
var를 통해 초기화하고 빌더 패턴으로 객체를 생성합니다.

2. 회원정보 저장
Repository의 save메서드를 통해 저장한다.

 

Repository의 save메서드 정의 :

--> id값을 통해 null 값이면, 삽입(insert)한다.

--> null값이 아니면, 갱신(update)한다.

 

private Member insert(Member member) {
    SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(namedParameterJdbc.getJdbcTemplate())
            .withTableName("Member")
            .usingGeneratedKeyColumns("id");
    SqlParameterSource params = new BeanPropertySqlParameterSource(member);
    
    var id = simpleJdbcInsert.executeAndReturnKey(params).longValue();
    return Member.builder()
            .id(id)
            .nickname(member.getNickname())
            .email(member.getEmail())
            .birthdate(member.getBirthdate())
            .createdAt(member.getCreatedAt())
            .build();
}

 

Repository는 NamedParameterJdbcTemplete을 주입받아 insert와 update에 관한 Jdbc 메서드를 생성합니다.
SimpleJdbcInsert를 통해 테이블과 키값을 지정하고 삽입을 수행
SqlParameterSource를 통해 객체 필드를 SQL 파라미터로 변환

 

Swagger UI : http://localhost:8080/swagger-ui/index.html#/

 

 

+ Recent posts