스프링 부트 3 백엔드 개발자 되기(자바편) week3

Ethan·2025년 2월 9일
post-thumbnail

데이터베이스 조작이 편해지는 ORM

ORM이란?

Object-relational mapping
객체와 데이터베이스를 연결하는 프로래밍 기법이다.

JPA란?

자바에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스이다.

하이버네이트

JPA의 대표적인 구현체로, 자바언어를 위한 ORM프레임워크이다.

블로그 기획하고 API만들기

기능 : 글 작성, 조회, 수정, 삭제
활용기술 : 스프링부트, 스프링데이터JPA, 롬복(Lombok), H2

프레젠테이션 계층 : controller
비즈니스 계층 : service
퍼시스턴스 계층 : repository
데이터베이스와 연결되는 DAO : domain
데이터를 옮기는 전달자 DTO : dto

엔티티 구성하기

엔티티 구성

domain/Article.java


import...

@Entity//엔티티로 지정
@Getter//게터 어노테이션
@NoArgsConstructor(access = AccessLevel.PROTECTED)//기본 생성자 어노테이션
public class Article {

    @Id//id 필드를 기본키로 지정
    @GeneratedValue(strategy = GenerationType.IDENTITY)//기본키를 1씩 증가
    @Column(name = "id", updatable = false)
    private long id;

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

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

    @Builder//빌더패턴으로 객체생성
    public Article(String title, String content){
        this.title = title;
        this.content = content;
    }

    public void update(String title, String content){
        this.title = title;
        this.content =content;
    }
//    protected Article(){//기본생성자
//
//    }
    //게터
//    public long getId() {
//        return id;
//    }
//
//    public String getTitle(){
//        return title;
//    }
//
//    public String getContent() {
//        return content;
//    }
}

리포지터리 만들기

repository/BlogRepository.java

import ...

public interface BlogRepository extends JpaRepository<Article, Long> {

}

블로그 글 작성을 위한 API구현하기

DTO

dto/AddArticleRequest.java

@AllArgsConstructor//기본생성자 추가
@NoArgsConstructor//모든 필드값을 파라미터로 받는 생성자 추가
@Getter
public class AddArticleRequest {
    private String title;
    private String content;
    
    public Article toEntity() {//생성자 이용해 객체 생성
        return Article.builder()
                .title(title)
                .content(content)
                .build();
    }

}

toEntity() : 빌더패턴을 사용해 DTO를 엔티티로 만들어주는 메서드

dto/ArticleResponse.java

import ...

@Getter
public class ArticleResponse {
    private final String title;
    private final String content;


    public ArticleResponse(Article article){
        this.title = article.getTitle();
        this.content = article.getContent();
    }
}

dto/UpdateArticleRequest.java

import ...

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

Service

service/blogRepository.java

import ...

@RequiredArgsConstructor//final이 붙거나 @NotNull이 붙은 필드로 생성자 추가
@Service// 해당클래스를 빈으로 서블릴 컨테이너에 등록
public class BlogService {

    private final BlogRepository blogRepository;

    public Article save(AddArticleRequest request){
        return blogRepository.save(request.toEntity());
    }

    //DB전체 글 조회
    public List<Article> findAll(){
        return blogRepository.findAll();
    }

    public Article findById(long id){
        return blogRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("not found: " + id));
    }

    public void delete(long id) {
        blogRepository.deleteById(id);
    }

    @Transactional
    public Article update(long id, UpdateArticleRequest request){
        Article article = blogRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("not found: " + id));
        article.update(request.getTitle(), request.getContent());

        return article;
    }

}

save() : AddArticleRequest클래스에 저장된 값들을 article데이터베이스에 저장한다.

Controller

controller/BlogApiController.java

import ...

@RequiredArgsConstructor
@RestController // HTTP Response Body에 객체 데이터를 JSON 형식으로 반환하는 컨트롤러

public class BlogApiController {

    private final BlogService blogService;

//HTTP 메서드가 post일 때 전달받은 URL과 동일하면 매서드로 매핑
    @PostMapping("api/articles")
    
    //@RequestBody로 요청 본문 값 매핑
    public ResponseEntity<Article> addArticle(@RequestBody AddArticleRequest request) {
        Article savedArticle = blogService.save(request);

        //요청자원 성공적 생성
        return ResponseEntity.status(HttpStatus.CREATED)
                .body(savedArticle);
    }

    @GetMapping("api/articles")
    public ResponseEntity<List<ArticleResponse>> findAllArticles(){
        List<ArticleResponse> articles = blogService.findAll()
                .stream()
                .map(ArticleResponse::new)
                .toList();


        return ResponseEntity.ok()
                .body(articles);
    }

    @GetMapping("/api/articles/{id}")
    public ResponseEntity<ArticleResponse> findArticle(@PathVariable("id") long id){
        Article article = blogService.findById(id);

        return ResponseEntity.ok()
                .body(new ArticleResponse(article));
    }

    @DeleteMapping("api/articles/{id}")
    public ResponseEntity<Void> deleteArticle(@PathVariable("id") long id){
        blogService.delete(id);

        return ResponseEntity.ok()
                .build();
    }

    @PutMapping("api/articles/{id}")
    public ResponseEntity<Article> updateArticle(@PathVariable("id") long id,
                                                 @RequestBody UpdateArticleRequest request){
        Article updatedArticle = blogService.update(id, request);

        return ResponseEntity.ok()
                .body(updatedArticle);
    }
}

진행순서
URL매핑 -> save() 호출 -> addArticle() <생성된 블로그 글 반환>

H2 데이터베이스

resources/application.yml

spring:
  application:
    name: springboot - developer

  datasource:
    url: jdbc:h2:mem:testdb

  h2:
    console:
      enabled: true
profile
코딩하는 알파카

0개의 댓글