Skip to content
Open
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
9407b7a
refactor : 공통 패키지 명에서 board 제거
DongCaprio Apr 22, 2025
e644327
refactor : ArticleEntity 에 createdAt 추가
DongCaprio Apr 22, 2025
68ed2a9
feat : 댓글 기능 관련 Entity / Service 개발
DongCaprio Apr 22, 2025
41f37e4
feat : 댓글 삭제 기능 리팩토링(상태true, false로 관리)
DongCaprio Apr 23, 2025
03df248
feat : 댓글 관련 service test 추가
DongCaprio Apr 23, 2025
171ea5f
feat : 댓글 기능 추가(controller, test)
DongCaprio Apr 24, 2025
e5ff8ec
test : 댓글 통합테스트 작성
DongCaprio Apr 28, 2025
46653fd
refactor : jwt 패턴 추가(댓글 url)
DongCaprio Apr 28, 2025
fd7d7a2
refactor : 개별 게시글 조회때만 내용 보이게 수정
DongCaprio Apr 28, 2025
8d35c9e
feat : 게시글 조회수 기능 추가
DongCaprio Apr 28, 2025
d7fc582
refactor : 메서드 명 및 분리 등 리팩토링 진행
DongCaprio Apr 29, 2025
db1869a
refactor : 클래스명 더 알맞게 리팩토링
DongCaprio May 1, 2025
ab235c4
refactor : findAll(여러개) 반환 시 Page 관련 DTO로 반환하도록 수정
DongCaprio May 1, 2025
9ce6cf6
refactor : 게시글 포함 안하는 response
DongCaprio May 1, 2025
533e160
refactor : sort 기본값(최신순 정렬)로 보이도록 수정
DongCaprio May 1, 2025
a61a1cc
refactor : 삭제 기능 추가(soft delete)
DongCaprio May 1, 2025
08d082e
refactor : 파일 위치(패키지) 변경
DongCaprio May 2, 2025
f5f6699
feat : SortUtils 클래스 생성(내용 아직 미완성)
DongCaprio May 2, 2025
e83c64e
feat : 공통 정렬 util 클래스 완성
DongCaprio May 2, 2025
2145079
refactor : 로그인 예외처리 더 자세하게 변경
DongCaprio May 2, 2025
9410b16
feat : 로그아웃 / 회원탈퇴 기능 추가
DongCaprio May 2, 2025
4c253f5
refactor : null 코드에 명시한 부분 제거
DongCaprio May 7, 2025
0a33f9f
refactor : boolean 변수명 앞에 is 접두사 붙여 명시적으로 변경
DongCaprio May 7, 2025
0eccefb
refactor : 변수명 deleted > isDeleted로 변경했으므로 repository 메서드명도 변경
DongCaprio May 8, 2025
4baafc9
refactor : long vs Long 구분해서 더 적절한것으로 변경
DongCaprio May 8, 2025
7e08bc7
refactor : requestDTO의 Long 변수에도 유효성 체크 어노테이션 추가
DongCaprio May 8, 2025
ce53e20
refactor : 공통되는 entity 속성 extends와 @MappedSuperclass 사용하여 공통화
DongCaprio May 8, 2025
f85e734
refactor : 동등성 어노테이션 추가
DongCaprio May 8, 2025
54139ac
refactor : jwt 인증 필요 유무 JwtAuthFilter에서 관리
DongCaprio May 9, 2025
cb5d446
test : MemberEntity의 @EqualsAndHashCode 추가로 인한 테스트 코드 변경
DongCaprio May 9, 2025
07e454c
refactor : 게시글 조회수 증가 -> 동시성 문제로 인한 리팩토링
DongCaprio May 11, 2025
f0922e9
refactor,test : 통합테스트 커스텀 어노테이션 생성 및 사용
DongCaprio May 11, 2025
b2e1876
refactor : 비회원도 요청가능한 controller 요청 분리
DongCaprio May 13, 2025
fd990dd
refactor : jwt가 필요한 경로 및 httpMethod enum으로 분리 진행
DongCaprio May 13, 2025
22430a2
refactor : 댓글관련 controller restApi에 맞게 변경
DongCaprio May 15, 2025
0b9d34f
refactor : cookie 관련 내용 전부 삭제
DongCaprio May 15, 2025
df2932a
feat : 리프레시 토큰 기능 추가
DongCaprio May 18, 2025
fbfff37
refactor : 토큰의 id를 emial -> memberId로 수정
DongCaprio May 18, 2025
168e5ef
test, feat : 스프링 컨텍스트 초기화용 어노테이션 추가
DongCaprio May 19, 2025
16e145e
feat, build, test : 통합테스트에 @Transactional 제거 후 CleanDatabase 추가
DongCaprio May 21, 2025
edbb190
test : ddl-auto 속성 변경
DongCaprio May 21, 2025
91ea56c
feat : 대댓글 기능 추가
DongCaprio May 31, 2025
d8cfa32
test : 대댓글 기능 테스트 작성
DongCaprio May 31, 2025
90e07f8
feat : Redis 활용하여 조회수 증가 처리 및 조회
DongCaprio Jun 1, 2025
e6a552b
refactor : 조회수 증가 Controller > Service로 로직 이동 , 게시글 삭제시 Redis에도 삭제되는 …
DongCaprio Jun 1, 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
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.board;
package com;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
Expand Down
22 changes: 0 additions & 22 deletions src/main/java/com/board/board/dto/response/ArticleResponse.java

This file was deleted.

7 changes: 0 additions & 7 deletions src/main/java/com/board/board/repository/BlogRepository.java

This file was deleted.

64 changes: 0 additions & 64 deletions src/main/java/com/board/board/service/BlogService.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package com.board.board.controller;
package com.board.controller;

import com.board.board.dto.request.ArticleCreateRequest;
import com.board.board.dto.request.ArticleUpdateRequest;
import com.board.board.dto.response.ArticleResponse;
import com.board.board.entity.ArticleEntity;
import com.board.board.service.BlogService;
import com.board.config.auth.annotation.AuthenticatedMember;
import com.board.dto.request.ArticleCreateRequest;
import com.board.dto.request.ArticleUpdateRequest;
import com.board.dto.response.ArticleResponse;
import com.board.entity.ArticleEntity;
import com.board.service.ArticleService;
import com.config.auth.annotation.AuthenticatedMember;
import com.util.page.PageResponse;
import com.util.sort.SortUtils;
import jakarta.validation.Valid;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
Expand All @@ -26,36 +28,35 @@
@RequiredArgsConstructor
@RestController
@RequestMapping("/articles")
public class BlogApiController {
public class ArticleController {

private final BlogService blogService;
private final ArticleService articleService;

@PostMapping("")
public ResponseEntity<ArticleResponse> addArticle(@Valid @RequestBody ArticleCreateRequest request,
@AuthenticatedMember Long memberId) {
ArticleEntity savedArticle = blogService.save(request, memberId);
ArticleEntity savedArticle = articleService.save(request, memberId);

return ResponseEntity.status(HttpStatus.CREATED)
.body(new ArticleResponse(savedArticle));
}

@GetMapping("")
public ResponseEntity<List<ArticleResponse>> findAllArticles(@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
Pageable pageable = PageRequest.of(page, size);
public ResponseEntity<PageResponse<ArticleResponse>> findAllArticles(@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(defaultValue = "latest") String sort) {
Pageable pageable = PageRequest.of(page, size, SortUtils.getArticleSort(sort));

List<ArticleResponse> articles = blogService.findAll(pageable)
.stream()
.map(ArticleResponse::new)
.toList();
Page<ArticleResponse> articlePage = articleService.findAll(pageable)
.map(ArticleResponse::withoutContent);

return ResponseEntity.ok()
.body(articles);
.body(PageResponse.from(articlePage));
}

@GetMapping("/{id}")
public ResponseEntity<ArticleResponse> findArticle(@PathVariable long id) {
ArticleEntity article = blogService.findById(id);
ArticleEntity article = articleService.findByIdAndIncreaseViewCount(id);

return ResponseEntity.ok()
.body(new ArticleResponse(article));
Expand All @@ -64,7 +65,7 @@ public ResponseEntity<ArticleResponse> findArticle(@PathVariable long id) {
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteArticle(@PathVariable long id,
@AuthenticatedMember Long memberId) {
blogService.delete(id, memberId);
articleService.delete(id, memberId);

return ResponseEntity.noContent()
.build();
Expand All @@ -74,7 +75,7 @@ public ResponseEntity<Void> deleteArticle(@PathVariable long id,
public ResponseEntity<ArticleResponse> updateArticle(@PathVariable long id,
@AuthenticatedMember Long memberId,
@Valid @RequestBody ArticleUpdateRequest request) {
ArticleEntity updateArticle = blogService.update(id, memberId, request);
ArticleEntity updateArticle = articleService.update(id, memberId, request);

return ResponseEntity.ok()
.body(new ArticleResponse(updateArticle));
Expand Down
73 changes: 73 additions & 0 deletions src/main/java/com/board/controller/CommentController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.board.controller;

import com.board.dto.request.CommentCreateRequest;
import com.board.dto.request.CommentUpdateRequest;
import com.board.dto.response.CommentResponse;
import com.board.entity.CommentEntity;
import com.board.service.CommentService;
import com.config.auth.annotation.AuthenticatedMember;
import com.util.page.PageResponse;
import com.util.sort.SortUtils;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RestController
@RequestMapping("/comments")
public class CommentController {

private final CommentService commentService;

@GetMapping
public ResponseEntity<PageResponse<CommentResponse>> findAllComments(@RequestParam Long articleId,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(defaultValue = "latest") String sort) {
Pageable pageable = PageRequest.of(page, size, SortUtils.getCommentSort(sort));
Page<CommentResponse> commentPage = commentService.findAllComments(articleId, pageable)
.map(CommentResponse::new);

return ResponseEntity.ok(PageResponse.from(commentPage));
}

@PostMapping
public ResponseEntity<CommentResponse> addComment(@Valid @RequestBody CommentCreateRequest request,
@AuthenticatedMember Long memberId) {
CommentEntity savedComment = commentService.createComment(request, memberId);

return ResponseEntity.status(HttpStatus.CREATED)
.body(new CommentResponse(savedComment));
}

@PatchMapping("/{commentId}")
public ResponseEntity<CommentResponse> updateComment(@PathVariable long commentId,
@Valid @RequestBody CommentUpdateRequest request,
@AuthenticatedMember Long memberId) {
request.setCommentId(commentId);
CommentEntity updatedComment = commentService.updateComment(request, memberId);
return ResponseEntity.ok()
.body(new CommentResponse(updatedComment));
}

@DeleteMapping("/{commentId}")
public ResponseEntity<Void> deleteComment(@PathVariable long commentId,
@AuthenticatedMember Long memberId) {
commentService.deleteComment(commentId, memberId);
return ResponseEntity.noContent()
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.board.board.dto.request;
package com.board.dto.request;

import jakarta.validation.constraints.NotBlank;
import lombok.Builder;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.board.board.dto.request;
package com.board.dto.request;

import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/com/board/dto/request/CommentCreateRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.board.dto.request;

import jakarta.validation.constraints.NotBlank;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class CommentCreateRequest {

@NotBlank(message = "내용을 입력해주세요")
private String content;
private Long articleId;

@Builder
public CommentCreateRequest(String content, Long articleId) {
this.content = content;
this.articleId = articleId;
}
}
23 changes: 23 additions & 0 deletions src/main/java/com/board/dto/request/CommentUpdateRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.board.dto.request;

import jakarta.validation.constraints.NotBlank;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
public class CommentUpdateRequest {

@NotBlank(message = "내용을 입력해주세요")
private String content;
private Long commentId;

@Builder
public CommentUpdateRequest(String content, Long commentId) {
this.content = content;
this.commentId = commentId;
}
}
44 changes: 44 additions & 0 deletions src/main/java/com/board/dto/response/ArticleResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.board.dto.response;

import com.board.entity.ArticleEntity;
import lombok.Builder;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Getter
public class ArticleResponse {

private final Long id;
private final String title;
private String content;
private final Long memberId;
private final long viewCount;

@Builder
public ArticleResponse(Long id, String title, String content, Long memberId, long viewCount) {
this.id = id;
this.title = title;
this.content = content;
this.memberId = memberId;
this.viewCount = viewCount;
}

public ArticleResponse(ArticleEntity article) {
this.id = article.getId();
this.title = article.getTitle();
this.content = article.getContent();
this.memberId = article.getMember().getId();
this.viewCount = article.getViewCount();
}

public static ArticleResponse withoutContent(ArticleEntity article) {
return ArticleResponse.builder()
.id(article.getId())
.title(article.getTitle())
.content(null) // content 포함 안함
.memberId(article.getMember().getId())
.viewCount(article.getViewCount())
.build();
}
}
27 changes: 27 additions & 0 deletions src/main/java/com/board/dto/response/CommentResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.board.dto.response;

import com.board.entity.CommentEntity;
import java.time.LocalDateTime;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Getter
public class CommentResponse {

private final Long id;
private final String content;
private final Long authorId;
private final String authorName;
private final LocalDateTime createdAt;
private final boolean deleted;

public CommentResponse(CommentEntity comment) {
this.id = comment.getId();
this.content = comment.getContent();
this.authorId = comment.getMember().getId();
this.authorName = comment.getMember().getNickName();
this.createdAt = comment.getCreatedAt();
this.deleted = comment.isDeleted();
}
}
Loading