코드스테이츠 수강 10주차 4일차에는 DTO에 대해 배웟다.
DTO란?
DTO는 Data Transfer Object의 줄인말로, 데이터 전송 객체 라고 보면된다.
뭔말이냐고?
데이터를 "전송"하는 것만 따로 클래스든 인스턴스든 만들어서 담당하게 한 "객체"라는 것이다.
DTO가 왜 필요하냐?
앞서 우리가 spring MVC 에서 배운 컨트롤러에 뭔 로직(메서드 핸들러 등)을 넣는다고 했는데, 거기에다가 그냥 전송하는 기능을 넣으면 그만 아닌가? 라고 할 수 있다.
그런데 이렇게 되면 문제가 생긴다.
기본적으로 뭐 손님의 이름, 이메일, 전화번호만 데이터로 저장하다가, 성별, 나이, 주문 성향 등의 정보까지 넣어서 상품을 추천하는 기능을 수행한다고 치자.
이렇게 되면 컨트롤러 부분에 성별, 나이, 주문 등등등 필요한 부분을 모두 만들어줘야 한다는 것이다.
DTO를 쓰면 코드를 간결하게 만들 수 있다!
코드 예시
@RestController
@RequestMapping("/v1/members")
public class MemberController {
@PostMapping
public ResponseEntity postMember(@RequestParam("email") String email,
@RequestParam("name") String name,
@RequestParam("phone") String phone) {
Map<String, String> map = new HashMap<>();
map.put("email", email);
map.put("name", name);
map.put("phone", phone);
// 이 밑에 뭐가 계속 생기면 계속 써줘야댐
return new ResponseEntity<Map>(map, HttpStatus.CREATED);
}
...
...
}
그런데, DTO를 사용해서 클래스 등으로 만들어서 하나의 "객체"로 만들어 주면
@RestController
@RequestMapping("/v1/members")
public class MemberController {
@PostMapping
public ResponseEntity postMember(MemberDto memberDto) {
return new ResponseEntity<MemberDto>(memberDto, HttpStatus.CREATED);
//DTO 객체를 직접 전달 해주는것으로 코드가 간결해진다.
}
...
...
}
위의 코드처럼 간결해 진다.
- DTO를 쓰지 않았을 때 : postMember()에 @RequestParam 파라미터가 계속 추가됨
- DTO를 썻을 때 : 직접 DTO를 객체(MemberDTO)로 만들어서 전달(ResponseEntity로 반환)하기 때문에 그냥 객채로만 만들면 그만임
-> 코드의 간결화, 데이터를 객체로 다룰 수 있게 하기 위해 DTO가 필요하다!
또, 데이터 유효성 검증의 단순화가 가능하다.
만약, 컨트롤러에 DTO를 사용하지 않은 상태에서 이메일, 이름, 전화번호 등을 저장한다고 치자.
이때, 이메일에는 영어만 사용 가능하게 하고 싶을 때 정규식을 활용해서 지정 가능하다.
@RestController
@RequestMapping("/no-dto-validation/v1/members")
public class MemberController {
@PostMapping
public ResponseEntity postMember(@RequestParam("email") String email,
@RequestParam("name") String name,
@RequestParam("phone") String phone) {
// 이메일에 알파벳만 들어가고, 특수문자는 못들어가게 하는 정규 표현식
if (!email.matches("^[a-zA-Z0-9_!#$%&'\\*+/=?{|}~^.-]+@[a-zA-Z0-9.-]+$")) {
throw new InvalidParameterException();
}
Map<String, String> map = new HashMap<>();
map.put("email", email);
map.put("name", name);
map.put("phone", phone);
return new ResponseEntity<Map>(map, HttpStatus.CREATED);
}
...
...
}
위 코드의 if 문을 보면, 이메일 주소를 영어만 넣을 수 있게끔 하는 정규 표현식이 있다.
한마디로 지정한 글자 외의 것이 들어오면 예외처리 되고 데이터에 안넣는다는것이다.
이것을"유효성 검증"이라고 한다!
유효성 검증은 지정한 조건 외에 것이 들어오면 처리 안하는것 이라고 보면 된다.
마치, 현관문 자물쇠 처럼, 언뜻 비슷해보이는 열쇠를 꼳아도 딱 맞는 열쇠가 아니면 열리지 않는 것 처럼, 조건을 설정 할 수 있다는 것이다.
위의 코드 예시를 보면, @RequestParam 파라미터를 줄줄 써서 만들었는데, DTO를 사용하면 다르게 만들 수 있다.
public class MemberDto {
// @Email 에너테이션을사용하면 그 바로 뒤에 있는 변수에 이메일 형식의 데이터만 드간다.
@Email
private String email;
private String name;
private String phone;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
위의 DTO 클래스를 활용해서 하나의 객체로 만들고, 조건만 달아주면 그만이다.
@RequestParam 파라미터를 줄줄 써줄 필요가 없다는 것이다.
@Email 에너테이션을 넣어주면 알아서 처리해주기 때문!
이렇게 DTO를 클래스로 만들어 주면 기존 컨트롤러는
@RestController
@RequestMapping("/v1/members")
public class MemberController {
@PostMapping
public ResponseEntity postMember(@Valid MemberDto memberDto) {
return new ResponseEntity<MemberDto>(memberDto, HttpStatus.CREATED);
}
...
...
}
이렇게 간략히 표현된다.
"잘 이해가 안간다고?"
핵심은 이거다
DTO를 사용하지 않으면, 컨트롤러에 일일히 파라미터를 넣어줘야 한다 -> 유효성 검증은 자물쇠와 같다.
-> 검증할게 많아질 수록 자물쇠 갯수가 콸콸콸!
위의 사진처럼, 검증할게 많아질수록 자물쇠도 많아진다!
DTO를 쓰면...
요즘 쓰는 비밀번호 도어락을 쓰는것과 같아진다.
왜냐? 검증할게 바뀌면 그냥 조건만 바꿔주면 되니까! -> 도어락의 비밀번호를 바꾸는 것과 같다!
해봐야 뭐 RFID 태크 칩을 새로 인식하는 정도만 다르고 도어락이 변하는 조건(검증 조건)에 대응 할 수 있어진다 이말이다!
DTO를 쓰면 자료 변환이 수월하다!
아무래도 데이터를 객체로 뭉탱이로 만들어서 휙 던지는 것이다 보니까 일일히 우리가 지정할 필요도 없고, 콤퓨터한테 맡겨버리면 그만이다.
대표적으로 JSON형식의 변환의 예시가 있다.
JSON이란?
우리가 클라이언트에서 서버로, 서버에서 클라이언트로 데이터를 던져줄때 사용하는 일종의 양식이라고 생각하면된다.
아래의 사진을 보면 이해가 빠르다.
왼쪽은 JSON타입, 오른쪽은 JAVA클래스 이다.
둘다 같은 객체를 담고 있다(정확한 값, 양념치킨 / 쥰맛탱 치킨/ 17500 등은 클래스에 안보이지만..)
대략 JSON은 전하고자 하는 데이터를 뭔가 필요한것만 담아서 요약한 형태로 보내주는 것과 비슷한 형태라고 생각하면 쉽다.
위의 JSON변환은 이 링크에서 해볼 수 있다. : https://jsonformatter.org/json-to-java
이때, JAVA클래스(객체)에서 JSON타입으로 만드는 것을 ->직렬화(Serialization)
JSON타입을 JAVA 객체 타입으로 만드는 것을 -> 역직렬화 (Deserialization)
라고 한다.
우리가 보기에는 복잡한 과정이 있을 것 같은데, 사실 그냥 DTO객체로 만들어서 스프링에 짬때리면 된다!
스프링에서 2가지 에너테이션이 있는데
- @RequestBody : 특정 JSON타입 객체 앞에 @RequestBody 를 붙여주면 JAVA클래스 객체로 변환 시켜준다. (직렬화)
- @ResponseBody : 특정 JAVA클래스 객체 앞에 @ResponseBody 를 붙여 주면 JSON으로 변환 시켜준다 (역직렬화)
와 같다.
앞서서 이메일, 이름, 전화번호를 담은 DTO 클래스를 적용한 컨트롤러를 작성한다고 치면
@PostMapping
public ResponseEntity postMember(@RequestBody MemberPostDto memberPostDto) {
return new ResponseEntity<>(memberPostDto, HttpStatus.CREATED);
}
위와 같이 @RequestBody 로 들어온 JSON데이터를 JAVA클래스로 바꿀 수 있다.
위의 코드는 JSON으로 들어온 것을 JAVA클래스로 바꾸고, DTO클래스에 넣어서 객체를 만들어서 다시 JSON으로 반환하는 코드이다.
@ResponseBody 가 없는데 어떻게 JAVA 클래스에서 JSON으로 변하냐고?
Spring MVC에서는 핸들러 메서드에 @ResponseBody가 붙거나, 핸들러 메서드 리턴값이 ResponseEntity 일 때, 내부적으로 HttpMessageConverter가 동작하여 자동으로 응답하는 객체를 JSON으로 바꿔준다!!
죠큼 늦게 블로그 글을 썻다.
이제는 실습 위주라서 이거를 코드를 우르르 다 올릴수도 없고...
다 안올리면 내 블로그 글을 보고 누군가 실습을 진행 할 수도 없다.
그래서 그냥 중요 개념을 알려주는 정도로 글을 작성하기로 햇다.
적어도 핵심 개념이나, 왜 이렇게 쓰는지 등의 이유를 파악하는게 중요하다고 생각해서다.
누가 이 글을 볼지 모르겟지만. 위의 코드만 가지고 스프링을 실습 할 수 없다.
실습 하는 부분은 다른 실력 좋은분들을 보고 배우고. 내 글은 간략히 참고만 하는 용도로 생각하자.
내가 입문자이기 때문에, 내 글도 입문자 수준에서만 볼만 할 것 같다.
'백엔드 > 코드스테이츠 수강' 카테고리의 다른 글
코드스테이츠 수강_11주차_3일차~_12주차_1일차 Spring Data JDBC , DDD (0) | 2022.11.02 |
---|---|
코드스테이츠 수강_11주차_1~2일차_Spring MVC 서비스 계층, 예외처리 (1) | 2022.10.25 |
코드스테이츠 수강_10주차_4일차_Spring MVC, Controller (API계층) (0) | 2022.10.20 |
[회고]코드스테이츠 수강_10주차_3일차 부스트캠프 2달 경과 (2) | 2022.10.19 |
코드스테이츠 수강_9주차_3일차_Spring Framework의 핵심개념 (빈, 스프링 컨테이너, 싱글톤) (1) | 2022.10.13 |