[백업][가리사니] 스프링 컨트롤러와 파라미터 : 2. 파라미터 밸리데이션
java, spring

이 문서는 가리사니 개발자 포럼에 올렸던 글의 백업 파일입니다. 오래된 문서가 많아 현재 상황과 맞지 않을 수 있습니다.

스프링 컨트롤러와 파라미터 시리즈

서론

이전 장에서는 컨트롤러에서 파라미터를 받는 방법에 대해서 강의하였습니다. 이번 장에서는 받은 파라미터에 대한 밸리데이션에 대해서 강의 해보도록 하겠습니다.

자바 스펙에는 아래와 같은 기본 밸리데이션 셋이 존재합니다. [http://docs.oracle.com/javaee/7/api/javax/validation/constraints/package-summary.html 위 밸리데이션 중 몇가지만 정리하면 아래와 같습니다.

  • 설명이 간단하니 직접 링크를 보시는 것도 좋습니다. AssertFalse : 거짓인 경우만 통과 AssertTrue : 참인 경우만 통과 Future : 미래날짜인 경우만 통과 Past : 과거날짜인 경우만 통과 Pattern : 해당 패턴 내에서만 통과 Null : null 인 경우만 통과 NotNull : null 이 아닌 경우에만 통과 NotNull.List : 리스트 전체가 null 이 아닌 경우에만 통과 Size : 스트링의 사이즈 조건이 일치할 때 통과. Min : 숫자 형태의 최소 min 이상 [텍스트에서도 숫자로 치환하여 연산] Max : 숫자 형태의 최소 max 이상 [텍스트에서도 숫자로 치환하여 연산]

@RequestParam를 통한 밸리데이션

@RestController
class TempController
{
	@GetMapping("/temp")
	String temp(@RequestParam(value="p1") @NotNull String p1)
	{
		return "통과";
	}
}

결과 : /temp

  • 오류 : p1 이 null 임 결과 : /temp?p1=abcde 통과
@GetMapping("/temp")
String temp(@RequestParam(value="p1") @Valid @Pattern(regexp="[a-z]{3}") String p1)
{
	return "통과";
}

결과 : /temp?p1=aa 통과

  • 오류 나야하지 않나?? @Valid를 줘야하나?
@GetMapping("/temp")
String temp(@RequestParam(value="p1") @Valid @NotNull @Pattern(regexp="[a-z]{3}") String p1)
{
	return "통과";
}

결과 : /temp?p1=aa 통과

  • 그렇습니다. RequestParam 에서는 @NotNull 는 사용할 수 있으나 @Pattern 을 사용할 수 없습니다.
  • 심지어 @NotNull 보단 아래 방법이 더 나을 겁니다.
String temp(@RequestParam(value="p1", required=true) String p1)

그럼 모델을 가지고 해보도록 하겠습니다.

모델 클래스를 통한 밸리데이션

@RestController
class TempController
{
	@GetMapping("/temp")
	String temp(@Valid Abc abc)
	{
		return "통과 : " + p1;
	}

	@Data
	@ToString @Getter @Setter
	static public class Abc {
		@NotNull
		@Pattern(regexp = "[a-z]{3}")
		String p1 = "default";
	}
}

결과 : /temp

  • 오류 : p1 이 null 임 결과 : /temp?p1=Daa
  • 오류 : p1 이 영문소문자3자("[a-z]{3}") 가 아니다. 결과 : /temp?p1=try 통과 : try

그렇다면 파라미터를 체크하는 것인가? 또한 다중 조건들이 될 것인가?

@RestController
class TempController
{
	@GetMapping("/temp")
	String temp(@Valid Abc abc)
	{
		return "통과 : " + abc.getP1();
	}

	@Data @ToString @Getter @Setter
	static public class Abc {
		@NotNull @Size(min=1, max=10)
		String p1 = "default";

		@Min(1) @Max(100)
		int p2 = 1;
	}
}

결과 : /temp 통과 : TempController.Abc(p1=default, p2=1) 파라미터를 체크하는 것이 아닌 모델을 체크하는 것 입니다.!!! 즉, 아무런 인자를 넣지 않았지만 모델이 조건에 맞으니 통과합니다. 결과 : /temp?p1=AbcdeAbcdea

  • 오류 : p1의 길이가 10자를 넘어갑니다. 결과 : /temp?p1=AbcdeAbc&p2=32 통과 : TempController.Abc(p1=AbcdeAbc, p2=32)
@Data @ToString @Getter @Setter
static public class Abc {
	@NotNull @Min(1) @Max(100)
	String p1;

	@Min(1) @Max(100)
	int p2 = 1;
}

결과 : /temp

  • 오류 : p1 이 null 입니다. 결과 : /temp?p1=a
  • 오류 : @Min(1) @Max(100) 조건으로 p1은 숫자 형태여야합니다. 결과 : /temp?p1=33 통과 : TempController.Abc(p1=33, p2=1)
  • 스트링으로 받아야하지만 숫자로 검증할 때 유용합니다.

PathVariable

  • 앞 장에서도 설명됬지만 PathVariable 은 새로운 형태에 다른 플로우를 타는 것이 아닌 표현방식이 다른것 입니다.
  • 즉, 사용법은 같습니다.
@RestController
class TempController
{
	@GetMapping("/temp/{p1}")
	String temp(@Valid Abc abc)
	{
		return "통과 : " + abc.toString();
	}

	@Data @ToString @Getter @Setter
	static public class Abc {
		@NotNull @Min(1) @Max(1000)
		String p1;
	}
}

결과 : /temp/a

  • 오류 : @Min(1) @Max(1000) 조건으로 오직 숫자 형태로 넘겨야합니다. 결과 : /temp/23231
  • 오류 : 범위를 초과합니다. 결과 : /temp/23 통과 : TempController.Abc(p1=23)

기타 : 날짜

  • 날짜 같은경우는 입력 포멧을 설정해 주어야 합니다.
@RestController
class TempController
{
	@GetMapping("/temp")
	String temp(@Valid Abc abc)
	{
		return "통과 : " + abc.toString();
	}

	@Data @ToString @Getter @Setter
	static public class Abc {
		@NotNull
		@Future
		@DateTimeFormat(pattern = "yyyyMMdd")
		Date date;
	}
}

결과 [작성일로부터 과거날짜] : /temp?date=20001122

  • 오류 결과 [작성일로부터 미래날짜] : /temp?date=20171122 통과 : TempController.Abc(date=Wed Nov 22 00:00:00 KST 2017)

추신

  • null이 있는 조것들은 @NotNull 을 주지 않으면 조건에 맞지 않더라도 통과됩니다.!!