본문 바로가기
BackEnd/Project

[SNS] Ch02. 회원가입과 로그인 기능 개발(1)

by 개발 Blog 2024. 9. 7.

공부 내용을 정리하고 앞으로의 학습에 이해를 돕기 위해 작성합니다.

 

이번 포스팅에서는 지난 시간에 작성한 테스트 코드를 바탕으로 회원가입과 로그인 기능을 구현한 내용을 설명한다. TDD(Test Driven Development)를 기반으로 테스트를 먼저 작성한 후, 해당 테스트를 통과하도록 실제 기능을 구현하는 방식으로 진행한다.

 

컨트롤러 관련 클래스

UserController

UserController 클래스는 사용자의 회원가입 및 로그인 요청을 처리하는 역할을 한다.

package com.example.sns.controller;

import com.example.sns.controller.request.UserJoinRequest;
import com.example.sns.controller.response.Response;
import com.example.sns.controller.response.UserJoinResponse;
import com.example.sns.model.User;
import com.example.sns.service.UserService;
import lombok.RequiredArgsConstructor;
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;

@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;

    // TODO : implement
    @PostMapping("/join")
    public Response<UserJoinResponse> join(@RequestBody UserJoinRequest request) {
       User user = userService.join(request.getUserName(), request.getPassword());
        return Response.success(UserJoinResponse.fromUser(user));
    }
}

수정 전

원래 UserController는 단순히 userService.join("", "") 메서드를 호출하는 형태로, 요청 데이터 처리나 응답 반환을 고려하지 않은 단순한 구조였다. 클라이언트가 보내는 데이터를 제대로 처리하지 못하고 있었으며, 클라이언트에게 적절한 응답을 제공하지 못했다.

 

수정 후

UserController는 더 이상 단순히 빈 문자열을 전달하지 않고, 클라이언트로부터 UserJoinRequest 객체를 받아 해당 객체 안에 담긴 userName과 password 정보를 활용해 회원가입 처리를 진행한다.

  1. 요청 데이터 처리: 클라이언트로부터 JSON 형태로 회원가입 정보를 받기 위해 @RequestBody 어노테이션을 사용해 UserJoinRequest 객체를 매핑한다. 이 객체는 userName과 password 필드를 포함하여 회원가입 시 필요한 사용자 정보를 담고 있다.
  2. 서비스 호출: 컨트롤러는 받은 userName과 password 정보를 userService.join() 메서드에 전달해 회원가입 로직을 처리한다. userService는 해당 정보를 바탕으로 데이터베이스에 새로운 사용자를 저장하는 역할을 한다.
  3. 응답 처리: Response와 UserJoinResponse 클래스를 사용하여 클라이언트에게 적절한 응답을 반환하도록 변경되었다. UserJoinResponse는 회원가입 후 생성된 사용자 정보를 포함하고, Response는 성공적인 처리 결과를 나타내는 상태 코드와 함께 이를 클라이언트에게 전달한다.

이러한 구조 변경으로 인해, 컨트롤러가 클라이언트의 요청을 보다 명확하게 처리하고, 적절한 응답을 제공하는 역할을 수행하게 되었다.

 

UserControllerTest

이 클래스는 UserController에 대한 테스트를 담당한다. MockMvc를 사용해 API 호출을 모방하며, MockBean으로 UserService를 모킹(mocking)한다.

//수정 전
when(userService.login(userName, password)).thenThrow(new SnsApplicationException());

//수정 후
when(userService.login(userName, password)).thenThrow(new SnsApplicationException(ErrorCode.DUPLICATED_USER_NAME,""));
수정 전
  • 이전 코드에서는 userService.login(userName, password) 메서드가 호출될 때 예외를 발생시키도록 설정되어 있지만, 예외가 발생할 때 구체적인 에러 코드나 메시지가 포함되어 있지 않다. 이는 어떤 예외 상황인지 명확하게 드러나지 않게 하며, 처리된 에러 상황에 대해 구체적인 정보를 제공하지 못하는 문제점이 있다.

수정 후

 
  • 수정된 코드에서는 SnsApplicationException 예외를 발생시킬 때, ErrorCode와 함께 구체적인 에러 정보를 전달하도록 변경되었다. 이 경우 ErrorCode.DUPLICATED_USER_NAME이라는 구체적인 에러 코드를 전달함으로써, 예외가 발생한 상황이 사용자 이름 중복에 의한 것임을 명확하게 알 수 있다.

이러한 방식으로 예외를 처리함으로써, 테스트 코드가 보다 명확하게 어떤 상황에서 에러가 발생했는지, 그리고 그 에러가 어떤 이유 때문인지를 드러내어, 테스트의 가독성과 유지보수성을 높이는 역할을 하게 된다.

서비스 관련 클래스(UserService)

서비스 클래스는 회원가입과 로그인 기능을 처리하는 핵심 로직을 담고 있다. 이 클래스는 UserEntityRepository를 사용하여 데이터베이스에 접근하고, 사용자의 정보가 유효한지 확인하고 처리하는 역할을 한다. 수정 전과 수정 후의 로직 차이를 설명하겠다.

 

join 메서드 

수정 전

public User join(String userName, String password) {
    // 회원가입하려는 userName으로 회원가입된 user가 있는지
    Optional<UserEntity> userEntity = userEntityRepository.findByUserName(userName);

    // 회원가입 진행 = user를 등록
    userEntityRepository.save(new UserEntity());

    return new User();
}
  • 기존의 join 메서드는 단순히 userName을 조회한 후, 바로 새로운 UserEntity 객체를 생성하고 저장하는 방식이다.
  • 저장되는 정보는 비어있기 때문에 로직이 제대로 구현되지 않았다.
  • 중복된 userName에 대한 처리가 없다.

수정 후

public User join(String userName, String password) {
    // 회원가입하려는 userName으로 회원가입된 user가 있는지 체크
    userEntityRepository.findByUserName(userName).ifPresent(it -> {
        throw new SnsApplicationException(ErrorCode.DUPLICATED_USER_NAME, String.format("%s is duplicated", userName));
    });

    // 회원가입 진행 = user를 등록
    UserEntity userEntity = userEntityRepository.save(UserEntity.of(userName, password));

    return User.fromEntity(userEntity);
}
  • 수정된 join 메서드는 회원가입 시 userName의 중복 여부를 먼저 확인한다. findByUserName(userName)를 통해 이미 등록된 사용자 이름이 존재하면, SnsApplicationException이 발생하고 중복 메시지를 클라이언트에 반환한다.
  • 중복된 사용자가 없을 경우에만 UserEntity.of(userName, password)를 통해 새로운 사용자 정보를 저장하고, User.fromEntity(userEntity)로 변환하여 클라이언트에 반환한다.
  • 이렇게 함으로써 중복된 사용자 이름을 방지하고, 사용자 등록을 안전하게 처리할 수 있다.

login 메서드 

수정 전

public String login(String username, String password) {
    // 회원가입 여부 체크
    UserEntity userEntity = userEntityRepository.findByUserName(username).orElseThrow(() -> new SnsApplicationException());

    // 비밀번호 체크
    if(!userEntity.getPassword().equals(password)){
        throw new SnsApplicationException();
    }

    // 토큰 생성
    return "";
}
  • login 메서드의 기존 로직은 userName으로 사용자가 있는지 확인한 후, 비밀번호가 일치하는지 비교만 하고 있다.
  • 비밀번호가 일치하지 않을 경우나 사용자가 없을 경우, 예외 처리가 명확하지 않고 구체적인 에러 메시지가 없다.

수정 후

public String login(String username, String password) {
    // 회원가입 여부 체크
    UserEntity userEntity = userEntityRepository.findByUserName(username).orElseThrow(() -> new SnsApplicationException(ErrorCode.DUPLICATED_USER_NAME, ""));

    // 비밀번호 체크
    if(!userEntity.getPassword().equals(password)){
        throw new SnsApplicationException(ErrorCode.DUPLICATED_USER_NAME, "");
    }

    // 토큰 생성
    return "";
}
  • 수정된 login 메서드는 먼저 userName으로 사용자를 찾고, 찾을 수 없을 경우 SnsApplicationException을 발생시킨다.
  • 비밀번호가 일치하지 않으면, 역시 SnsApplicationException을 발생시킨다. 이때 구체적인 ErrorCode를 사용하여 클라이언트가 어떤 이유로 로그인이 실패했는지 명확히 알 수 있도록 처리한다.
  • 토큰 생성은 여전히 구현되지 않았지만, 로그인 과정에서의 예외 처리가 명확해졌고, 클라이언트에 더 나은 에러 정보를 제공할 수 있게 되었다.

전체 흐름

  • join 메서드는 사용자 이름 중복 여부를 확인한 후, 새로운 사용자 정보를 데이터베이스에 저장하고 User 객체를 반환한다.
  • login 메서드는 사용자가 입력한 userName과 password를 확인하고, 일치하지 않으면 적절한 예외를 던진다.

3. 예외 처리 및 응답 처리 관련 클래스

예외 처리 및 응답 처리는 클라이언트에게 발생한 오류에 대한 명확한 메시지를 전달하고, 성공적인 요청에 대해서는 일관된 응답을 반환하는 중요한 역할을 한다. GlobalControllerAdvice, SnsApplicationException, ErrorCode, Response, UserJoinResponse와 같은 클래스가 어떻게 예외와 응답을 처리하는지 설명한다.

 

GlobalControllerAdvice(추가)

이 클래스는 글로벌 예외 처리를 담당한다. @RestControllerAdvice 어노테이션을 사용해 컨트롤러에서 발생하는 예외를 한 곳에서 처리할 수 있도록 설정했다.

package com.example.sns.exception;

import com.example.sns.controller.response.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@Slf4j
@RestControllerAdvice
public class GlobalControllerAdvice {

    @ExceptionHandler(SnsApplicationException.class)
    public ResponseEntity<?> applicationHandler(SnsApplicationException e) {
        log.error("Error occurs {}", e.toString());
        return ResponseEntity.status(e.getErrorCode().getStatus())
                .body(Response.error(e.getErrorCode().name()));
    }
}
  • @ExceptionHandler(SnsApplicationException.class)는 SnsApplicationException이 발생했을 때 처리한다.
  • 로그로 발생한 예외를 기록한 후, ResponseEntity를 통해 클라이언트에 상태 코드와 에러 메시지를 반환한다.
  • 반환되는 메시지는 Response.error()를 통해 전달되며, 클라이언트는 명확한 에러 상태와 메시지를 받을 수 있다.

SnsApplicationException

SnsApplicationException은 애플리케이션에서 발생하는 예외를 처리하는 커스텀 예외 클래스이다.

package com.example.sns.exception;

import lombok.AllArgsConstructor;
import lombok.Getter;

//TODO : implement
@Getter
@AllArgsConstructor
public class SnsApplicationException extends RuntimeException{
    private ErrorCode errorCode;
    private String message;

    @Override
    public String getMessage() {
        if (message == null) {
            return errorCode.getMessage();
        }
        return String.format("%s. %s", errorCode.getMessage(), message);
    }
}
  • 예외가 발생할 때 ErrorCode를 통해 구체적인 에러 상태와 메시지를 설정할 수 있다.
  • getMessage() 메서드는 메시지가 없을 때 ErrorCode의 기본 메시지를 반환하고, 메시지가 있는 경우 이를 형식화해 반환한다. 이 방식으로 더 구체적이고 유용한 예외 메시지를 제공한다.

ErrorCode(추가)

ErrorCode는 에러 메시지와 상태 코드를 관리하는 Enum 클래스이다.

package com.example.sns.exception;

import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
public enum ErrorCode {
    DUPLICATED_USER_NAME(HttpStatus.CONFLICT, "user name is duplicated");

    private HttpStatus status;
    private String message;
}
  • DUPLICATED_USER_NAME은 사용자 이름이 중복될 때 발생하는 에러로, HTTP 상태 코드 409 CONFLICT와 함께 "user name is duplicated" 메시지를 반환한다.
  • 이 클래스를 통해 애플리케이션에서 발생하는 다양한 예외를 명확하고 일관되게 처리할 수 있다.

Response(추가)

Response 클래스는 API 응답을 표준화하는 클래스이다.

package com.example.sns.controller.response;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class Response<T> {
    private String resultCode;
    private T result;

    public static Response<Void> error(String errorCode) {
        return new Response<>(errorCode, null);
    }

    public static <T> Response<T> success(T result) {
        return new Response<>("SUCCESS", result);
    }
}
  • 성공적인 응답은 Response.success() 메서드를 통해, 에러 응답은 Response.error() 메서드를 통해 클라이언트에 전달된다.
  • 이 클래스는 모든 API 응답이 일관된 구조로 반환될 수 있도록 해준다.

UserJoinResponse(추가)

UserJoinResponse는 회원가입 후 클라이언트에게 반환될 사용자 정보를 정의한 클래스이다.

package com.example.sns.controller.response;

import com.example.sns.model.User;
import com.example.sns.model.UserRole;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class UserJoinResponse {
    private Integer id;
    private String userName;
    private UserRole role;

    public static UserJoinResponse fromUser(User user) {
        return new UserJoinResponse(
                user.getId(),
                user.getUserName(),
                user.getUserRole()
        );
    }
}
  • fromUser(User user) 메서드를 통해 User 객체를 받아, 필요한 사용자 정보를 UserJoinResponse로 변환하여 클라이언트에 반환한다.
  • 이 클래스는 API 응답으로 사용자 정보를 클라이언트에게 제공하는 역할을 한다.

4. 모델 관련 클래스

모델 관련 클래스는 데이터베이스와 직접적으로 매핑되는 UserEntity 클래스와, 비즈니스 로직에서 사용되는 User 클래스, 그리고 사용자 권한을 관리하는 UserRole로 구성된다. 이 클래스들은 사용자 정보를 처리하는 데 중요한 역할을 한다.

 

UserEntity

수정 전

@Entity
@Table
@Setter
@Getter
public class UserEntity {
    @Id
    private Integer id;

    @Column(name = "user_name")
    private String userName;

    private String password;
}
  • UserEntity는 데이터베이스에 사용자 정보를 저장하는 역할을 한다.
  • @Entity와 @Table 어노테이션을 사용하여 JPA와 매핑된다.
  • 사용자의 id, userName, password 필드를 가지고 있으며, 기본적인 정보만 저장한다.
  • 수정 전에는 사용자 역할, 등록 시간, 수정 시간 등의 추가 정보가 포함되지 않았다.

수정 후 

수정된 UserEntity 클래스는 더 많은 기능을 포함하고 있다.

@Entity
@Table(name = "\"user\"")
@Getter
@Setter
@SQLDelete(sql = "UPDATE \"user\" SET deleted_at = NOW() where id=?")
@Where(clause = "deleted_at is NULL")
@NoArgsConstructor
public class UserEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "user_name")
    private String userName;

    @Column(name = "password")
    private String password;

    @Column(name = "role")
    @Enumerated(EnumType.STRING)
    private UserRole role = UserRole.USER;

    @Column(name = "registered_at")
    private Timestamp registeredAt;

    @Column(name = "updated_at")
    private Timestamp updatedAt;

    @Column(name = "deleted_at")
    private Timestamp deletedAt;

    @PrePersist
    void registeredAt() {
        this.registeredAt = Timestamp.from(Instant.now());
    }

    @PreUpdate
    void updatedAt() {
        this.updatedAt = Timestamp.from(Instant.now());
    }

    public static UserEntity of(String userName, String password) {
        UserEntity userEntity = new UserEntity();
        userEntity.userName = userName;
        userEntity.password = password;
        return userEntity;
    }
}

역할 관리

  • role 필드는 사용자의 권한을 관리하는데 사용된다. UserRole 열거형(Enum)을 사용하여 사용자 권한을 USER 또는 ADMIN으로 설정할 수 있다. 기본값으로는 USER 역할이 부여되며, 필요에 따라 ADMIN 권한을 설정할 수 있다. 이를 통해 애플리케이션에서 사용자의 접근 권한을 제어할 수 있다.

등록 및 수정 시간 기록

  • @PrePersist: 사용자가 처음 등록될 때 registeredAt 필드에 현재 시간이 자동으로 기록된다. 이를 통해 사용자가 언제 처음 등록되었는지를 추적할 수 있다.
  • @PreUpdate: 사용자가 정보를 수정할 때마다 updatedAt 필드에 수정 시간이 기록된다. 이를 통해 데이터가 언제 업데이트되었는지를 쉽게 파악할 수 있다.

소프트 삭제

  • 소프트 삭제는 데이터베이스에서 데이터를 실제로 삭제하지 않고, 삭제된 상태로 표시하는 기법이다. @SQLDelete 어노테이션은 delete 요청이 발생했을 때 deleted_at 필드에 삭제 시간을 기록하고, 물리적인 삭제 대신 논리적인 삭제를 구현한다.
  • @Where 어노테이션은 deleted_at 값이 NULL인 데이터만 조회되도록 설정한다. 즉, 삭제된 데이터를 포함하지 않고 조회할 수 있게 하여, 삭제된 데이터는 기록되지만 사용자에게 보이지 않도록 처리한다.

객체 생성 (of 메서드)

  • UserEntity.of(String userName, String password)는 정적 팩토리 메서드로, 새로운 UserEntity 객체를 생성하고 사용자 이름과 비밀번호를 초기화한다. 이렇게 함으로써 객체 생성 방식을 명확히 하고, 코드의 가독성을 높인다.

User

기존에는 userName과 password만을 가지고 있었으며, 데이터가 비어있는 상태로 구성되어 있었다.

package com.example.sns.model;

import com.example.sns.model.entity.UserEntity;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.sql.Timestamp;

@Getter
@AllArgsConstructor
public class User {

    private Integer id;
    private String userName;
    private String password;
    private UserRole userRole;
    private Timestamp registeredAt;
    private Timestamp updatedAt;
    private Timestamp deletedAt;

    public static User fromEntity(UserEntity entity) {
        return new User(
                entity.getId(),
                entity.getUserName(),
                entity.getPassword(),
                entity.getRole(),
                entity.getRegisteredAt(),
                entity.getUpdatedAt(),
                entity.getDeletedAt()
        );
    }
}
  • 수정된 User 클래스는 엔티티와 비즈니스 로직에서 사용되는 도메인 모델 간의 변환을 위한 fromEntity 메서드를 포함하고 있다. 이를 통해 UserEntity 객체를 User 객체로 변환한다.
  • User는 비즈니스 로직에서 사용되는 정보들을 포함하고 있으며, 사용자의 id, userName, password, userRole, 등록 시간, 수정 시간, 삭제 시간 등의 정보를 포함한다.
  • UserRole 필드를 추가하여, 사용자의 역할을 비즈니스 로직에서 쉽게 처리할 수 있다.

UserRole(추가)

package com.example.sns.model;

public enum UserRole {
    ADMIN,
    USER
}
  • UserRole은 사용자의 역할을 관리하는 enum 클래스이다.
  • 기본적으로 USER와 ADMIN 두 가지 역할을 정의하고 있으며, 이를 통해 사용자 권한에 따라 서비스에서 차별화된 기능을 제공할 수 있다.

5. Heroku 설정 및 PostgreSQL 연결

Heroku는 클라우드 환경에서 애플리케이션을 쉽게 배포하고 운영할 수 있는 플랫폼이다. 이번 프로젝트에서는 Heroku의 PostgreSQL 서비스를 이용해 데이터베이스를 설정하고 연결했다.

 

1) Heroku PostgreSQL 추가

  • Heroku 대시보드에서 PostgreSQL 데이터베이스를 추가한 후, 해당 데이터베이스를 SNS 서비스 애플리케이션에 연결했다. 이때 사용된 플랜은 Essential 0 플랜으로, 기본적인 데이터베이스 사용량에 맞춰 설정되었다.

2) Heroku에서 제공하는 환경 변수

  • Heroku는 자동으로 데이터베이스 연결에 필요한 자격 증명을 제공하며, 애플리케이션이 실행될 때 이 자격 증명은 Heroku의 환경 변수로부터 동적으로 로드된다.
  • Host, Database, User, Port, Password 정보는 Heroku가 자동으로 제공하며, application.yaml에 해당 변수를 지정해 데이터베이스와 연결을 설정한다.

application.yaml (추가)

application.yaml 파일은 스프링 부트 애플리케이션에서 설정 정보를 관리하는 중요한 역할을 한다. 이 파일에서 데이터베이스 설정, JPA 설정, 및 기타 애플리케이션의 전반적인 설정을 관리할 수 있다. 

spring:
  jpa:
    database: postgresql
    hibernate:
      dialect: org.hibernate.dialect.PostgreSQLDialect
      ddl-auto: update
    properties:
      hibernate:
        format_sql: true
    show-sql: true
  datasource:
    hikari:
      maximum-pool-size: 4
    url: ${DB_URL}
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}
    platform: postgres
    driver-class-name: org.postgresql.Driver
  • JPA 설정
    • spring.jpa.database: PostgreSQL을 사용하기 위한 설정이다. JPA는 데이터베이스와 상호작용할 때 사용하는 ORM이기 때문에, 이를 통해 애플리케이션이 어떤 데이터베이스와 연결될지를 지정할 수 있다.
    • spring.jpa.hibernate.dialect: 스프링 부트에서 JPA와 함께 사용할 데이터베이스의 방언(dialect)을 지정한다. 여기서는 PostgreSQL 방언을 지정했으며, 이를 통해 Hibernate가 PostgreSQL에 맞게 SQL을 생성할 수 있다.
    • spring.jpa.hibernate.ddl-auto: 데이터베이스 테이블의 생성을 관리한다. update로 설정하여, 애플리케이션이 실행될 때마다 엔티티 클래스가 데이터베이스의 테이블과 동기화되도록 한다.
    • spring.jpa.properties.hibernate.format_sql: SQL을 보기 쉽게 포맷팅해서 출력한다.
    • spring.jpa.show-sql: Hibernate가 실행하는 SQL을 콘솔에 출력하는 설정이다. true로 설정하면 실행되는 SQL 쿼리를 확인할 수 있다.
  • 데이터소스 설정
    • spring.datasource.hikari.maximum-pool-size: HikariCP라는 커넥션 풀을 사용하여 동시에 몇 개의 데이터베이스 커넥션을 유지할지 설정한다. 이 설정에서는 최대 4개의 커넥션을 유지하도록 설정되어 있다.
    • spring.datasource.url: 애플리케이션이 연결할 데이터베이스의 URL을 설정한다. DB_URL이라는 환경 변수를 통해 설정된 값을 가져온다. 이 값을 설정함으로써 데이터베이스 URL을 외부에서 관리할 수 있다.
    • spring.datasource.username 및 spring.datasource.password: 데이터베이스에 접근하기 위한 사용자 이름과 비밀번호를 지정한다. 이 역시 환경 변수를 통해 설정되며, 외부에서 값이 제공된다.
    • spring.datasource.platform: postgres로 설정하여, PostgreSQL 데이터베이스를 사용한다는 것을 명시한다.
    • spring.datasource.driver-class-name: PostgreSQL 데이터베이스를 사용하기 위한 드라이버 클래스명을 지정한다.

6. 메인 애플리케이션 클래스

이전에는 @SpringBootApplication 어노테이션에 exclude = DataSourceAutoConfiguration.class 설정이 추가되어 있었다. 이 설정은 데이터소스 자동 설정을 비활성화하기 위한 것이다. 개발 초기 단계에서는 데이터베이스 설정이 필요 없을 때 사용된다.

//수정 전
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

//수정 후 
@SpringBootApplication
  • 수정 후 exclude 부분이 제거되었다. 이제 애플리케이션이 정상적으로 데이터소스를 자동으로 설정하게 된다. @SpringBootApplication 어노테이션은 스프링 부트 애플리케이션을 설정하고 구동하는 데 중요한 어노테이션이다.

7. Postman을 통한 회원가입 테스트

Postman을 이용하여 회원가입 API를 테스트한 결과, 요청에 대한 성공적인 응답을 확인할 수 있다. 클라이언트는 아래와 같은 JSON 요청을 전송한다.

 

데이터베이스에 test03이라는 유저가 성공적으로 등록되었음을 알 수 있다. 아래는 PostgreSQL에서 조회한 결과이다.

  • PostgreSQL 쿼리 결과, 새롭게 등록된 유저 test03이 데이터베이스에 추가된 것을 확인할 수 있다. registered_at 컬럼을 통해 회원가입 시간을 기록하고 있으며, 기본 USER 역할을 부여받았다.

이번 포스팅에서는 회원가입 기능을 테스트하고, 실제로 데이터베이스에 유저가 정상적으로 저장되는 과정을 살펴보았다. 하지만 아직 비밀번호가 암호화되지 않고 그대로 저장되는 문제와 보안 강화를 위한 비밀번호 암호화 문제가 남아 있다. 이 문제는 다음 포스팅에서 해결한다.