[springboot-webserivce] Post 수정/조회 API 생성 및 분석과 테스트

Updated:

[2020.12.28] 부터 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 책을 통해 스프링 공부를 시작했다.

공부한 내용을 글로 정리하려고 한다.

그래야 나중에 다시 찾아보며 공부 할 수 있을테니까 !!

✏️ Post 수정 / 조회 API 생성

[Spring] Post 등록 API 생성 및 분석과 테스트 에서 Post 를 등록하는 API 를 만들었다.

이어서 Post 를 수정하고 조회하는 API 를 만들어보려고 한다.

두 가지 API 만 완성하면 머스테치를 이용해 View 부분을 만들 예정이다.

⚖️ PostApiController

java/com/boks/springboot/web/PostsApiController 에 수정 / 조회 API 를 추가할 것이다.

package com.boks.springboot.web;

@RequiredArgsConstructor
@RestController
public class PostsApiController {
    private final PostsService postsService;

		...

    @PutMapping("/api/v1/posts/{id}")
    public Long update(@PathVariable Long id, @RequestBody PostsUpdateRequestDto requestDto) {
        return postsService.update(id, requestDto);
    }

    @GetMapping("/api/v1/posts/{id}")
    public PostsResponseDto findById(@PathVariable Long id) {
        return postsService.findById(id);
    }
}

@PutMapping

HTTP PUT 요청을 의미한다.


@GetMapping

HTTP GET 요청을 의미한다.


@PathVariable

URL 에 변수를 사용할 수 있게 한다.

REST 한 API 를 만들 수 있게 된다.

Controller 에 API 를 만들었으니 이제 Service 에서 트랜잭션을 처리할 차례이다.

🔨 PostsService

java/com/boks/springboot/service/posts/PostsService

package com.boks.springboot.service.posts;

@RequiredArgsConstructor
@Service
public class PostsService {
    private final PostsRepository postsRepository;

		...

    @Transactional
    public Long update(Long id, PostsUpdateRequestDto requestDto) {
        Posts posts = postsRepository.findById(id).orElseThrow(() ->
                new IllegalArgumentException("해당 게시글이 없습니다. id = " + id));

        posts.update(requestDto.getTitle(), requestDto.getContent());

        return id;
    }

    public PostsResponseDto findById(Long id) {
        Posts entity = postsRepository.findById(id).orElseThrow(() ->
                new IllegalArgumentException("해당 게시글이 없습니다. id = " + id));

        return new PostsResponseDto(entity);
    }
}

update 메소드를 보게 되면 Repository 를 통해 수정하고자 하는 Post 를 가져온다.

수정을 할 때는 Title, Content 만 가져와 수정하면 되기 때문에 PostUpdateRequestDTO 는 Title, Content 필드만 가진다.

그리고 Post Entity 의 update 메소드를 수행하게 되는데 코드는 다음과 같다.

java/com/boks/springboot/domain/posts/Posts

package com.boks.springboot.domain.posts;

@Getter  // 롬복의 Get 생성 어노테이션
@NoArgsConstructor // 롬복의 기본 생성자 자동 추가 어노테이션
@Entity  // DB의 테이블과 매칭 될 클래스임을 나타냄
public class Posts extends BaseTimeEntity {

  ...
    
    public void update(String title, String content) {
        this.title = title;
        this.content = content;
    }
}

지금까지 코드를 보면 무언가 이상한 부분이 보인다.

분명히 데이터베이스의 데이터를 수정하는데 쿼리문을 던져주는 곳이 없다.

바로 영속성 컨텍스트 때문이다.

JPA 의 엔티티 매니저를 활성화 시킨 상태로 트랜잭션에서 데이터베이스에 있는 데이터에 접근하면

이 데이터는 영속성 컨텍스트가 유지된 상태이다.

이때 데이터를 변경하게 되면 트랜잭션이 끝나는 시점에 해당 테이블에 변경된 부분을 반영한다.

즉 Entity 객체의 값만 변경하게 되면 따로 쿼리문을 던져줄 필요가 없다는 것이다.

Spring Data JPA 는 기본으로 엔티티 매니저를 활성화 시킨다.

이 개념을 더티 체킹 이라고 한다.

📦 DTO

java/com/boks/springboot/web/dto/PostsUpdateRequestDto

포스트를 수정 한 정보를 받아오려면 title, content 만 알고있으면 된다.

글쓴이를 수정할 일은 없기 때문이다.

package com.boks.springboot.web.dto;

@Getter
@NoArgsConstructor
public class PostsUpdateRequestDto {
    private String title;
    private String content;

    @Builder
    public PostsUpdateRequestDto(String title, String content) {
        this.title = title;
        this.content = content;
    }
}


java/com/boks/springboot/web/dto/PostsResponseDto

package com.boks.springboot.web.dto;

@Getter
public class PostsResponseDto {
    private Long id;
    private String title;
    private String content;
    private String author;

    public PostsResponseDto(Posts entity) {
        this.id = entity.getId();
        this.title = entity.getTitle();
        this.content = entity.getContent();
        this.author = entity.getAuthor();
    }
}

책의 설명을 보면 이 DTO 는 Entity 의 필드 중 일부만 사용하므로 생성자로 Entity 를 받아와 필드에 대입한다고 한다.

굳이 모든 필드를 가진 생성자가 필요하진 않으므로 DTO 는 Entity 를 받아 처리한다고 한다.

그런데 이해가 가지 않는 부분이 service 에 findById 메소드를 보면 id 를 통해 찾아주는 메소드인데..

이때 왜 모든 필드가 필요하진 않다는 걸까.. findById 를 통해 특정 글쓴이의 글만 찾을 수도 있으니 그런건가.. 일단 더 해봐야겠다.

☀️ 수정 API 테스트

수정 / 조회 기능을 다 만들었으니 테스트를 할 시간이다.

[Spring] Post 등록 API 생성 및 분석과 테스트 에서 만들었던 테스트 코드에 이어서 작성한다.

java/com/boks/springboot/web/PostsApiControllerTest

package com.boks.springboot.web;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class PostsApiControllerTest {

  ...

    @Test
    public void updatePost() throws Exception {
        // given
        Posts savedPost = postsRepository.save(Posts.builder()
                .title("title")
                .content("content")
                .author("author")
                .build());

        Long updateId = savedPost.getId();
        String expectedTitle = "title2";
        String expectedContent = "content2";

        PostsUpdateRequestDto requestDto = PostsUpdateRequestDto.builder()
                .title(expectedTitle)
                .content(expectedContent)
                .build();

        String url = "http://localhost:" + port + "/api/v1/posts/" + updateId;

        HttpEntity<PostsUpdateRequestDto> requestEntity = new HttpEntity<>(requestDto);

        // when
        ResponseEntity<Long> responseEntity = restTemplate.exchange(url, HttpMethod.PUT, requestEntity, 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(expectedTitle);
        assertThat(all.get(0).getContent()).isEqualTo(expectedContent);
    }
}

image

쿼리문을 보면 글 한 개를 만들고, 선택을 하고, 수정을 하는 로그를 볼 수 있다.

결과는 통과!

📡 조회 API 테스트

Post 를 조회하는 테스트는 실제로 어플리케이션을 실행시켜 확인해보려고 한다.

로컬에서는 H2DB 를 사용하기 때문에 웹 콘솔로 접근해야 한다.

resources/application.properties

spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.h2.console.enabled=true

JPA 적용을 하면서 MySQL 쿼리문을 로그로 보기 위해 설정했던 파일에 spring.h2.console.enabled=true 를 추가한다.

그리고 어플리케이션을 실행 시킨 뒤 localhost:8080/h2-console 에 접속하자.

스크린샷 2021-01-04 오전 12 51 09

JDBC URL 이 jdbc:h2:mem:testdb 로 안되어있다면 꼭 이렇게 작성하고 Connect 를 누르자.

연결을 하고 나면 아래와 같은 화면이 보이는데 테이블을 보게되면 지금까지 만들었던 posts 테이블이 보인다 !

쿼리문을 통해 글을 한 개 작성하자.

스크린샷 2021-01-04 오전 12 53 52

그리고 localhost:8080/api/v1/posts/1 주소로 접속을 하게 되면..


스크린샷 2021-01-04 오전 12 56 14

Post 등록이 잘 된 것을 볼 수 있다.

📕 정리

Post 등록 API 만 만들고 나서는 컨트롤러와 서비스 DTO 간의 관계가 잘 이해가 가지 않았었다.

하지만 수정, 조회 API 까지 만들고 나니 전체적인 흐름을 알게 됐다.

이제 이 구조를 완전히 나 혼자 코딩할 수 있도록 해야한다..

우선 내일부터 머스테치를 이용해 View 부분을 구현하는데 얼른 하고싶다.



Categories:

Updated:

Leave a comment