회원 가입 API 개발

oh_eol·2024년 4월 17일
0

📍 개발 순서

  • 회원 도메인 및 dto 작성
  • 회원가입 repository 작성
  • 회원가입 비즈니스 로직 작성
  • 회원가입 컨트롤러 작성

📍 개발

회원 도메인 및 dto 작성

User

package com.example.realtimestreaming.Domain;

import com.example.realtimestreaming.Dto.Request.User.UserSignupReq;
import jakarta.persistence.*;
import lombok.*;

import java.util.ArrayList;
import java.util.List;

@Entity
@Getter @Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor // @Builder 와 @NoArgsConstructor 함께 사용하는 문제 해결
@Table(name = "user")
public class User {

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

    @Column(name = "email", nullable = false, unique = true, columnDefinition = "varchar(512)")
    private String email;

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

    @Column(name = "nickname", nullable = false, columnDefinition = "varchar(512)")
    private String nickname;

    @Column(name = "token", columnDefinition = "varchar(512)")
    private String token;

    @OneToMany(mappedBy = "owner", cascade = CascadeType.REMOVE)
    private List<Stream> streams = new ArrayList<>();

}

UserSignupReq

package com.example.realtimestreaming.Dto.Request.User;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserSignupReq {
    private String email;
    private String password;
    private String nickname;
}

UserSignRes

package com.example.realtimestreaming.Dto.Response;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class UserSignRes {
    private Long userId;
    private String nickname;
    private String token;
}

ResponseDto

package com.example.realtimestreaming.Common.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResponseDto<T> {
    private T data;

    public static <T> ResponseEntity<ResponseDto<T>> ok(T data) {
        return ResponseEntity.ok(new ResponseDto<T>(data));
    }
    public static <T> ResponseEntity<ResponseDto<T>> created(T data) {
        return ResponseEntity.status(HttpStatus.CREATED).body(new ResponseDto<T>(data));
    }
}

회원가입 repository 작성

UserRespsitory

package com.example.realtimestreaming.Repository;

import com.example.realtimestreaming.Domain.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

    Boolean existsByNickname(String nickname);
    Boolean existsByEmail(String email);

    User findUserByUserId(Long userId);
}

회원가입 비즈니스 로직 작성

UserService

package com.example.realtimestreaming.Service;

import com.amazonaws.services.kms.model.AlreadyExistsException;
import com.example.realtimestreaming.Common.ErrorCode;
import com.example.realtimestreaming.Domain.User;
import com.example.realtimestreaming.Dto.Request.User.UserSignupReq;
import com.example.realtimestreaming.Dto.Response.UserSignRes;
import com.example.realtimestreaming.Repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;

@Service
@RequiredArgsConstructor
public class UserService {

    private final UserRepository userRepository;

    // TODO 추후 보안 적용
    @Transactional
    public UserSignRes signup(UserSignupReq request) {
        if (userRepository.existsByNickname(request.getNickname())) {
            throw new AlreadyExistsException(ErrorCode.NICKNAME_IS_DUPLICATED.getMessage());
        } else if (userRepository.existsByEmail(request.getEmail())) {
            throw new AlreadyExistsException(ErrorCode.EMAIL_IS_DUPLICATED.getMessage());
        }

        var createdUser = userRepository.save(
                User.builder()
                        .nickname(request.getNickname())
                        .email(request.getEmail())
                        .password(request.getPassword())
                        .token(UUID.randomUUID().toString())
                        .build()
        );

        return new UserSignRes(
                createdUser.getUserId(),
                createdUser.getNickname(),
                createdUser.getToken()
        );
    }

}

회원가입 컨트롤러 작성

UserController

package com.example.realtimestreaming.Controller;

import com.example.realtimestreaming.Common.dto.ResponseDto;
import com.example.realtimestreaming.Domain.User;
import com.example.realtimestreaming.Dto.Request.User.UserSignupReq;
import com.example.realtimestreaming.Dto.Response.UserSignRes;
import com.example.realtimestreaming.Service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(path = "/user", produces = MediaType.APPLICATION_JSON_VALUE)
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;

    @PostMapping("/signup")
    public ResponseEntity<ResponseDto<UserSignRes>> signup(@RequestBody UserSignupReq request) {
        var user = userService.signup(request);
        return ResponseDto.created(user);
    }
}

📍 Error

1. Incorrect table definition

[Incorrect table definition; there can be only one auto column and it must be defined as a key]

  • 스프링 어플리케이션 실행 시 이러한 오류가 발생했다.

오류 내용 해석

  • 하나의 자동 컬럼만 존재해야 하고, 이는 반드시 키로 지정돼야 한다.

코드 분석

  • 코드 분석그런데 User 도메인을 보면, userId 에 @Id, @GeneratedValue 로써 PK로 지정되어 있다. 이는 실행 후 나오는 table에도 다음과 같이 나와 있다.

2. Unknown column

BackendError - JDBC exception executing SQL [select u1_0.userId from user u1_0 where u1_0.nickname=? limit ?][Unknown column 'u1_0.userId' in 'field list'] [n/a]; SQL [n/a]

  • 이것은 POSTMAN 으로 데이터를 보냈을 때의 에러이다.

오류 내용 해석

  • select 시 필드를 찾지 못하는 오류이다.

코드 분석

  • 이 경우 비슷한 문제를 가진 블로그 글을 찾았는데, 그 경우에는 필드명과 컬럼 명이 일치하지 않는데 따로 지정하지 않아서 생기는 문제였다.
  • 하지만 나는 userId 의 필드와 컬럼 명도 일치하고, 컬럼 네임도 같은 것으로 지정해놨다.

해결

  • 중간에 User 도메인의 이름을 id -> userId 로 변경한 것이 생각났다.
  • 터미널에서 mysql을 확인하자 역시 컬럼 이름이 id로 되어 있었다.
  • 해당 데이터베이스를 삭제한 후 스프링을 다시 실행했다.

📍 결과

회원 가입 테스트

닉네임 중복 테스트

이메일 중복 테스트

profile
공부 중입니다.

0개의 댓글