SEB_BE_43 / 23.02.14 회고

rse·2023년 2월 14일
0

코드스테이츠_BE_43

목록 보기
34/65

오늘

  • DTO

DTO

DTO = Data Transfer Object

Transfer을 봤을때 무언가를 전송하기 위한 객체.
계층간 데이터 교환을 위해 사용되는 객체다.

내가 배운 부분에서 데이터 전송이 이루어 지는 곳은

  • 클라이언트가 서버쪽으로 전송하는 요청(Request) 데이터
  • 서버가 클라이언트쪽으로 전송하는 응답(Response) 데이터

이 구간에서 DTO를 사용 할 수 있다.

DTO의 필요성

어제 작성한 coffeeController 클래스이다.

지금 보면 @RequestParam 으로 값을 저장하고 있다.
지금은 email, name, phone 세 종류뿐이지만, 실제 회원가입 사이트들을 보면 정보를 더 기입해야 한다. 예로 들어 주소, 로그인 패스워드 등등
이렇게 추가되는 값이 많아질 수록 @RequestParam 애너테이션을 계속 써줘야한다.

DTO를 쓰면 이런 문제를 해결할 수 있다.
클라이언트의 요청을 하나의 객체로 모두 받을 수 있도록 해준다.

DTO를 클래스에 적용하면 이런 모습일 것이다.

굉장히 코드가 간결해진 것을 알 수 있다.

정리

HTTP 요청의 수를 줄일 수 있다.
코드가 간결해지고 깔끔해진다.
도메인을 분리시킬 수 있다.

HTTP 요청/응답 데이터에 DTO 적용

내가 계속 사용하고 있었던 요청 Body는 JSON형식이 아니고 X-www-form-urlencoded 형식이다.
이유는 @RequestParam을 사용했기 때문이다.

이제 JSON으로 변경해보자.

일단 DTO가 적용되지 않았다는 가정하에 DTO 클래스를 만들어보자.

회원 등록에 사용되는 PostDto, 수정에 사용되는 PatchDto도 참고해서 비슷하게 만들면 된다.

주의할 점

  • getter 메서드가 꼭 있어야 한다.
    만약 없으면 Response Body에 해당 멤버 변수 값이 포함안 될 수도 있다.

현업에서는 lombok이라는 라이브러리를 이용해서 만든 getter/setter 메서드를 사용한다고 한다.


만든 DTO를 클래스에 적용해주자.

@RequestParam 대신 DTO를 넣어줬다. @Request Body를 사용하면 한번에 전달 할 수 있다.

이렇게 Json 형식으로 PostDto 핸들러 메서드를 호출한 것을 알 수 있다.

JSON 형식으로 바뀐 이유는 @RequestBody 애너테이션 덕분인데

JSON 형식의 Request Body 를 MemberPostDto 클래스 안에 객체로 변환을 시켜준다.

즉 위 postman 사진처럼 JSON 형식의 요청 Body 부분을 @RequestBody에서 MemberPostDto 클래스 안에 있는

  private String email;
  private String name;
  private String phone;
    

객체로 변환을 시켜준다는 의미.

반대로 JSON 형식의 Response Body를 클라이언트에게 전달하려면 @ResponseBody 라는 애너테이션을 사용하면 된다.
DTO 클래스의 객체를 Response Body로 변환해줌.

우리가 짠 코드에는 @ResponseBody 애너테이션은 없지만, ResponseEntity로 반환을 해주고 있는 것을 알 수 있다.

ResponseEntity는 내부적으로 HttpMessageConverter가 동작하게 되어 응답 객체를 JSON 형식으로 바꿔준다.

참고 사항

JSON 직렬화(Serialization)와 역직렬화(Deserialization)

클라이언트 쪽에서 JSON 형식의 데이터를 서버 쪽으로 전송하면 서버 쪽의 웹 애플리케이션은 전달 받은 JSON 형식의 데이터를 DTO 같은 Java의 객체로 변환하는 것을 역직렬화(Deserialization) 라고 한다.
즉 아까 @RequestBody 같은 상황.

직렬화는 역직렬화의 반대.
서버 쪽에서 클라이언트에게 응답 데이터를 전송하기 위해서 DTO 같은 Java의 객체를 JSON 형식으로 변환하는 것
@ResponseBody 같은 상황.

DTO의 단점

아까 MemberController 에 해당되는 DTO 클래스는 2개였다.
그런데 이 DTO 클래스를 CoffeeController와 OrderController에도 각각 작성을 한다면 클래스가 늘어날 때마다 계속 DTO 역시 늘어 날 것이다.

이 부분은 공통된 멤버 변수의 추출 밎 내부 클래스를 이용해서 어느정도 개선이 가능하다고 한다.
우리는 아직 배우지 않았으니 배우면 새로 포스팅을 하겠다.

DTO 유효성 검증을 하기 전 단순하게 유효성 검증을 해보자

이메일 형식 확인을 위한 정규표현식

하지만 이런 방식은 좋지 않은 방식이다.
HTTP(클라이언트)의 요청을 받는 핸들러 메서드는 요청을 전달 받는 것이 주 목적이기 때문에 최대한 간결하게 작성하는 것이 좋다.

DTO 유효성 검증

유효성 검증은 왜 필요한가?

보안적인 측면에서 올바르지 않은 데이터가 서버로 전송되거나, DB에 저장되지 않도록 하기 위해.
이메일을 예시로 들자면 OOO@naver.com 이런 양식으로 작성을 해야하고, 이름을 예시로 들면 공백이 아니여야하는 등... 각자 맞는 양식인지를 확인해야한다.

아까 작성한 MemberPostDto 클래스의 코드에 유효성 검증을 적용시켜보자.

이런식으로 MemberPostDto 클래스에 애너테이션으로 정의를 해준다면 원하는 방식으로 입력을 받을 수 있다.

@NotBlank = 빈칸을 허용하지 않는다 / null 값이나 공백(””), 스페이스(” “) 같은 값들을 모두 허용하지 않는다
@Email

javax에서 지원하는 표준 Email 애너테이션(javax.validation.constraints.Email)
을 쓰고 이메일 형식에 맞는지 검사한다.

그런데 왜 이메일 형식이 아닌데도 이건 통과가 될까?

gmail.com과 같은 이메일 주소에서 gmial.com 은 도메인 네임(Domain Name)을 의미한다. 그 중에서 .com은 최상위 도메인(TLD, Top-Level Domain)을 의미하는데 이메일 주소의 스펙(사양, Specification)을 확인해보면 최상위 도메인이 없는 이메일 주소의 경우도 때로는 정상 이메일 주소로 허용을 하는 것을 확인할 수 있다.

만약 현실적으로 최상위 도메인까지 포함되어야 유효한 이메일 주소라고 판단하고 싶은 경우에는 정규 표현식을 이용해 조금 더 세밀한 유효성 검사 조건을 지정할 수 있다.

Controller 클래스에 적용시키기

@Valid = 유효성 검증 로직이 실행될 수 있게 해준다.

만약 잘못된 형식으로 요청을 보내게되면 postman에서는 400에러를, 콘솔창에서는 밑에 사진같은 에러를 출력한다.


회원 정보를 수정하는 patchMember 핸들러 메서드에서
@PathVariable 는 URL 변수로 받는다.

이렇게 member뒤에 1이라는 member-id를 넣어줌으로써 아이디 1인 사람의 정보를 수정하는 것이다.

Custom Validator를 사용한 유효성 검증

DTO 클래스에 유효성을 적용하다 보면 Jakarta Bean Validation에 내장된(Built-in) 애너테이션 중 내가 원하는 애너테이션이 없을 수도 있다.

그럴때는 원하는 목적에 맞는 애너테이션을 직접 만들어서 유효성 검증에 적용할 수 있다.

이름의 유효성을 검증하는 부분 을 Custom Validator 로 바꿔보자.

Custom Validator을 사용하려면 밑에 있는 절차를 따르면 된다.

  1. Custom Validator를 사용하기 위해 Custom Annotation을 정의.
  2. 정의한 Custom Annotation에 바인딩 되는 Custom Validator를 구현한다.
  3. 유효성 검증이 필요한 DTO 클래스의 멤버 변수에 Custom Annotation을 추가한다.

예시로 memberPatchDto 이름부분에서 공백 여부를 검증하도록 해보자.

Custom Annotation을 만든다.

아까만든 인터페이스 구현.


MemberPatchDto 에 적용.

강사님이 알려주신 Controller 구성하는 팁

  1. Controller 리소스 구성. (파일만.)
  2. 메서드 껍데기 (Body가 빈)
  3. 제 역할을 할 수 있게 핸들러 메서드를 애너테이션으로 작성.
profile
기록을 합시다

0개의 댓글