diff --git a/build.gradle b/build.gradle index c36d658..2acc06b 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-validation' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' diff --git a/src/main/java/org/example/commerce_site/CommerceSiteApplication.java b/src/main/java/org/example/commerce_site/CommerceSiteApplication.java index daa6b7a..4bbeee8 100644 --- a/src/main/java/org/example/commerce_site/CommerceSiteApplication.java +++ b/src/main/java/org/example/commerce_site/CommerceSiteApplication.java @@ -3,8 +3,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; -@SpringBootApplication (exclude = SecurityAutoConfiguration.class) +@EnableJpaAuditing +@SpringBootApplication(exclude = SecurityAutoConfiguration.class) public class CommerceSiteApplication { public static void main(String[] args) { SpringApplication.run(CommerceSiteApplication.class, args); diff --git a/src/main/java/org/example/commerce_site/application/partner/PartnerService.java b/src/main/java/org/example/commerce_site/application/partner/PartnerService.java new file mode 100644 index 0000000..a60496f --- /dev/null +++ b/src/main/java/org/example/commerce_site/application/partner/PartnerService.java @@ -0,0 +1,19 @@ +package org.example.commerce_site.application.partner; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.example.commerce_site.application.partner.dto.PartnerRequestDto; +import org.example.commerce_site.application.partner.dto.PartnerResponseDto; +import org.example.commerce_site.infrastructure.PartnerRepository; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@RequiredArgsConstructor +public class PartnerService { + private final PartnerRepository partnerRepository; + + public PartnerResponseDto.Create create(PartnerRequestDto.Create dto) { + return PartnerResponseDto.Create.of(partnerRepository.save(PartnerRequestDto.Create.toEntity(dto))); + } +} diff --git a/src/main/java/org/example/commerce_site/application/partner/dto/PartnerRequestDto.java b/src/main/java/org/example/commerce_site/application/partner/dto/PartnerRequestDto.java new file mode 100644 index 0000000..3b6c13e --- /dev/null +++ b/src/main/java/org/example/commerce_site/application/partner/dto/PartnerRequestDto.java @@ -0,0 +1,29 @@ +package org.example.commerce_site.application.partner.dto; + +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; +import org.example.commerce_site.attribute.PartnerStatus; +import org.example.commerce_site.domain.Partner; + +public class PartnerRequestDto { + @Getter + @Builder + @ToString + public static class Create { + private String name; + private String email; + private String password; + private String businessNumber; + + public static Partner toEntity(PartnerRequestDto.Create dto) { + return Partner.builder() + .name(dto.getName()) + .email(dto.getEmail()) + .password(dto.getPassword()) + .status(PartnerStatus.ACTIVE) + .businessNumber(dto.getBusinessNumber()) + .build(); + } + } +} diff --git a/src/main/java/org/example/commerce_site/application/partner/dto/PartnerResponseDto.java b/src/main/java/org/example/commerce_site/application/partner/dto/PartnerResponseDto.java new file mode 100644 index 0000000..ada7d08 --- /dev/null +++ b/src/main/java/org/example/commerce_site/application/partner/dto/PartnerResponseDto.java @@ -0,0 +1,25 @@ +package org.example.commerce_site.application.partner.dto; + +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; +import org.example.commerce_site.domain.Partner; + +public class PartnerResponseDto { + @Builder + @Getter + @ToString + public static class Create { + private String name; + private String email; + private String businessNumber; + + public static PartnerResponseDto.Create of(Partner partner) { + return Create.builder() + .name(partner.getName()) + .email(partner.getEmail()) + .businessNumber(partner.getBusinessNumber()) + .build(); + } + } +} diff --git a/src/main/java/org/example/commerce_site/application/user/UserService.java b/src/main/java/org/example/commerce_site/application/user/UserService.java new file mode 100644 index 0000000..f0928a0 --- /dev/null +++ b/src/main/java/org/example/commerce_site/application/user/UserService.java @@ -0,0 +1,19 @@ +package org.example.commerce_site.application.user; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.example.commerce_site.application.user.dto.UserRequestDto; +import org.example.commerce_site.application.user.dto.UserResponseDto; +import org.example.commerce_site.infrastructure.UserRepository; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@RequiredArgsConstructor +public class UserService { + private final UserRepository userRepository; + + public UserResponseDto.Create create(UserRequestDto.Create dto) { + return UserResponseDto.Create.of(userRepository.save(UserRequestDto.Create.toEntity(dto))); + } +} diff --git a/src/main/java/org/example/commerce_site/application/user/dto/UserRequestDto.java b/src/main/java/org/example/commerce_site/application/user/dto/UserRequestDto.java new file mode 100644 index 0000000..7b22471 --- /dev/null +++ b/src/main/java/org/example/commerce_site/application/user/dto/UserRequestDto.java @@ -0,0 +1,27 @@ +package org.example.commerce_site.application.user.dto; + +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; +import org.example.commerce_site.attribute.UserStatus; +import org.example.commerce_site.domain.User; + +public class UserRequestDto { + @Getter + @Builder + @ToString + public static class Create { + private String name; + private String email; + private String password; + + public static User toEntity(UserRequestDto.Create dto) { + return User.builder() + .name(dto.getName()) + .email(dto.getEmail()) + .password(dto.getPassword()) + .status(UserStatus.ACTIVE) + .build(); + } + } +} diff --git a/src/main/java/org/example/commerce_site/application/user/dto/UserResponseDto.java b/src/main/java/org/example/commerce_site/application/user/dto/UserResponseDto.java new file mode 100644 index 0000000..3b85175 --- /dev/null +++ b/src/main/java/org/example/commerce_site/application/user/dto/UserResponseDto.java @@ -0,0 +1,23 @@ +package org.example.commerce_site.application.user.dto; + +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; +import org.example.commerce_site.domain.User; + +public class UserResponseDto { + @Builder + @Getter + @ToString + public static class Create { + private String name; + private String email; + + public static UserResponseDto.Create of(User user) { + return Create.builder() + .name(user.getName()) + .email(user.getEmail()) + .build(); + } + } +} diff --git a/src/main/java/org/example/commerce_site/attribute/PartnerStatus.java b/src/main/java/org/example/commerce_site/attribute/PartnerStatus.java new file mode 100644 index 0000000..bd7e45b --- /dev/null +++ b/src/main/java/org/example/commerce_site/attribute/PartnerStatus.java @@ -0,0 +1,7 @@ +package org.example.commerce_site.attribute; + +public enum PartnerStatus { + ACTIVE, + INACTIVE, + DORMANT, +} diff --git a/src/main/java/org/example/commerce_site/attribute/UserStatus.java b/src/main/java/org/example/commerce_site/attribute/UserStatus.java new file mode 100644 index 0000000..cb5e7d1 --- /dev/null +++ b/src/main/java/org/example/commerce_site/attribute/UserStatus.java @@ -0,0 +1,7 @@ +package org.example.commerce_site.attribute; + +public enum UserStatus { + ACTIVE, + INACTIVE, + DORMANT, +} diff --git a/src/main/java/org/example/commerce_site/common/domain/BaseTimeEntity.java b/src/main/java/org/example/commerce_site/common/domain/BaseTimeEntity.java new file mode 100644 index 0000000..f3f7a13 --- /dev/null +++ b/src/main/java/org/example/commerce_site/common/domain/BaseTimeEntity.java @@ -0,0 +1,29 @@ +package org.example.commerce_site.common.domain; + +import jakarta.persistence.Column; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.MappedSuperclass; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; + +@Getter +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public abstract class BaseTimeEntity extends IdKeyEntity { + @CreatedDate + @Column(name = "created_at") + protected LocalDateTime createdAt; + + @LastModifiedDate + @Column(name = "updated_at") + protected LocalDateTime updatedAt; +} diff --git a/src/main/java/org/example/commerce_site/common/domain/IdKeyEntity.java b/src/main/java/org/example/commerce_site/common/domain/IdKeyEntity.java new file mode 100644 index 0000000..a87dc31 --- /dev/null +++ b/src/main/java/org/example/commerce_site/common/domain/IdKeyEntity.java @@ -0,0 +1,20 @@ +package org.example.commerce_site.common.domain; + +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.MappedSuperclass; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@MappedSuperclass +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public abstract class IdKeyEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; +} diff --git a/src/main/java/org/example/commerce_site/common/util/PasswordUtil.java b/src/main/java/org/example/commerce_site/common/util/PasswordUtil.java new file mode 100644 index 0000000..ef7d0f4 --- /dev/null +++ b/src/main/java/org/example/commerce_site/common/util/PasswordUtil.java @@ -0,0 +1,4 @@ +package org.example.commerce_site.common.util; + +public class PasswordUtil { +} diff --git a/src/main/java/org/example/commerce_site/domain/Partner.java b/src/main/java/org/example/commerce_site/domain/Partner.java new file mode 100644 index 0000000..7e50b75 --- /dev/null +++ b/src/main/java/org/example/commerce_site/domain/Partner.java @@ -0,0 +1,27 @@ +package org.example.commerce_site.domain; + +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.example.commerce_site.attribute.PartnerStatus; +import org.example.commerce_site.common.domain.BaseTimeEntity; + +@Entity +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "partners") +public class Partner extends BaseTimeEntity { + private String name; + private String businessNumber; + private String password; + private String email; + @Enumerated(EnumType.STRING) + private PartnerStatus status; +} diff --git a/src/main/java/org/example/commerce_site/domain/User.java b/src/main/java/org/example/commerce_site/domain/User.java new file mode 100644 index 0000000..a46519e --- /dev/null +++ b/src/main/java/org/example/commerce_site/domain/User.java @@ -0,0 +1,26 @@ +package org.example.commerce_site.domain; + +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.example.commerce_site.attribute.UserStatus; +import org.example.commerce_site.common.domain.BaseTimeEntity; + +@Entity +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "users") +public class User extends BaseTimeEntity { + private String name; + private String email; + private String password; + @Enumerated(EnumType.STRING) + private UserStatus status; +} diff --git a/src/main/java/org/example/commerce_site/infrastructure/PartnerRepository.java b/src/main/java/org/example/commerce_site/infrastructure/PartnerRepository.java new file mode 100644 index 0000000..4d7b0e7 --- /dev/null +++ b/src/main/java/org/example/commerce_site/infrastructure/PartnerRepository.java @@ -0,0 +1,7 @@ +package org.example.commerce_site.infrastructure; + +import org.example.commerce_site.domain.Partner; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface PartnerRepository extends JpaRepository { +} diff --git a/src/main/java/org/example/commerce_site/infrastructure/UserRepository.java b/src/main/java/org/example/commerce_site/infrastructure/UserRepository.java new file mode 100644 index 0000000..05a27ed --- /dev/null +++ b/src/main/java/org/example/commerce_site/infrastructure/UserRepository.java @@ -0,0 +1,9 @@ +package org.example.commerce_site.infrastructure; + +import org.example.commerce_site.domain.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserRepository extends JpaRepository { +} diff --git a/src/main/java/org/example/commerce_site/representation/partner/PartnerController.java b/src/main/java/org/example/commerce_site/representation/partner/PartnerController.java new file mode 100644 index 0000000..459339f --- /dev/null +++ b/src/main/java/org/example/commerce_site/representation/partner/PartnerController.java @@ -0,0 +1,25 @@ +package org.example.commerce_site.representation.partner; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.example.commerce_site.application.partner.PartnerService; +import org.example.commerce_site.representation.partner.request.PartnerRequest; +import org.example.commerce_site.representation.partner.response.PartnerResponse; +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; + +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/partner") +public class PartnerController { + private final PartnerService partnerService; + + @PostMapping() + public PartnerResponse.Create createPartner(@Valid @RequestBody PartnerRequest.Create request) { + return PartnerResponse.Create.of(partnerService.create(PartnerRequest.Create.toDTO(request))); + } +} diff --git a/src/main/java/org/example/commerce_site/representation/partner/request/PartnerRequest.java b/src/main/java/org/example/commerce_site/representation/partner/request/PartnerRequest.java new file mode 100644 index 0000000..18bc29b --- /dev/null +++ b/src/main/java/org/example/commerce_site/representation/partner/request/PartnerRequest.java @@ -0,0 +1,36 @@ +package org.example.commerce_site.representation.partner.request; + +import jakarta.validation.constraints.NotBlank; +import lombok.Getter; +import lombok.ToString; +import org.example.commerce_site.application.partner.dto.PartnerRequestDto; + +public class PartnerRequest { + @Getter + @ToString + public static class Create { + @NotBlank + private String name; + + @NotBlank + //TODO email 형식 체크 + private String email; + + @NotBlank + //TODO 패스워드 형식 체크 (8자리 이상 20자리 이하 영문 + 숫자) + private String password; + + @NotBlank + private String businessNumber; + + public static PartnerRequestDto.Create toDTO(PartnerRequest.Create request) { + return PartnerRequestDto.Create.builder() + .name(request.getName()) + .email(request.getEmail()) + //TODO PWD 암호화 + .password(request.getPassword()) + .businessNumber(request.getBusinessNumber()) + .build(); + } + } +} diff --git a/src/main/java/org/example/commerce_site/representation/partner/response/PartnerResponse.java b/src/main/java/org/example/commerce_site/representation/partner/response/PartnerResponse.java new file mode 100644 index 0000000..145cbc5 --- /dev/null +++ b/src/main/java/org/example/commerce_site/representation/partner/response/PartnerResponse.java @@ -0,0 +1,26 @@ +package org.example.commerce_site.representation.partner.response; + +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; +import org.example.commerce_site.application.partner.dto.PartnerResponseDto; + +public class PartnerResponse { + + @Getter + @Builder + @ToString + public static class Create { + private String name; + private String email; + private String businessNumber; + + public static PartnerResponse.Create of(PartnerResponseDto.Create dto) { + return PartnerResponse.Create.builder() + .name(dto.getName()) + .email(dto.getEmail()) + .businessNumber(dto.getBusinessNumber()) + .build(); + } + } +} diff --git a/src/main/java/org/example/commerce_site/representation/user/UserController.java b/src/main/java/org/example/commerce_site/representation/user/UserController.java new file mode 100644 index 0000000..14f2b13 --- /dev/null +++ b/src/main/java/org/example/commerce_site/representation/user/UserController.java @@ -0,0 +1,25 @@ +package org.example.commerce_site.representation.user; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.example.commerce_site.application.user.UserService; +import org.example.commerce_site.representation.user.request.UserRequest; +import org.example.commerce_site.representation.user.response.UserResponse; +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; + +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/user") +public class UserController { + private final UserService userService; + + @PostMapping() + public UserResponse.Create createUser(@Valid @RequestBody UserRequest.Create request) { + return UserResponse.Create.of(userService.create(UserRequest.Create.toDTO(request))); + } +} diff --git a/src/main/java/org/example/commerce_site/representation/user/request/UserRequest.java b/src/main/java/org/example/commerce_site/representation/user/request/UserRequest.java new file mode 100644 index 0000000..b19ce7d --- /dev/null +++ b/src/main/java/org/example/commerce_site/representation/user/request/UserRequest.java @@ -0,0 +1,32 @@ +package org.example.commerce_site.representation.user.request; + +import jakarta.validation.constraints.NotBlank; +import lombok.Getter; +import lombok.ToString; +import org.example.commerce_site.application.user.dto.UserRequestDto; + +public class UserRequest { + @Getter + @ToString + public static class Create { + @NotBlank + private String name; + + @NotBlank + //TODO email 형식 체크 + private String email; + + @NotBlank + //TODO 패스워드 형식 체크 (8자리 이상 20자리 이하 영문 + 숫자) + private String password; + + public static UserRequestDto.Create toDTO(UserRequest.Create request) { + return UserRequestDto.Create.builder() + .name(request.getName()) + .email(request.getEmail()) + //TODO PWD 암호화 + .password(request.getPassword()) + .build(); + } + } +} diff --git a/src/main/java/org/example/commerce_site/representation/user/response/UserResponse.java b/src/main/java/org/example/commerce_site/representation/user/response/UserResponse.java new file mode 100644 index 0000000..a5821ff --- /dev/null +++ b/src/main/java/org/example/commerce_site/representation/user/response/UserResponse.java @@ -0,0 +1,24 @@ +package org.example.commerce_site.representation.user.response; + +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; +import org.example.commerce_site.application.user.dto.UserResponseDto; + +public class UserResponse { + + @Getter + @Builder + @ToString + public static class Create { + private String name; + private String email; + + public static UserResponse.Create of(UserResponseDto.Create dto) { + return UserResponse.Create.builder() + .name(dto.getName()) + .email(dto.getEmail()) + .build(); + } + } +} diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 00260fd..5f5093a 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -2,7 +2,7 @@ spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/ecommerce_site - username: ecommerce + username: root password: 8cfv67b67af12zxc jpa: show-sql: true diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 2d16582..5aa302e 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -4,8 +4,13 @@ spring: instance-id: 0 jpa: hibernate: + naming: + physical-strategy: org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy + implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy ddl-auto: none open-in-view: false + jackson: + property-naming-strategy: SNAKE_CASE server: port: 8080 forward-headers-strategy: framework