Compare commits

...

2 Commits

Author SHA1 Message Date
d235b44ca0 . 2025-10-27 12:38:51 +09:00
f7b0094abf . 2025-10-27 12:32:06 +09:00
8 changed files with 195 additions and 0 deletions

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@@ -0,0 +1,23 @@
package dev.ptnr.frontalobebackend.controller;
import dev.ptnr.frontalobebackend.domain.Article;
import dev.ptnr.frontalobebackend.dto.AddArticleRequest;
import dev.ptnr.frontalobebackend.service.BlogService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
@RestController // HTTP Response Body의 객체 데이터를 JSON 형식으로 반환하는 컨트롤러
public class BlogApiController {
private final BlogService blogService;
@PostMapping("/api/articles")
public ResponseEntity<Article> addArticle(@RequestBody AddArticleRequest request) {
Article savedArticle = blogService.save(request);
return ResponseEntity.status(HttpStatus.CREATED).body(savedArticle);
}
}

View File

@@ -0,0 +1,29 @@
package dev.ptnr.frontalobebackend.domain;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Article {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@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;
}
}

View File

@@ -0,0 +1,18 @@
package dev.ptnr.frontalobebackend.dto;
import dev.ptnr.frontalobebackend.domain.Article;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class AddArticleRequest {
private String title;
private String content;
public Article toEntity() {
return Article.builder().title(title).content(content).build();
}
}

View File

@@ -0,0 +1,15 @@
package dev.ptnr.frontalobebackend.dto;
import dev.ptnr.frontalobebackend.domain.Article;
import lombok.Getter;
@Getter
public class ArticleResponse {
private final String title;
private final String content;
public ArticleResponse(Article article) {
this.title = article.getTitle();
this.content = article.getContent();
}
}

View File

@@ -0,0 +1,8 @@
package dev.ptnr.frontalobebackend.repository;
import dev.ptnr.frontalobebackend.domain.Article;
import org.springframework.data.jpa.repository.JpaRepository;
public interface BlogRepository extends JpaRepository<Article, Long> {
}

View File

@@ -0,0 +1,24 @@
package dev.ptnr.frontalobebackend.service;
import dev.ptnr.frontalobebackend.domain.Article;
import dev.ptnr.frontalobebackend.dto.AddArticleRequest;
import dev.ptnr.frontalobebackend.repository.BlogRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
@RequiredArgsConstructor // final or @NotNull이 붙은 생성자를 만들어 줌
@Service // BlogService as Spring Bean
public class BlogService {
private final BlogRepository blogRepository;
// Add Blog Article
public Article save(AddArticleRequest request) {
return blogRepository.save(request.toEntity());
}
public List<Article> findAll() {
return blogRepository.findAll();
}
}

View File

@@ -0,0 +1,72 @@
package dev.ptnr.frontalobebackend.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import dev.ptnr.frontalobebackend.domain.Article;
import dev.ptnr.frontalobebackend.dto.AddArticleRequest;
import dev.ptnr.frontalobebackend.repository.BlogRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import java.util.List;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.jupiter.api.Assertions.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
class BlogApiControllerTest {
@Autowired
protected MockMvc mockMvc;
@Autowired
protected ObjectMapper objectMapper; // Marshal, Unmarshal을 위한 클래스
@Autowired
private WebApplicationContext context;
@Autowired
BlogRepository blogRepository;
@BeforeEach
public void mockMvcSetup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
blogRepository.deleteAll();
}
@DisplayName("addArticle: 블로그 글 추가 성공 확인")
@Test
public void addArticle() throws Exception {
// given
final String url = "/api/articles";
final String title = "title";
final String content = "content";
final AddArticleRequest userRequest = new AddArticleRequest(title, content);
// Marshal JSON
final String requestBody = objectMapper.writeValueAsString(userRequest);
// when
// given에서 설정한 내용을 바탕으로 요청 전송
ResultActions result = mockMvc.perform(post(url).contentType(MediaType.APPLICATION_JSON_VALUE).content(requestBody));
// then
result.andExpect(status().isCreated());
List<Article> articles = blogRepository.findAll();
assertThat(articles.size()).isEqualTo(1);
assertThat(articles.get(0).getTitle()).isEqualTo(title);
assertThat(articles.get(0).getContent()).isEqualTo(content);
}
}