[Spring Boot] 예외 처리하기

우롱차·2022년 11월 9일
0

Spring Boot

목록 보기
6/7

요구사항

  • HTTP Protocol을 요청했을 때 DB에 일치하는 값이 없다면, 일치하는 데이터가 없다는 의미의 NoSuchDataException을 만들어 예외 처리를 해준다.
  • User 테이블의 경우 username과 email이 unique로 설정되어 있으므로 POST 요청을 할 때 이미 존재하는 username이나 email이라면 DuplicateKeyException을 처리하도록 한다.
  • 각 테이블의 Key 중 Not Null로 설정된 key 값이 null로 POST 되는 경우 DataIntegrityViolationException을 처리하도록 한다.

1. Exception 클래스 작성

📎 NoSuchDataException.java 파일을 작성한다.

  • 파일 위치

  • 코드

    • RuntimeException을 상속하여 예외를 처리한다.
package <project name>.exception;

public class NoSuchDataException extends RuntimeException {
    public NoSuchDataException(String message) {
        super(message);
    }
}

2. Service에서 직접 만든 Exception을 throw하도록 코드 작성

🔨 NoSuchDataException

📎 UserMapper.java 파일

getUserList: 테이블이 비어있으면 빈 리스트 반환
getUserById: 일치하는 데이터가 없으면 null 반환
updateUser: update된 데이터가 없으면 0 반환
deleteUser: delete된 데이터가 없으면 0 반환

📎 UserService.java 파일

  • DB의 데이터를 처리했을 때 결과에 따라 NoSuchDataException을 throw 한다.

3. Controller에서 예외 처리 코드 작성

📎 ResCode.java 파일

api의 실행 결과를 dto에 code, message로 담아 보내기 위해 code의 의미를 설정해준다.

  • 파일 위치

  • 코드

package <project name>.consts;

public enum ResCode {
    SUCCESS(0), NO_SUCH_DATA(-1), DUPLICATE_KEY(-2), NULL_VALUE(-3), UNKNOWN(-99);
    // 성공했을 때, 일치하는 data가 없을 때, Not Null Key가 Null 값으로 왔을 때, 다른 exception이 발생했을 때

    private final int value;

    ResCode(int value) {
        this.value = value;
    }

    public int value() {
        return value;
    }
}

📎 UpdateUserRespDto.java 파일

UserControllerupdateUser 메서드가 실행될 때 반환되는 클래스

  • 코드
package <project name>.dto.user;

import <project>.consts.ResCode;
import lombok.Data;

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UpdateUserRespDto { // default로 성공했을 때의 값을 넣어둔다.
    private int code = ResCode.SUCCESS.value();
    private String message;
}

@JsonInclude(JsonInclude.Include.NON_NULL)

  • 데이터를 전송할 때 Null 값이 아닌 데이터들만 전송하는 annotation.
  • 성공했을 때의 message는 default로 null로 설정되어 있으므로 데이터의 크기를 줄이기 위해 의미 없는 데이터는 보내지 않는다.

🔨 NoSuchDataException

📎 UserController.java 파일 중 updateUser 메서드

  • 코드

    • 상황에 따라 updateUserRespDto의 code와 message를 다르게 설정해준다.

      • updateService의 updateUser 메서드가 정상적으로 실행됐을 때, NoSuchDataException이 발생했을 때, 다른 Exception이 발생했을 때
    • Exception이 발생하면 console에 ERROR log가 찍히도록 log.error()를 작성한다. (@Slf4j lombok 사용)

      • @Slf4j lombok을 사용하지 않으면 "private static final Logger log = LoggerFactory.getLogger(AlbumController.class);" 코드를 작성해줘야 한다.

      • 에러 발생시

      • log를 설정해주지 않으면 WARN log만 나타난다.
@PutMapping("/users/{id}")
public UpdateUserRespDto updateUser(@PathVariable Long id, @RequestBody UpdateUserReqDto updateUserReqDto) {
    UpdateUserRespDto updateUserRespDto = new UpdateUserRespDto();
    try {
        UserVo userVo = new UserVo(id, updateUserReqDto.getName(), updateUserReqDto.getUsername(), updateUserReqDto.getEmail(), updateUserReqDto.getPassword(), updateUserReqDto.getAddress(), updateUserReqDto.getPhone(), updateUserReqDto.getWebsite(), updateUserReqDto.getCompany());
        userService.updateUser(userVo);
    } catch (NoSuchDataException e) {
        updateUserRespDto.setCode(ResCode.NO_SUCH_DATA.value());
        updateUserRespDto.setMessage("No such user exists.");
    } catch (Exception e) {
        log.error("[UserController updateUser]", e);
        updateUserRespDto.setCode(ResCode.UNKNOWN.value());
        updateUserRespDto.setMessage(e.getLocalizedMessage());
    }
    return updateUserRespDto;
}

try: 프로그램이 정상적으로 실행됐을 때의 실행 코드
catch: 예외가 발생했을 때의 실행 코드


🔨 DuplicateKeyException, DataIntegrityViolationException

📎 UserController.java 파일 중 createUser 메서드

  • 코드
    • DuplicateKeyExceptionDataIntegrityViolationException이 발생하면 createUserRespDto에 code와 message를 담아준다.
@PostMapping("/users")
public CreateUserRespDto createUser(@RequestBody CreateUserReqDto createUserReqDto) {
    CreateUserRespDto createUserRespDto = new CreateUserRespDto();
    try {
        UserVo userVo = new UserVo(0L, createUserReqDto.getName(), createUserReqDto.getUsername(), createUserReqDto.getEmail(), createUserReqDto.getPassword(), createUserReqDto.getAddress(), createUserReqDto.getPhone(), createUserReqDto.getWebsite(), createUserReqDto.getCompany());
        userService.createUser(userVo);
    } catch (DuplicateKeyException e) {
        createUserRespDto.setCode(ResCode.DUPLICATE_KEY.value());
        createUserRespDto.setMessage("Duplicate 'username' or 'email'.");
    } catch (DataIntegrityViolationException e) {
        createUserRespDto.setCode(ResCode.NULL_VALUE.value());
        createUserRespDto.setMessage("'username', 'email' are required.");
    } catch (Exception e) {
        log.error("[UserController createUser]", e);
        createUserRespDto.setCode(ResCode.UNKNOWN.value());
        createUserRespDto.setMessage(e.getLocalizedMessage());
    }
    return createUserRespDto;
}

4. 실행 결과

  • 존재하지 않는 id의 데이터를 요청했을 때 NoSuchDataException이 처리된 모습

  • 이미 존재하는 username이나 email을 전송했을 때 DuplicateKeyException이 처리된 모습

  • username이나 email을 입력하지 않고 전송했을 때 DataIntegrityViolationException이 처리된 모습

Source Code
https://github.com/wooryung/REST_API_Basic.git

profile
아직 따끈따끈합니다🍵

0개의 댓글