본문 바로가기

Spring 공부

spring - 블로그 예제 domain, dto, controller

728x90
반응형

 

domain: Article

 

 

@EntityListeners(AuditingEntityListener.class)
@Entity
@Getter // 필드값 가져오기 lombok에 있음 getter 필요 없음
@NoArgsConstructor(access = AccessLevel.PROTECTED) // 접근제어자가 prtected인 기본생성자 별도 코드없이 생성 // 생성자 필요없단말

 

@EntityListeners(AuditingEntityListener.class): 이 어노테이션은 엔티티의 변경을 감지하고 자동으로 관리하는 JPA의 기능을 활성화한다. AuditingEntityListener 클래스는 엔티티의 생성 및 수정 날짜를 자동으로 관리하는데 사용된다.

 

@Entity: 이 어노테이션은 해당 클래스가 JPA 엔티티임을 나타냄. 이 클래스의 객체는 데이터베이스 테이블에 매핑.

 

@Getter: 이 어노테이션은 Lombok에서 제공하는 기능으로, 해당 클래스의 모든 필드에 대한 getter 메서드를 자동으로 생성.

 

@NoArgsConstructor(access = AccessLevel.PROTECTED): 이 어노테이션은 인자 없는 생성자를 자동으로 생성. access 속성을 AccessLevel.PROTECTED로 설정하여 해당 생성자를 protected로 만들어 외부에서 직접 호출하지 못하도록 제한된다. 이는 JPA에서 엔티티를 생성할 때 사용됨.

 

public class Article {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "id", updatable = false)
  private Long id;

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

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

 

@Id: 이 어노테이션은 해당 필드가 엔티티의 주요 식별자(primary key)임을 나타냄. 따라서 데이터베이스 테이블에서 이 필드는 주요 키 역할한다.

 

@GeneratedValue(strategy = GenerationType.IDENTITY): 이 어노테이션은 주요 키 값이 자동으로 생성되는 방식을 지정. 여기서는 데이터베이스의 자동 증가 기능을 사용하여 주요 키 값을 생성하도록 지정됨. 데이터베이스가 지원하는 자동 증가 기능을 사용하기 위해서는 GenerationType.IDENTITY 전략을 사용한다.

 

@Column(name = "id", updatable = false): 이 어노테이션은 해당 필드가 데이터베이스의 열과 매핑될 때 열의 속성을 지정. 여기서는 name 속성을 사용하여 데이터베이스의 열 이름을 id로 설정하고, updatable 속성을 false로 설정하여 이 필드가 업데이트되지 않도록 한다. 주요 키 값은 보통 변경되지 않으므로, updatable을 false로 설정하여 보안을 강화하고 실수로 업데이트되는 것을 방지한다.

 

@CreatedDate  // 엔티티가 생성될 때 생성 시간 createAt 에 저장함
  @Column(name = "created_at")
  private LocalDateTime createdAt;

 

@CreatedDate 어노테이션은 Spring Data JPA에서 제공하는 기능 중 하나로, 엔티티가 생성될 때 자동으로 현재 시간을 저장하는 역할. 이를 통해 엔티티의 생성 시간을 간편하게 추적할 수 있다.

 

@Column(name = "created_at") 어노테이션은 이 필드가 데이터베이스의 특정 열과 매핑될 때 열의 속성을 정의한다. 여기서는 데이터베이스의 열 이름을 "created_at"으로 설정했습니다. 이는 실제 데이터베이스에서 엔티티의 생성 시간이 저장될 열을 지정하는 것.

 

  @LastModifiedDate  // 앤티티가 마지막에 수정됐을때 시간 updateAt에 저장함
  @Column(name = "updated_at")
  private LocalDateTime updatedAt;

 

@LastModifiedDate 어노테이션은 엔티티가 마지막으로 수정될 때 자동으로 현재 시간을 저장.

 

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

 

@Builder 어노테이션이 적용된 메서드를 통해 객체를 생성할 수 있다.

 

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

 

Article 객체의 제목과 내용을 업데이트하는 역할을한다.

 

dto: AddArticleRequest, ArticleResponse, UpdateArticleRequest

 

 

post - AddArticleRequest
get - ArticleResponse
delete - x
put - UpdateArticleRequest

 

 

@NoArgsConstructor // 기본생성자
@AllArgsConstructor // 모든 필드값 파라미터로 받는 생성자
@Getter
public class AddArticleRequest {
  private String title;

  private String content;

  public Article toEntity() {  // 생성자 사용해 객체 생성 // DTO를 앤티티로 만들어줌
    return Article.builder()
            .title(title)
            .content(content)
            .build();
  }
}

 

@NoArgsConstructor: 이 어노테이션은 매개변수 없는 기본 생성자를 자동으로 생성. 이 생성자를 사용하면 객체를 초기화할 때 매개변수를 전달하지 않아도 된다.

 

@AllArgsConstructor: 이 어노테이션은 모든 필드 값을 파라미터로 받는 생성자를 자동으로 생성한다. 이 생성자를 사용하면 객체를 초기화할 때 모든 필드 값을 한 번에 설정할 수 있다.

 

public Article toEntity(): 이 메서드는 AddArticleRequest 객체를 Article 객체로 변환하는 역할을 합니다. 이를 통해 DTO(데이터 전송 객체)를 앤티티로 변환할 수 있다. Article 객체를 생성하고 제목과 내용을 설정한 후 반환한다.

 

@Getter
public class ArticleResponse {

  private final String title;
  private final String content;

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

 

private final String title; 및 private final String content;: 이 두 필드는 블로그 글의 제목과 내용을 나타낸다. final 키워드가 사용되어 이 필드들은 한 번 설정되면 변경할 수 없다.

 

public ArticleResponse(Article article): 이 생성자는 Article 객체를 받아와서 해당 객체의 제목과 내용을 사용하여 ArticleResponse 객체를 생성한다. 이를 통해 엔티티 객체를 DTO로 변환할 수 있다.

 

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

 

public ArticleResponse(Article article): 이 생성자는 Article 객체를 받아와서 해당 객체의 제목과 내용을 사용하여 ArticleResponse 객체를 생성한다. 이를 통해 엔티티 객체를 DTO로 변환할 수 있다.

 

controller: BlogApiController

 

 

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

 

@RequiredArgsConstructor 어노테이션은 Lombok에서 제공하는 기능 중 하나로, 클래스의 필드에 대한 생성자를 자동으로 생성한다.

 

@RestController 어노테이션은 Spring Framework에서 제공하는 기능 중 하나로, 해당 클래스가 RESTful 웹 서비스의 컨트롤러임을 나타낸다. 즉, HTTP 요청을 처리하고 HTTP 응답을 생성하여 클라이언트에게 전송하는 역할

 

private final BlogService blogService;

 

BlogService 타입의 필드를 선언하는 코드. 이 필드는 final로 선언되어 있기 때문에 한 번 초기화되면 다른 값으로 변경할 수 없다. 이러한 구조는 의존성 주입(Dependency Injection)을 통해 외부에서 BlogService 인스턴스를 주입받아 사용할 수 있도록 하는데 일반적으로 사용된다.

// HTTP 메서드가 POST일때 전달받은 URL과 동일하면 매서드로 매핑 // post && url
  @PostMapping("/api/articles")
  // @RequestBody로 요청 본문 값 매핑
  public ResponseEntity<Article> addArticle(@RequestBody AddArticleRequest request) { 
    // @RequestBody : 응답에 해당하는객체를 매핑 AddArticleRequest에
    Article savedArticle = blogService.save(request);
  // 요청한 자원이 성공적으로 생성되었으며 저장된 블로그 글 정보를 응답 객체에 담아 전송
    return ResponseEntity.status(HttpStatus.CREATED)
            .body(savedArticle);  // ResponseEntity.status().body() : 응답코드 201, created 응답 후 저장된 객체 반환
  }

 

@PostMapping("/api/articles"): 이 어노테이션은 해당 메서드가 HTTP POST 요청을 처리하고, 요청이 /api/articles 엔드포인트에 도착할 때 실행된다.

 

public ResponseEntity<Article> addArticle(@RequestBody AddArticleRequest request): 이 메서드는 요청 본문을 받아들이고 (@RequestBody 어노테이션을 통해), AddArticleRequest 객체로 매핑한다. 이 객체에는 새로운 글을 생성하는 데 필요한 정보가 포함된다. 메서드는 ResponseEntity<Article>을 반환하는데, 이는 HTTP 응답을 나타낸다. 반환된 ResponseEntity는 생성된 블로그 글에 대한 정보를 담고 있다.

 

Article savedArticle = blogService.save(request);: blogService의 save() 메서드를 호출하여 새로운 블로그 글을 생성한다. AddArticleRequest 객체를 사용하여 필요한 정보를 전달한다.

 

return ResponseEntity.status(HttpStatus.CREATED).body(savedArticle);: 생성된 블로그 글을 응답으로 반환. 응답 코드는 201 (Created)으로 설정되며, 생성된 블로그 글은 응답 본문에 포함된다.

 

 @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"): 이 어노테이션은 해당 메서드가 HTTP GET 요청을 처리하고, 요청이 /api/articles 엔드포인트에 도착할 때 실행된다.

 

public ResponseEntity<List<ArticleResponse>> findAllArticles(): 이 메서드는 모든 블로그 글을 조회합니다. 반환 형식은 ResponseEntity<List<ArticleResponse>>로, HTTP 응답을 나타낸다. 응답 본문에는 블로그 글 목록을 포함한 리스트가 들어간다.

 

List<ArticleResponse> articles = blogService.findAll()...: blogService의 findAll() 메서드를 호출하여 모든 블로그 글을 가져온다. 그 후, map() 함수를 사용하여 각 블로그 글을 ArticleResponse 객체로 변환한다. 이후, toList() 함수를 사용하여 이를 리스트 형태로 변환한다.

 

return ResponseEntity.ok().body(articles);: 변환된 블로그 글 목록을 응답 본문에 담아 ResponseEntity로 래핑하여 반환한다. ok() 메서드는 HTTP 응답의 상태 코드를 200 (OK)로 설정한다.

 

@GetMapping("/api/articles/{id}") //HTTP GET 요청을 처리하는 메소드임을 나타냄
  public ResponseEntity<ArticleResponse> findArticle(@PathVariable long id) { //@PathVariable : 메소드의 인자가 URL 경로 변수와 연결
    Article article = blogService.findById(id);

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

 

@GetMapping("/api/articles/{id}"): 이 어노테이션은 해당 메서드가 HTTP GET 요청을 처리하고, 요청이 /api/articles/{id} 엔드포인트에 도착할 때 실행된다는 것을 나타낸다. {id}는 경로 변수로, 이 위치에 실제로 들어오는 값을 사용한다.

 

public ResponseEntity<ArticleResponse> findArticle(@PathVariable long id): 이 메서드는 URL 경로에서 받아온 id 값을 사용하여 특정 블로그 글을 조회한다. @PathVariable 어노테이션을 통해 URL 경로 변수와 메서드의 매개변수를 연결한다. 반환 형식은 ResponseEntity<ArticleResponse>로, HTTP 응답을 나타낸다. 응답 본문에는 블로그 글을 변환한 ArticleResponse 객체가 포함된다.

 

Article article = blogService.findById(id);: blogService의 findById() 메서드를 호출하여 해당 id 값을 가진 블로그 글을 조회한다.

 

return ResponseEntity.ok().body(new ArticleResponse(article));: 조회된 블로그 글을 ArticleResponse 객체로 변환하여 응답 본문에 담아 ResponseEntity로 래핑하여 반환한다. ok() 메서드는 HTTP 응답의 상태 코드를 200 (OK)로 설정한다.

 

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

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

 

@DeleteMapping("/api/articles/{id}"): 이 어노테이션은 해당 메서드가 HTTP DELETE 요청을 처리하고, 요청이 /api/articles/{id} 엔드포인트에 도착할 때 실행된다. {id}는 경로 변수로, 이 위치에 실제로 들어오는 값을 사용한다.

 

public ResponseEntity<Void> deleteArticle(@PathVariable long id): 이 메서드는 URL 경로에서 받아온 id 값을 사용하여 특정 블로그 글을 삭제한다. @PathVariable 어노테이션을 통해 URL 경로 변수와 메서드의 매개변수를 연결한다. 반환 형식은 ResponseEntity<Void>로, HTTP 응답을 나타낸다. 응답 본문이 없으므로 Void를 사용한다.

 

blogService.delete(id);: blogService의 delete() 메서드를 호출하여 해당 id 값을 가진 블로그 글을 삭제한다.

 

return ResponseEntity.ok().build();: 요청이 성공적으로 처리되었음을 나타내는 HTTP 상태 코드 200 (OK)와 빈 응답 본문을 함께 반환한다. 이 메서드는 삭제 작업에 대한 응답으로 사용된다.

 

@PutMapping("/api/articles/{id}")
  public ResponseEntity<Article> updateArticle(@PathVariable long id,
                                               @RequestBody UpdateArticleRequest request) {
    //request는 업데이트할 게시물의 정보를 담은 UpdateArticleRequest 객체
    Article updatedArticle = blogService.update(id, request); // 서비스에 id와 request보냄

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

 

@PutMapping("/api/articles/{id}"): 이 어노테이션은 해당 메서드가 HTTP PUT 요청을 처리하고, 요청이 /api/articles/{id} 엔드포인트에 도착할 때 실행된다. {id}는 경로 변수로, 이 위치에 실제로 들어오는 값을 사용한다.

 

public ResponseEntity<Article> updateArticle(@PathVariable long id, @RequestBody UpdateArticleRequest request): 이 메서드는 URL 경로에서 받아온 id 값을 사용하여 특정 블로그 글을 업데이트한다. @PathVariable 어노테이션을 통해 URL 경로 변수와 메서드의 첫 번째 매개변수를 연결한다. @RequestBody 어노테이션을 통해 요청 본문을 받아들이고, 해당 내용을 UpdateArticleRequest 객체로 매핑한다. 반환 형식은 ResponseEntity<Article>로, HTTP 응답을 나타낸다. 응답 본문에는 업데이트된 블로그 글이 포함된다.

 

Article updatedArticle = blogService.update(id, request);: blogService의 update() 메서드를 호출하여 해당 id 값을 가진 블로그 글을 주어진 요청으로 업데이트한다.

 

return ResponseEntity.ok().body(updatedArticle);: 업데이트된 블로그 글을 응답 본문에 담아 ResponseEntity로 래핑하여 반환한다. ok() 메서드는 HTTP 응답의 상태 코드를 200 (OK)로 설정한다.

반응형