데이터 유효성체크에 대해서 알아보자.
데이터를 실제로 처리하기전에 해당 데이터가 처리할 수 있는 정상적인 데이터인지 대해서 우선 체크하는 것.
그리고 보통 좋은 서비스를 개발하는 개발자는 항상 데이터를 처리하는 서비스 로직을 작성하기전에 처리해야할 데이터의 유효성을 어떻게 체크하고 예외처리 할 것 인지에 대한 고민을 한다.
만약 유효성체크에 대한 고민이 없이 프로그램을 작성하다보면, 비정상적인 데이터를 처리하다가 프로세스가 다운되는 개발자로서 가슴아픈(?) 상황을 맞이하기도 한다. -_-;
그리고 디버거를 통해서 왜 프로세스가 다운되었는지 파악을 해야하고,
파악 되면, 소스코드를 그제서야 보완하게된다.
제가 말씀드리고 싶은 결론은 항상 개발을 할 때, 처리해야할 데이터에 대한 유효성에 대해서 고민하는 습관을 들이고, 유비무환하면 좋지 않을까?
암튼, 내가 사랑하는(?) 내가 직접 개발한, 나의 코드가 비정상적인 행동을 하지 않도록,
참고) 유비무환(有備無患)
미리 준비해 두면 근심 될 것이 없음.
즉, 유비무환의 한자구성으로는 있을 유(有) 갖출 비(備) 없을 무(無) 근심 환(換) 이며 직역을 하게 되면 갖춘 것이 있다면 근심은 없다라는 말. ^^
유비무환의 유례는 ?
유비무환은 서경(書經)의 열명(說命)편에서 유래되었는데 열명(說命)은 은(殷)나라의 고종(高宗)이 부열(傅說)이라는 재상(宰相)을 얻게되는 경위와 부열의 정사(政事)를 하는 내용을 기록한 글.
여기에서 처음으로 나왔다고 알려져 있음.
處善以動 動有厥時 矜其能 喪厥功 惟事事 及其有備 有備無患(처선이동 동유궐시 긍기능 상궐공 유사사 급기유비 유비무환)
생각이 옳으면 이를 행동으로 옮기게 되고,
그 옮기는 것이 시기에 맞게하며 그 능한 것을 자랑하게 되면,
그 공을 잃게 되고 모든 일은 다 갖춘 것이있는 법이니,
갖춘 것만 있어야 근심이 없어지게 될 것이다 라는 뜻.
암튼 다시, 본론으로 들어가면,
예를 들어, 아래와 같은 데이터 유효성 체크가 가능하다.
사용자 필드가 비어 있지는 않은지?
데이터 값이 지정된 범위내에서 작거나 큰지?
데이터의 크기가 지정된 범위내에서 있는지?
기타 등등
그럼, Spring 에서 지원하는 Bean 벨리데이션 API 를 알아보자.
참조 구현을 사용해, 서비스에서 유효성체크를 구현함.
즉, Bean 벨리데이션 API는 Bean을 유효화 하는데 사용될 수 있는 여러가지 어노테이션을 제공함.
JSR-349 에서는 Bean 벨리테이션 API 1.1을 정의함.
아래 2가지 모두 spring-boot-starter-web 프로젝트의 의존성으로 정의됨.
hibernate-validator-5.2.4.Final.jar
validation-api-1.1.0.Final.jar
그리고, hibernate-validator는 참조 구현체임.
그럼, 벨리데이션을 만드는 단계를 알아보자.
하나, Controller 메소드에 벨리데이션 사용
둘, Bean 에 벨리데이션 추가.
그럼, Bean을 검증하는데 사용할 수 있는 주요 어노테이션에 대해서 알아보자.
@Size
어노테이션 요소 크기는 지정된 범위내에 있어어 함.
@NotNull
어노테이션이 달린 요소는 null일 수 없음.
@Max
어노테이션이 달린 요소는 값이 지정된 최대값보다 작거나 같은 숫자여야함.
@Min
어노테이션이 달린 요소는 값이 지정된 최소값보다 크거나 같은 숫자여야함.
@Pattern
어노테이션된 {@code CharSequence} 요소는 지정된 정규 표현식과 일치해야 함.
정규표현식은 JAVA 정규표현식 규칙을 따름.
@Past
어노테이션이 달린 요소는 과거의 날짜여야 함.
@Future
어노테이션이 달린 요소는 미래의 날짜여야 함.
@AssertFalse / @AssertTrue
Boolean 요소, 어노테이션이 달린 요소를 체크함.
즉, 거짓인지? 참인지?
그럼, 간단한 샘플프로그램을 작성해보자.
하나, pom.xml 에 아래 의존성을 추가한다.
둘,Controller 메소드에 밸리테이션을 사용해보자.
package com.example.rest.demo.controller;
import com.example.rest.demo.bean.ThubUser;
import com.example.rest.demo.exception.ThubUserNotFoundException;
import com.example.rest.demo.service.ThubUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.server.mvc.ControllerLinkBuilder;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@RestController
public class ThubUserController {
private final static int ZERO = 0;
@Autowired
private ThubUserService thubUserService;
@GetMapping("/thubusers/{nickname}")
public ThubUser retrieveThubUser(@PathVariable String nickname) {
ThubUser thubUser = thubUserService.retrieveThubUser(nickname);
if(thubUser == null) {
throw new ThubUserNotFoundException("User not found!");
}
return thubUser;
}
@GetMapping("/thubusers/rank/{rank}")
public EntityModel<ThubUser> retrieveThubUserResource(@PathVariable int rank){
ThubUser thubUser = thubUserService.retrieveThubUserRank(rank);
if(thubUser == null) {
throw new ThubUserNotFoundException("User not found!");
}
EntityModel<ThubUser> thubUserResource = new EntityModel<ThubUser>(thubUser);
ControllerLinkBuilder linkTo = ControllerLinkBuilder.linkTo(ControllerLinkBuilder.methodOn(this.getClass()).retrieveThubUser(thubUser.getNickname()));
thubUserResource.add(linkTo.withRel("parent"));
return thubUserResource;
}
@PostMapping("/thubusers")
public ResponseEntity<?> addThubUser(@Valid @RequestBody ThubUser thubUser, BindingResult bindingResult) {
if(bindingResult.hasErrors()) {
String errorMessage = bindingResult.getAllErrors().get(ZERO).getDefaultMessage();
return new ResponseEntity<>(errorMessage, HttpStatus.BAD_REQUEST);
}
ThubUser thubuser = thubUserService.addThubUser(thubUser.getNickname(), thubUser.getRank());
return new ResponseEntity<>(thubUser, HttpStatus.OK);
}
}
설명
ThubUserController에 @PostMapping 으로 addThubUser 메소드를 추가함.
그리고, 해당 메소드에 @Valid 어노테이션을 추가함.
셋, Bean 벨리데이션을 정의해보자.
package com.example.rest.demo.bean;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class ThubUser {
@NotNull(message = "nickname is null")
@Size(max = 10, message = "invalid nickname size(max 10)")
private String nickname;
@Min(value=1, message="Invalid rank value, min value is 1")
private int rank;
public ThubUser(String nickname, int rank) {
this.nickname = nickname;
this.rank = rank;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public int getRank() {
return rank;
}
public void setRank(int rank) {
this.rank = rank;
}
}
설명
nickname 에 대한 유효성 체크 추가
@NotNull(message = "nickname is null")
nickname 이 null 이면, "nickname is null" 이라는 에러메시지 세팅.
@Size(max = 10, message = "invalid nickname size(max 10)")
nickname 의 size 가 10 보다 크면, "invalid nickname size(max 10)" 이라는 에러메시지 세팅
rank 에 대한 유효성 체크 추가
@Min(value=1, message="Invalid rank value, min value is 1")
rank 가 1 보다 작으면, "Invalid rank value, min value is 1" 이라는 에러메시지 세팅
그럼, 서버를 구동해보자.
그럼, Postman을 사용해서 정상적으로 동작하는지 확인해보자..^^
테스트 케이스
case1) nickname 이 null 인 경우
설명
에러응답값을 아래와 같이 확인 할 수 있음.
응답코드값으로 400 Bad Request
body 에 "nickname is null" 에러 메시지
case2) nickname 의 size 가 10 보다 큰 경우
설명
에러응답값을 아래와 같이 확인 할 수 있음.
응답코드값으로 400 Bad Request
body 에 "invalid nickname size(max 10)" 에러 메시지
case3) rank 가 1보다 작은 경우
설명
에러응답값을 아래와 같이 확인 할 수 있음.
응답코드값으로 400 Bad Request
body 에 "invalid rank value, min value is 1" 에러 메시지
case4) 정상일 경우
설명
아래와 같이 정상응답을 확인할 수 있음.
응답코드값으로 200 OK
body 에는 추가한 데이터 반환
결론
데이터 유효성체크란?
데이터를 실제로 처리하기전에 해당 데이터가 처리할 수 있는 정상적인 데이터인지 대해서 우선 체크하는 것.
Spring 에서 지원하는 Bean 벨리데이션 API 는 참조 구현을 사용해, 서비스에서 유효성체크를 구현함.
즉, Bean 벨리데이션 API는 Bean을 유효화 하는데 사용될 수 있는 여러가지 어노테이션을 제공함.
JSR-349 에서는 Bean 벨리테이션 API 1.1을 정의함.
아래 2가지 모두 spring-boot-starter-web 프로젝트의 의존성으로 정의됨.
hibernate-validator-5.2.4.Final.jar
validation-api-1.1.0.Final.jar
그리고, hibernate-validator는 참조 구현체임.
Bean 벨리데이션을 사용하면, 손쉽게 데이터 유효성 체크를 할 수 있음.
오늘도 Spring 관련 데이터 유효성체크에 대한 지식 마술(?) 한가지 획득완료! 감사합니다.
오늘의 명언 한마디
과거의 실수나 잘못, 짜증나는 일을 몇번이고 떠올린다고 무엇 하나 바꿀 수 없으니 과거에 얽매일 필요 없다.
과거에 얽매여 사는 인생은 뒤를 보고 가는 인생이다.
여러분 중에는 자전거를 타거나 자동차를 운전하는 사람도 있을 것이다.
그 때 뒤를 보고 타는 사람은 없다. 앞을 보고 탄다.
뒤를 보고 타거나 계속 뒤만 보고 있으면 앞으로 나아갈 수 없다.
미즈모토 카즈야, "자꾸만 떠오르는 괴로운 과거와 헤어지는법" 중에서..
오늘의 영어 한마디
What do you do to keep in shape?
무엇을 당신은 / 하니 / 유지하려고 / 건강한 상태로
설명
"What do you do ~" 는 무엇을 하는지를 물어보는 의무문.
"keep in shape" 는 건강한 상태로 유지하는 것을 의미함.
오늘의 민법 한마디
제1편 총칙 / 제5장 법률행위 / 제4절 무효와 취소
제139조(무효행위의 추인)
무효인 법률행위는 추인하여도 그 효력이 생기지 아니한다.
그러나 당사자가 그 무효임을 알고 추인한 때에는 새로운 법률행위로 본다.
나의 목표 및 다짐을 항상 내곁에 두기.
목표
나의 강점을 바탕으로 나의 일을 잘해냄으로써 타인과 사회를 아릅답게 만든다.
현재 내가 가진 능력으로 누군가에 도움이 될 수 있을까? 에 대해서 항상 생각하기
목표를 이루기 위한 실천방안
꾸준한 블로깅/기록법/독서법으로 넘버원이 아닌 온리원이 되보자.
천사불여일행(千思不如一行)을 항상생각하며 체화 및 각인시키자.
"천번 생각하는것보다 한번 행동하는 것이 더 중요하다."
기기일약 불능십보(騏驥一躍 不能十步) / 노마십가 공재불사(駑馬十駕 功在不舍)
천리마도 한번에 열걸음을 뛸 수 없고, 느리고 둔한말이라도 열흘이면 하룻길을 간다.
'좋아하는 것_매직IT > 1.spring' 카테고리의 다른 글
31.Spring, 스프링 시큐리티(기본인증)에 대해서 알아보자. (1/2) (0) | 2021.02.06 |
---|---|
30.Spring, 서비스의 문서화에 대한 필요성을 알아보고 간단한 샘플프로그램을 만들어 보자. (0) | 2021.02.06 |
28.Spring, HATEOAS에 대해서 알아보고 간단한 샘플 프로그램을 만들어보자. (0) | 2021.02.06 |
27.Spring, 예외처리(Exception)에 대해서 알아보고 간단한 샘플 프로그램을 만들어보자. (0) | 2021.02.06 |
26.Spring, REST(Representational State Transfer)에 대해서 알아보고 간단한 샘플 프로그램을 만들어보자. (0) | 2021.02.06 |