Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Binary file added .DS_Store
Binary file not shown.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ out/

### VS Code ###
.vscode/

.env
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
# backend-study-sns
강지원
25 changes: 24 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,34 @@ repositories {
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'com.mysql:mysql-connector-j:9.0.0'
implementation 'me.paulschwarz:spring-dotenv:4.0.0'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

// lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'

// test
testImplementation 'org.springframework.boot:spring-boot-starter-test'

}
test{
useJUnitPlatform()
}

configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
tasks.named('test') {
useJUnitPlatform()
}
43 changes: 43 additions & 0 deletions src/main/java/com/example/devSns/controller/CommentController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.example.devSns.controller;

import com.example.devSns.entity.Comment;
import com.example.devSns.service.CommentService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/post/{postId}/comment")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

postId를 해당 컨트롤러 내의 모든 코드에서 사용할까요? 예를 들어, 댓글을 삭제할 때도 postId가 필요할까요?

public class CommentController {
private CommentService commentService;

public CommentController(CommentService commentService) {
this.commentService = commentService;
}

@GetMapping
public List<Comment> getComments(@PathVariable Long postId) {
return commentService.getCommentByPost(postId);
}

@PostMapping
public Comment createComment(@PathVariable Long postId, @RequestBody Comment comment) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

RequestBody로 Comment를 바로 받게 되면, 필요없는 정보까지 받아내야해서 낭비가 될 수 있어요 (ex createAt은 사용자가 주어야하는 정보가 아니라, db가 자동으로 저장할 수 있는 정보) DTO를 만들어서 필요한 정보만을 받을 수 있도록 하면 좋을 것 같아요

return commentService.addComment(postId, comment);
}

@DeleteMapping("/{commentId}")
public void deleteComment(@PathVariable Long commentId) {
commentService.deleteComment(commentId);
}

@PatchMapping("/{commentId}")
public ResponseEntity<Comment> updateComment(
@PathVariable Long commentId,
@RequestBody Map<String, String> request
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Map을 DTO로 만들어서 사용하면 코드를 더욱 유연하게 작성할 수 있을 것 같아요!

) {
String newContent = request.get("content");
Comment updated = commentService.updateComment(commentId, newContent);
return ResponseEntity.ok(updated);
}
}
47 changes: 47 additions & 0 deletions src/main/java/com/example/devSns/controller/PostController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.example.devSns.controller;

import com.example.devSns.entity.Post;
import com.example.devSns.service.PostService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/post")
public class PostController {
private final PostService postService;

public PostController(PostService postService) {
this.postService = postService;
}

@GetMapping
public List<Post> getAllPosts(){
return postService.findAll();
}

@GetMapping("/{id}")
public ResponseEntity<Post> getPostById(@PathVariable Long id){
Post post = postService.findById(id);
return ResponseEntity.ok(post);
}

@PostMapping
public Post createPost(@RequestBody Post post){
return postService.save(post);
}

@PutMapping("/{id}")
public Post updatePost(@PathVariable Long id, @RequestBody Post updatedPost){

return postService.updatePost(id,updatedPost);
}

@DeleteMapping("/{id}")
public void deletePost(@PathVariable Long id){
postService.delete(id);
}
}
41 changes: 41 additions & 0 deletions src/main/java/com/example/devSns/entity/Comment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.example.devSns.entity;

import com.fasterxml.jackson.annotation.JsonBackReference;
import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDateTime;

@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Comment{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String content;
private String username;
private LocalDateTime createdAt;

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(
name="post_id",
nullable = false,
foreignKey = @ForeignKey(name = "fk_diary_user_id_ref_user_id")
)
Comment on lines +23 to +27
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

해당 코드에서 foreign key를 설정해둔 이유가 있을까요?

@JsonBackReference
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

위에서 Entity를 직접 사용하는 것에서 Dto를 사용하는 것으로 변경하면 해당 직렬화 어노테이션은 필요가 없어질 것입니당!!

private Post post;

@PrePersist
public void onCreate(){
createdAt = LocalDateTime.now();
}
public void update(String content){
this.content = content;
}
public void assignTo(Post post){
this.post = post;
}
}
48 changes: 48 additions & 0 deletions src/main/java/com/example/devSns/entity/Post.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.example.devSns.entity;

import com.fasterxml.jackson.annotation.JsonManagedReference;
import jakarta.persistence.*;
import lombok.*;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String content;
private int likes;
private String username;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;

@OneToMany(mappedBy = "post", cascade = CascadeType.ALL,orphanRemoval = true)
@JsonManagedReference
private List<Comment> comments = new ArrayList<>();

@PrePersist
public void onCreate(){
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}

@PreUpdate
public void onUpdate(){
updatedAt = LocalDateTime.now();
}
public void update(String content){
this.content = content;
}
public void addComment(Comment comment){
comments.add(comment);
comment.assignTo(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.example.devSns.repository;

import com.example.devSns.entity.Comment;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;

public interface CommentRepository extends JpaRepository<Comment, Long> {
List<Comment> findByPost_Id(Long postId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.example.devSns.repository;

import com.example.devSns.entity.Post;
import org.springframework.data.jpa.repository.JpaRepository;

public interface PostRepository extends JpaRepository<Post, Long> {}
43 changes: 43 additions & 0 deletions src/main/java/com/example/devSns/service/CommentService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.example.devSns.service;

import com.example.devSns.entity.Comment;
import com.example.devSns.entity.Post;
import com.example.devSns.repository.CommentRepository;
import com.example.devSns.repository.PostRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class CommentService {
private final CommentRepository commentRepository;
private final PostRepository postRepository;

public CommentService(CommentRepository commentRepository, PostRepository postRepository) {
this.commentRepository = commentRepository;
this.postRepository = postRepository;
}

@Transactional(readOnly = true)
public List<Comment> getCommentByPost(Long postId){
return commentRepository.findByPost_Id(postId);
}

public Comment addComment(Long postId, Comment comment){
Post post = postRepository.findById(postId).orElseThrow(()-> new IllegalArgumentException("post not found"));

post.addComment(comment);
postRepository.save(post);
return commentRepository.save(comment);
}
public Comment updateComment(Long commentId, String newContent){
Comment comment = commentRepository.findById(commentId).orElseThrow(() -> new IllegalArgumentException("comment not found"));
comment.update(newContent);
return commentRepository.save(comment);
}

public void deleteComment(Long id){
commentRepository.deleteById(id);
}
}
39 changes: 39 additions & 0 deletions src/main/java/com/example/devSns/service/PostService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.example.devSns.service;

import com.example.devSns.entity.Post;
import com.example.devSns.repository.PostRepository;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

@Service
public class PostService {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

아래 코드들은 모두 DB쪽을 건드리는 코드이기 때문에 @transactional 어노테이션을 사용하여 트랜잭션을 설정하는 것이 좋아요! 트랜잭션을 설정해야하는 이유는 무엇일까요?

private final PostRepository postRepository;

public PostService(PostRepository postRepository) {
this.postRepository = postRepository;
}

public List<Post> findAll(){
return postRepository.findAll();
}

public Post findById(Long id){
return postRepository.findById(id).orElseThrow(()-> new IllegalArgumentException("Post not found"));
}

public Post save(Post post){
return postRepository.save(post);
}
public Post updatePost(Long id, Post updatedPost) {
Post existingPost = postRepository.findById(id).orElseThrow(() -> new RuntimeException("Post not found"));
existingPost.update(updatedPost.getContent());
return postRepository.save(existingPost);
}

public void delete(Long id){
postRepository.deleteById(id);
}
}
12 changes: 12 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1 +1,13 @@
spring.application.name=devSns

# DB ????
spring.datasource.url=${DATASOURCE_URL}
spring.datasource.username=${DATASOURCE_USERNAME}
spring.datasource.password=${DATASOURCE_PASSWORD}
# DB ????
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.hibernate.ddl-auto=update
# true? ???? ?? ???? sql?? ???? ??? ? ????.
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
Loading