본문 바로가기
따라 공부하기/Spring boot 혼자 개발하는 웹 서비스

[Spring Boot]Spring의 웹 계층과 등록 API 만들기

by DawIT 2020. 12. 23.
320x100

이 글은 이 책을 바탕으로 쓰여졌습니다.

 

Spring에서의 웹 계층

 

  • Web Layer : 컨트롤러와 JSP/Freemaker 등의 뷰 템플릿이고, 외부 요청과 응답에 대한 전반적인 영역
  • Service Layer : 서비스 영역. Controller와 Dao의 중간 영역이며, @Transactional 이 사용되는 영역.
  • Repository Layer : DB에 직접 접근하는 영역. Persistence Layer이고, Service와 DB를 연결하는 고리 역할을 함. DAO 라고도 부름.
  • DTO(Data Transfer Object) : 계층 간의 데이터를 교환하기 위한 객체. 예로 뷰 템플릿 엔진에서 사용될 객체나 Repository Layer에서 결과로 넘겨준 객체

웹 계층들의 차이점에 대해서는 이곳에서 정보를 얻으면 좋을 것 같다.

 

그리고 게시판의 글 등록을 위한 API를 작성했다.

 

PostsApiController.java

 

컨트롤러에서 Dto를 받아와 서비스로 넘겨준다.

 

PostsService.java

 

Service에서는 requestDto의 toEntity 함수로 Repository를 통해 DB에 접근한다.

 

package com.david.book.springboot.web.dto;
import com.david.book.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();
    }
}

 

PostsSaveRequestDto.java 는 언뜻 Entity클래스와 매우 유사하지만, Entity클래스(Posts)를 절대로 Request/Response로 사용하면 안된다고 한다. 왜나하면 Entity클래스는 많은 다른 기능들에 영향을 끼치는데 이를 Request/Response로 사용하게 된다면 변경이 필요할 때마다 많은 다른 기능들에게 영향을 끼칠 수 있기 때문이다.

 

만든 PostsApiController를 위한 테스트 코드도 작성하였다.

 

package com.david.book.springboot.web;

import com.david.book.springboot.domain.posts.Posts;
import com.david.book.springboot.domain.posts.PostsRepository;
import com.david.book.springboot.web.dto.PostsSaveRequestDto;
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.Assertions.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{
        //given
        String title = "title";
        String content = "content";
        PostsSaveRequestDto requestDto = PostsSaveRequestDto.builder()
                .title(title)
                .content(content)
                .author("author")
                .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);
    }
}

 

댓글