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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,8 @@ out/

### VS Code ###
.vscode/

### Custom ###
db_dev.mv.db
db_dev.trace.db
.env
2 changes: 2 additions & 0 deletions src/main/java/com/back/BackApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@EnableJpaAuditing // 테이블에 로우데이터가 쌓일 때 수정일/생성일이 자동으로 갱신된다.
@SpringBootApplication
public class BackApplication {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.back.boundedContext.member.app;


import com.back.boundedContext.member.domain.Member;
import com.back.global.exception.DomainException;
import com.back.boundedContext.member.out.MemberRepository;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
public class MemberService {
private final MemberRepository memberRepository;

public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}

public long count() {
return memberRepository.count();
}

public Member join(String username, String password, String nickname) {
findByUsername(username).ifPresent(m -> {
throw new DomainException("409-1", "이미 존재하는 username 입니다.");
});

return memberRepository.save(new Member(username, password, nickname));
}

public Optional<Member> findByUsername(String username) {
return memberRepository.findByUsername(username);
}

public Optional<Member> findById(int id) {
return memberRepository.findById(id);
}
}
30 changes: 30 additions & 0 deletions src/main/java/com/back/boundedContext/member/domain/Member.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.back.boundedContext.member.domain;

import com.back.global.jpa.entity.BaseIdAndTime;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@NoArgsConstructor
@Getter
public class Member extends BaseIdAndTime {
@Column(unique = true)
private String username;
private String password;
private String nickname;
private int activityScore;

public Member(String username, String password, String nickname) {
this.username = username;
this.password = password;
this.nickname = nickname;
}

public int increaseActivityScore(int amount) {
return this.activityScore+=amount;
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.back.boundedContext.member.in;

import com.back.boundedContext.member.domain.Member;
import com.back.boundedContext.member.app.MemberService;
import com.back.shared.post.event.PostCommentCreatedEvent;
import com.back.shared.post.event.PostCreatedEvent;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionalEventListener;

import static org.springframework.transaction.annotation.Propagation.REQUIRES_NEW;
import static org.springframework.transaction.event.TransactionPhase.AFTER_COMMIT;


@Component
@RequiredArgsConstructor
public class MemberEventListener {
private final MemberService memberService;

@TransactionalEventListener(phase = AFTER_COMMIT)
@Transactional(propagation = REQUIRES_NEW)
public void handle(PostCreatedEvent event) {
Member member = memberService.findById(event.getPost().getAuthorId()).get();

member.increaseActivityScore(3);
}

@TransactionalEventListener(phase = AFTER_COMMIT)
@Transactional(propagation = REQUIRES_NEW)
public void handle(PostCommentCreatedEvent event) {
Member member = memberService.findById(event.getPostComment().getAuthorId()).get();

member.increaseActivityScore(1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.back.boundedContext.member.out;

import com.back.boundedContext.member.domain.Member;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface MemberRepository extends JpaRepository<Member, Integer> {
Optional<Member> findByUsername(String username);

Optional<Member> findById(int id);
}
39 changes: 39 additions & 0 deletions src/main/java/com/back/boundedContext/post/app/PostService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.back.boundedContext.post.app;


import com.back.boundedContext.member.domain.Member;
import com.back.boundedContext.post.domain.Post;
import com.back.boundedContext.post.out.PostRepository;
import com.back.global.EventPublisher.EventPublisher;
import com.back.shared.dto.PostDto;
import com.back.shared.post.event.PostCreatedEvent;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
@RequiredArgsConstructor
public class PostService {
private final PostRepository postRepository;
private final EventPublisher eventPublisher;

public long count() {
return postRepository.count();
}

public Post write(Member author, String title, String content) {
Post post = postRepository.save(new Post(author, title, content));

eventPublisher.publish(
new PostCreatedEvent(
new PostDto(post)
)
);

return post;
}
public Optional<Post> findById(int id) {
return postRepository.findById(id);
}
}
53 changes: 53 additions & 0 deletions src/main/java/com/back/boundedContext/post/domain/Post.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.back.boundedContext.post.domain;

import com.back.boundedContext.member.domain.Member;
import com.back.global.jpa.entity.BaseIdAndTime;
import com.back.shared.dto.PostCommentDto;
import com.back.shared.post.event.PostCommentCreatedEvent;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import lombok.Getter;
import lombok.NoArgsConstructor;

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

import static jakarta.persistence.CascadeType.PERSIST;
import static jakarta.persistence.CascadeType.REMOVE;
import static jakarta.persistence.FetchType.LAZY;

@Entity
@NoArgsConstructor
@Getter
public class Post extends BaseIdAndTime {

@ManyToOne(fetch = LAZY) //지연 로딩
private Member author;
private String title;
@Column(columnDefinition = "LONGTEXT")
private String content;

@OneToMany(mappedBy = "post",cascade = {PERSIST, REMOVE}, orphanRemoval = true) // 영속성 전이 및 고아 객체 제거
private List<PostComment> comments = new ArrayList<>();

public Post(Member author, String title, String content) {
this.author = author;
this.title = title;
this.content = content;
}

public PostComment addComment(Member author, String content) {
PostComment postComment = new PostComment(this, author, content);

comments.add(postComment);
publishEvent(new PostCommentCreatedEvent(new PostCommentDto(postComment)));

return postComment;
}

public boolean hasComments() {
return !comments.isEmpty();
}
}
29 changes: 29 additions & 0 deletions src/main/java/com/back/boundedContext/post/domain/PostComment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.back.boundedContext.post.domain;

import com.back.boundedContext.member.domain.Member;
import com.back.global.jpa.entity.BaseIdAndTime;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
import lombok.Getter;
import lombok.NoArgsConstructor;

import static jakarta.persistence.FetchType.LAZY;

@Entity
@NoArgsConstructor
@Getter
public class PostComment extends BaseIdAndTime {
@ManyToOne(fetch = LAZY)
private Post post;
@ManyToOne(fetch = LAZY)
private Member author;
@Column(columnDefinition = "TEXT")
private String content;

public PostComment(Post post, Member author, String content) {
this.post = post;
this.author = author;
this.content = content;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.back.boundedContext.post.out;

import com.back.boundedContext.post.domain.Post;
import org.springframework.data.jpa.repository.JpaRepository;

public interface PostRepository extends JpaRepository<Post, Integer> {
}
17 changes: 17 additions & 0 deletions src/main/java/com/back/global/EventPublisher/EventPublisher.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.back.global.EventPublisher;


import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class EventPublisher {
private final ApplicationEventPublisher applicationEventPublisher;

public void publish(Object event){
applicationEventPublisher.publishEvent(event);
}

}
15 changes: 15 additions & 0 deletions src/main/java/com/back/global/exception/DomainException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.back.global.exception;

import lombok.Getter;

@Getter
public class DomainException extends RuntimeException {
private final String resultCode;
private final String msg;

public DomainException(String resultCode, String msg) {
super(resultCode + " : " + msg);
this.resultCode = resultCode;
this.msg = msg;
}
}
18 changes: 18 additions & 0 deletions src/main/java/com/back/global/global/GlobalConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.back.global.global;


import com.back.global.EventPublisher.EventPublisher;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

@Configuration
public class GlobalConfig {
@Getter
private static EventPublisher eventPublisher;

@Autowired
public void setEventPublisher(EventPublisher eventPublisher) {
GlobalConfig.eventPublisher = eventPublisher;
}
}
Loading