springmvc (4)

 

 

 

 

 

API 문서화

 

 

➤ API 문서화란?

 

API 문서화란 클라이언트가 REST API 백엔드 애플리케이션에 요청을 전송하기 위해서 알아야 되는 요청 정보(요청 URL 또는 URI, request body, query parameter 등)를 문서로 잘 정리하는 것을 의미한다.

 

 

▶️ API 요청을 위해 필요한 정보를 문서로 정리해야 하는 이유는 무엇인가?

 

백엔드에서 만든 REST API 기반의 애플리케이션을 클라이언트 쪽에서 사용하려면 API 사용을 위한 정보가 필요하기 때문이다.

 

API 사용을 위한 정보가 담겨 있는 문서를 API 문서 또는 API 스펙(사양, Specification)이라고 한다.

 

 

▶️ API 문서를 만드는 방법

 

🥑 개발자가 수기로 작성 ➡️ 비효율적!, 기능을 빠뜨릴 수 있음!

🥑 애플리케이션 빌드를 통해 API 문서를 자동으로 생성

 

 

 

➤ Spring Rest Docs vs Swagger

 

 

▶️ Swagger의 API 문서화 방식

 

🍋 Swagger는 API 문서 자동화 오픈 소스이다.

🍋 Java 기반의 애플리케이션에서는 전통적으로 Swagger를 많이 사용해왔다.

🍋 많은 양의 애너테이션이 추가된다. ➡️ 가독성이 떨어짐

🍋 코드가 길어지면 그만큼 API 문서화를 위한 코드도 길어진다. ➡️ 유지보수성이 떨어짐

🍋 Controller 뿐만 아니라 DTO 클래스에도 애너테이션을 일일이 추가해주어야 한다.

🍋 Swagger 기반의 API 문서는 [Excute] 라는 버튼하나로 Controller에 요청을 전송할 수 있다. ➡️ API 요청 툴로서 기능을 사용할 수 있다.

 

 

▶️ Spring Rest Docs의 API 문서화 방식

 

🍑 애플리케이션 기능 구현과 관련된 코드에 API 문서 생성을 위한 애너테이션과 같은 정보를 추가하지 않는다.

🍑 Controller 테스트 클래스에 API 문서화를 위한 정보가 추가된다.

🍑 테스트 케이스의 실행결과가 “passed”로 만들지 않으면 API 문서 생성이 완료되지 않는다. ➡️ API 스펙 정보와 API 문서 정보의 불일치로 생길 수 있는 문제 방지

🍑 테스트 케이스에서 전송하는 API 문서 정보와 Controller에서 구현한 request body, response body, query parameter 등의 정보가 하나라도 일치하지 않으면 테스트 케이스 실행 결과가 “failed” 되면서 API 문서가 정상적으로 생성이 되지 않는다.

🍑 Swagger 처럼 API 호출할 수 있는 툴의 역할은 하지 못한다.

 

 

 

 

Spring Rest Docs

 

 

➤ Spring Rest Docs 란?

 

Rest API 문서를 자동으로 생성해주는 Spring 하위 프로젝트이다.

 

 

➤ Spring Rest Docs 의 API 문서 생성 흐름

 

Spring Rest Docs

 

 

1. 테스트 코드 작성

🍒 슬라이스 테스트 코드 작성

🍒 API 스펙 정보(Request Body, Response Body, Query Parameter 등) 코드 작성

 

 

2. test task 실행

🍒 작성된 슬라이스 테스트 코드를 실행한다.

🍒 하나의 테스트 클래스를 실행시켜도 되지만 일반적으로 Gradle의 build task 중 하나인 test task 를 실행시켜서 API 문서 snippet(스니핏*)을 일괄 생성한다.

🍒 테스트 실행 결과가 “passed” 이면 다음 작업을 진행한다.

🍒 실행결과가 “failed” 일 경우 문제를 해결하기 위해 테스트 케이스를 수정한 뒤 다시 테스트를 진행한다.

 

※ 스니핏(snippet)

일반적으로 코드의 조각을 의미한다.

여기선 문서의 일부 조각을 의미한다.

테스트 케이스 하나당 하나의 스니핏이 생성되며, 여러개의 스니핏을 모아서 하나의 API 문서를 생성할 수 있다.

 

 

3. API 문서 스니핏(.adoc 파일) 생성

🍒 API 스펙 정보 코드를 기반으로 API 문서 스니핏이 .adoc 확장자를 가진 파일로 생성된다.

 

 

4. API 문서 생성

🍒 생성된 API 문서 스니핏을 모아서 하나의 API 문서로 생성한다.

 

 

5. API 문서를 HTML로 변환

🍒 생성된 API 문서를 HTML 파일로 변환한다.

🍒 HTML로 변환된 API 문서는 HTML 파일 자체를 공유해도 되고 URL을 통해 해당 HTML에 접속해서 확인할 수 있다.

 

 

 

➤ Spring Rest Docs 설정

 

1. build.gradle 설정

2. API 문서 snippet 을 사용하기 위한 템플릿 API 문서 생성

 

 

▶️ build.gradle 설정

 

API 문서를 자동으로 생성하기 위해 아래 설정 코드 추가

plugins {
	...
	id "org.asciidoctor.jvm.convert" version "3.3.2"
	...
}

...
ext {
	set('snippetsDir', file("build/generated-snippets"))
}

...
configurations {
	asciidoctorExtensions
}

dependencies {
	...
	testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
	asciidoctorExtensions 'org.springframework.restdocs:spring-restdocs-asciidoctor'
    ...
}

...
tasks.named('test') {
	outputs.dir snippetsDir
	useJUnitPlatform()
}

...
tasks.named('asciidoctor') {
	configurations "asciidoctorExtensions"
	inputs.dir snippetsDir
	dependsOn test
}

...
task copyDocument(type: Copy) {
	dependsOn asciidoctor
	from file("${asciidoctor.outputDir}")
	into file("src/main/resources/static/docs")
}

build {
	dependsOn copyDocument
}

...
bootJar {
	dependsOn copyDocument
	from ("${asciidoctor.outputDir}") {
		into 'static/docs'
	}
}

 

 

애플리케이션 실행 후 웹 브라우저에서 아래 주소로 이동하면 API 문서를 눈으로 확인할 수 있다.

http://localhost:8080/docs/index.html

 

 

 

▶️ API 문서 snippet을 사용하기 위한 템플릿(또는 source 파일) 생성

 

API 문서 스니핏이 생성 되었을 때 이 스니핏을 사용해서 최종 API 문서로 만들어 주는 템플릿 문서(index.adoc)을 생성한다.

 

아래 경로에 해당하는 디렉토리 생성 (Gradle 기반 프로젝트)

src/docs/asciidoc/

 

디렉토리 내에 비어있는 템플릿 문서를 생성 (index.adoc)

 

 

 

 

Controller 테스트 케이스에 Spring Rest Docs 적용하기

 

 

➤ API 문서화를 위한 슬라이스 테스트 케이스 작성

 

Controller 슬라이스 테스트 클래스를 작성하고 API 문서화를 위한 코드를 추가해준다.

 

 

▶️ @SpringBootTest -> @WebMvcTest 로 변경

 

🍎 @WebMvcTest 는 Controller를 테스트 하기 위한 전용 애너테이션이다.

🍎 @WebMvcTest 괄호 안에 테스트 대상 Controller 클래스를 지정해준다.

 

 

▶️ @MockBean(JpaMetamodelMappingContext.class)

 

🍎 JPA에서 사용하는 Bean 들을 Mock 객체로 주입해주는 설정이다.

 

Spring Boot 기반의 테스트는 항상 최상위 패키지 경로에 있는 ~Application 클래스를 찾아서 실행한다.

~Application 클래스에 @EnableJpaAuditing 추가

➡️ JPA와 관련된 Bean을 필요로 하기 때문에 @WebMvcTest 애너테이션을 사용해서 테스트를 진행할 경우 JpaMetamodelMappingContext를 Mock 객체로 주입해주어야 한다.

 

 

▶️ 테스트 클래스 위에 @AutoConfigureRestDocs 추가

 

🍎 Spring Rest Docs 에 대한 자동 구성을 해준다.

 

 

▶️ document(..)

 

🍎 API 문서 자동 생성을 위한 API 스펙 정보 추가

🍎 .anDo(..) 메서드 : andExpect() 처럼 어떤 검증 작업을 하는 것이 아닌 일반적인 동작을 정의하고자 할 때 사용한다.

 

 

▶️ @SpringBootTest vs @WebMvcTest

 

🍓 @SpringBootTest

  • @AutoConfigureMockMvc 와 함께 사용되어 Controller 를 테스트할 수 있다.
  • 프로젝트에서 사용하는 전체 Bean을 ApplicationContext 에 등록하여 사용한다.
  • 테스트 환경을 구성하는 것은 편리하지만 실행속도가 상대적으로 느리다.

 

🍓 @WebMvcTest

  • Controller 테스트에 필요한 Bean만 ApplicationContext에 등록한다.
  • 실행 속도가 상대적으로 빠르다.
  • 하지만 테스트 하려는 클래스에서 의존하고 있는 객체가 있다면 해당 객체에 대해서 Mock 객체를 사용하여 의존성을 일일이 제거해주어야 한다.

 

 

 

 

 

 

감사합니다.

오개념에 대한 지적은 늘 환영입니다. 🤩

 

 

 

 

 

 

 

 

 

Spring Data JDBC를 통한 데이터 액세스 계층 구현 (서비스, 레포지토리 구현)

 

 

➤ Repository Interface

 

Spring Data JDBC, Spring Data JPA에서 데이터 액세스 계층에서 데이터베이스와 상호작용하는 역할을 하는 인터페이스를 repository라고 한다.

 

기본적으로 CrudRepository를 상속하는 repository 인터페이스 작성한다.

ex) public interface MemberRepository extends CrudRepository<Member, long> { }

 

CrudRepository 인터페이스를 통해 데이터를 데이터베이스 테이블에 저장, 조회, 수정, 삭제가 가능하다.

 

 

 

➤ 쿼리 메서드(Query Method)

 

Spring Data JDBC에서 쿼리 메서드(Query Method)를 지원한다.

 

✅ ‘find + By + SQL 쿼리문에서 WHERE 절의 칼럼명 + (WHERE 절 칼럼의 조건이 되는 데이터)’

형식으로 쿼리 메서드(Query Method)를 정의하면 조건에 맞는 데이터를 테이블에서 조회한다.

ex) findByName(String name);

 

리턴값으로 SQL 질의를 통한 결과 데이터를 받아서 엔티티 클래스의 객체로 지정해준다.

그리고 Spring Data JDBC 에서 Optional을 지원하기 때문에 리턴값을 Optional로 래핑해준다.

래핑해주는 이유는?

Optional을 사용해서 리턴값을 래핑하면 Service 클래스에서 이 Optional을 이용해서 코드를 더 효율적이고 간결하게 구성할 수 있다.

 

WHERE 절의 조건 칼럼을 여러 개 지정하고 싶다면 ‘And’를 사용하면 된다.

ex) findByPhoneAndName(String phone, String name);

 

쿼리 메서드에 작성한 칼럼명은 내부적으로 테이블의 칼럼명으로 바뀌지만

Spring JDBC 입장에서는 엔티티 클래스를 바라보고 작업한다.

반드시 엔티티 클래스의 멤버 변수명을 적어주어야 한다.

테이블의 칼럼명으로 적는다. ❌

 

(단어를 일치시키면 가장 좋지만 Java에서는 CamelCase 표기법을 사용하고 테이블 칼럼명은 언더스코어(_) 표기법을 사용하기 때문에 2 단어 이상 작성시 이름이 다를 수 있다.)

 

 

➤ @Query 메서드

 

쿼리 메서드명에 작성하지 않고 직접 쿼리문을 작성해서 질의를 할 경우 사용

Attribute로 쿼리문을 작성한다.

동적 쿼리 파라미터(named parameter)

콜론(:) 뒤에는 findBy~()의 괄호안에 동적 쿼리 파라미터(named parameter)를 작성해준다.

ex) @Query(“SELCET * FROM ORDER WHERE ORDER_ID = :orderId”);

 

단순한 쿼리의 경우 쿼리 메서드를 이용하는 것이 간결한 코드 유지와 생산성 면에서 바람직하다.

 

 

➤ Repository 인터페이스 Service 에서 사용하기

 

Service에서 DI를 주입해서 Repository 생성

 

Repository는 인터페이스인데 구현 클래스를 작성하지 않았지만 사용 가능하다.

Repository 인터페이스 구현 클래스는 Spring Data JDBC에서 내부적으로 Java 리플렉션 기술과 Proxy 기술을 이용해서 repository 인터페이스의 구현 클래스 객체를 생성해준다.

 

비즈니스 로직에서 어떤 검증이 필요한 로직은 검증하는 로직을 추출해서 메서드를 작성 후 호출한다. ➡️ 코드의 간결성, 가독성 향상

ex) 회원 정보 리소스를 데이터베이스에 Insert할 경우 이미 Insert된 리소스인지 여부를 검증하는 로직 분리 (findVerifiedMember)

 

 

✅ Optional.ofNullable(...)

파라미터로 전달받은 엔티티 클래스 객체는 클라이언트 쪽에서 선택적으로 수정할 수 있기 때문에 멤버 변수에 null 이 있을 수도 있다.

이처럼 멤버 변수 값이 null 일 경우

Optional.of()가 아닌 Optional.ofNullable()을 이용해서 null 값을 허용할 수 있다.

null 이더라도 NullPointerException이 발생하지 않고 원하는 다음 메서드를 호출할 수 있다.

ifPresent() 메서드를 이용해서 null 값이 아니라면 코드가 실행 되도록 작성한다. (람다식으로 작성)

이 때 값이 null 이라면 실행되지 않는다.

ex) Optional.ofNullable(coffee.getName).ifPresent(name -> findCoffee.setName(name));

 

 

✅ delete 를 사용하여 회원 정보 삭제 ?

실무에서는 회원 정보 자체를 테이블에서 삭제하기 보다 MEMBER_STATUS 같은 칼럼을 두어 상태 값만 변경한다.

회원의 회원 가입 상태를 ‘가입’ , ‘휴면’ , ‘탈퇴’ 등의 상태 정보로 나누어 관리하는 것이 바람직하다.

 

 

✅ orElseThrow()

Optional의 메서드인 orElseThrow()를 이용하면 해당 객체가 null 이 아닐경우에는 해당 객체를 리턴하고 null 이라면 괄호 안의 예외를 던진다.

 

 

✅ 참고) @Builder

Lombok에서 지원

Builder를 사용하고자 하는 클래스 위에 @Builder 애너테이션을 추가한다.

객체를 생성할 때 빌더를 함수를 통해 호출하고 셋팅하고자 하는 필드값을 하나씩 지정해주고 마지막에 build()로 닫아서 작동시킨다.

생성자 파라미터가 많을 경우 builder를 사용하면 가독성이 좋아진다.

자기 자신을 리턴하기 때문에 체인형식으로 생성해줄 수 있다.

최종적으로 build()를 해야 만들어진다.

Member.builder()
	.name("김아무개")
   	.city("서울")
   	.email("kim123@gmail.com")
   	.phone("010-1111-2222")
   	.build();

 

 

https://projectlombok.org/features/Builder

 

@Builder

 

projectlombok.org

 

 

 

 

읽어주셔서 감사합니다. ^^ 좋은하루 보내세요.

오개념에 대한 지적은 늘 환영입니다.

 

 

 

 

 

 

 

 

❑ Service 계층

 

 

Spring MVC layer architecture

 

 

➤ DI를 통한 서비스 계층과 API 계층 연동

 

✔️ API 계층과 서비스 계층을 연동한다?

API 계층에서 구현한 Controller 클래스가 서비스 계층의 Service 클래스와 메서드 호출을 통해 서로 상호작용한다.

 

 

▶️ Service의 의미

 

애플리케이션에서 Service는 도메인 업무 영역을 구현하는 비즈니스 로직과 관련이 있다.

Serivce는 쉽게 말해 비즈니스 로직을 처리하기 위한 Service 클래스이다.

애플리케이션의 서비스 계층은 대부분 도메인 모델을 포함하고 있다.

도메인 모델은 빈약한 모델(anemic domain model)풍부한 도메인 모델(rich domain model)로 구분할 수 있다.

이러한 도메인 모델은 DDD(Domain Driven Design, 도메인 주도 설계)와 관련있다.

(DDD는 현업에서 클래스 설계 경험이 풍부해야 제대로 사용할 수 있다.)

 

 

 

➤ 도메인 엔티티(Domain Entity) 클래스

 

서비스 계층에서 데이터 엑세스 계층과 연동하면서 비즈니스 로직을 처리하기 위해 필요한 데이터를 담는 클래스

보통 리소스 이름으로 만든다. ex) Member, Coffee, Order

 

 

➤ 도메인 엔티티 클래스에 붙는 애너테이션

 

lombok 라이브러리에서 제공한다.

 

@Getter / @Setter

  • getter/setter 메서드를 일일이 작성할 필요 없도록 추가해준다.

 

@AllArgsConstructor

  • 클래스에 존재하는 모든 필드를 매개변수로 갖는 생성자를 자동으로 생성해준다.
  • 만약에 필드 중에 @NotNull 애너테이션이 붙어 있다면 해당 부분은 생성자 내에서 null-check로직을 자동으로 생성한다.

 

@NoArgsConstructor

  • 매개변수가 없는 생성자를 생성한다.
  • 필드에 final 키워드가 있을 경우 초기화 할 수 없기 때문에 에러가 발생한다.
  • 필드에 @NotNull 같은 제약조건이 설정되어 있을 경우, 생성자 내 null-check 로직이 생성되지 않는다.

 

@RequiredArgsConstructor

  • 초기화 되지 않은 모든 final 필드, @NotNull이 설정되 있는 필드들에 대한 생성자를 자동으로 생성해준다.

 

 

 

※ lombok 라이브러리의 더 많은 애너테이션

https://projectlombok.org/features/all

 

Stable

 

projectlombok.org

 

 

 

➤ DI 주입

 

Service 클래스에 @Service 애너테이션 추가해서 Spring Bean으로 등록해주고

Controller 클래스와 Service 클래스간에 느슨한 결합(Losse Coupling)을 위해 DI를 주입해준다.

(Controller는 @RestController 로 이미 Spring Container에 등록되어 있다.)

 

※ 일반적으로 생성자가 하나일 경우에는 @Autowired 를 붙이지 않아도 Spring이 알아서 DI를 적용한다.

하지만 생성자가 하나 이상일 경우, DI를 적용하기 위해선 반드시 @Autowired를 붙여야 한다!

 

 

 

 

❑ Mapper(매퍼)

 

 

➤ Mapper를 이용한 DTO 클래스와 Entity(엔티티) 클래스 매핑

 

▶️ Mapper를 사용하지 않을 경우

 

  • Controller의 핸들러 메서드가 DTO 클래스를 엔티티 클래스로 변환 하는 작업까지 하게 되어 여러 역할을 가지게 된다.
  • 서비스 계층인 엔티티(Entity) 클래스 객체를 클라이언트의 응답으로 전송(API 계층의 역할)해서 계층 간의 역할 분리가 이루어지지 않는다.

 

 

▶️ Mapper 사용법

 

  • 클래스를 Spring Bean으로 등록하기 위해 @Component 애너테이션을 추가한다.
  • 등록된 빈은 Controller에서 사용된다.

 

 

➤ MapStruct를 이용한 Mapper 자동 생성

 

Mapper를 수작업으로 작성하는 것은 비효율 적이다.

Mapper를 자동으로 만들 수 있는 MapStruct을 이용하면 편리하다.

DTO클래스 처럼 Java Bean 규약을 지키는 객체들 간의 변환 기능을 제공하는 매퍼(Mapper) 구현 클래스를 자동으로 생성해주는 코드 자동 생성기이다.

 

MapStruct를 사용하려면 먼저 의존 라이브러리를 추가 해주어야 한다.

Gradle

build.gradle파일 dependencies에 아래 코드 추가한다.

dependencies {

implementation 'org.mapstruct:mapstruct:1.4.2.Final'

annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'

}

 

 

Mapper 인터페이스 추가하고 인터페이스에 @Mapper 애너테이션 추가한다.

-> 인터페이스가 MapStruct의 매퍼 인터페이스로 정의된 것임을 알려준다.

attribute로 componentModel = “spring” 지정해서 Spring Bean으로 등록한다.

MapStruct가 Mapper 인터페이스를 기반으로 매퍼(Mapper) 구현 클래스를 자동으로 생성해준다!

Gradle에 build task를 실행하면 자동으로 생성된다.

intelliJ에서 build task 실행하기

Gradle 탭 -> 해당 프로젝트 명 -> Tasks 디렉토리 -> build 디렉토리 -> build 더블클릭

 

 

 

 

읽어주셔서 감사합니다.

오개념에 대한 지적은 늘 환영입니다. 😆

 

 

 

 

 

 

DTO(Data Transfer Object)

 

 

 

➤ DTO(데이터 전송 객체)란?

 

  • 마틴 파울러(Martin Fowler)의 저서 ‘Patterns of Enterprise Application Architecture’에서 소개되었다.
  • enterprise application architecture의 한 패턴이다.
  • 계층 간 데이터 교환을 위한 자바 bean을 말한다.

 

 

 

➤ DTO는 왜 나온 것인가?

 

실제로 서비스를 만들다보면 실무에서 Request Param에 많은 양의 정보들을 보낸다.

그렇게 되면 @RequestParam의 개수가 계속 늘어나서 코드가 길어지고 보기 어렵다.

요청 데이터로 받을 정보들을 하나의 객체로 전달한다면 훨씬 코드가 간결해 질 것이다.

바로 DTO가 그런 역할을 해준다.

DTO 클래스가 요청 데이터를 하나의 객체로 전달 받는 역할을 해준다.

 

DTO를 사용하면 @RequestParam 부분이 사라지고 Dto 객체로 대체된다.

 

 

 

 

➤ 데이터 유효성(Validation) 검증의 단순화

 

클라이언트 쪽에서 올바르지 않은 데이터 형식으로 요청할 수 있다.

예를 들면 휴대폰 번호에 문자를 넣거나, 이메일에 @를 안 쓴다거나 이름에 이모티콘을 넣는 등 클라이언트가 우리가 기대하지 않은 값을 전달할 수도 있다.

이럴 때 데이터 유효성을 검사하지 않으면 틀린 형식도 정상적으로 핸들러 메서드에 전달받을 수 있다.

 

서버에서 유효한 데이터를 전달받기 위해 데이터를 검증하는 것을 유효성(Validation) 검증이라고 한다.

 

if문을 이용해서 직접 데이터가 맞는 형식인지 확인해서 틀리면 요청을 거부하도록 작성할 수 있다.

하지만 이 방법은 형식별로 코드가 다르고 복잡하다.

 

HTTP 요청을 전달 받는 핸들러 메서드는 요청을 전달 받는 것이 주 목적이기 때문에 최대한 간결하게 작성되는 것이 좋다.

 

 

 

➤ DTO 클래스 만들기

 

DTO는 타입을 지정할 변수와 getter/setter, 애너테이션으로 구성되어 있다.

DTO 클래스를 사용하면 유효성 검증 로직을 DTO 클래스로 빼내어 핸들러 메서드의 간결함을 유지할 수있다.

 

 

 

 

❑ DTO 유효성 검증

 

핸들러 메서드의 매개변수 중 유효성 검증을 원하는 부분에 작성한 Dto 객체로 매개변수를 작성하고 @Valid 를 타입 앞에 써준다.

@PostMapping
public ResponseEntity postMember(@Valid MemberDto memberDto) {
	...
}

 

@Valid 는 ~Dto 객체에 유효성 검증을 적용하게 해준다.

DTO 유효성 검증의 사용 목적 : 비용이 많이 드는 작업인 HTTP 요청의 수를 줄이기 위함 + 도메인 객체와의 분리

 

 

 

 

 

 

➤ HTTP Request Body가 JSON 형식일 경우

 

 

요청 데이터 🟰 Request Body

 

~PostDto, ~PatchDto 등의 이름으로 dto 클래스 생성

사용하려는 http 메서드에 따라 다르게 명명하면 된다.

 

 

▶️ @RequestBody

 

JSON 형식의 Request Body를 Dto 클래스의 객체로 변환 시켜주는 역할을 한다.

클라이언트에서 전송하는 Request body가 JSON 형식이어야 한다.

JSON 형식이 아닌 다른 형식의 데이터 전송할 경우 Spring 내부에서 ‘Unsupported Media Type’ 과 같은 에러 메시지를 포함한 응답을 전달한다.

 

 

▶️ @ResponseBody

 

JSON 형식의 Response Body를 클라이언트에 전달하기 위해 DTO 클래스의 객체를 Response Body로 변환하는 역할을 한다.

Spring MVC에서 핸들러 메서드에 @ResponseBody 애너테이션이 붙거나 핸들러 메서드의 리턴값이 ResponseEntity 일 경우 내부적으로 HttpMessageConverter 가 동작하여 응답 객체(DTO 클래스의 객체)를 JSON 형식으로 바꿔준다.

 

 

 

➤ JSON Serialization(직렬화) & JSON Deserialization(역직렬화)

 

▶️ Serialization(직렬화)

서버 쪽에서 클라이언트에 응답 데이터로 DTO같은 자바 객체를 JSON형식으로 변환하는 것

Java 객체 ➡️ JSON

 

▶️ Deserialization(역직렬화)

클라이언트에서 JSON 형식의 데이터를 서버에 전송 ➡️ 서버 쪽 애플리케이션에서 전달받은 JSON 형식의 데이터를 DTO 같은 자바 객체로 변환하는 것

JSON ➡️ Java 객체

 

 

 

 

DTO 유효성 검증(Validation)

 

 

➤ DTO 유효성 검증(Validation)이 필요한 이유

 

REST API 통신을 하는 프론트엔드 쪽 웹 앱에서도 자바스크립트를 이용해서 1차적으로 유효성 검사를 진행한다.

그렇다면 왜 굳이 백엔드 애플리케이션에서도 유효성 검증을 할 필요가 있을까?

프론트엔드 쪽에서 유효성 검사를 통과했다고 해서 그 값이 반드시 유효한 값이라는 보장은 없다.

프론트 엔드에서 유효성 검사를 통과한 뒤 HTTP Request 요청이 전송된다.

여기서 자바스크립트로 전송되는 데이터는 개발자 도구를 사용해서 브레이크 포인트(break point)를 건 뒤 얼마든지 그 값을 조작할 수 있기 때문이다.

그렇기에 백엔드 애플리케이션에서도 유효성 검증을 해줄 필요가 있다.

 

 

 

➤ DTO 클래스에 유효성 검증 적용하기

 

유효성 검증을 위한 의존 라이브러리 추가

DTO 클래스에 유효성 검증을 적용하기 위해서 Spring Boot에서 지원하는 Starter가 필요하다.

 

build.gradle 파일의 dependencies 항목에 아래 항목 추가

implementation 'org.springframework.boot:spring-boot-starter-validation'

 

 

 

➤ 유효성 검증에 사용하는 주요 애너테이션

 

▶️ @NotBlank

  • 정보가 비어있지 않은지 검증한다.
  • null 값과 공백(“”), whitspace(“ “) 모두 허용하지 않는다.
  • attribute message로 원하는 에러 메시지를 넣을 수 있다.

 

▶️ @Pattern

  • attribute regexp 로 작성한 정규표현식(Regular Expression)에 매치되는 data인지 검증한다.
  • 유효성 검증에 실패하면 message attribute에 작성한 에러 메시지가 콘솔에 출력된다.

 

 

▶️ @Size(min= , max= )

  • 문자열 또는 배열이 지정된 길이 사이인지 검증한다.

 

▶️ @Max(value) / @Min(value)

  • 값이 value에 적은 값의 이상인지 이하인지 검증한다.

 

▶️ @NotNull

  • null 값이 아닌 경우만 통과한다.

 

▶️ @NotEmpty

  • 공백을 포함해서 길이가 0이면 오류 발생한다.

 

▶️ @Email

  • 유효한 이메일 주소가 포함되어 있지 않을 경우 유효성 검증에 실패한다.

 

 

 

정규식 연습할 수 있는 페이지

(알려주신 페어분께 감사드립니다.ㅎㅎ)

https://regexr.com/

 

RegExr: Learn, Build, & Test RegEx

RegExr is an online tool to learn, build, & test Regular Expressions (RegEx / RegExp).

regexr.com

 

 

 

 

※ CSR(Client Side Rendering) vs SSR(Server Side Rendering)

 

Rendering의 대상은? HTML

 

CSR(Client Side Rendering)

 

SSR(Server Side Rendering)

서버 쪽에서 HTML 렌더링

HTML 페이지를 클라이언트 쪽에 내려준다.

HTML을 템플릿으로 취급, 동적인 데이터를 채워준다.

 

 

 

 

 

 

 

1