Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
649e8e5
feat: /introduce 응답기능 추가
NIF404 May 5, 2025
ecbd0e5
feat : /introduce?name 기능 추가
NIF404 May 5, 2025
2daa92f
feat : /json 기능 추가
NIF404 May 5, 2025
03c41c7
refactor : /json 기능을 RestController를 이용해 리팩토링
NIF404 May 5, 2025
4212b5f
feat : CRUD API 작성
NIF404 May 5, 2025
3317b28
feat : 6주차 과제
NIF404 May 12, 2025
bec4afd
feat : DB연결후 정상 실행 확인
NIF404 May 18, 2025
6faf3dc
feat : BoardRepository DB와 연결
NIF404 May 18, 2025
ece05fd
feat : MemberRepository DB와 연결
NIF404 May 18, 2025
00978ba
feat : ArticleRepository DB와 연결
NIF404 May 18, 2025
06d4b90
feat : 기존 초기값 삭제 및 6주차 과제까지 DB로 구현 확인
NIF404 May 18, 2025
d8a7748
feat : 7주차 과제 요구 사항 구현
NIF404 May 18, 2025
be8ff92
feat : 트랜잭셔널 어노테이션 추가
NIF404 May 19, 2025
d29cc8f
feat : 삭제 예외처리를 위한 예외 클래스 구현
NIF404 May 22, 2025
aeecbac
feat : 생성 예외처리를 위한 예외 클래스 구현
NIF404 May 22, 2025
c6d1c96
feat : 기존 예외 클래스 이름 변경
NIF404 May 22, 2025
88826c7
feat : NULL이 존재하는 생성 예외처리 클래스 생성
NIF404 May 22, 2025
36d01a7
feat : 이메일 중복 예외처리 클래스 생성
NIF404 May 22, 2025
6c91648
feat : 조회 예외처리를 위한 예외 클래스 구현
NIF404 May 22, 2025
7fe8b9b
feat : 예외처리를 위한 헨들러 클래스 구현
NIF404 May 25, 2025
8d8ca66
feat : 데이터 베이스를 사용하면서 쓰이면 안되는 객체의 SETTER코드 삭제
NIF404 May 25, 2025
86a3c3e
feat : 예외처리를 위한 코드 구현 및 작동 확인을 위한 코드 구현
NIF404 May 26, 2025
ece0f32
feat : board 관련 예외처리 구현
NIF404 May 26, 2025
b1f6868
feat : member 관련 예외처리 구현
NIF404 May 26, 2025
04136e7
feat : article 관련 예외처리 구현
NIF404 May 26, 2025
0b95708
feat : 7주차 피드백에 따라 코드 변경
NIF404 May 26, 2025
cd40e82
feat : JPA를 이용한 DB관리 구현, note : 노트북으로 pull 받아서 DB 작동 여부확인 필요
NIF404 Jun 22, 2025
a31fa9a
fix : posts가 작동하지 않는 오류 수정
NIF404 Jun 23, 2025
8dfd075
feat : 연관관계, 영속성 전이 및 고아객체 구현
NIF404 Jun 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@ repositories {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
runtimeOnly 'mysql:mysql-connector-java:8.0.33'
}

tasks.named('test') {
Expand Down
81 changes: 81 additions & 0 deletions src/main/java/com/example/bcsd/Article.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.example.bcsd;

import jakarta.persistence.*;

import java.time.LocalDateTime;

@Entity
public class Article {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "author_id")
private Long memberId;

private String title;
private String content;

@Column(name = "created_date")
private LocalDateTime createdAt;

@Column(name = "modified_date")
private LocalDateTime modifiedAt;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "board_id")
private Board board;

protected Article() {
}

public Article(Long memberId, String title, String content) {
this.memberId = memberId;
this.title = title;
this.content = content;
this.createdAt = LocalDateTime.now();
Comment on lines +36 to +37
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CreatedDate 어노테이션에 대해 알아보는 것도 좋을 것 같아요

과제 수준에서는 변경하지 않아도 괜찮을 것 같습니다!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 더불어서
@LastModifiedDate 등도 과제하면서 찾아봤는데 해당 과제에서는 기존에 쓰던 기능으로 해도 무관할것같아 사용하지 않았습니다

this.modifiedAt = this.createdAt;
}

public Long getId() {
return id;
}

public Long getMemberId() {
return memberId;
}

public String getTitle() {
return title;
}

public String getContent() {
return content;
}

public LocalDateTime getCreatedAt() {
return createdAt;
}

public LocalDateTime getModifiedAt() {
return modifiedAt;
}

public void updateTitle(String newTitle) {
this.title = newTitle;
this.modifiedAt = LocalDateTime.now();
}

public void updateContent(String newContent) {
this.content = newContent;
this.modifiedAt = LocalDateTime.now();
}

public void setBoard(Board board){
this.board = board;
if(!board.getArticles().contains(this)){
board.getArticles().add(this);
}
}
}
111 changes: 111 additions & 0 deletions src/main/java/com/example/bcsd/ArticleController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package com.example.bcsd;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/articles")
public class ArticleController {
private final ArticleService articleService;
private final MemberService memberService;
private final BoardService boardService;

public ArticleController(ArticleService articleService,
MemberService memberService,
BoardService boardService) {
this.articleService = articleService;
this.memberService = memberService;
this.boardService = boardService;
}

@PostMapping
public ResponseEntity<Article> post(@RequestBody Map<String, String> article) {
long memberId = Long.parseLong(article.get("memberId"));
long boardId = Long.parseLong(article.get("boardId"));

try {
memberService.validId(memberId);
boardService.validId(boardId);
} catch (RuntimeException e) {
throw new ReferencedEntityNotFoundException("유효하지 않은 게시판 또는 사용자 입니다.");
}
Comment on lines +37 to 39
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

service에서 ReferencedEntityNotFoundException 예외를 던져도 되지 않았을까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

예외처리의 경우에는 의도적으로 컨트롤러에서 처리했었습니다 아마 이것 관련해서 옛날 과제에서 말씀하셨던것같은데 관련해서 다음과제때 조사해보겠습니다

Copy link
Author

@NIF404 NIF404 Jun 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그리고 제가 저번주 수요일부터 미국에와있고 7월 4일까지 해외에 있어서 이번 11주차과제를 수행 못하여 미리 말씀드립니다
해당 과제는 12주차 과제때 함께 구현하여 제출하도록 하겠습니다


String title = article.get("title");
String content = article.get("content");

if (title == null || content == null) {
throw new InvalidRequestBodyException("유효하지 않은 요청입니다.");
}

Article created = articleService.save(memberId, boardId, title, content);
return ResponseEntity.created(URI.create("/articles/" + created.getId())).build();
}

@GetMapping("/{id}")
public ResponseEntity<Article> get(@PathVariable long id) {
try {
Article article = articleService.findById(id);
return ResponseEntity.ok(article);
} catch (RuntimeException e) {
throw new EntityNotFoundException("게시물을 찾을 수 없습니다");
}
}

@PutMapping("/{id}")
public ResponseEntity<Article> put(@PathVariable long id,
@RequestBody Map<String, String> article) {
long memberId = Long.parseLong(article.get("memberId"));
long boardId = Long.parseLong(article.get("boardId"));

try {
memberService.validId(memberId);
boardService.validId(boardId);
} catch (RuntimeException e) {
throw new ReferencedEntityNotFoundException("유효하지 않은 게시판 또는 사용자 입니다.");
}

String password = article.get("password");
if (!memberService.findById(articleService.findById(id).getMemberId()).getPassword().equals(password)) {
throw new InvalidRequestBodyException("비밀번호가 일치하지 않습니다.");
}

String title = article.get("title");
String content = article.get("content");
Article updated = articleService.update(id, title, content);
return ResponseEntity.ok(updated);
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable long id,
@RequestBody Map<String, String> article) {
try {
articleService.validArticle(id);
} catch (RuntimeException e) {
throw new InvalidRequestBodyException("유효한 게시물 ID가 아닙니다.");
}

String password = article.get("password");
if (!memberService.findById(articleService.findById(id).getMemberId()).getPassword().equals(password)) {
throw new InvalidRequestBodyException("비밀번호가 일치하지 않습니다.");
}

articleService.delete(id);
return ResponseEntity.noContent().build();
}

@GetMapping
public ResponseEntity<List<Article>> getArticlesByBoardId(@RequestParam(name = "boardId", required = true)
Long id) {
List<Article> articles = articleService.findByBoardId(id);

return ResponseEntity.ok(articles);
}
}
12 changes: 12 additions & 0 deletions src/main/java/com/example/bcsd/ArticleRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.example.bcsd;

import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface ArticleRepository extends JpaRepository<Article, Long> {

List<Article> findByBoardId(Long boardId);

List<Article> findByMemberId(Long memberId);
}
65 changes: 65 additions & 0 deletions src/main/java/com/example/bcsd/ArticleService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.example.bcsd;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class ArticleService {
private final ArticleRepository articleRepository;
private final BoardRepository boardRepository;

public ArticleService(ArticleRepository articleRepository,
BoardRepository boardRepository) {
this.articleRepository = articleRepository;
this.boardRepository = boardRepository;
}

@Transactional
public Article save(long memberId, long boardId, String title, String content) {
Board board = boardRepository.findById(boardId).get();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

null 반환한다면 어쩌죠?

null을 핸들링 하기 위해 Optional을 사용한다고 생각합니다

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

맞습니다 과제할때 미처 생각하지 못한 문제였던것 같습니다


Article article = new Article(memberId, title, content);
article.setBoard(board);

return articleRepository.save(article);
}

@Transactional(readOnly = true)
public Article findById(long id) {
return articleRepository.findById(id).get();
}

@Transactional(readOnly = true)
public List<Article> findByBoardId(long boardId) {
return articleRepository.findByBoardId(boardId);
}

@Transactional(readOnly = true)
public List<Article> findByMemberId(long memberId) {
return articleRepository.findByMemberId(memberId);
}

@Transactional
public Article update(long id, String title, String content) {
Article article = articleRepository.findById(id).get();
article.updateTitle(title);
article.updateContent(content);
return articleRepository.save(article);
}

@Transactional
public void delete(long id) {
articleRepository.deleteById(id);
}

@Transactional(readOnly = true)
public List<Article> findAll() {
return articleRepository.findAll();
}

public boolean validArticle(long id) {
return articleRepository.existsById(id);
}
}
1 change: 0 additions & 1 deletion src/main/java/com/example/bcsd/BcsdApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ public class BcsdApplication {
public static void main(String[] args) {
SpringApplication.run(BcsdApplication.class, args);
}

}
42 changes: 42 additions & 0 deletions src/main/java/com/example/bcsd/Board.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.example.bcsd;

import jakarta.persistence.*;

import java.util.ArrayList;
import java.util.List;

@Entity
public class Board {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

@OneToMany(mappedBy = "board", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Article> articles = new ArrayList<>();
Comment on lines +17 to +18
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


protected Board() {
}

public Board(String name) {
this.name = name;
}

public Long getId() {
return id;
}

public String getName() {
return name;
}

public void updateName(String newName) {
this.name = newName;
}

public List<Article> getArticles(){
return articles;
}
}
49 changes: 49 additions & 0 deletions src/main/java/com/example/bcsd/BoardController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.example.bcsd;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.net.URI;
import java.util.Map;

@RestController
@RequestMapping("/board")
public class BoardController {
private final BoardService boardService;
private final ArticleService articleService;

public BoardController(BoardService boardService, ArticleService articleService1) {
this.boardService = boardService;
this.articleService = articleService1;
}

@PostMapping
public ResponseEntity<Board> post(@RequestBody Map<String, String> article) {
String name = article.get("name");

if (name == null) {
throw new InvalidRequestBodyException("유효하지 않은 요청입니다.");
}

Board created = boardService.save(name);
return ResponseEntity.created(URI.create("/board/" + created.getId())).build();
}

@GetMapping("/{id}")
public ResponseEntity<Board> get(@PathVariable long id) {
try {
Board board = boardService.findById(id);
return ResponseEntity.ok(board);
} catch (RuntimeException e) {
throw new EntityNotFoundException("게시판을 찾을 수 없습니다.");
}
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable long id) {

boardService.delete(id);
return ResponseEntity.noContent().build();
}
}
13 changes: 13 additions & 0 deletions src/main/java/com/example/bcsd/BoardRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.bcsd;

import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface BoardRepository extends JpaRepository<Board, Long> {

@Override
@EntityGraph(attributePaths = "articles")
Optional<Board> findById(Long id);
}
Loading