728x90

들어가며


 

 

 

MVC패턴


2023.11.26 - [Learning Java Spring] - 처음 자바 스프링을 공부한다면?Java Spring 프레임워크의 기본

 

처음 자바 스프링을 공부한다면?Java Spring 프레임워크의 기본

백엔드 개발자를 선택하고 나서 개발자에게 프론트는 js, 백은 Java를 선택해야(?)만 할정도로 한국 사회에서 가장 널리 보급되고 있는 것 같다. 프론트 백엔드 웹 html, css, js (React, Next) Java, Java Spri

wooltech.tistory.com

회원 엔터티 개발


@Entity @Getter @Setter 등을 통해 클래스 생성하며, @Id @GeneratedValue @Column으로 기본키 PK설정 및 컬럼명을 지정한다.

 

 

@Entity
@Table(name = "member")
@Getter @Setter
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "member_id")
    private Long id;

    private String name;

    @Embedded
    private Address address;

    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>();
}

@Embeded와 protected를 통해 별도의 정보 클래스를 정의하고 상위 엔티티에 포함시키는 방법:

  • 회원과 배송 모두 @Embeded를 통해 주소 클래스의 정보를 가진다.
  • 주소 클래스는 생성자를 통해 객체 정보를 사용가능하도록 초기화 한다.
  • 생성된 객체는 protected로 보호되는데 이는 캡슐화된 정보에 접근하기 위한 접근자이다. 즉, 변경을 제한한다.
@Embedded
 private Address address;

@Embeddable
@Getter
public class Address {
 private String city;
 private String street;
 private String zipcode;
 
 protected Address() {
 }
 public Address(String city, String street, String zipcode) {
 this.city = city;
 this.street = street;
 this.zipcode = zipcode;
 }

 

 

 

회원 리포지토리 개발


@Repository를 통해 리포지토리 클래스임을 지정한다.

@PersistenceContext에서 엔티티 매니저를 주입해 도메인에서 만들어 둔 엔티티를 관리한다.

 

save(), findOne(), findAll(), findByName() 메서드를 통해 본격적으로 기능을 구현한다.

@Repository
public class MemberRepository {

    @PersistenceContext
    private EntityManager em;

 

1.  save(Member member) 메서드:

save를 통해 전달 받은 Member 객체를 persist메서드를 사용하여 영속성 컨텍스트에 저장한다.

이후 서비스 계층에서 트랜잭션이 커밋되면, DB에 반영된다.

 

2.  findOne(Long id) 메서드:

Member의 주어진 id를 찾는 메서드이다.

1차적으로 영속성 컨텍스트내의 캐시에서 조회를 한 후, 없다면 JPA가 직접 데이터베이스에 select구문을 만들어 조회한다. 이는 id가 식별자이기 때문에 가능한 것이다.

  • em.find(클래스, 기본키)

3. findAll() 메서드:

DB에 저장된 모든 회원을 List로 반환한다. 

select m from Member m을 통해 모든 회원을 조회하는 쿼리 구문을 생성한다.

select 쿼리가 실행된 후 getResultList를 통해 리스트로 받아온다.

 

4. findByName(String name) 메서드:

매개변수인 이름값으로 조회하는 방법

이름에 들어갈 내용은 동적인 데이터이기 때문에 setParameter 매개변수 바인딩을 사용해 안정적으로 제공한다.

예를 들면,

select m from Member m where m.name = 'John' 이 쿼리에서는 .setParameter("name", John)이 된다.

    public void save(Member member) {
        em.persist(member);
    }

    public Member findOne(Long id) {
        return em.find(Member.class, id);
    }

    public List<Member> findAll() {
        return em.createQuery("select m from Member m", Member.class)
                .getResultList();
    }
    public List<Member> findByName(String name) {
        return em.createQuery("select m from Member m where m.name = :name", Member.class)
                .setParameter("name", name)
                .getResultList();
    }
}

회원 서비스 개발


@Service 서비스 계층임을 나타내며, readOnly = true를 통해 읽기 전용으로 사용된다.

즉, 데이터의 수정은 일어나지 않음을 의미한다.

@RequiredArgsConstructor를 통해 생성자를 자동으로 생성하여, ItemRepository를 주입받는다.

(final 또는 @NonNull로 표시된 필드를 사용하여, 생성자를 만든다.)

 

생성자 주입을 하는 이유:

  • 리포지토리에서 구현된 회원 정보를 외부에서 받아와 사용하기 때문에 유연성과 재사용성의 장점을 가진다.
  • 리포지토리의 회원 정보를 수정하더라도 서비스의 내용은 수정하지 않아도 된다.
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class MemberService {

    private final MemberRepository memberRepository;

 

메서드에서 id를 반환하는 이유:

  • 새로운 회원정보가 데이터베이스에 저장되고 회원id가 반환되어야 클라이언트가 이 정보를 활용할 수 있다.
  • 로그인, 회원 정보 수정 등에 활용된다.
 //회원가입
    @Transactional
    public Long join(Member member) {
        validateDuplicateMember(member);
        memberRepository.save(member);
        return member.getId();
    }

    private void validateDuplicateMember(Member member) {
        List<Member> findMembers = memberRepository.findByName(member.getName());
        if (!findMembers.isEmpty()) {
            throw new IllegalStateException("이미 존재하는 회원입니다.");
        }
    }

 

 회원조회는 사용하지 않고 회원가입에만 Transactional이 사용된 이유:

  • Transactional을 사용하는 이유는 트랜잭션을 통해 리포지토리에서 구현한 정보를 DB에 반영하기 위함이다.
  • 즉, 가입에는 새로운 회원 정보를 DB에 저장해야 하지만 회원 조회에서는 새로운 값을 넣는 것이 아닌 get을 통한 호출만 다루고 있기 때문에 Transactional이 필요하지 않다.
    // 전체 회원 조회
    public List<Member> findMembers() {
        return memberRepository.findAll();
    }

    public Member findOne(Long memberId) {
        return memberRepository.findOne(memberId);
    }
}

+ Recent posts