Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

DOing

[Spring] Request를 어떻게 검증할 것인가? 본문

Spring

[Spring] Request를 어떻게 검증할 것인가?

mangdo 2021. 9. 13. 01:57

이전 프로젝트에서는 Request로 오는 객체를 모두 Service단에서 검증했었다.

그러다보니 Service단이 너무 뚱뚱해지는 기분이 들었다. Service단은 핵심 비지니스 로직에만 집중할 수 있게 만들어야한다고 생각하며 다른 방법을 알아보던 중 Bean validation이라는 것을 알게되었다.

 


🌱 Bean validation

Bean validation은 클래스의 필드에 annotation을 이용하여 필드가 갖는 제약 조건을 정의하는 구조로 이루어진 검사다.

validator가 그 클래스로 생성된 객체의 유효성 여부를 확인한다.

어떠한 비즈니스적 로직에 대한 검증이 아닌, 객체 자체의 필드에 대한 검증을 한다.

 

 

🌱 build.gradle에 의존성 추가

    // Spring Boot Bean Validation
    implementation("org.springframework.boot:spring-boot-starter-validation")

 

 

🌱 RequestDto에서 validation 

 어노테이션을 이용해서 validation을 해준다.

 어떤 어노테이션이 있는지는 공식 문서를 확인하면 된다.

 (https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#section-builtin-constraints)

package com.example.highlightbackend.dto.highlight.request;

import lombok.Getter;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Getter
public class HighlightCreateRequestDto {

    // 유저의 ID
    @NotNull(message = "userId 는 필수 값입니다.")
    Long userId;

    // 하이라이트한 문장이 있는 페이지의 URL
    @NotBlank(message="pageUrl 는 필수 값입니다.")
    String pageUrl;

    // 하이라이트한 색상값
    @NotBlank(message="colorHex 는 필수 값입니다.")
    String colorHex;

    // 하이라이트한 문장
    @NotBlank(message="text 는 필수 값입니다.")
    @Size(max=10, message = "text 는 최대 10자까지 지원합니다")
    String text;

}

 

🌱 에러 반환

현재 과정까지만 해준다면 다음과 같은 에러가 출력된다.

postman 결과

콘솔 창에서는 에러 로그가 다음과 같이 출력된다.

2021-09-13 01:42:09.542  WARN 11424 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: 
  Validation failed for argument [0] in public com.example.highlightbackend.dto.highlight.response.HighlightCreateResponseDto 
  com.example.highlightbackend.controller.HighlightController.createHighlight(com.example.highlightbackend.dto.highlight.request.HighlightCreateRequestDto): 
  [Field error in object 'highlightCreateRequestDto' on field 'text': rejected value [일이삼사오육칠팔구십일];
  codes [Size.highlightCreateRequestDto.text,Size.text,Size.java.lang.String,Size]; 
  arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [highlightCreateRequestDto.text,text]; 
  arguments []; 
  default message [text],10,0]; 
  default message [text 는 최대 6000자까지 지원합니다]]]

 이를 보았을 때 validation을 어기면 400 HTTP status가 반환되며, MethodArgumentNotValidException라는 에러가 발생하는 것을 알 수 있다.

 

 

🌱 예외처리

: 예외에 관련되어서 원하는 응답 형태로 주고 싶다면, ExceptionHandler를 만들어 처리해주면된다.

 

예외처리하여 원하는 반환 응답으로

[ ApiException.java ]

package com.example.highlightbackend.exception;

import lombok.Builder;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
public class ApiException {

    private final String message;
    private final HttpStatus httpStatus;

    @Builder
    public ApiException(String message, HttpStatus httpStatus){
        this.message = message;
        this.httpStatus = httpStatus;
    }
}

 

[ ApiException.java ]

package com.example.highlightbackend.exception;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class ApiExceptionHandler {
    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    public ResponseEntity<Object> handle(MethodArgumentNotValidException ex) {
        
        ApiException apiException = ApiException.builder()
                .httpStatus(HttpStatus.BAD_REQUEST)
                .message(ex.getFieldErrors().get(0).getDefaultMessage())
                .build();

        return new ResponseEntity<>(apiException, HttpStatus.BAD_REQUEST);
    }
}

 

 

 


 

🌱 @RequestPram와 @PathVariable에서 validation

더보기

아직 조금 불확실!!!

수정중!

@Validated
@RestController
public class TestRestController {

	@GetMapping(value = "/test")
	public String search(
			@Min(1) @RequestParam(value = "number") int number,
			@Range(min = 1, max = 10) @RequestParam(value = "keyword") String keyword) {
            
		// number는 최소 1이상
		// keyword는 글자수 1~10 사이
		return "number: "+number+" keyword: "+keyword;
	}
    
    @GetMapping(value = "/test/{number}")
	public String getProduct(@Min(1) @PathVariable("number") int number) {
		// number 최소 1이상
		return "number : "+ number;
	}
}

 

 

참고 사이트:

https://meetup.toast.com/posts/223

https://jeong-pro.tistory.com/203

https://kafcamus.tistory.com/10

'Spring' 카테고리의 다른 글

[Spring] Spring Data JPA 이해하기 (feat ORM, JPA)  (0) 2021.07.04
테스트의 중요성과 종류  (0) 2021.07.03
[Spring] POJO란?  (1) 2021.05.29
[Spring] Spring Framework의 정의와 목적  (0) 2021.05.29
Domain, Entity, Value(Object)  (3) 2021.05.27