회원가입 기능[백엔드]

Psj·2025년 3월 21일
0

UserController

@PostMapping("/signup")
public ResponseEntity<Response<?>> signUp(@RequestBody UserRequest userRequest) {
    userService.addUsers(userRequest);
    return ResponseEntity.ok(Response.success("회원가입 성공"));
}

ResponseEntity<Response\<?>> 반환값 설명

Response<T> 구조

@Data
@AllArgsConstructor
public class Response<T> {
    private boolean success;
    private int code;
    private String message;
    private T data;

    // 기본 성공 (data 없음)
    public static <T> Response<T> success() {
        return new Response<>(true, 200, "요청 성공", null);
    }

    // 기본 성공 (data 포함)
    public static <T> Response<T> success(T data) {
        return new Response<>(true, 200, "요청 성공", data);
    }

    // 커스텀 메시지 (data 포함)
    public static <T> Response<T> success(String message, T data) {
        return new Response<>(true, 200, message, data);
    }

    // 커스텀 메시지만 (data 없음)
    public static Response<Void> success(String message) {
        return new Response<>(true, 200, message, null);
    }

    // 실패
    public static <T> Response<T> fail(int code, String message) {
        return new Response<>(false, code, message, null);
    }
}

<T\>는 제네릭(Generic) 타입이라서, Response<T\>를 사용할 때마다 T에 어떤 타입이든 넣을 수 있어요.

예를 들어 String, Map, UserDTO, List<Something\> 등 모두 가능합니다.

현재 UerContoller의 Response.seccess("회원가입 성공")은
매개변수에 "회원가입 성공" 이라는 String 타입을 넘겼으므로

Response 클래스에서 아래 메소드가 동작한다.

// 커스텀 메시지만 (data 없음)
    public static Response<Void> success(String message) {
        return new Response<>(true, 200, message, null);
    }

반환타입 Response<T>Response<Void>이니
필드인 private T data;priavate Void data; 가 되고
data 자리 매개변수에 들어온값이 null 이니
최종 필드는 private Void data = null; 이 된다.

응답은 아래처럼 나온다.

{
  "success": true,
  "code": 200,
  "message": "회원가입 성공",
  "data": null
}

매개변수에 객체가 들어간다면?

UserDTO userDTO = new UserDTO("test@example.com", "홍길동");
Response<UserDTO> response = Response.success("회원가입 성공", userDTO);
  1. 이 메소드 동작
// 커스텀 메시지 (data 포함)
public static <T> Response<T> success(String message, T data) {
    return new Response<>(true, 200, message, data);
}

매개변수 T data -> UserDTO data

  1. 응답은 이렇게 한다
{
  "success": true,
  "code": 200,
  "message": "회원가입 성공",
  "data": {
    "email": "test@example.com",
    "name": "홍길동"
  }
}

ResponseEntity.ok(...) 동작방식

ResponseEntity는 REST API에서 응답 본문(body)HTTP 상태 코드를 함께 클라이언트에게 보내기 위해 쓰인다.

✅ 구체적인 동작 흐름

  1. Response.success("회원가입 성공")
    → 우리가 만든 응답 객체 (Response<String>)를 생성함
    → 내용: success=true, code=200, message="회원가입 성공", data=null

  2. ResponseEntity.ok(...)
    → 위 객체를 HTTP 응답 바디에 담고
    → HTTP 상태 코드는 200 OK로 설정됨

  3. Spring이 클라이언트에 JSON으로 응답

{
  "success": true,
  "code": 200,
  "message": "회원가입 성공",
  "data": null
}

ResponseEntity<T\>에서 T는 body의 타입이라고 생각하면된다.

여러가지 상태 사용 예시

Checked Exception, Unchecked Exception

예외 자세한 내용은 이곳을 참고하기

CheckedException은 컴파일러가 예외처리를 강제하므로 예외에 대한 대처를 할 throws 또는 try-catch 코드를 반드시 작성해야한다.

UncheckedException 런타임 시점에 예외가 발생하더라도 개발자가 알아서 조치하라는 말이다.

왜 예외처리를 강제하지 않을까?
예외가 발생할만한 곳에 모두 예외처리를 해야한다면 try-catch문 또는 throws를 무조건 넣어야 하므로 코드가 복잡해지게 됩니다.

그래서 java는 개발자가 알아서 처리할만한 예외는 알아서 처리하게 놔둡니다.

UserServiceImpl

@Override
    public void addUsers(UserRequest userRequest) {
        //검증 수행
        verification(userRequest);

        User builder = User.builder()
                .userEmail(userRequest.getUserEmail())
                .userPw(passwordEncoder.encode(userRequest.getUserPw()))
                .userNickname(userRequest.getUserNickname())
                .userIntroduce(userRequest.getUserIntroduce())
                .build();

        userRepository.save(builder);
    }

    private void verification(UserRequest userRequest) {
        // 비밀번호 확인 실패 시 예외 발생
        if (!checkPassword(userRequest)) {
            throw new CustomException(UserErrorCode.NOT_MATCH_PASSWORD_CONFIRM);
        }
        // 이메일 중복시 예외 발생
        if (emailDuplicateCheck(userRequest)) {
            throw new CustomException(UserErrorCode.DUPLICATE_USER_ID);
        }
    }

GlobalExceptionHandler

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    public ResponseEntity<Response> handleException(Exception e) {

        Response errorResponse = new Response(false, HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage(), e.getCause());

        // 에러 응답 생성
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
    }

    @ExceptionHandler(CustomException.class)
    public ResponseEntity<Response> handleCustomException(CustomException e) {
        // 에러 정보를 담은 ErrorResponse 객체 생성
        Response errorResponse = new Response(false, e.getErrorCode().getCode(), e.getMessage(), null);

        // 에러 응답 생성
        return ResponseEntity.status(e.getErrorCode().getCode()).body(errorResponse);
    }
}

@RestControllerAdvice

  • 전역적으로 모든 @RestController에서 발생하는 예외를 처리해주는 클래스
  • 모든 컨트롤러에 공통적으로 적용됨

@ExceptionHandler(...)

  • 특정 예외 클래스가 발생했을 때, 해당 메서드로 예외를 넘김
  • 여러 메서드를 예외 타입별로 나눠서 처리 가능

@ExceptionHandler(Exception.class)

  • 일반적인 예외 (NullPointerException, IllegalStateException 등) 을 처리

@ExceptionHandler(CustomException.class)

  • 우리가 만든 CustomException 들을 처리함
profile
Software Developer

0개의 댓글

관련 채용 정보