-
10. 스프링부트와 AWS - 게시글 등록 API 만들기실습/AWS 2021. 5. 7. 02:34
지난번 오늘 쓸 내용을 다루다가 내용이 산으로 가서...게시판을 마저 만들도록 하자.
게시물 등록용 API를 만들기 위해선 총 3개의 클래스가 필요하다.
- Request 데이터를 받을 dto
- API 요청을 받을 Controller
- 트랜잭션, 도메인 기능 간의 순서를 보장하는 Service
간단히 설명하면 사용자가 요청하는 Controller.
전달받은 내용과 데이터를 전달하는 dto.
이를 처리할 수 있도록 도와주는 Service.
이렇게 구성을 할 예정이다.
클래스 만들기
위에서 이야기했듯 만들어야 할 클래스는 총 3개다.
- src/main/java/com/my/practice00/springboot/controller/PostsApiController
- src/main/java/com/my/practice00/springboot/controller/dto/PostsSaveRequestDto
- src/main/java/com/my/practice00/springboot/service/posts/PostsService
PostsSaveRequestDto 생성
import com.my.practice00.springboot.domain.posts.Posts; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @Getter @NoArgsConstructor public class PostsSaveRequestDto { private String title; private String content; private String author; @Builder public PostsSaveRequestDto(String title, String content, String author){ this.title = title; this.content = content; this.author = author; } public Posts toEntity(){ return Posts.builder() .title(title) .content(content) .author(author) .build(); } }
Dto는 DB에 자료를 쓰거나 읽어올 때 그 데이터를 전달하는 용도로 쓴다.
참고로 DB를 이용하기 위해 Dto를 별도로 만들어서 이용해야 한다.
즉 @Entity가 달린 클래스 해당 프로젝트에서는 Posts클래스를 직접 읽기 쓰기 용도로 쓰지 않아야 한다.
@Entity는 DB와 직접 연결된 클래스로 이걸 수정하면 다른 클래스에도 영향을 줄 수 있다.
그러므로 자료를 다룰 때는 테이블과 연결된 @Entity 클래스 대신 Dto클래스를 만들어야 한다.
PostsService 생성
import com.my.practice00.springboot.controller.dto.PostsSaveRequestDto; import com.my.practice00.springboot.domain.posts.PostsRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import javax.transaction.Transactional; @RequiredArgsConstructor @Service public class PostsService { private final PostsRepository postsRepository; @Transactional public Long save(PostsSaveRequestDto requestDto){ return postsRepository.save(requestDto.toEntity()).getId(); } }
Service클래스는 이전 글에서 쓴대로 Controller로 전달된 요청을 처리하기 위해 사용되는 클래스다.
비즈니스 로직을 직접 처리하는건 아니다.
Transaction을 통해 요청을 구분하고 Domain을 불러와서 요청을 처리한다.
PostsApiController 생성
import com.my.practice00.springboot.controller.dto.PostsSaveRequestDto; import com.my.practice00.springboot.service.posts.PostsService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RequiredArgsConstructor @RestController public class PostsApiController { private final PostsService postsService; @PostMapping("/api/v1/posts") public Long save(@RequestBody PostsSaveRequestDto requestDto){ return postsService.save(requestDto); } }
고객의 요청을 처리하는 가장 상위에 있는 레이어의 Controller다.
고객에데 전달받은 데이터를 PostsSaveRequestDto 형식으로 전달받아서 이것을 Service로 넘긴다.
3개 클래스의 작동 방식
위에서 작성한 클래스를 기반으로 작동방식을 설명하면 위 그림과 같다
글로 좀 더 풀어쓰면 아래와 같다.
- 고객이 글쓰기 요청을 하면 데이터를 PostsApiController로 전달한다.
- 이때 데이터를 @Entity 클래스를 기반으로 만든 PostsSaveRequestDto형식으로 저장한다.
- 그리고 이 데이터를 PostsService 클래스로 전달한다.
- 데이터를 전달받은 PostsService는 PostsRepository로 전달한다.
- 이때 PostsRepository가 자동제공하는 메서드인 save()메서드를 이용한다.
- PostsReposotory 클래스는 전달받은 데이터를 Database에 저장한다.
이때 주의할 점은 앞서 말했듯 @Entity 클래스의 내용은 테이블과 연결되있다
그러므로 데이터를 읽고 쓸 때는 위에서처럼 Dto를 별도로 만들어서 이용해야 한다.
PostsApiControllerTest - 테스트하기
이제 위에 작성한 클래스가 제대로 작동하는지 테스트해보도록 하자.
"src/test/java/com/my/practice00/springboot/controller" 경로에 PostsApiControllerTest 클래스를 만든다.
import com.my.practice00.springboot.controller.dto.PostsSaveRequestDto; import com.my.practice00.springboot.domain.posts.Posts; import com.my.practice00.springboot.domain.posts.PostsRepository; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; import static org.assertj.core.api.Java6Assertions.assertThat; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class PostsApiControllerTest { @LocalServerPort private int port; @Autowired private TestRestTemplate restTemplate; @Autowired private PostsRepository postsRepository; @After public void tearDown() throws Exception{ postsRepository.deleteAll(); } @Test public void Posts_등록() throws Exception{ String title = "게시글 제목"; String content = "게시글 내용"; PostsSaveRequestDto requestDto = PostsSaveRequestDto.builder() .title(title) .content(content) .author("author") .build(); String url = "http://localhost:" + port + "/api/v1/posts"; ResponseEntity<Long> responseEntity = restTemplate.postForEntity(url, requestDto, Long.class); assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(responseEntity.getBody()).isGreaterThan(0L); List<Posts> all = postsRepository.findAll(); assertThat(all.get(0).getTitle()).isEqualTo(title); assertThat(all.get(0).getContent()).isEqualTo(content); } }
테스트 내용을 간단히 설명하면 다음과 같다.
title, content 내용을 넣은 requestDto를 생성한 다음 이걸 url에 넣고 그 결과값을 전달 받는다.
그리고나서 결과값이 입력한 내용과 동일한지 확인한다.
그 다음 테스트할 때 입력했던 내용을 전부 다 삭제한다.
참고로 여기서 테스트 할 때는 이전의 HelloController와 다른 것을 알 수 있다.
바로 @WebMvcTest를 사용하지 않는 것이다.
왜냐면 @WebMvcTest의 경우 JPA 기능이 작동하지 않기 때문이다.
JPA 기능을 테스트할 떄는 @SpringBootTest와 TestRestTemplate를 사용한다.
내용을 잘 입력하고 테스트하면 아래와 같은 결과를 확인할 수 있다.
'실습 > AWS' 카테고리의 다른 글
12. 스프링부트와 AWS - H2 Database로 로컬 테스트해보기 (0) 2021.05.08 11. 스프링부트와 AWS - 게시글 조회, 수정 API 만들기 (0) 2021.05.07 9. 스프링부트와 AWS - 트랜잭션 스크립트, 도메인 모델 (0) 2021.05.05 8. 스프링부트와 AWS - JPA 시작하기 (0) 2021.05.05 7. 스프링부트와 AWS - ORM&JPA 필요성 (0) 2021.04.28