[스프링부트로 API 만들기] 데이터를 관리해주는 모델

황상일·2021년 1월 2일
0

이제 제일 어렵고 중요한 모델에 대한 이야기를 해보자.

모델

모델은 백그라운드에서 동작하는 주요 로직을 처리하는 곳이다. 쉽게 말하면 데이터를 담당한다. 보통 데이터베이스와 직접적인 연관을 맺으며 동작한다.

ORM

Object Relational Mapping의 줄임말이다. RDB의 테이블을 객체로 자동으로 매핑하는걸 의미한다. ORM은 이 둘을 호환시키기 위하여 SQL을 자동으로 생성해서 처리를 해주는 역할을 한다. Java진영에서는 JPA(Java Persistence API)를 많이 사용하며, 스프링에서는 JPA를 더욱 쓰기 편하게 만들어놓은 모듈인 Spring Data JPA를 사용한다.

엔터티(Entity)

데이터베이스 테이블과 1:1로 매핑되는 클래스이다. 외부에서 무분별한 getter와 setter로 인해 데이터가 오염되어선 안되기 때문에 내부메소드로 데이터를 조작하여야 한다.

레포지터리(Repository)

Spring Data JPA가 JPA를 한단계 더 추상화시킨 인터페이스이다. DAO(Data Access Object) 역할을 수행한다. findBy같은 정해진 규칙의 인터페이스를 생성하면 Spring이 알아서 상황에 맞는 쿼리를 날리는 구현체를 만들어서 Bean으로 등록해준다. 자세한 내용은 JPA 시리즈에서 서술하겠다.

DTO

Data Transfer Object의 약자이며, 데이터 전송객체이다. 데이터를 Layer(Controller, Service 등)간 이동시킬 때 사용한다. 가능하면 데이터 전달 이외의 기능을 만들지 않는것이 좋다.

구현해보기

이번 시리즈에서는 H2데이터베이스를 사용하므로 데이터베이스 세팅을 하지 않아도 된다. 데이터베이스 설정부분은 JPA시리즈에서 다루도록 하겠다.

엔터티

@Entity
@Getter
@NoArgsConstructor
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long postId;

    @Column(length = 100, nullable = false)
    private String title;

    @Column(columnDefinition = "TEXT", nullable = false)
    private String body;

    @Column(nullable = false)
    private Long views;

    public Post(String title, String body) {
        this.title = title;
        this.body = body;
        this.views = (long) 0;
    }

    public void increaseViews() {
        this.views++;
    }

    public void updatePost(String title, String body) {
        this.title = title;
        this.body = body;
    }
}

다른 클래스와 동일하게 @Entity 어노테이션을 지정해주고 @Id를 지정해주면 엔터티를 생성할 수 있다.
@GeneratedValue 어노테이션은 Id(PK)값이 자동으로 생성되는 규칙을 지정하는 옵션이며 IDENTITY는 데이터베이스에 키 생성을 위임하는 옵션이다.
@Column어노테이션으로 자세한 컬럼의 설정을 할 수 있다.
엔터티에 대한 처리는 본인이 직접 할 수 있도록 변수는 전부 private레벨로 선언 한 후 내부메소드를 만들어주는것이 좋다.

레포지터리

public interface PostRepository extends JpaRepository<Post,Long> {
    Post findByTitle(String title);
}

레포지터리는 앞에서 설명했듯이 인터페이스이며 JpaRepository를 상속해야 한다. Id값 기반으로 기본적인 인터페이스들은 선언되어있으므로, 그 이외의 기능은 위와같이 규칙에 맞게 생성하면 된다.

DTO

@Getter
@AllArgsConstructor
public class PostDto {
    private String title;
    private String body;
    private Long views;
}

데이터 전송만들 위해 데이터 이외의 기능을 만들지 말자

서비스에 의존성 주입하기

@Service
@RequiredArgsConstructor
public class PostService {
    
    private final PostRepository postRepository;
    
    public void getPosts(Long page) {
        this.postRepository.findAll();
    }

    public void getPost(long postId) {
        this.postRepository.findById(postId);
    }

    public void addPost(String title, String body) {
        this.postRepository.save(new Post());
    }

    public void updatePost(long postId, String title, String body) {
        this.postRepository.findById(postId);
    }

    public void deletePost(long postId) {
        this.postRepository.deleteById(postId);
    }
}

컨트롤러에 서비스를 주입한것 처럼 서비스에 레포지터리를 주입하면 된다.

현재까지의 패키지 구조

마무리

지금까지 API서버를 만드는데 필요한 기본적인 준비는 끝났다. 이제 이들을 조합해서 기능을 완성해보자

profile
받은만큼 나눠주자

0개의 댓글