윤개발

Vue.js + Spring Boot + MySQL+JPA 게시판 만들기(7) - 회원가입 API 생성 본문

프로젝트/Vue.js, Spring 게시판

Vue.js + Spring Boot + MySQL+JPA 게시판 만들기(7) - 회원가입 API 생성

DEV_SJ 2020. 11. 15. 23:23

이번 포스팅에서는 User의 Controller, Service, Repository 를 생성하고 회원가입 API를 만들어보겠습니다.

 

먼저 JpaRepository를 상속받는 UserRepository를 생성합니다. 

JPARepository를 상속받으면 기본적인 CRUD는 자동생성되며 메소드 이름으로 쿼리를 만들 수 있습니다.

package com.board.My.Board.repository;

import com.board.My.Board.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;

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

이처럼 껍데기만 만들어도 기본적인 save, find, update, delete를 사용할 수 있습니다.

 

 

다음으로 UserService를 생성합니다.

package com.board.My.Board.service;

import com.board.My.Board.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class UserService {
    
    private final UserRepository userRepository;
    
}

 

@RequiredArgsConstructor 어노테이션을 통해 UserRepository를 받습니다.

이 어노테이션은 초기화 되지않은 final 필드나, @NonNull 이 붙은 필드의 생성자를 생성해 줍니다.

주로 의존성 주입(Dependency Injection) 편의성을 위해서 사용되곤 합니다.

@Autowired 없이 의존성 주입이 가능합니다.

 

 

마지막으로 UserController를 생성합니다.

package com.board.My.Board.controller;

import com.board.My.Board.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequiredArgsConstructor
@ResponseBody
public class UserController {

    private final UserService userService;

}

 

UserRepository와 마찬가지로 UserService를 final 필드로 등록합니다.

 

 

이로써 가장 기본적인 파일만 생성한 상태가 되었으며 

이전 포스팅에서 설명한 구조에 맞게 Controller -> Service -> Repository 의 구조가 되었습니다.

 

 

이제 새로운 User를 등록하는 API를 추가해보겠습니다.

사전 작업으로 프론트에서 회원가입 정보를 받는 UserForm DTO를 생성합니다.

package com.board.My.Board.dto;

import lombok.Getter;
import lombok.Setter;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;

@Getter
@Setter
public class UserForm {


    @NotEmpty(message = "이메일은 필수 입니다.")
    @Size(max = 100, message = "이메일은 100자리를 초과할 수 없습니다.")
    private String email;

    @NotEmpty(message = "이름은 필수 입니다.")
    @Size(max = 20, message = "이름은 20자리를 초과할 수 없습니다.")
    private String userName;

    @NotEmpty(message = "비밀번호는 필수 입니다.")
    @Size(max = 100, message = "비밀번호는 100자리를 초과할 수 없습니다.")
    private String password;
    
}

@NotEmpty와, @Size 어노테이션을 통해 dto내용을 검증하고 검증 실패시 에러를 던져줍니다.

코드단에서 직접 null , size를 체크하면 코드가 길어지므로 어노테이션을 통해 검증하는 것입니다.

 

 

다음으로 동일 이메일 가입을 방지하기 위해 이메일을 가진유저가 존재하는지 확인하는 메소드를 UserRepository에 추가합니다.

public interface UserRepository extends JpaRepository<User, Long> {
    boolean existsByEmail(String email);
}

어플리케이션 실행시점에 JPA가 메소드 이름을 보고 위의 쿼리를 만들어줍니다. 쿼리가 틀렷다면 런타임에러가 발생하며 어플리케이션이 실행되지 않습니다.

 

 

다음으로 중복이메일 가입시 던질 예외를 exception 패키지에 추가합니다.

package com.board.My.Board.exception;

public class DuplicateEmailException extends RuntimeException {
}

 

이처럼 예외로 처리하고 하나의 클래스에서 모든 예외를 처리하면됩니다.

아직 생성하지 않았지만 모든 예외를 처리하는 곳은 이전포스팅의 에러처리 부분(Exception Handler)입니다.

 

 

이제 User에 생성자 및 정적 팩토리 메소드를 추가합니다.

생성자를 바로 호출하지 않는 이유는 정적팩토리 메소드 링크를 눌러보시면 알수 있습니다.

 	public User(){}

    public User(UserForm userForm) {
        this.email = userForm.getEmail();
        this.userName = userForm.getUserName();
        this.password = userForm.getPassword();
    }

    public static User createUser(UserForm userForm){
        return new User(userForm);
    }

빈 User 생성자는 JPA에서 필요로 하기때문에 추가하였습니다.

 

 

이제 UserService에 다음과 같이 추가합니다.

    @Transactional
    public void signUpUser(UserForm userForm) throws Exception {
        validateDuplicateEmail(userForm.getEmail());
        userRepository.save(User.createUser(userForm));
    }

    private void validateDuplicateEmail(String email) throws Exception {
        if(userRepository.existsByEmail(email)){
            throw new DuplicateEmailException();
        }
    }

유저를 회원가입하는 메소드를 생성하고 이메일 중복을 체크합니다.

이메일이 중복이라면 예외를 던지며 없을시 가입을 시키는 코드입니다.

Insert 쿼리가 작동되기 때문에 @Transactional을 붙였습니다.

 

 

 

마지막으로 UserController에 아래 코드를 추가합니다.

    @PostMapping("/signup")
    public void signUpUser(@RequestBody @Valid UserForm userForm) throws Exception {
        userService.signUpUser(userForm);
    }

@RequestBody를 통해 userForm을 JSON으로 받고 @Valid를 통해 값을 검증합니다.

 

 

 

API 구성이 완료되었으니 Swagger 라이브러리를 이용하여 손쉽게 api를 호출해보겠습니다.

pom.xml에 swagger를 추가해줍니다. 

		<!-- Swagger -->
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
			<version>2.6.1</version>
		</dependency>
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger-ui</artifactId>
			<version>2.6.1</version>
		</dependency>

 

 

그리고 인텔리제이 상단 오른쪽에 뜨는 메이븐 새로고침을 눌러줍니다.

변경된 pom.xml을 인식하여 의존성을 추가해줍니다. 

 

다음으로 SwaggerConfiguration을 추가해줍니다.

package com.board.My.Board.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfiguration {
    @Bean
    public Docket swaggerApi() {
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(swaggerInfo()).select()
                .apis(RequestHandlerSelectors.basePackage("com.board.My.Board.controller"))
                .paths(PathSelectors.any())
                .build()
                .useDefaultResponseMessages(false);
    }
    private ApiInfo swaggerInfo() {
        return new ApiInfoBuilder().title("Spring API Documentation")
                .description("웹 개발시 사용되는 서버 API에 대한 연동 문서입니다")
                .license("").licenseUrl("").version("1").build();
    }
}

.apis의 경로는 Controller 패키지가 존재하는 경로로 변경해줍니다.

 

 

이제 Application을 실행시키고 https://locahost:8080/swagger-ui.html 에 접속합니다.

그러면 로그인창이 뜨게되는데 Spring Security의 기본설정이 되어있어 그렇습니다.

 

pom.xml에서 시큐리티부분을 잠깐 주석처리하고 위와 마찬가지로 메이븐 새로고침을 합니다.

<!--		<dependency>-->
<!--			<groupId>org.springframework.boot</groupId>-->
<!--			<artifactId>spring-boot-starter-security</artifactId>-->
<!--		</dependency>-->

 

메이븐을 새로고침하고 프로젝트를 재실행하면 아래와 같이 SwaggerUI가 나타나게됩니다.

이제 잘 동작하는지 확인하기 위해 userForm에 값을 넣고 회원가입을 진행해보겠습니다.

{
  "email": "yoon@kt.com",
  "password": "1234",
  "userName": "yoon"
}

값을 넣고 아래 Try it out!을 클릭합니다. 

그러면 Spring boot console에서 아래와 같이 로그가 나옵니다.

Hibernate: insert into user (email, password, user_name, user_id) values (?, ?, ?, ?)

중복 회원이 방지되는지 보기위해 한번 더 클릭을 해봅니다.

 

그럼 아래와 같이 아까 만들었던 예외가 나오게됩니다.

com.board.My.Board.exception.DuplicateEmailException: null

아직 예외처리를 완벽히 하지않아 500에러가 나오는 모습입니다.

 

실제 DB에도 값이 잘 들어가 있는지 확인해봅니다.

 

이로써 회원가입 API 작성이 완료되었습니다.

 

전체 코드는 아래 링크에서 확인할 수 있습니다.

https://github.com/sungjaeyoon/board

 

sungjaeyoon/board

블로그에 포스팅중인 게시판 만들기입니다. Contribute to sungjaeyoon/board development by creating an account on GitHub.

github.com

 

Comments