diff --git a/src/main/java/com/back/domain/post/category/controller/CategoryController.java b/src/main/java/com/back/domain/post/category/controller/CategoryController.java new file mode 100644 index 00000000..2e7c1032 --- /dev/null +++ b/src/main/java/com/back/domain/post/category/controller/CategoryController.java @@ -0,0 +1,39 @@ +package com.back.domain.post.category.controller; + +import com.back.domain.post.category.dto.request.CategoryCreateRequestDto; +import com.back.domain.post.category.entity.Category; +import com.back.domain.post.category.service.CategoryService; +import com.back.global.rsData.RsData; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +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.RestController; + +@RestController +@RequestMapping("/category") +@Tag(name = "ApiCategoryController", description = "API 카테고리 컨트롤러") +@RequiredArgsConstructor +public class CategoryController { + + private final CategoryService categoryService; + + @PostMapping + @Operation(summary = "카테고리 생성") + public RsData createCategory( + @Valid @RequestBody CategoryCreateRequestDto reqBody + ) { + return RsData.successOf(categoryService.createCategory(reqBody)); // code=200, message="success" + } + + @GetMapping + @Operation(summary = "카테고리 목록 조회") + public RsData> getCategories() { + return RsData.successOf(categoryService.getCategories()); // code=200, message="success" + } +} diff --git a/src/main/java/com/back/domain/post/category/dto/request/CategoryCreateRequestDto.java b/src/main/java/com/back/domain/post/category/dto/request/CategoryCreateRequestDto.java new file mode 100644 index 00000000..26a4503c --- /dev/null +++ b/src/main/java/com/back/domain/post/category/dto/request/CategoryCreateRequestDto.java @@ -0,0 +1,11 @@ +package com.back.domain.post.category.dto.request; + +import jakarta.validation.constraints.NotBlank; + +public record CategoryCreateRequestDto( + @NotBlank(message = "이름은 필수입니다.") + String name, + @NotBlank (message = "설명은 필수입니다.") + String description +) { +} \ No newline at end of file diff --git a/src/main/java/com/back/domain/post/category/service/CategoryService.java b/src/main/java/com/back/domain/post/category/service/CategoryService.java new file mode 100644 index 00000000..4b91835e --- /dev/null +++ b/src/main/java/com/back/domain/post/category/service/CategoryService.java @@ -0,0 +1,33 @@ +package com.back.domain.post.category.service; + +import com.back.domain.post.category.dto.request.CategoryCreateRequestDto; +import com.back.domain.post.category.entity.Category; +import com.back.domain.post.category.repository.CategoryRepository; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class CategoryService { + + private final CategoryRepository categoryRepository; + + // 카테고리 작성 로직 + @Transactional + public Category createCategory(CategoryCreateRequestDto reqBody) { + Category category = Category.builder() + .name(reqBody.name()) + .description(reqBody.description()) + .build(); + + return categoryRepository.save(category); + } + + // 카테고리 목록 조회 로직 + @Transactional(readOnly = true) + public List getCategories() { + return categoryRepository.findAll(); + } +} diff --git a/src/main/java/com/back/domain/post/comment/service/CommentService.java b/src/main/java/com/back/domain/post/comment/service/CommentService.java index e589cc50..cd937589 100644 --- a/src/main/java/com/back/domain/post/comment/service/CommentService.java +++ b/src/main/java/com/back/domain/post/comment/service/CommentService.java @@ -32,6 +32,9 @@ public class CommentService { @Transactional public CommentResponseDto createComment(Long postId, CommentCreateRequestDto reqBody) { User user = rq.getActor(); + if (user == null) { + throw new IllegalStateException("로그인한 사용자만 댓글을 작성할 수 있습니다."); + } Post post = postRepository.findById(postId) .orElseThrow(() -> new IllegalArgumentException("게시글이 존재하지 않습니다. id=" + postId)); @@ -51,6 +54,10 @@ public CommentResponseDto createComment(Long postId, CommentCreateRequestDto req ); Comment saved = commentRepository.save(comment); + + // 게시글 댓글 수 증가 + post.increaseCommentCount(); + // 활동 점수: 댓글 작성 +0.2 abvScoreService.awardForComment(user.getId()); return new CommentResponseDto(saved); @@ -100,6 +107,9 @@ public CommentResponseDto updateComment(Long postId, Long commentId, CommentUpda public void deleteComment(Long postId, Long commentId) { User user = rq.getActor(); + Post post = postRepository.findById(postId) + .orElseThrow(() -> new IllegalArgumentException("게시글이 존재하지 않습니다. id=" + postId)); + Comment comment = findCommentWithValidation(postId, commentId); if (!comment.getUser().equals(user)) { @@ -107,6 +117,9 @@ public void deleteComment(Long postId, Long commentId) { } comment.updateStatus(CommentStatus.DELETED); + + // 게시글 댓글 수 감소 + post.decreaseCommentCount(); // 활동 점수: 댓글 삭제 시 -0.2 (작성자 기준) abvScoreService.revokeForComment(user.getId()); diff --git a/src/main/java/com/back/domain/post/post/controller/PostController.java b/src/main/java/com/back/domain/post/post/controller/PostController.java index 8d874866..ae763845 100644 --- a/src/main/java/com/back/domain/post/post/controller/PostController.java +++ b/src/main/java/com/back/domain/post/post/controller/PostController.java @@ -7,6 +7,8 @@ import com.back.domain.post.post.service.PostService; import com.back.global.rsData.RsData; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import java.util.List; @@ -41,6 +43,7 @@ public class PostController { @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @Operation(summary = "게시글 작성") public RsData createPost( + @Parameter(description = "게시글 JSON", required = true, schema = @Schema(type = "string", format = "json")) @RequestPart("post") @Valid PostCreateRequestDto reqBody, @RequestPart(value = "images", required = false) List images ) { diff --git a/src/main/java/com/back/domain/post/post/entity/Post.java b/src/main/java/com/back/domain/post/post/entity/Post.java index c4769d85..c0734789 100644 --- a/src/main/java/com/back/domain/post/post/entity/Post.java +++ b/src/main/java/com/back/domain/post/post/entity/Post.java @@ -87,13 +87,15 @@ public class Post { @Column(name = "like_count", nullable = false) private Integer likeCount = 0; - // 게시글 댓글 수 - @Column(name = "comment_count") - private Integer commentCount; + // 게시글 댓글 수 (기본값: 0) + @Builder.Default + @Column(name = "comment_count", nullable = false) + private Integer commentCount = 0; - // 게시글 조회 수 - @Column(name = "view_count") - private Integer viewCount; + // 게시글 조회 수 (기본값: 0) + @Builder.Default + @Column(name = "view_count", nullable = false) + private Integer viewCount = 0; public void updateCategory(Category category) { this.category = category; @@ -139,4 +141,18 @@ public void increaseLikeCount() { public void decreaseLikeCount() { this.likeCount--; } + + public void increaseCommentCount() { + this.commentCount++; + } + + public void decreaseCommentCount() { + if (this.commentCount > 0) { + this.commentCount--; + } + } + + public void increaseViewCount() { + this.viewCount++; + } } diff --git a/src/main/java/com/back/domain/post/post/service/PostService.java b/src/main/java/com/back/domain/post/post/service/PostService.java index 0ed5c2f8..8e49745c 100644 --- a/src/main/java/com/back/domain/post/post/service/PostService.java +++ b/src/main/java/com/back/domain/post/post/service/PostService.java @@ -136,10 +136,12 @@ public List getPosts(PostSortScrollRequestDto reqBody) { // 게시글 단건 조회 로직 @Transactional(readOnly = true) public PostResponseDto getPost(Long postId) { - return new PostResponseDto( - postRepository.findById(postId) - .orElseThrow(() -> new NoSuchElementException("해당 게시글을 찾을 수 없습니다. ID: " + postId)) - ); + Post post = postRepository.findById(postId) + .orElseThrow(() -> new NoSuchElementException("해당 게시글을 찾을 수 없습니다. ID: " + postId)); + + post.increaseViewCount(); + + return new PostResponseDto(post); } // 게시글 수정 로직