Springboot Rest エラーハンドリング

今回は、Springを使ってREST API例外処理を実装する方法を見ていきたいと思います。

build.gradle

implementation 'org.springframework.boot:spring-boot-starter-validation'
  • Springバリデーションを使用するために上記を追加してbuildします。

MessageSourceのBean設定

@Configuration
public class WebConfig {

@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource
= new ReloadableResourceBundleMessageSource();

messageSource.setBasename("classpath:messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}

@Bean
public LocalValidatorFactoryBean getValidator() {
LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
bean.setValidationMessageSource(messageSource());
return bean;
}

}
  • メッセージをプロパティとして管理するためにBean設定をおこないます。
  • LocalValidatorFactoryBeanはコントローラーでバリデーションを使うためにBean設定をおこないます。

ApiError

/**
* status: the HTTP status code
* message: the error message associated with exception
* error: List of constructed error messages
*/
@Getter
public class ApiError {

private HttpStatus status;
private String message;
private List<String> errors;

public ApiError(HttpStatus status, String message, List<String> errors) {
super();
this.status = status;
this.message = message;
this.errors = errors;
}

public ApiError(HttpStatus status, String message, String error) {
super();
this.status = status;
this.message = message;
errors = Arrays.asList(error);
}
}
  • このエラークラスは共通的に使用するために作成しました。
  • status: HTTP status code
  • message: Exception内容を保存します。
  • error: エラーメッセージをリスト型に保存します。(カスタム)

RestControllerAdvice

@Slf4j
@org.springframework.web.bind.annotation.RestControllerAdvice
public class RestControllerAdvice extends ResponseEntityExceptionHandler {

@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex,
HttpHeaders headers,
HttpStatus status,
WebRequest request) {
List<String> errors = new ArrayList<String>();
for (FieldError error : ex.getBindingResult().getFieldErrors()) {
errors.add(error.getField() + ":" + error.getDefaultMessage());
}
for (ObjectError error : ex.getBindingResult().getGlobalErrors()) {
errors.add(error.getObjectName() + ":" + error.getDefaultMessage());
}

ApiError apiError =
new ApiError(HttpStatus.BAD_REQUEST, ex.getLocalizedMessage(), errors);
return handleExceptionInternal(
ex, apiError, headers, apiError.getStatus(), request);
}

}
  • コントローラでExceptionが発生したとき、共通処理を行うためのクラスです。
  • ResponseEntityExceptionHandlerを継承し、カスタムを行います。
  • handleMethodArgumentNotValidはバリデーションエラー発生時に実行されるメソッドです。

RestController

@RequiredArgsConstructor
@RestController
public class MemberApiController {

private final MemberService memberService;

@PostMapping("/api/v1/m")
public Long save(@RequestBody @Valid MemberSaveRequestDto requestDto) {
return memberService.save(requestDto);
}
}
  • サンプルコントローラーです。
  • @Validアノテーションを付与してバリデーションチェックを行われるように指定します。

messages.properties

E00001=システムエラーが発生しました。
E00002=未入力です。
  • resources配下に作成します。
  • エラーコードでメッセージを取得するために使用します。
  • 取得はMessageSourceがやってくれます。

MemberSaveRequestDto

@Getter
@NoArgsConstructor
public class MemberSaveRequestDto {

    @NotBlank(message = "{E00002}")
    private String email;
    private String name;
    private Long employmentType;
    private String enteredDate;
    private Long department;
    private Long position;
    private Long age;
    private Long sex;
    private Long nationality;

    @Builder
    public MemberSaveRequestDto(String email, String name, Long employmentType, String enteredDate, Long department, Long position, Long age, Long sex, Long nationality) {
        this.email = email;
        this.name = name;
        this.employmentType = employmentType;
        this.enteredDate = enteredDate;
        this.department = department;
        this.position = position;
        this.age = age;
        this.sex = sex;
        this.nationality = nationality;
    }
}
  • emailにバリデーションのアノテーションを付与します。
  • @NotBlank(message = “{E00002}”)を付与して「messages.properties」のコード名を指定します。

終わり

今回、フロント側の実装は扱っていないですが正常に表示されることが確認できました。

コメントを残す