본문 바로가기

Java/Spring

[Spring] 게시판 만들기 : 등록/수정/조회 API - Spring Data Jpa 이용

반응형

아래의 테스트 코드는 이전글의 Spring Data Jpa를 적용한 후 그에 관련된 테스트 코드를 작성했음을 참고부탁드립니다.

 

✭ [참고] https://chati.tistory.com/68

 

[Spring] 게시판 만들기 : Spring Data Jpa 적용

1. Spring Data Jpa의 의존성 설정 - build.gradle ... dependencies { compile('org.springframework.boot:spring-boot-starter-web') compile('org.springframework.boot:spring-boot-starter-data-jpa') //(1)..

chati.tistory.com


1. 게시글 등록 관련 컨트롤러, 서비스, 도메인 생성

 

도메인

- main/java/.../web/dto/PostsSaveRequestDto.java

import com.moimone.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();
    }
}

 

Entity 클래스를 Request/Response 클래스로 사용해서는 안됩니다.

 

지금 생성한 RequestDto는 View를 위한 클래스로 자주 변경이 필요합니다.

그러나, Entity 클래스를 기준으로 테이블이 생성되고, 스키마가 변경되어 자주 변경이 되면 여러 클래스에 영향을 끼칩니다.

 

따라서, View Layer와 DB Layer의 역할 분리를 철저하게 하는게 좋습니다.

 

만약 Controller에서 결과값으로 여러 테이블을 조인해서 줘야하는 경우가 빈번하다면 

이때는 Entity 클래스가 아닌 Dto 클래스를 사용할 것을 권장드립니다.

 

서비스

- main/java/.../service/PostsService.java

import com.moimone.domain.posts.PostsRepository;
import com.moimone.web.dto.PostsSaveRequestDto;
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();
    }
}

 

컨트롤러

- main/java/.../web/PostsSaveRequestDto.java

import com.moimone.service.PostsService;
import com.moimone.web.dto.PostsSaveRequestDto;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RestController
public class PostsApiController {

    private final PostsService postsService;

    @PutMapping("/api/v1/posts")
    public Long save(@RequestBody PostsSaveRequestDto requestDto) {
        return postsService.save(requestDto);
    }
}

 

스프링에서는 Bean을 주입하는 방식들은 " @Autowired, setter, 생성자 " 로,

가장 권장하는 방식은 생성자로 주입받는 방식입니다.

 

현업에서는 @Autowired 를 많이 쓰고 있었는데, 이 어노테이션은 권하지 않는다고 하네요.

단, 생성자로 Bean 객체를 받도록 @Autowired와 동일한 효과를 주는 것이 @RequiedArgsConstructor 입니다.

 

final이 선언된 모든 필드를 @RequiredArgsConstructor 가 대신 생성해준다는데, 

이 어노테이션도 조금 말이 많긴 하더라구요. 

판단은 개발자의 몫 !

 


2. 게시글 등록 관련 테스트 코드로 검증

 

- test/java/.../web/PostsApiControllerTest.java

package com.moimone.web;

import com.moimone.domain.posts.Posts;
import com.moimone.domain.posts.PostsRepository;
import com.moimone.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 postSave() throws Exception {
        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";

        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);
    }
}

 

반응형

❥ CHATI Github