블로그 API(1): 구조 분석 및 블로그 작성 구현 (DTO, Service)

도람·2025년 7월 20일
post-thumbnail

블로그 개발을 위한 엔티티 구성

프로젝트 구성 build.grade

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'  //스프링 데이터 JPA
	runtimeOnly 'com.h2database:h2'
	compileOnly 'org.projectlombok:lombok' 									//롬복
	annotationProcessor 'org.projectlombok:lombok'

}

엔티티 구성

만들 엔티티와 매핑되는 테이블의 구조는 다음과 같다.

<domain/Article.java>

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Article {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) //기본 키 자동으로 1씩 증가
    @Column(name = "id", updatable = false)
    private Long id;

    @Column(name = "title", nullable = false) //title이라는 not null 속성인 테이블과 매핑
    private String title;

    @Column(name = "content", nullable = false)
    private  String content;

    @Builder // 빌더 패턴으로 객체 생성
    public Article(String title, String content) {
        this.title = title;
        this.content = content;
    }
}
  • @Builder : 롬복에서 지원하는 애너테이션으로, 어느 필드에 어떤 값이 들어가는지 명시적으로파악할 수 있다.
//빌더 패턴을 사용하지 않는 경우 (어느 필드에 어떤 값이 들어가는지 알기 어렵다.)
new Article("abc", "def");

//빌더 패턴을 사용하는 경우
Article.builder()
	   .title("abc")
       .content("def")
       .build();

리포지토리 생성

public interface BlogRepository extends JpaRepository<Article , Long> {
}
  • JpaRepository 클래스를 상속받을 때 엔ㄴ티티 Article과 엔티티의 PK 타입 Long을 인수로 넣어 인터페이스를 생성했다.

블로그 작성을 위한 API 구현

API 개발 흐름

  • 클라이언트: POST /api/articles 요청을 서버에 보낸다.

  • 컨트롤러 (BlogController.java): 클라이언트 요청을 받아 BlogService의 save() 메서드를 호출한다.

  • 서비스 (BlogService.java): 비즈니스 로직을 처리한 뒤 BlogRepository의 save()를 호출한다.

  • 리포지토리 (BlogRepository.java): DB에 데이터를 저장한다.

  • 테스트: Postman을 사용해 요청을 보내고, BlogControllerTest.java에서 테스트 코드를 작성하여 기능을 검증한다.


서비스 메서드 코드 작성

<dto/AddArticleRequest.java>

@NoArgsConstructor
@AllArgsConstructor
@Getter
public class AddArticleRequest {
    private String title;
    private String content;

    public Article toEntity(){
        return Article.builder()
                .title(title)
                .content(content)
                .build();
    }
}

+DTO(Data Transfer Object)
: 계층끼리 데이터를 교환하기 위해 사용하는 객체
(단순하게 데이터 옮기는 전달자 역할이라 비지니스 로직을 포함X)
: 컨트롤러 -> 서비스 넘어가기 전, 클라이언트로부터 받은 요청 데이터를 담는 객체.

+DAO(Data Access Object): 데이터베이스와 연결되고 데이터를 조회하고 수정하는데 사용되는 객체
(따라서 데이터 수정과 관련된 로직이 포함)

  • toEntity(): 빌더 패턴을 사용하여 DTO를 엔티티로 만들어주는 메서드.
    (블로그에 글을 추가할 때 저장할 엔티티로 변환하는 용도)

1. 사용자가 보낸 데이터(= JSON)는 왜 ENTITY로 바뀌어야 하는가?
클라이언트가 보낸 데이터(title, content)는 단순 문자열이기 때문에
DB에 저장하려면 JPA가 관리한느 ENTITY 객체로 변환해야 저장이 가능하다.


2. toEntity()는 비지니스 로직이 아닌가?
DTO는 비지니스 로직을 포함하지 않는다고 했는데, toEntity()는 비지니스 로직인가 아닌가 의문이 잠시 들었었다. 그러나 이는 단순 변환 로직이며 비지니스 로직은 검증, 계산, 조건 분기 등을 담고있어야 해서 비지니스 로직이 아니다.


서비스 클래스 구현

<service/BlogService.java>

@RequiredArgsConstructor //final이 붙거나 @NotNull이 붙은 필드의 생성자 추가
@Service                 //빈으로 등록
public class BlogService {
    private final BlogRepository blogRepository;

    //블로그 글 추가 메서드
    public Article save(AddArticleRequest request){
        return blogRepository.save(request.toEntity());
    }
}
  • @RequiredArgsConstructor : 빈을 생성자로 생성하는 애너테이션. final 키워드나 @NotNull이 붙은 필드를 생성자로 만들어준다.
  • save() : JpaRepository에서 지원하는 저장 메서드 save()로 AddArticleRequest 클래스에 저장된 값들을 article 데이터베이스에 저장한다.

해당 글은 다음 도서의 내용을 정리하고 참고한 글임을 밝힙니다.
신선영, ⌜스프링 부트 3 벡엔드 개발자 되기 - 자바 편⌟, 골든래빗(주), 2023, 384쪽

profile
정도를 걷는 엔지니어

0개의 댓글