Configures to add default member domain values only to email confirmed

users.

- using spring domain event
- add adapter layer
- add EventListener
- modulization account, member
This commit is contained in:
Rebwon
2021-09-27 11:44:27 +09:00
committed by MaengSol
parent 989857c43d
commit b8eecc0b67
21 changed files with 277 additions and 5 deletions

View File

@@ -4,6 +4,7 @@ import com.yam.app.account.domain.AccountNotFoundException;
import com.yam.app.account.domain.AccountReader;
import com.yam.app.account.domain.ConfirmRegisterAccountProcessor;
import com.yam.app.account.domain.LoginAccountProcessor;
import com.yam.app.account.domain.RegisterAccountConfirmEvent;
import com.yam.app.account.domain.RegisterAccountEvent;
import com.yam.app.account.domain.RegisterAccountProcessor;
import com.yam.app.account.presentation.AccountResponse;
@@ -47,6 +48,7 @@ public class AccountFacade {
@Transactional
public void registerConfirm(ConfirmRegisterAccountCommand command) {
confirmRegisterProcessor.registerConfirm(command.getToken(), command.getEmail());
publisher.publishEvent(new RegisterAccountConfirmEvent(command.getEmail()));
}
@Transactional(readOnly = true)

View File

@@ -51,4 +51,8 @@ public final class Account {
public boolean isValidToken(String token) {
return this.emailCheckToken.equals(token);
}
public void addMember(Long memberId) {
this.memberId = memberId;
}
}

View File

@@ -0,0 +1,15 @@
package com.yam.app.account.domain;
import lombok.Getter;
@Getter
public final class GenerateMemberEvent {
private final Long memberId;
private final String email;
public GenerateMemberEvent(Long memberId, String email) {
this.memberId = memberId;
this.email = email;
}
}

View File

@@ -0,0 +1,13 @@
package com.yam.app.account.domain;
import lombok.Getter;
@Getter
public final class RegisterAccountConfirmEvent {
private final String email;
public RegisterAccountConfirmEvent(String email) {
this.email = email;
}
}

View File

@@ -0,0 +1,31 @@
package com.yam.app.account.infrastructure;
import com.yam.app.account.domain.AccountNotFoundException;
import com.yam.app.account.domain.AccountReader;
import com.yam.app.account.domain.AccountRepository;
import com.yam.app.account.domain.GenerateMemberEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class AccountEventListener {
private final AccountReader accountReader;
private final AccountRepository accountRepository;
public AccountEventListener(AccountReader accountReader,
AccountRepository accountRepository) {
this.accountReader = accountReader;
this.accountRepository = accountRepository;
}
@EventListener
@Transactional
public void handle(GenerateMemberEvent event) {
var account = accountReader.findByEmail(event.getEmail())
.orElseThrow(() -> new AccountNotFoundException(event.getEmail()));
account.addMember(event.getMemberId());
accountRepository.update(account);
}
}

View File

@@ -0,0 +1,34 @@
package com.yam.app.adapter;
import com.yam.app.account.domain.RegisterAccountConfirmEvent;
import com.yam.app.member.domain.GenerateMemberEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionalEventListener;
@Component
class DomainEventTranslator {
private final ApplicationEventPublisher publisher;
public DomainEventTranslator(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
@Async
@TransactionalEventListener
public void handle(RegisterAccountConfirmEvent event) {
publisher.publishEvent(
new com.yam.app.member.domain.RegisterAccountConfirmEvent(event.getEmail()));
}
@Async
@TransactionalEventListener
public void handle(GenerateMemberEvent event) {
publisher.publishEvent(
new com.yam.app.account.domain.GenerateMemberEvent(event.getMemberId(),
event.getEmail()));
}
}

View File

@@ -0,0 +1,15 @@
package com.yam.app.member.domain;
import lombok.Getter;
@Getter
public final class GenerateMemberEvent {
private final Long memberId;
private final String email;
public GenerateMemberEvent(Long memberId, String email) {
this.memberId = memberId;
this.email = email;
}
}

View File

@@ -0,0 +1,18 @@
package com.yam.app.member.domain;
import lombok.Getter;
import lombok.ToString;
@Getter
@ToString
public final class Member {
private Long id;
private String nickname;
private String image;
public Member(String nickname, String image) {
this.nickname = nickname;
this.image = image;
}
}

View File

@@ -0,0 +1,8 @@
package com.yam.app.member.domain;
import java.util.Optional;
public interface MemberReader {
Optional<Member> findByNickname(String nickname);
}

View File

@@ -0,0 +1,6 @@
package com.yam.app.member.domain;
public interface MemberRepository {
void save(Member entity);
}

View File

@@ -0,0 +1,13 @@
package com.yam.app.member.domain;
import lombok.Getter;
@Getter
public final class RegisterAccountConfirmEvent {
private final String email;
public RegisterAccountConfirmEvent(String email) {
this.email = email;
}
}

View File

@@ -0,0 +1,37 @@
package com.yam.app.member.infrastructure;
import com.yam.app.member.domain.GenerateMemberEvent;
import com.yam.app.member.domain.Member;
import com.yam.app.member.domain.MemberReader;
import com.yam.app.member.domain.MemberRepository;
import com.yam.app.member.domain.RegisterAccountConfirmEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class MemberEventListener {
private final MemberReader memberReader;
private final MemberRepository memberRepository;
private final ApplicationEventPublisher publisher;
public MemberEventListener(MemberReader memberReader,
MemberRepository memberRepository,
ApplicationEventPublisher publisher) {
this.memberReader = memberReader;
this.memberRepository = memberRepository;
this.publisher = publisher;
}
@EventListener
@Transactional
public void handle(RegisterAccountConfirmEvent event) {
var nickname = event.getEmail().split("@")[0];
memberRepository.save(new Member(nickname, "temp.png"));
var member = memberReader.findByNickname(nickname)
.orElseThrow(IllegalArgumentException::new);
publisher.publishEvent(new GenerateMemberEvent(member.getId(), event.getEmail()));
}
}

View File

@@ -0,0 +1,21 @@
package com.yam.app.member.infrastructure;
import com.yam.app.member.domain.MemberReader;
import com.yam.app.member.domain.MemberRepository;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MemberModuleConfiguration {
@Bean
public MemberReader memberReader(SqlSessionTemplate template) {
return new MybatisMemberRepository(template);
}
@Bean
public MemberRepository memberRepository(SqlSessionTemplate template) {
return new MybatisMemberRepository(template);
}
}

View File

@@ -0,0 +1,32 @@
package com.yam.app.member.infrastructure;
import com.yam.app.member.domain.Member;
import com.yam.app.member.domain.MemberReader;
import com.yam.app.member.domain.MemberRepository;
import java.util.Optional;
import org.mybatis.spring.SqlSessionTemplate;
public final class MybatisMemberRepository implements MemberRepository, MemberReader {
private final SqlSessionTemplate template;
private static final String SAVE_FQCN = "com.yam.app.member.domain.MemberRepository.save";
public MybatisMemberRepository(SqlSessionTemplate template) {
this.template = template;
}
@Override
public Optional<Member> findByNickname(String nickname) {
return template.getMapper(MemberReader.class).findByNickname(nickname);
}
@Override
public void save(Member entity) {
int result = template.insert(SAVE_FQCN, entity);
if (result != 1) {
throw new RuntimeException(
String.format("There was a problem saving the object : %s", entity));
}
}
}

View File

@@ -12,7 +12,8 @@
withdraw = #{withdraw},
joined_at = #{joinedAt},
role = #{role},
last_modified_at = NOW()
last_modified_at = NOW(),
member_id = #{memberId}
WHERE id = #{id}
</update>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yam.app.member.domain.MemberRepository">
<insert id="save" parameterType="com.yam.app.member.domain.Member">
INSERT
INTO MEMBER(nickname, image)
VALUES (#{nickname}, #{image})
</insert>
</mapper>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yam.app.member.domain.MemberReader">
<select id="findByNickname" parameterType="String"
resultType="com.yam.app.member.domain.Member">
SELECT * FROM member WHERE nickname = #{nickname}
</select>
</mapper>

View File

@@ -25,8 +25,5 @@ create table member(
alter table account
add constraint UK_q0uja26qgu1atulenwup9rxyr unique (email);
alter table member
add constraint UK_hh9kg6jti4n1eoiertn2k6qsc unique (nickname);
alter table account
add constraint FKr5j0huynd7nsv1s7e9vb8qvwo foreign key (member_id) references member;

View File

@@ -21,10 +21,12 @@ final class ArchUnitTests {
.layer("Presentation").definedBy("..presentation..")
.layer("Infrastructure").definedBy("..infrastructure..")
.layer("Integration").definedBy("..integration..")
.layer("Adapter").definedBy("..adapter..")
.whereLayer("Presentation").mayOnlyBeAccessedByLayers("Application", "Integration")
.whereLayer("Application").mayOnlyBeAccessedByLayers("Presentation", "Domain")
.whereLayer("Domain").mayOnlyBeAccessedByLayers("Application", "Infrastructure")
.whereLayer("Domain").mayOnlyBeAccessedByLayers("Application", "Infrastructure", "Adapter")
.whereLayer("Infrastructure").mayOnlyBeAccessedByLayers("Presentation", "Integration")
.whereLayer("Adapter").mayNotBeAccessedByAnyLayer()
.whereLayer("Integration").mayNotBeAccessedByAnyLayer();
}