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

코드
package <project name>.exception;
public class NoSuchDataException extends RuntimeException {
public NoSuchDataException(String message) {
super(message);
}
}

getUserList: 테이블이 비어있으면 빈 리스트 반환
getUserById: 일치하는 데이터가 없으면 null 반환
updateUser: update된 데이터가 없으면 0 반환
deleteUser: delete된 데이터가 없으면 0 반환
NoSuchDataException을 throw 한다.
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;
}
}
UserController의updateUser메서드가 실행될 때 반환되는 클래스
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로 설정되어 있으므로 데이터의 크기를 줄이기 위해 의미 없는 데이터는 보내지 않는다.
코드
상황에 따라 updateUserRespDto의 code와 message를 다르게 설정해준다.
Exception이 발생하면 console에 ERROR log가 찍히도록 log.error()를 작성한다. (@Slf4j lombok 사용)
@Slf4j lombok을 사용하지 않으면 "private static final Logger log = LoggerFactory.getLogger(AlbumController.class);" 코드를 작성해줘야 한다.
에러 발생시

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이 발생하면 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;
}
존재하지 않는 id의 데이터를 요청했을 때 NoSuchDataException이 처리된 모습

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

DataIntegrityViolationException이 처리된 모습
Source Code
https://github.com/wooryung/REST_API_Basic.git