From 7e47d50524ecdc49d4b77b7afd55b650dae674a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=95=88=EC=A4=80=ED=97=8C?= Date: Tue, 18 Feb 2025 14:33:48 +0900 Subject: [PATCH] Refactor member persistence layer to use JPA entities Replaced DTO-based persistence with JPA entities and repository integration. Introduced `Member` entity, `MemberJpaRepository`, and custom `MemberRepositoryImpl`. Updated service and controller logic accordingly, and added a migration script for column renaming. --- spring-boot/build.gradle | 3 +- .../application/dto/MemberResponse.java | 18 --------- .../application/service/MemberService.java | 12 ++++-- .../member/domain/dto/MemberView.java | 17 --------- .../member/domain/entity/Member.java | 38 +++++++++++++++++++ .../exception/MemberNotFoundException.java | 14 +++++++ .../domain/mapping/MemberCodeConverter.java | 26 +++++++++++++ .../domain/repository/MemberRepository.java | 9 +++-- .../member/domain/vo/MemberName.java | 14 ++++--- .../jpa/repository/MemberJpaRepository.java | 12 ++++++ .../jpa/repository/MemberRepositoryImpl.java | 26 +++++++++++++ .../repository/MemberRepositoryImpl.java | 15 -------- .../controller/MemberRestController.java | 13 +++++-- .../src/main/resources/application.yml | 3 +- .../db/migration/V2__remove_prefix.sql | 2 + 15 files changed, 153 insertions(+), 69 deletions(-) delete mode 100644 spring-boot/src/main/java/com/mpc/springboot/member/application/dto/MemberResponse.java delete mode 100644 spring-boot/src/main/java/com/mpc/springboot/member/domain/dto/MemberView.java create mode 100644 spring-boot/src/main/java/com/mpc/springboot/member/domain/entity/Member.java create mode 100644 spring-boot/src/main/java/com/mpc/springboot/member/domain/exception/MemberNotFoundException.java create mode 100644 spring-boot/src/main/java/com/mpc/springboot/member/domain/mapping/MemberCodeConverter.java create mode 100644 spring-boot/src/main/java/com/mpc/springboot/member/infrastructure/persistence/jpa/repository/MemberJpaRepository.java create mode 100644 spring-boot/src/main/java/com/mpc/springboot/member/infrastructure/persistence/jpa/repository/MemberRepositoryImpl.java delete mode 100644 spring-boot/src/main/java/com/mpc/springboot/member/infrastructure/repository/MemberRepositoryImpl.java create mode 100644 spring-boot/src/main/resources/db/migration/V2__remove_prefix.sql diff --git a/spring-boot/build.gradle b/spring-boot/build.gradle index deca0c5..77626e9 100644 --- a/spring-boot/build.gradle +++ b/spring-boot/build.gradle @@ -32,8 +32,7 @@ dependencies { implementation 'com.mysql:mysql-connector-j:9.2.0' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.flywaydb:flyway-core:11.3.1' - implementation 'org.flywaydb:flyway-mysql:11.3.1' + implementation 'org.flywaydb:flyway-mysql:11.3.2' testImplementation 'org.springframework.boot:spring-boot-starter-test' diff --git a/spring-boot/src/main/java/com/mpc/springboot/member/application/dto/MemberResponse.java b/spring-boot/src/main/java/com/mpc/springboot/member/application/dto/MemberResponse.java deleted file mode 100644 index 34ad938..0000000 --- a/spring-boot/src/main/java/com/mpc/springboot/member/application/dto/MemberResponse.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.mpc.springboot.member.application.dto; - -import com.mpc.springboot.member.domain.dto.MemberView; -import com.mpc.springboot.member.domain.vo.MemberCode; -import com.mpc.springboot.member.domain.vo.MemberName; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Getter -public class MemberResponse { - private final MemberCode memberCode; - private final MemberName memberName; - - public static MemberResponse of(MemberView memberView) { - return new MemberResponse(memberView.getMemberCode(), memberView.getMemberName()); - } -} diff --git a/spring-boot/src/main/java/com/mpc/springboot/member/application/service/MemberService.java b/spring-boot/src/main/java/com/mpc/springboot/member/application/service/MemberService.java index db15e9a..c539d52 100644 --- a/spring-boot/src/main/java/com/mpc/springboot/member/application/service/MemberService.java +++ b/spring-boot/src/main/java/com/mpc/springboot/member/application/service/MemberService.java @@ -1,7 +1,8 @@ package com.mpc.springboot.member.application.service; import org.springframework.stereotype.Service; -import com.mpc.springboot.member.application.dto.MemberResponse; +import com.mpc.springboot.member.domain.entity.Member; +import com.mpc.springboot.member.domain.exception.MemberNotFoundException; import com.mpc.springboot.member.domain.repository.MemberRepository; import com.mpc.springboot.member.domain.vo.MemberCode; import lombok.RequiredArgsConstructor; @@ -12,7 +13,12 @@ public class MemberService { private final MemberRepository memberRepository; - public MemberResponse getMemberBy(MemberCode memberCode) { - return MemberResponse.of(memberRepository.findMemberBy(memberCode)); + public Member getMemberBy(MemberCode code) { + return memberRepository.findMemberBy(code) + .orElseThrow(MemberNotFoundException::new); + } + + public Member createMember(Member member) { + return memberRepository.save(member); } } diff --git a/spring-boot/src/main/java/com/mpc/springboot/member/domain/dto/MemberView.java b/spring-boot/src/main/java/com/mpc/springboot/member/domain/dto/MemberView.java deleted file mode 100644 index 26c11c1..0000000 --- a/spring-boot/src/main/java/com/mpc/springboot/member/domain/dto/MemberView.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.mpc.springboot.member.domain.dto; - -import com.mpc.springboot.member.domain.vo.MemberCode; -import com.mpc.springboot.member.domain.vo.MemberName; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Getter -public class MemberView { - private final MemberCode memberCode; - private final MemberName memberName; - - public static MemberView of(MemberCode memberCode, MemberName memberName) { - return new MemberView(memberCode, memberName); - } -} diff --git a/spring-boot/src/main/java/com/mpc/springboot/member/domain/entity/Member.java b/spring-boot/src/main/java/com/mpc/springboot/member/domain/entity/Member.java new file mode 100644 index 0000000..6c65044 --- /dev/null +++ b/spring-boot/src/main/java/com/mpc/springboot/member/domain/entity/Member.java @@ -0,0 +1,38 @@ +package com.mpc.springboot.member.domain.entity; + +import jakarta.persistence.*; + +import com.mpc.springboot.member.domain.vo.MemberCode; +import com.mpc.springboot.member.domain.mapping.MemberCodeConverter; +import com.mpc.springboot.member.domain.vo.MemberName; +import lombok.*; + +@Getter +@NoArgsConstructor +//@Table(name = "member") +@Entity +public class Member { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "`key`") + private Integer key; + + @Convert(converter = MemberCodeConverter.class) + @Column(name = "`code`") + private MemberCode code; + + @Embedded + private MemberName name; + + public Member(MemberCode code, MemberName name) { + this.code = code; + this.name = name; + } + + public static Member create(MemberCode code, MemberName name) { + return new Member(code, name); + } +} + + diff --git a/spring-boot/src/main/java/com/mpc/springboot/member/domain/exception/MemberNotFoundException.java b/spring-boot/src/main/java/com/mpc/springboot/member/domain/exception/MemberNotFoundException.java new file mode 100644 index 0000000..4739b46 --- /dev/null +++ b/spring-boot/src/main/java/com/mpc/springboot/member/domain/exception/MemberNotFoundException.java @@ -0,0 +1,14 @@ +package com.mpc.springboot.member.domain.exception; + +public class MemberNotFoundException extends RuntimeException { + + private static final String MESSAGE = "Member not found"; + + public MemberNotFoundException() { + super(MESSAGE); + } + + public MemberNotFoundException(String message) { + super(message); + } +} diff --git a/spring-boot/src/main/java/com/mpc/springboot/member/domain/mapping/MemberCodeConverter.java b/spring-boot/src/main/java/com/mpc/springboot/member/domain/mapping/MemberCodeConverter.java new file mode 100644 index 0000000..ded5acf --- /dev/null +++ b/spring-boot/src/main/java/com/mpc/springboot/member/domain/mapping/MemberCodeConverter.java @@ -0,0 +1,26 @@ +package com.mpc.springboot.member.domain.mapping; + +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; + +import java.util.Objects; + +import com.mpc.springboot.member.domain.vo.MemberCode; + +@Converter(autoApply = true) +public class MemberCodeConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(MemberCode attribute) { + if (attribute == null) { + return ""; + } + return attribute.getValue(); + } + + @Override + public MemberCode convertToEntityAttribute(String dbData) { + String value = Objects.requireNonNullElse(dbData, ""); + return new MemberCode(value); + } +} diff --git a/spring-boot/src/main/java/com/mpc/springboot/member/domain/repository/MemberRepository.java b/spring-boot/src/main/java/com/mpc/springboot/member/domain/repository/MemberRepository.java index 459c365..89de60c 100644 --- a/spring-boot/src/main/java/com/mpc/springboot/member/domain/repository/MemberRepository.java +++ b/spring-boot/src/main/java/com/mpc/springboot/member/domain/repository/MemberRepository.java @@ -1,10 +1,13 @@ package com.mpc.springboot.member.domain.repository; -import org.springframework.stereotype.Repository; -import com.mpc.springboot.member.domain.dto.MemberView; +import java.util.Optional; + +import com.mpc.springboot.member.domain.entity.Member; import com.mpc.springboot.member.domain.vo.MemberCode; public interface MemberRepository { - MemberView findMemberBy(MemberCode memberCode); + Optional findMemberBy(MemberCode code); + + Member save(Member member); } diff --git a/spring-boot/src/main/java/com/mpc/springboot/member/domain/vo/MemberName.java b/spring-boot/src/main/java/com/mpc/springboot/member/domain/vo/MemberName.java index ab1bd3e..6a0775a 100644 --- a/spring-boot/src/main/java/com/mpc/springboot/member/domain/vo/MemberName.java +++ b/spring-boot/src/main/java/com/mpc/springboot/member/domain/vo/MemberName.java @@ -1,13 +1,17 @@ package com.mpc.springboot.member.domain.vo; -import lombok.Getter; -import lombok.RequiredArgsConstructor; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; + +import lombok.*; @Getter -@RequiredArgsConstructor +@NoArgsConstructor +@Embeddable public class MemberName { - private final String firstName; - private final String lastName; + + private String firstName; + private String lastName; public String getFullName() { return firstName + " " + lastName; diff --git a/spring-boot/src/main/java/com/mpc/springboot/member/infrastructure/persistence/jpa/repository/MemberJpaRepository.java b/spring-boot/src/main/java/com/mpc/springboot/member/infrastructure/persistence/jpa/repository/MemberJpaRepository.java new file mode 100644 index 0000000..4f4621c --- /dev/null +++ b/spring-boot/src/main/java/com/mpc/springboot/member/infrastructure/persistence/jpa/repository/MemberJpaRepository.java @@ -0,0 +1,12 @@ +package com.mpc.springboot.member.infrastructure.persistence.jpa.repository; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; +import com.mpc.springboot.member.domain.entity.Member; +import com.mpc.springboot.member.domain.vo.MemberCode; + +public interface MemberJpaRepository extends JpaRepository { + + Optional findByCode(MemberCode code); +} diff --git a/spring-boot/src/main/java/com/mpc/springboot/member/infrastructure/persistence/jpa/repository/MemberRepositoryImpl.java b/spring-boot/src/main/java/com/mpc/springboot/member/infrastructure/persistence/jpa/repository/MemberRepositoryImpl.java new file mode 100644 index 0000000..9c1328b --- /dev/null +++ b/spring-boot/src/main/java/com/mpc/springboot/member/infrastructure/persistence/jpa/repository/MemberRepositoryImpl.java @@ -0,0 +1,26 @@ +package com.mpc.springboot.member.infrastructure.persistence.jpa.repository; + +import java.util.Optional; + +import org.springframework.stereotype.Repository; +import com.mpc.springboot.member.domain.entity.Member; +import com.mpc.springboot.member.domain.repository.MemberRepository; +import com.mpc.springboot.member.domain.vo.MemberCode; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Repository +public class MemberRepositoryImpl implements MemberRepository { + + private final MemberJpaRepository memberJpaRepository; + + @Override + public Optional findMemberBy(MemberCode code) { + return memberJpaRepository.findByCode(code); + } + + @Override + public Member save(Member member) { + return memberJpaRepository.save(member); + } +} diff --git a/spring-boot/src/main/java/com/mpc/springboot/member/infrastructure/repository/MemberRepositoryImpl.java b/spring-boot/src/main/java/com/mpc/springboot/member/infrastructure/repository/MemberRepositoryImpl.java deleted file mode 100644 index ae8308a..0000000 --- a/spring-boot/src/main/java/com/mpc/springboot/member/infrastructure/repository/MemberRepositoryImpl.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.mpc.springboot.member.infrastructure.repository; - -import org.springframework.stereotype.Repository; -import com.mpc.springboot.member.domain.dto.MemberView; -import com.mpc.springboot.member.domain.repository.MemberRepository; -import com.mpc.springboot.member.domain.vo.MemberCode; -import com.mpc.springboot.member.domain.vo.MemberName; - -@Repository -public class MemberRepositoryImpl implements MemberRepository { - @Override - public MemberView findMemberBy(MemberCode memberCode) { - return new MemberView(memberCode, new MemberName("준헌", "안")); - } -} diff --git a/spring-boot/src/main/java/com/mpc/springboot/member/presentation/controller/MemberRestController.java b/spring-boot/src/main/java/com/mpc/springboot/member/presentation/controller/MemberRestController.java index 12dafe2..3bce35d 100644 --- a/spring-boot/src/main/java/com/mpc/springboot/member/presentation/controller/MemberRestController.java +++ b/spring-boot/src/main/java/com/mpc/springboot/member/presentation/controller/MemberRestController.java @@ -2,8 +2,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import com.mpc.springboot.member.application.dto.MemberResponse; import com.mpc.springboot.member.application.service.MemberService; +import com.mpc.springboot.member.domain.entity.Member; import com.mpc.springboot.member.domain.vo.MemberCode; import lombok.*; @@ -14,8 +14,13 @@ public class MemberRestController { private final MemberService memberService; - @GetMapping("/{memberCode}") - public ResponseEntity getMemberBy(@PathVariable MemberCode memberCode) { - return ResponseEntity.ok(memberService.getMemberBy(memberCode)); + @GetMapping("/{code}") + public ResponseEntity getMemberBy(@PathVariable MemberCode code) { + return ResponseEntity.ok(memberService.getMemberBy(code)); + } + + @PostMapping + public ResponseEntity createMember(@RequestBody Member member) { + return ResponseEntity.ok(memberService.createMember(member)); } } diff --git a/spring-boot/src/main/resources/application.yml b/spring-boot/src/main/resources/application.yml index 7e135bd..6f767ec 100644 --- a/spring-boot/src/main/resources/application.yml +++ b/spring-boot/src/main/resources/application.yml @@ -6,10 +6,9 @@ spring: driver-class-name: com.mysql.cj.jdbc.Driver jpa: - database-platform: org.hibernate.dialect.MySQL8Dialect database: mysql hibernate: - ddl-auto: update + ddl-auto: validate show-sql: true properties: hibernate.format_sql: true diff --git a/spring-boot/src/main/resources/db/migration/V2__remove_prefix.sql b/spring-boot/src/main/resources/db/migration/V2__remove_prefix.sql new file mode 100644 index 0000000..bbdc1d5 --- /dev/null +++ b/spring-boot/src/main/resources/db/migration/V2__remove_prefix.sql @@ -0,0 +1,2 @@ +alter table member rename column member_key to `key`; +alter table member rename column member_code to `code`;