이전 포스팅에 이어서 오늘은 등록 API를 만들어보겠습니다
1. 다음과 같이 패키지와 파일들을 만들어주세요
2. PostsSaveRequestDto
@Getter
@NoArgsConstructor
public class PostsSaveRequestDto {
private String title;
private String content;
private String author;
@Builder
public PostsSaveRequestDto(String title, String content, String writer) {
this.title = title;
this.content = content;
this.writer = writer;
}
public Posts toEntity() {
return Posts.builder()
.title(title)
.content(content)
.writer(writer)
.build();
}
}
※ Dto클래스가 Entitiy클래스와 거의 비슷한데 굳이 따로 만들어서 쓰는 이유가 무엇일까요?
Entity클래스는 Request/Response 클래스로 쓰면 안되고, Request/Response 클래스는 자주 변경이 됩니다. Entity클래스는 테이블과 연결되어 있기 때문에 Entity클래스를 변경하는 것은 큰 영향을 끼치는 변경이 됩니다. 따라서 Dto클래스를 Request/Response 클래스로 쓰고 Dto클래스는 자주 변경이 되어도 됩니다
@NoArgsConstructor - 기본 생성자를 추가해줍니다
@Builder - 이 클래스에 빌더패턴을 사용합니다
toEntity() - 이 메소드는 빌더패턴을 사용하여 title, content, writer 값을 가지는 객체를 리턴합니다
3. PostsService
@RequiredArgsConstructor
@Service
public class PostsService {
private final PostsRepository postsRepository;
@Transactional
public Long save(PostsSaveRequestDto requestDto) {
return postsRepository.save(requestDto.toEntity()).getId();
}
}
@RequiredArgsConstructor - final이 선언된 모든 필드를 인자값으로 하는 생성자를 생성해줍니다
@Service - 서비스 레이어, 비지니스 로직을 가진 클래스에 사용합니다
@Transactional - 트랜잭션을 설정합니다, ??
save() - requestDto의 toEntity메소드로 Posts 객체를 가져와 postRepository에 저장하고, id값을 리턴합니다????
4. PostsApiController
@RequiredArgsConstructor
@RestController
public class PostsApiController {
private final PostsService postService;
@PostMapping("/api/v1/posts")
public Long save(@RequestBody PostsSaveRequestDto requestDto) {
return postService.save(requestDto);
}
}
@RequiredArgsConstructor - final이 선언된 모든 필드를 인자값으로 하는 생성자를 생성해줍니다
@RestController - 컨트롤러를 JSON으로 반환하는 컨트롤러로 만들어줍니다
@RequestBody - HTTP 요청 몸체를 자바 객체로 변환하는데 사용됩니다
5. PostsApiControllerTest
@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 등록() throws Exception {
//given
String title = "title";
String content = "content";
PostsSaveRequestDto requestDto = PostsSaveRequestDto.builder()
.title(title)
.content(content)
.writer("writer")
.build();
String url = "http://localhost:" + port + "/api/v1/posts";
//when
ResponseEntity<Long> responseEntity = restTemplate.postForEntity(url, requestDto, Long.class);
//then
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);
}
}
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) - 테스트를 할 때 랜덤한 포트 번호로 실행한다는 의미입니다
@LocalServerPort -로컬서버의 포트번호를 나타냅니다
@Autowired - 빈을 자동으로 주입받습니다
@After - 단위 테스트가 끝날 때 수행되는 메소드를 지정하는 것입니다
TestRestTemplate
- 여러 테스트 종류 중 하나로, REST API 호출이후 응답을 받을 때까지 기다리는 동기방식입니다
@SpringBootTest와 TestRestTemplate을 사용하면 편리하게 웹 통합 테스트를 할 수 있습니다.
MockMvc와는 차이가 존재합니다. MockMvc는 Servlet Container를 생성하지 않는 반면, @SpringBootTest와 TestRestTemplate는 Servlet Container를 사용합니다. 그래서 마치 실제 서버가 동작하는 것처럼 테스트를 할 수 있는 것입니다
ResponseEntity - 헤더와 바디, 상태 코드로 구성되어 있고 http 응답을 나타낼 때 사용 합니다. Http 응답을 편하게 구성하여 보낼 때 사용 하는 클래스입니다
.postForEntity() - POST 요청을 보내고 결과로 ResponseEntity로 반환받습니다. postForEntity의 1번째 인자는 요청 url이고 2번째 인자는 post할 객체이며 3번째 인자는 response할 데이터의 타입 클래스입니다.
[참고]
'Back-end > Spring' 카테고리의 다른 글
[SpringBoot] Spring Data JPA로 게시판 만들기(5) - JPA Auditing으로 생성시간/수정시간 자동화 (0) | 2020.11.22 |
---|---|
[SpringBoot] Spring Data JPA로 게시판 만들기(4) - 수정/조회 API (0) | 2020.11.22 |
[SpringBoot] Spring Data JPA로 게시판 만들기(2) - repository테스트 코드 작성 (0) | 2020.11.16 |
[SpringBoot] Spring Data JPA로 게시판 만들기(1) - domain, repository 생성 (0) | 2020.11.16 |
[SpringBoot] 롬복(Lombok) 적용하기 (0) | 2020.11.15 |