MSA

[MSA] Part 9. UserService (Create User)

cwchoiit 2023. 10. 11. 16:29
728x90
반응형
SMALL
728x90
반응형
SMALL

UserService의 API 중 Create 부분을 만들어보자.

 

 

VO

우선, vo 패키지를 하나 추가하고 그 패키지 안에서 CreateUser.java 파일을 생성한다.

이 클래스는 User를 생성하고자 하는 사용자의 요청을 받을 때 Payload를 담는 클래스다. 

package com.example.tistoryuserservice.vo;

import lombok.Data;

@Data
public class CreateUser {
    private String email;
    private String name;
    private String password;
}

위처럼 작성하면 되는데 좀 더 완성도를 높여보자. 각 필드 별 Validation을 걸 수 있다. 예를 들면 최소한의 길이, 최대 길이, NotNull 조건 등 여러 유효성 검사를 필드에 걸어놓을 수 있는데 이를 위해 dependency 하나를 추가해야 한다.

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
    <version>3.1.3</version>
</dependency>

위 의존성을 내려받고 아래와 같이 코드를 수정해 보자.

 

package com.example.tistoryuserservice.vo;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;

@Data
public class CreateUser {
    @NotNull(message = "Email must be required")
    @Size(min = 2, message = "Email should be more than two characters")
    @Email
    private String email;
    
    @NotNull
    @Size(min = 2, message = "Name should be more than two characters")
    private String name;
    
    @NotNull
    @Size(min = 8, message = "Password should be more than 8 characters")
    private String password;
}

@NotNull, @Size, @Email과 같은 어노테이션은 방금 내려받은 dependency에 의해 사용할 수 있다. 이런 제약조건을 걸어놓으면 payload로 받은 데이터를 이 클래스에 담으려고 할 때 조건에 해당하지 않으면 담지 못한다. 이와 같이 유효성 검사를 간단하게 적용할 수 있다.

 

 

DTO

이제 DTO를 만들 차례다. 즉, 외부 요청에 의해 전달된 새로운 유저를 만들 데이터를 DB에 저장하기 전 DB에 들어갈 알맞은 형식의 데이터가 필요한데 그때 사용되는 클래스라고 보면 된다.

package com.example.tistoryuserservice.dto;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;

import java.util.Date;

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(value = JsonInclude.Include.NON_NULL)
public class CreateUserDto {
    private String email;
    private String name;
    private String password;
    private String userId;
    private Date createdAt;

    private String encryptedPassword;
}

 

dto 패키지를 추가한 후 CreateUserDto라는 클래스로 만들고 위와 같이 작성했다. CreateUser 클래스에는 없는 userId, createdAt, encryptedPassword 필드는 DB에 넣기 전 서비스 클래스에서 추가될 내용이고 나머지는 CreateUser 클래스에서 받아올 거다.

 

CrudRepository

이제 CrudRepository를 사용해서 기본적인 CRUD API를 제공하는 JPA의 도움을 받을 것이다.

repository라는 패키지를 하나 만들고 그 안에 UserRepository 인터페이스를 생성하자.

package com.example.tistoryuserservice.repository;

import com.example.tistoryuserservice.entity.User;
import org.springframework.data.repository.CrudRepository;

public interface UserRepository extends CrudRepository<User, Long> {}

이렇게 인터페이스를 만들면 User Entity에 대한 기본적인 CRUD 메서드를 가져다가 사용할 수 있다. 그 방법은 이후에 서비스 클래스를 구현하면서 볼 수 있다.

 

Service

UserService를 구현해 볼 차례다. 인터페이스를 만들고 필요한 메서드들을 정의한 뒤 그 인터페이스를 구현한 서비스 클래스를 만들어보자. 우선 service라는 패키지에 UserService 인터페이스를 만들자.

package com.example.tistoryuserservice.service;

import com.example.tistoryuserservice.dto.CreateUserDto;

public interface UserService {
    CreateUserDto createUser(CreateUserDto createUserDto);
}

 

 

그리고 이 인터페이스를 상속받는 서비스 클래스를 만든다. 우선은 메서드들을 정의한 인터페이스 먼저 만들자.

service라는 패키지안에 UserService 인터페이스를 만들어준다.

package com.example.tistoryuserservice.service;

import com.example.tistoryuserservice.dto.CreateUserDto;

public interface UserService {
    CreateUserDto createUser(CreateUserDto createUserDto);
}

이 인터페이스를 구현하는 UserServiceImpl 클래스를 만들어준다.

package com.example.tistoryuserservice.service;

import com.example.tistoryuserservice.dto.CreateUserDto;
import com.example.tistoryuserservice.entity.User;
import com.example.tistoryuserservice.repository.UserRepository;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.UUID;

@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {

    private final UserRepository userRepository;

    @Override
    public CreateUserDto createUser(CreateUserDto createUserDto) {
        createUserDto.setUserId(UUID.randomUUID().toString());

        ObjectMapper mapper = new ObjectMapper();
        User user = mapper.convertValue(createUserDto, User.class);
        user.setEncryptedPassword("encrypted_password");

        userRepository.save(user);
        return createUserDto;
    }
}

이 서비스 클래스에서 createUser()를 구현하고 있다. 여기서는 DTO에는 없는 userId와 encryptedPassword를 직접 추가해 준다. encryptedPassword를 만들어 내는 것을 구현하지 않았기 때문에 일단은 텍스트로 써넣는다. 이건 추후에 구현 예정이다.

 

DTO 데이터를 가지고 실제 데이터베이스에 들어갈 User라는 Entity로 타입 변환을 해준다. 그리고 그렇게 변환한 객체를 UserRepository를 주입받아서 save() 메서드를 호출한다. CrudRepository가 제공하는 save() 메서드에 어떠한 문제도 발생하지 않는다면 정상적으로 DTO 데이터를 다시 리턴한다.

 

이제 이 서비스 클래스를 호출할 Controller를 구현해야 한다. 실제로 유저가 사용할 API를 받아줄 수 있는.

 

Controller

controller 패키지 안에 UserController.java 파일을 만들자. 

package com.example.tistoryuserservice.controller;

import com.example.tistoryuserservice.dto.CreateUserDto;
import com.example.tistoryuserservice.service.UserService;
import com.example.tistoryuserservice.vo.CreateUser;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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-service")
public class UserController {

    private final UserService userService;

    @PostMapping("/users")
    public CreateUserDto createUser(@RequestBody CreateUser createUser) {
        ObjectMapper mapper = new ObjectMapper();
        CreateUserDto createUserDto = mapper.convertValue(createUser, CreateUserDto.class);

        return userService.createUser(createUserDto);
    }
}

별건 없다. PostMapping으로 유저를 생성하는 API를 선언하고, @RequestBody 어노테이션을 사용하여 Request의 Body에서 데이터를 받아 CreateUser 클래스로 변환시킨다. 이걸 스프링이 알아서 다 해주는 것이다. 매우 편하다.

 

받아온 데이터를 서비스가 받아줄 수 있는 DTO 타입의 데이터로 변환해 주기 위해 ObjectMapper를 이용한다.

그리고 서비스를 호출해 실제 유저를 생성하고 DB에 저장한 뒤 서비스가 돌려주는 데이터인 CreateUserDto 데이터를 컨트롤러도 리턴한다. 테스트해보자!

 

Create User

Gateway를 통해 UserService를 호출한다. Gateway로부터 요청을 UserService는 전달받을 거고 요청에 대한 처리를 해준 후 응답한 결과다.

728x90
반응형
LIST