: 데이터베이스의 테이블과 매핑하는 객체. 쉽게 말하면 SQL Query문을 통해 만들어진 테이블을, 객체형태로 바꾼 것이 Entity라고 생각하면 된다.
테이블과 매핑하므로 Primary Key가 존재하며, 각 Property의 자료형을 정의할 수 있다.
@Entity
@Getter
@Setter
public class Member {
@Id
@GeneratedValue(
private Long id;
private String name;
private int age;
}
이는 SQL의 다음 쿼리문에 대응된다.
CREATE TABLE MEMBER(
id INT PRIMARY KEY,
name VARCHAR,
age INT
)
@OnetoOne@OneToMany(mappedBy = "종속 관계 객체의 필드명", cascade = CascadeType.REMOVE)@ManyToOne@ManyToMany (권장하지 않음, 중간 엔티티를 두어 해소)@GeneratedValue(strategy = GenerationType.IDENTITY@JoinColumn(name = 'Column 명')@Entity@Getter: 데이터베이스에 실질적으로 접근하는 객체로, DB의 CRUD 작업을 도맡는다. (삽입, 수정, 삭제 등등…)
데이터베이스에 접근하는 로직과, 비즈니스 로직을 분리시킴으로써 관리를 하기 편하도록 하는 것이 DAO의 역할.
: 계층 간 데이터의 교환을 위해 사용하는 객체. 별다른 로직이 없는 순수한 객체로 getter와 setter로 이루어져 있으며, DB 처리 간 로직을 숨기기 위해 나왔다.
@Getter
@Setter
static class ResponseDto {
private String name;
private String result = "결과입니다.";
public ResponseDto(Member member) {
name = member.getName();
}
}
DTO는 다음과 같이 사용된다.
@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);
}
requestBody의 id를 통해 Service에게 아이디를 찾도록 요구한다.findOne(id)를 통해 member 객체를 반환한다.name을 전달한다.다음과 같이 name 이라는 데이터를 전달하기 위해 DTO가 쓰인 것을 볼 수 있다.
⇒ Member의 특정 정보를 뽑아오고 싶을 때 API를 여러번 계속 호출하는 것이 아닌, DTO를 통해 Member의 데이터를 한번에 뽑아오고 그 DTO에서 데이터를 선택적으로 추출하기 위해 DTO를 사용하는 것이다.
보통 DTO는 클라이언트와 서버 간의 통신 과정에서 데이터의 교환을 중계하는 역할을 한다. 조금 더 쉽게 이해하자면, 프론트엔드에서 서버 측에 데이터를 송신하거나 요청할 때, 서버에서는 객체 자체를 주는 것이 아니라, 객체의 데이터를 대신 옮겨주는 중계자를 통해 전달한다.
왜 중계를 하느냐? 바로, 객체를 외부로부터 은닉할 수 있으며, 어떤 데이터를 줄지 선택할 수 있다. 가령, 사용자의 정보를 요청할 때, 사용자의 비밀번호 같은 개인적인 정보까지 주면 안된다. 서버 입장에서는 사용자의 이름과 같은 정보만 주고 싶고 그외의 정보는 주고 싶지 않을 때, DTO를 선언하여 이름과 같은 정보만 전달할 수 있도록 선언하고, 그 외의 정보는 주지 않는 것이다.
public class Membership {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID")
private String id;
private String password; //민감한 정보
private String name;
private String tel_phone;
private String card_number; //민감한 정보
...
}
@Getter
@AllArgsConstructor
public class ResponseMembershipDto {
private String id;
private String name;
private String tel_phone;
private ResponseMembershipDto of(Membership membership){
return new ResponseMembershipDto(membership.getId(), membership.getName(),
membership.getTel_phone());
}
public static ResponseMembershipDto from(Membership membership){
return new ResponseMembershipDto(membership);
}
여기서보면 Membership 객체에는 이름, 전화번호, 아이디 뿐만 아니라 비밀번호, 카드번호와 같은 민감한 정보까지 모두 포함하고 있다. 프론트엔드 측에서는 이름과 같은 공개된 정보만 받으면 되는데, 이 과정에서 Membership 객체 자체를 넘기게 되면 민감한 정보까지 그대로 전달하게 된다.

이때, DTO를 통해 대신 정보를 넘기도록 한다면 비밀번호와 카드번호는 넘기지 않도록 설정하고, 나머지 정보만 전달할 수 있도록 설정하면 훨씬 더 안전하게 정보를 전달할 수 있을 것이다.
조금 신기한게, 프론트엔드 단에서도 동일하게 DTO를 구현해야 한다. 왜냐? 서버에서 프론트 쪽으로 데이터를 전송할 때는 DTO 객체 자체를 전달하기 때문이다. 비유하자면 프로토콜과 유사하다. 프로토콜은 양 쪽에서 서로 대칭적인 구조를 지녀야만 통신이 가능한데, 마찬가지로 프론트 단에서도 동일한 구조의 DTO를 가지고 있어야 전달받은 DTO 객체를 해석할 수 있기 때문이다.