#04 기본 클래스 세팅 (feat. request, response)

김대진·2023년 4월 10일
0

MyMemory Project

목록 보기
5/9
post-thumbnail

스프링부트 백엔드 서버 코드를 입력하기 전에, 필요한 클래스들을 미리 세팅해 볼 것이다.

01. 기본 클래스 세팅

먼저, 다음과 같이 각각의 엔티티명으로 된 폴더를 만들고 안에 Entity 클래스와 Controller, Service, Repository 파일을 만든다.
그리고 requestresponse 폴더를 만들자.

Entity, Controller, Service, Repository 에 대해서는 다음 포스트에 설명되어 있다.
https://velog.io/@phraqe/Sekkison03

이번 포스트에서 설명할 것은 requestresponse이다.
프론트에서 API 요청이나, 페이지 요청이 있을 때 데이터를 서버로 넘기게 되는데, 이 데이터를 서버에서 사용하기 편하게 가공하기 위해 필요하게 된다.

02. request 세팅

예시로, user/requestJoinrequest를 보자.

JoinRequest.class

@Data
public class JoinRequest {

    @NotBlank(message = "아이디는 필수 입력 값입니다.")
    @Size(min = 4, max = 10, message = "아이디는 4~10자만 가능합니다")
    private String username;

    @NotBlank(message = "비밀번호는 필수 입력 값입니다.")
    @Pattern(regexp = "(?=.*[0-9])(?=.*[a-zA-Z])(?=.*\\W)(?=\\S+$).{8,16}",
            message = "비밀번호는 8~16자 영문 대 소문자, 숫자, 특수문자를 사용하세요.")
    private String password;

    @NotBlank(message = "별명을 설정해주세요")
    @Pattern(regexp = "^[ㄱ-ㅎ가-힣a-z0-9-_]{2,10}$",
            message = "닉네임은 특수문자를 제외한 2~10자리여야 합니다.")
    private String name;

    public User toUser() {
        User user = new User();
        user.setUsername(this.username);
        user.setPassword(this.password);
        user.setName(this.name);
        return user;
    }
}

@NotBlank, @Pattern, @Size 어노테이션을 이용하여 클래스의 변수에 조건을 걸어놓고 toUser() 함수에서 User 객체를 반환하게 된다.

컨트롤러를 보면, 다음과 같이 프론트에서 받아온 데이터를 @Validated를 사용하여 JoinRequest 객체에 담게 된다.

UserController.class

@PostMapping("/join")
    public JoinResponse join(@RequestBody @Validated JoinRequest request) {
        User user = request.toUser();
        return JoinResponse.of(userService.upsertUser(user));
    }

@Validated 어노테이션으로 인해, 만약 프론트에서 받아온 데이터가 유효하지 않다면, Exceptionthrow하게 된다.

이것만으로 충분한 것 같지만, 에러가 발생했을 때를 대비해 Exception을 관리하는 클래스를 만들 것이다.

03. Exception 세팅

Exception을 관리하기 위해 다음과 같이 ExceptionController, 프로젝트명 + Exception 클래스를 생성한다.

먼저, 프로젝트명 + Exception 클래스에서는 @Validated 에서 발생한 에러가 아닌, 직접 throw 해주는 Exception들이 담길 것이다.

MyMemoryException.class

@Getter
@AllArgsConstructor
public class MyMemoryException extends RuntimeException {
    private int status;
    private String message;
}

사용방법은 다음과 같이 데이터를 넘겨줄 수 없을 때 throw 하기만 하면 된다.

UserService.class

public User upsertUser(User user) {
        User dupUser = userRepository.findByUsername(user.getUsername());
        if (dupUser != null) throw new MyMemoryException(404, "이미 존재하는 아이디입니다.");

        user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
        return userRepository.save(user);
    }

그리고 ExceptionController에서는 @Validated와 직접 throw한 예외들을 관리해서 프론트로 에러를 담아 넘겨줄 것이다.

ExceptionController.class

@RestControllerAdvice
public class ExceptionController {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ErrorResponse handle(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();

        StringBuilder builder = new StringBuilder();
        FieldError fieldError = bindingResult.getFieldErrors().get(0);
        builder.append(fieldError.getDefaultMessage());
        return new ErrorResponse(400, builder.toString());
    }

    @ExceptionHandler(MyMemoryException.class)
    public ErrorResponse handle(MyMemoryException e) {
        return new ErrorResponse(e.getStatus(), e.getMessage());
    }

    @Data
    @AllArgsConstructor
    public static class ErrorResponse {
        private int status;
        private String message;
    }
}

MethodArgumentNotValidException.class

@Validated를 통한 예외가 발생하게 되면 ErrorResponse객체를 프론트로 보내게 된다. 이 경우 status는 400으로 설정하였다.

MyMemoryException.class

직접 예외를 throw하면 ErrorResponse객체를 프론트로 보내게 된다.

04. response 세팅

예외 발생 없이 성공했을 때 프론트로 넘겨줄 객체 또한 필요하다.
예시로, user/response 패키지의 DeleteResponse를 보자.

DeleteResponse.class

@Data
public class DeleteResponse {
    private int status;
    private String message;

    public static DeleteResponse of(int status) {
        DeleteResponse response = new DeleteResponse();
        response.setStatus(status);
        response.setMessage("회원 탈퇴 성공");
        return response;
    }
}

컨트롤러에서 JoinResponse.of(유저객체) 를 리턴하면, statusmessage가 담긴 Response객체를 프론트로 보내게 된다.

그러면 프론트에서는 다음 코드처럼 status가 200이 아닐 때 message를 보여주면 된다.

javascript

$.ajax({
  contentType: 'application/json',
  url: `/api/join`,
  type:"POST",
  dataType: 'json',
  data: JSON.stringify({
    "username": username,
    "password": password,
    "name": name
  }),
  success : function(data) {
    if (data.status == 200) alert("회원가입 완료");
    else alert(data.message);
  }
})
profile
만재 개발자

0개의 댓글