들어가며
MVC패턴
2023.11.26 - [Learning Java Spring] - 처음 자바 스프링을 공부한다면?Java Spring 프레임워크의 기본
회원 엔터티 개발
@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);
}
}
'Java Spring > Spring Boot' 카테고리의 다른 글
웹 계층 컨트롤러 개발 Spring Boot 기본 (5) (0) | 2023.12.12 |
---|---|
주문 도메인 개발 Spring Boot 기본 (4) (0) | 2023.12.11 |
상품 도메인 개발 Spring Boot 기본 (3) (0) | 2023.12.11 |
도메인 설계 Spring Boot 기본 (1) (1) | 2023.12.07 |