일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- CentOS
- 프로그래머스
- 스프링의 정석
- 카프카
- Spring Security
- docker
- 개인프로젝트
- EC2
- 패스트캠퍼스
- 스파르타코딩클럽
- visualvm
- emqx
- 데이터베이스
- MYSQL
- java
- 남궁성과 끝까지 간다
- 생성자 주입
- AWS
- JWT
- DB
- Spring
- 스웨거
- @jsonproperty
- WEB SOCKET
- 시큐리티
- Kafka
- 웹개발
- JavaScript
- 쇼트유알엘
- 항해99
- Today
- Total
Nellie's Blog
[TIL-221129화] 항해99 16일차 본문
배운점
Entity란?
Entity 클래스는 DB의 테이블에 존재하는 Column들을 필드로 가지는 객체를 말한다. Entity는 DB의 테이블과 1대 1로 대응된다.
JPA를 사용할 때 Entity 클래스에는 @Entity 어노테이션을 붙여서 Entity임을 명시해 줘야 하며,
내부의 필드에는 @Column, @Id 어노테이션 등을 사용한다.
Entity는 외부에서 최대한 Entity의 Getter를 사용하지 않도록 내부에 로직을 구현하는데, 이 때 Domain 로직만 구현하고 Presentation 로직은 구현하지 않는다.
Entity의 Getter 사용을 최대한 피하라고 했지만, 기본적으로 Entity를 만들 때 Getter는 만들어줘야 한다. 그런데 이동욱님이 쓰신 책을 보니, Entity 클래스에서 Setter를 만드는 것은 피하라는 조언이 있었다.
일반적으로 자바 클래스를 만들때 private 필드들을 가지고 습관적으로 Getter와 Setter를 만들고는 하는데, 문제는 Setter의 사용이 Entity의 일관성을 해칠 수 있다는 것이다.
Setter를 무분별하게 사용하게 되면, Entity의 인스턴스 값들이 언제 어디서 변하는지 명확히 알 수 없다. 따라서 Setter 대신 다른 방법으로 필드에 값을 넣어 주는 것이 좋다.
그런데 일반적으로 생각할 수 있는 인스턴스의 생성 시점에 생성자로 필드에 값을 넣어주는 방법 또한 그다지 좋지 않은 방법일 수 있는데, 생성자에 현재 넣는 값이 어떤 필드인지 명확히 알 수 없고, 매개변수끼리의 순서가 바뀌더라도 코드가 모두 실행되기 전까지는 문제를 알 수 없다는 단점이 있기 때문이다.
따라서 Builder 패턴을 사용하는 것이 가장 좋다. 멤버 변수가 많아지더라도 어떤 값을 어떤 필드에 넣는지 코드를 통해 확인할 수 있고, 필요한 값만 집어넣는 것이 가능하기 때문이다.
DAO란?
DAO는 Data Access Object의 약자로, 실제로 DB에 접근하는 객체다. DAO는 프로젝트의 서비스 모델과 실제 데이터베이스를 연결하는 역할을 하며, JPA에서는 DB에 데이터를 CRUD 하는 Repository 객체들이 DAO라고 볼 수 있다.
DB의 data에 접근하기 위한 객체이다. DB에 접근하기 위한 로직을 분리하기 위해 사용한다.
직접 DB에 접근하여 data를 삽입, 삭제, 조회 등 조작할 수 있는 기능을 수행한다.
MVC 패턴의 Model에서 이와 같은 일을 수행한다. Repository package가 바로 DAO.
@Repository
@RequiredArgsConstructor
public class MemberRepository {
private final EntityManager em;
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();
}
}
DTO란?
DTO는 Data Transfer Object의 약자로, 계층 간 데이터 교환 역할을 한다. DB에서 꺼낸 데이터를 저장하는 Entity를 가지고 만드는 일종의 Wrapper라고 볼 수 있는데, Entity를 Controller 같은 클라이언트단과 직접 마주하는 계층에 직접 전달하는 대신 DTO를 사용해 데이터를 교환한다.
DTO는 그저 계층간 데이터 교환이 이루어 질 수 있도록 하는 객체이기 때문에, 특별한 로직을 가지지 않는 순수한 데이터 객체여야 한다. 또한 DB에서 꺼낸 값을 DTO에서 임의로 조작할 필요가 없기 때문에 DTO에는 Setter를 만들 필요가 없고 생성자에서 값을 할당한다. 개인적으로는 생성자 또한 사용하지 않고 Entity처럼 Builder 패턴을 통해 값을 할당하는 것이 가장 좋은 것 같다.
DTO는 계층 간(Controller, View, Business Layer) 데이터 교환을 위한 자바 빈즈(Java Beans)를 의미한다.
DTO는 로직을 가지지 않는 데이터 객체이고 getter/setter 메소드만 가진 클래스를 의미한다.
- DTO는 즉, getter/setter 메서드만 가진 클래스를 의미합니다.
- DB에서 데이터를 얻어서 Service나 Controller 등으로 보낼 때 사용합니다.
- 즉 엔티티를 DTO 형태로 변환한 후 사용합니다.
한번 예시 코드로 정리해 보겠습니다.
- domain(Entity) logic
- DTO logic
- Controller logic
1) 먼저 아래와 같은 Entity가 있다고 가정합시다.
@Entity
@Getter
@Setter
public class Member {
@Id
@GeneratedValue
private Long id;
private String name;
private int age;
}
2) 아래는 DTO class
@Getter
@Setter
static class ResponseDto {
private String name;
private String result = "결과입니다.";
public ResponseDto(Member member) {
name = member.getName();
}
}
3) 아래는 Controller logic
@PostMapping("api/useDTO")
@ResponseBody
public ResponseDto useDTO(@RequestParam String name, @RequestParam Long id) {
Member findMember = memberService.findOne(id);
return new ResponseDto(findMember);
}
@PostMapping("api/notUseDTO")
@ResponseBody
public FindMember notUseDTO(@RequestParam String name, @RequestParam Long id) {
Member findMember = memberService.findOne(id);
return new FindMember(findMember);
}
결과
useDTO 메서드는 Entitiy의 결과를 DTO로 변환하여 원하는 결과인 name과 result만 클라이언트에게 반환합니다. 하지만 notUseDTO는 Member엔티티의 모든 정보 즉, 엔티티 그 자체를 클라이언트에게 반환합니다.
현재 예시는 DTO를 Response에만 이용했지만 Request역시 적용할 수 있습니다.
Entity와 DTO를 분리하는 이유
Entity의 값이 변하면 Repository 클래스의 Entity Manager의 flush가 호출될 때 DB에 값이 반영되고, 이는 다른 로직들에도 영향을 미친다.
때문에 View와 통신하면서 필연적으로 데이터의 변경이 많은 DTO 클래스를 분리해주어야 한다.
또한 도메인 설계가 아무리 잘 되었다 해도 Getter만을 이용해서 원하는 데이터를 표시하기 어려운 경우가 발생할 수 있는데, 이 경우에 Entity와 DTO가 분리되어 있지 않다면 Entity 안에 Presentation을 위한 필드나 로직이 추가되게 되어 객체 설계를 망가뜨리게 된다.
때문에 이런 경우에는 분리한 DTO에 Presentation 로직 정도를 추가해서 사용하고, Entity에는 추가하지 않아서 도메인 모델링을 깨뜨리지 않는다.
DTO와 VO와의 차이
VO(Value Object)도 DTO와 동일한 개념이다. 다만 DTO와의 차이는, DTO는 데이터를 계층간 교환(Transfer)하는데 의미가 있고, VO는 읽기만 가능한 read-only 속성을 가진 객체로서 데이터 그 자체에 의미를 두고 있다는 점이다.
JPA도 배웠다.
쿼리를 직접 작성하지 않고, 엔터티객체만 만들어줘서 사용자가 훨씬 편하도록 설계된 기술이다.
느낀점
스프링부트를 시작했는데, 스프링보다는 훨씬 편했다. JPA도 편하긴 했지만 그 과정을 아직 다 알지는 못해서,
개인적으로 공부를 더 탄탄하게 해야 할 것 같다.
어제는 공부를 거의 못했는데 오늘은 10시간 이상 공부했다. 뿌듯했다. 역시 집보다는 도서관이 공부가 잘된다.
'회고록' 카테고리의 다른 글
[TIL-221201목] 항해99 18일차 -[Spring] 회원 조회 API 만들기 시험 (0) | 2022.12.01 |
---|---|
[TIL-221130수] 항해99 17일차 (0) | 2022.11.30 |
[TIL-221128월] 항해99 15일차 (0) | 2022.11.29 |
[TIL-221125금] 항해99 12일차 (0) | 2022.11.25 |
[TIL-221124목] 항해99 11일차 - 알고리즘 테스트 (0) | 2022.11.24 |