ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring boot + React 시작하기 2 (로그인 및 회원가입, 회원 관리 만들기) - 회원 가입
    DEV/spring 2024. 2. 6. 17:04

    1. Spring boot + React 시작하기 1 (로그인 및 회원가입, 회원 관리 만들기) - 기본설정

    https://seokbong.tistory.com/246

     

    Spring boot + React 시작하기 1 (로그인 및 회원가입, 회원 관리 만들기)

    연습용 프로젝트를 생성하면서 Sample로 진행 내역을 남겨봄 연습용 프로젝트는 Spring boot + React로 로그인 / 회원가입 및 회원관리 페이지를 만들어 보려고 한다. 개발 환경은 M1 Mac Os, Spring boot, Reac

    seokbong.tistory.com


    본 게시물의 흐름도 : 

    DTO 작성(SignUpDto, ResponseDto 등등…) > Controller 작성(AuthController) > Postman으로 작동 확인 > 회원 가입 페이지 구성(React) >  Controller의 CrossOrigin(origins 어노테이션 제거, main에 WebMvcConfigurer작성 (각 Controller마다 CORS 처리를 하지 않기 위해 분리) > UserEntity 생성자 작성 > Auth Service 생성 및 작성 (Repository를 통해 DB에 데이터 적재) > AuthController 에서 불러오기

     

    환경 : Mac OS, JDK17, Gradle, Spring 3.2.2

    1. DTO 작성

    Dto를 작성해야 하는 이유

    1. 데이터 전송의 목적 명확화: DTO는 데이터를 전달하고자 하는 목적을 명확히 하여 데이터 전송 프로세스를 단순화하고 투명하게 만듭니다.
    2. 데이터 구조의 단순화: DTO는 관련된 데이터를 하나의 객체로 그룹화하여 복잡성을 줄입니다. 이는 특히 여러 필드를 한 번에 전송해야 하는 경우에 유용합니다.
    3. 레이어 간 데이터 전달의 유연성 향상: DTO를 사용하면 서로 다른 계층 간에 데이터를 쉽게 전송할 수 있습니다. 예를 들어, 비즈니스 로직 계층에서 데이터베이스 계층으로 데이터를 전달할 때 DTO를 사용하여 데이터의 형식을 맞출 수 있습니다.
    4. 데이터의 보호: DTO를 사용하면 클라이언트에게 전달되는 데이터의 일부를 보호할 수 있습니다. 필요한 데이터만 포함시켜 보안을 강화할 수 있습니다.
    5. API 설계와 호환성: 외부 시스템과의 통합을 위해 API를 설계할 때 DTO를 사용하여 API의 요구사항을 충족하고 호환성을 유지할 수 있습니다.
    6. 클라이언트와 서버 간의 통신 최적화: DTO를 사용하여 클라이언트와 서버 간의 데이터 전송 양을 최적화할 수 있습니다. 불필요한 데이터를 제거하거나 필요한 데이터만 전송함으로써 통신 성능을 향상시킬 수 있습니다.

     

    Dto Pakage를 생성하고 Dto를 작성하자.

     

    ResponseDto.java

    package com.ssg.demo.v2.ssgdemov2.Dto;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    
    @Data
    @AllArgsConstructor(staticName = "set")
    public class ResponseDto<D> {
        private boolean result;
        private String message;
        private D data;
    
        public  static <D> ResponseDto<D> setSuccess(String message) {
            return ResponseDto.set(true, message, null);
        }
    
        public static <D> ResponseDto<D> setFailed(String message)
        {
            return ResponseDto.set(false, message, null);
        }
    
        public static <D> ResponseDto<D> setSuccessData(String message, D data) {
            return ResponseDto.set(true, message, data);
        }
    
        public static <D> ResponseDto<D> setFailedData(String message, D data) {
            return ResponseDto.set(false, message, data);
        }
    }

     

    SignUpDto.java

    package com.ssg.demo.v2.ssgdemov2.Dto;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.time.LocalDateTime;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class SignUpDto {
        private String id;
        private String email;
        private String name;
        private String password;
        private String confirmPassword;
        private String phoneNumber;
        private String userType;
        private LocalDateTime createdAt;
        private LocalDateTime editedAt;
        private LocalDateTime lastLoginAt;
        private String token;
    }

     

    2. AuthController 작성

    테스트를 위해 임시로 하단 코드와 같이 작성한 후 Postman을 이용하여 정상 작동을 확인하자
    (다른 방법을 이용해도 좋다.)

     

    나중에 코드는 수정할 것이다.

    Controller의 경로

     

    AuthController.java

    package com.ssg.demo.v2.ssgdemov2.Controller;
    
    import com.ssg.demo.v2.ssgdemov2.Dto.ResponseDto;
    import com.ssg.demo.v2.ssgdemov2.Dto.SignUpDto;
    import org.springframework.web.bind.annotation.*;
    
    @RestController
    // 본인 포트에 맞춰 설정
    @CrossOrigin(origins = "http://localhost:3000")
    @RequestMapping("/api/auth")
    public class AuthController {
        @PostMapping("/signUp")
        public ResponseDto<SignUpDto> signUp(@RequestBody SignUpDto requestBody) {
            System.out.println(requestBody.toString());
            return null;
        }
    }

     

    Postman

    Return 값을 null로 던졌기 때문에 따로 값이 넘어오지는 않는다. 통신 성공 여부인 "200 OK" 만 확인하고 넘어가자.

     

     

    3. 회원가입 페이지 구성 (React)

    React 파트의 경우는 나중에 따로 글을 작성할 예정이다. (작성이 완료되면 링크를 걸어두겠다.)

    Front는 본인 입맛에 맛는 구성으로 진행하자.

     

    우선 본인의 경우에는 다음과 같이 구성했다.

     

    (쓰면서 생각난게 admin 여부 선택하는 버튼을 추가해야겠다...)

     

    4. WebMvcConfigurer 작성(Controller의 Cors 어노테이션 제거), 

    Controller의 "@CrossOrigin" 어노테이션을 생각해 보자.

    @CrossOrigin(origins = "http://localhost:3000")

     

    컨트롤러를 생성할 때마다 저러한 어노테이션을 작성하는것은 귀찮은 일이다.

     

    그래서 WebMvcConfigurer를 작성하려고 한다.

     

    Controller의 모든 CrossOrigin 어노테이션을 모두 제거하고 하단의 파일을 생성 및 작성하자.

     

    mvcConfigurer.java

    package com.ssg.demo.v2.ssgdemov2;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.CorsRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    @Configuration
    public class mvcConfigurer implements WebMvcConfigurer {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**").allowedOriginPatterns();
        }
    }

     

    5. UserEntity 생성자 작성

    UserEntity를 다음과 같이 수정해보자.

     

    UserEntity.java

    package com.ssg.demo.v2.ssgdemov2.Entity;
    
    import com.ssg.demo.v2.ssgdemov2.Dto.SignUpDto;
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import jakarta.persistence.Entity;
    import jakarta.persistence.Id;
    import jakarta.persistence.Table;
    import java.time.LocalDateTime;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @Entity
    @Table(name="user")			// 본인 테이블명과 맞춰주어야 함
    public class UserEntity {
        @Id
        private String id;
        private String email;
        private String password;
        private String name;
        private String phoneNumber;
        private String userType;
        private String token;
        private LocalDateTime createdAt;
        private LocalDateTime editedAt;
        private LocalDateTime lastLoginAt;
    
        // 본인은 Email과 id를 동일하게 구성하기 위해 다음과 같이 작성하였다.
        public UserEntity(SignUpDto dto) {
            this.id = dto.getEmail();
            this.email = dto.getEmail();
            this.password = dto.getPassword();
            this.name = dto.getName();
            this.phoneNumber = dto.getPhoneNumber();
            this.userType = dto.getUserType();
            this.token = "";
            this.createdAt = LocalDateTime.now();
            this.editedAt = LocalDateTime.now();
        }
    }

     

    6. Auth Service 생성 작성

    Service package를 생성하고 AuthService.java를 생성하고 다음과 같이 작성하자.

    Serrvice 구성

     

    AuthService.java

    package com.ssg.demo.v2.ssgdemov2.Service;
    
    import com.ssg.demo.v2.ssgdemov2.Dto.ResponseDto;
    import com.ssg.demo.v2.ssgdemov2.Dto.SignUpDto;
    import com.ssg.demo.v2.ssgdemov2.Entity.UserEntity;
    import com.ssg.demo.v2.ssgdemov2.Repository.UserRepository;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    @Service
    public class AuthService {
        @Autowired UserRepository userRepository;
        public ResponseDto<?> signUp(SignUpDto dto) {
            String email = dto.getEmail();
            String password = dto.getPassword();
            String confirmPassword = dto.getConfirmPassword();
    
            // email(id) 중복 확인
            try {
                // 존재하는 경우 : true / 존재하지 않는 경우 : false
                if(userRepository.existsById(email)) {
                    return ResponseDto.setFailed("중복된 Email 입니다.");
                }
            } catch (Exception e) {
                return ResponseDto.setFailed("데이터베이스 연결에 실패하였습니다.");
            }
    
            // password 중복 확인
            if(!password.equals(confirmPassword)) {
                return ResponseDto.setFailed("비밀번호가 일치하지 않습니다.");
            }
    
            // UserEntity 생성
            UserEntity userEntity = new UserEntity(dto);
    
            // UserRepository를 이용하여 DB에 Entity 저장 (데이터 적재)
            try {
                userRepository.save(userEntity);
            } catch (Exception e) {
                return ResponseDto.setFailed("데이터베이스 연결에 실패하였습니다.");
            }
    
            return ResponseDto.setSuccess("회원 생성에 성공했습니다.");
        }
    }

     

    *existsById 메서드는 주어진 ID에 해당하는 엔티티가 데이터베이스에 존재하는지 여부를 확인하는 데 사용됩니다. 이 메서드는 데이터베이스에서 엔티티를 실제로 가져오지 않고, 주어진 ID가 데이터베이스에 존재하는지만 확인합니다. 따라서 존재 여부만 확인하고 데이터를 가져오지 않기 때문에 효율적입니다.

     

    *JpaRepository는 Spring Data JPA의 핵심 인터페이스 중 하나이며, 엔티티의 CRUD(Create, Read, Update, Delete) 작업을 처리하는 메서드를 제공합니다. existsById는 JpaRepository에서 제공하는 메서드 중 하나로, 데이터베이스에 엔티티가 존재하는지 여부를 확인하는 데 사용됩니다.

     

    *일반적으로 JpaRepository를 상속받은 인터페이스를 사용하여 엔티티에 대한 데이터베이스 작업을 수행합니다. JpaRepository를 구현한 인터페이스를 사용하면 기본적인 CRUD 작업 외에도 다양한 데이터베이스 관련 메서드를 사용할 수 있습니다. existsById 메서드도 그러한 메서드 중 하나입니다.

     

    7. AuthController 수정

    AuthController.java

    package com.ssg.demo.v2.ssgdemov2.Controller;
    
    import com.ssg.demo.v2.ssgdemov2.Dto.ResponseDto;
    import com.ssg.demo.v2.ssgdemov2.Dto.SignUpDto;
    import com.ssg.demo.v2.ssgdemov2.Service.AuthService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    
    @RestController
    @RequestMapping("/api/auth")
    public class AuthController {
        @Autowired AuthService authService;
        @PostMapping("/signUp")
        public ResponseDto<?> signUp(@RequestBody SignUpDto requestBody) {
            ResponseDto<?> result = authService.signUp(requestBody);
            return result;
        }
    }

     

    여기 까지 진행 후 구성한 React에 연결하고 나니 계정 생성까지 완성되었다.

     

    댓글

Designed by Tistory.