@PostMapping("/signup")
public ResponseEntity<Response<?>> signUp(@RequestBody UserRequest userRequest) {
userService.addUsers(userRequest);
return ResponseEntity.ok(Response.success("회원가입 성공"));
}
@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);
// 커스텀 메시지 (data 포함)
public static <T> Response<T> success(String message, T data) {
return new Response<>(true, 200, message, data);
}
매개변수 T data
-> UserDTO data
{
"success": true,
"code": 200,
"message": "회원가입 성공",
"data": {
"email": "test@example.com",
"name": "홍길동"
}
}
ResponseEntity
는 REST API에서 응답 본문(body)과 HTTP 상태 코드를 함께 클라이언트에게 보내기 위해 쓰인다.
✅ 구체적인 동작 흐름
Response.success("회원가입 성공")
→ 우리가 만든 응답 객체 (Response<String>
)를 생성함
→ 내용: success=true
, code=200
, message="회원가입 성공"
, data=null
ResponseEntity.ok(...)
→ 위 객체를 HTTP 응답 바디에 담고
→ HTTP 상태 코드는 200 OK
로 설정됨
Spring이 클라이언트에 JSON으로 응답
{
"success": true,
"code": 200,
"message": "회원가입 성공",
"data": null
}
ResponseEntity<T\>
에서 T는 body의 타입이라고 생각하면된다.
여러가지 상태 사용 예시
예외 자세한 내용은 이곳을 참고하기
CheckedException은 컴파일러가 예외처리를 강제하므로 예외에 대한 대처를 할 throws
또는 try-catch
코드를 반드시 작성해야한다.
UncheckedException 런타임 시점
에 예외가 발생하더라도 개발자가 알아서 조치하라는 말이다.
왜 예외처리를 강제하지 않을까?
예외가 발생할만한 곳에 모두 예외처리를 해야한다면try-catch
문 또는throws
를 무조건 넣어야 하므로 코드가 복잡해지게 됩니다.그래서 java는 개발자가 알아서 처리할만한 예외는 알아서 처리하게 놔둡니다.
@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);
}
}
@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 들을 처리함