Skip to content

Commit

Permalink
Merge pull request #9 from Fairy-Taless/feature/#8-user
Browse files Browse the repository at this point in the history
✨ FEAT. 회원가입 API 추가
  • Loading branch information
junhaa authored Apr 10, 2024
2 parents 0cb0c21 + e977d2e commit 71501ad
Show file tree
Hide file tree
Showing 17 changed files with 435 additions and 1 deletion.
11 changes: 11 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'

//logging
implementation 'org.springframework.boot:spring-boot-starter-log4j2'
modules {
module("org.springframework.boot:spring-boot-starter-logging") {
replacedBy("org.springframework.boot:spring-boot-starter-log4j2")
}
}

// ElevenLabs API
implementation ('net.andrewcpu:elevenlabs-api:2.7.8')

// AWS
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package fairytale.tbd.domain.user.converter;

import fairytale.tbd.domain.user.entity.User;
import fairytale.tbd.domain.user.web.dto.UserRequestDTO;
import fairytale.tbd.domain.user.web.dto.UserResponseDTO;

public class UserConverter {
public static User toUser(UserRequestDTO.AddUserDTO request){
return User.builder()
.loginId(request.getLoginId())
.password(request.getPassword())
.username(request.getUsername())
.gender(request.getGender())
.build();
}

public static UserResponseDTO.AddUserResultDTO toAddUserResultDTO(User user){
return UserResponseDTO.AddUserResultDTO.builder()
.userId(user.getId())
.createdAt(user.getCreatedAt())
.build();
}
}
44 changes: 44 additions & 0 deletions src/main/java/fairytale/tbd/domain/user/entity/User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package fairytale.tbd.domain.user.entity;


import fairytale.tbd.domain.user.enums.Gender;
import fairytale.tbd.global.entity.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Builder
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class User extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long id;

@Column(name = "login_id", nullable = false)
private String loginId;

@Column(name = "password", nullable = false)
private String password;

@Enumerated(EnumType.STRING)
@Column(name = "gender", nullable = false)
private Gender gender;

@Column(name = "username", nullable = false)
private String username;

}
5 changes: 5 additions & 0 deletions src/main/java/fairytale/tbd/domain/user/enums/Gender.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package fairytale.tbd.domain.user.enums;

public enum Gender {
MALE, FEMALE;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package fairytale.tbd.domain.user.exception;

import fairytale.tbd.global.enums.statuscode.BaseCode;
import fairytale.tbd.global.exception.GeneralException;

public class ExistUsernameException extends GeneralException {
public ExistUsernameException(BaseCode errorStatus) {
super(errorStatus);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package fairytale.tbd.domain.user.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import fairytale.tbd.domain.user.entity.User;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
boolean existsByUsername(String username);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package fairytale.tbd.domain.user.service;

import fairytale.tbd.domain.user.entity.User;
import fairytale.tbd.domain.user.web.dto.UserRequestDTO;

public interface UserCommandService {
public User addUser(UserRequestDTO.AddUserDTO request);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package fairytale.tbd.domain.user.service;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import fairytale.tbd.domain.user.converter.UserConverter;
import fairytale.tbd.domain.user.entity.User;
import fairytale.tbd.domain.user.repository.UserRepository;
import fairytale.tbd.domain.user.web.dto.UserRequestDTO;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class UserCommandServiceImpl implements UserCommandService{

private final UserRepository userRepository;

@Transactional
@Override
public User addUser(UserRequestDTO.AddUserDTO request) {
User user = UserConverter.toUser(request);
return userRepository.save(user);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package fairytale.tbd.domain.user.validation.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import fairytale.tbd.domain.user.validation.validator.ExistUsernameValidator;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;

@Documented
@Constraint(validatedBy = ExistUsernameValidator.class)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExistUsername {
String message() default("이미 존재하는 닉네임입니다.");

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package fairytale.tbd.domain.user.validation.validator;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import fairytale.tbd.domain.user.repository.UserRepository;
import fairytale.tbd.domain.user.validation.annotation.ExistUsername;
import fairytale.tbd.global.enums.statuscode.ErrorStatus;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class ExistUsernameValidator implements ConstraintValidator<ExistUsername, String> {

private static final Logger LOGGER = LogManager.getLogger(ExistUsernameValidator.class);
private final UserRepository userRepository;

@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
boolean isValid = !userRepository.existsByUsername(value);
if(!isValid){
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(ErrorStatus._EXIST_USERNAME.getMessage().toString()).addConstraintViolation();
}
return isValid;
}

@Override
public void initialize(ExistUsername constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package fairytale.tbd.domain.user.web.controller;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
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;

import fairytale.tbd.domain.user.converter.UserConverter;
import fairytale.tbd.domain.user.entity.User;
import fairytale.tbd.domain.user.service.UserCommandService;
import fairytale.tbd.domain.user.web.dto.UserRequestDTO;
import fairytale.tbd.domain.user.web.dto.UserResponseDTO;
import fairytale.tbd.global.response.ApiResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/user")
public class UserRestController {

private final UserCommandService userCommandService;
private static final Logger LOGGER = LogManager.getLogger(UserRestController.class);

@PostMapping("")
public ApiResponse<UserResponseDTO.AddUserResultDTO> join(@Valid @RequestBody UserRequestDTO.AddUserDTO request) {
LOGGER.info("request = {}", request);
User user = userCommandService.addUser(request);
return ApiResponse.onSuccess(UserConverter.toAddUserResultDTO(user));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package fairytale.tbd.domain.user.web.dto;

import fairytale.tbd.domain.user.enums.Gender;
import fairytale.tbd.domain.user.validation.annotation.ExistUsername;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;

public class UserRequestDTO {
@Getter
@Setter
public static class AddUserDTO{

@Size(min = 4, message = "아이디는 최소 4자 이상이어야 합니다.")
@NotBlank(message = "LoginId값은 필수입니다.")
private String loginId;

@NotBlank(message = "password값은 필수입니다.")
@Size(min = 8, message = "비밀번호는 최소 8자 이상이어야 합니다.")
@Pattern(regexp = "^(?=.*[0-9])(?=.*[a-z])(?=.*[!@#$%^&*()_+={};:,<.>]).{8,}$", message = "비밀번호는 영어, 숫자, 특수문자를 포함해야 합니다.")
private String password;

@NotNull(message = "gender값은 필수입니다.")
private Gender gender;

@ExistUsername
@NotBlank(message = "username값은 필수입니다.")
private String username;

@Override
public String toString() {
return "AddUserDTO{" +
"loginId='" + loginId + '\'' +
", password='" + password + '\'' +
", gender=" + gender +
", username='" + username + '\'' +
'}';
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package fairytale.tbd.domain.user.web.dto;

import java.time.LocalDateTime;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

public class UserResponseDTO {
@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class AddUserResultDTO{
private Long userId;
private LocalDateTime createdAt;
}
}
Loading

0 comments on commit 71501ad

Please sign in to comment.