Assert를 커스텀custom해보자
커스텀한 애노테이션을 통해 파라미터 검증하기을 통해 파라미터 검증하는 방법을 알아보았다. 하지만 이는 @RequestBody
이나 @ModelAttribute
에나 적용이 가능하기 때문에 Request로 들어오는 파라미터만 아닌 일반 파라미터에 대한 것도 파라미터 검증이 필요할 때가 있다.
이 때 AOP를 사용해도 되지만 너무 어렵다는 단점이 있다. 간단하게 파라미터 검증을 할 수 있는 방법이 있다.
바로 Assert
이다
1. 기본 Assert
Assert 스프링공식문서를 확인하거나 직접 코드를 import해서 확인해보면 기본의 Assert 사용법이 잘 나와있다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public abstract class Assert {
...
public static void isTrue(boolean expression, String message) {
if (!expression) {
throw new IllegalArgumentException(message);
}
}
...
}
Integer i = 0;
Assert.isTrue(i > 0, "The value must be greater than zero"); //실제사용코드
- 위 코드에서 6번째 라인을 보면
IllegalArgumentException
을 던지는 것을 확인할 수 있다. - 하지만
IllegalArgumentException
이 아니라 자기가 원하는 Exception을 던지고 싶을수 있다.
2. 기본 Assert 튜닝
2.1 원하는 Exception 던지기
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
32
33
34
35
36
public class CustomAssert extends Assert {
...
public static void notNull(@Nullable Object object, String message, final Class<? extends RuntimeException> exceptionClass) {
if (object == null) {
throw throwException(message, exceptionClass);
}
}
...
private static RuntimeException throwException(String message, final Class<? extends RuntimeException> exceptionClass) {
try {
return exceptionClass.getDeclaredConstructor( String.class ).newInstance( message );
} catch (Exception e) {
e.printStackTrace();
throw new AssertException("예외 처리 중 오류가 발생했습니다. "+e.getMessage());
}
}
}
public class ValidateKeyException extends RuntimeException{
public ValidateKeyException() {}
public ValidateKeyException(String message) {
super(message);
}
public ValidateKeyException(String message, Throwable cause) {
super(message, cause);
}
public ValidateKeyException(Throwable cause) {
super(cause);
}
}
2.2 다음과 같이 사용
1
2
3
4
5
6
7
8
9
10
11
@Transactional
public boolean verifyEmail(String key) {
//Redis를 이용하여 Key값의 Value값을 통해 사용자 메일 정보를 가져온다
RequestMail requestMail = redisService.getMailData(key,RequestMail.class);
// 유효한 Key가 아닐경우 email = null
CustomAssert.notNull(requestMail,"유효한 키가 아닙니다", ValidateKeyException.class);
...
}
- 여기서의 8번째줄의
ValidateKeyException
는 직접 만든 Exception이며 이 Exception은 RuntimeException을 상속받아야 한다 - 12번째의
AssertException
또한 직접 만든 Exception이다 throwException()
은ValidateKeyException
을 인스턴스화시켜준다
3. 심화
- 사용자의 ID 입력값을 확인하여 패턴에 맞는 ID가 들어오는지 검증해보자
- 패턴은 다음과 같다
[a-zA-Z0-9]{6,20}
- 영어나 숫자로만 6-20글자
3.1 CustomAssert
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
32
33
34
35
36
37
38
39
public class CustomAssert extends Assert {
private static final String NUM_ALPHA_PATTERN = "^[a-zA-Z0-9]{6,20}$";
public static void isLoginPattern(String object, String message) {
isMatched(object, NUM_ALPHA_PATTERN, message, PatternException.class);
}
public static void isMatched(String object, String pattern, String message, Class<PatternException> patternExceptionClass) {
if(object == null || "".equalsIgnoreCase(object)) return;
if(!object.matches(pattern)) {
throw throwException(message, patternExceptionClass);
}
}
private static RuntimeException throwException(String message, final Class<? extends RuntimeException> exceptionClass) {
try {
return exceptionClass.getDeclaredConstructor( String.class ).newInstance( message );
} catch (Exception e) {
e.printStackTrace();
throw new AssertException("예외 처리 중 오류가 발생했습니다. "+e.getMessage());
}
}
}
public class PatternException extends AccountStatusException {
public PatternException() {
super("패턴 오류");
}
public PatternException(String message) {
super(message);
}
public PatternException(String message, Throwable cause) {
super(message, cause);
}
}
- 27번째 라인의
PatternException
은AccountStatusException
을 상속한다 - 여기서는 Spring Security를 사용하기때문에
AccountStatusException
를 상속했지만 Spring Security을 사용하지않는 일반적인 경우에는RuntimeException
을 상속받는다public class PatternException extends RuntimeException {
- 패턴에 맞지않는 값이 들어올 경우 6번째 라인에 의해
PatternException
이 던져진다
3.2 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public UserDetails loadUserByUsername(String loginId) throws UsernameNotFoundException {
//파라미터 검증
CustomAssert.isLoginPattern(loginId, "아이디나 비밀번호 패턴이 맞지않습니다");
LoginUserDto loginUserDto = this.findUserByLoginId(loginId);
...
return member;
}
Spring
👉 Spring Security - Role (단일 권한, 복합 권한)
2022.11.10
👉 Spring Security를 이용한 로그인 처리
2022.10.31
👉 REST API - Exception을 통하여 HTTP Response 처리
2022.10.10
👉 Assert을 커스텀(custom)하여 파라미터 검증
2022.10.10
👉 애노테이션을 사용한 파라미터 검증
2022.10.09
👉 제네릭 기본 및 응용
2022.10.07
👉 DataSource와 ConnectionPool
2022.07.11
👉 JSP - EL 표현식에서 언제 오류 페이지가 나타날까
2022.05.27
👉 IoC와 DI컨테이너
2022.05.26
👉 DI(의존성 주입) 생성자 주입는 왜 필요한가
2022.05.25
👉 스프링을 왜 사용하는가
2022.05.23
👉 Servlet
2022.02.07
Java
👉 Spring Security - Role (단일 권한, 복합 권한)
2022.11.10
👉 Spring Security를 이용한 로그인 처리
2022.10.31
👉 REST API - Exception을 통하여 HTTP Response 처리
2022.10.10
👉 Assert을 커스텀(custom)하여 파라미터 검증
2022.10.10
👉 애노테이션을 사용한 파라미터 검증
2022.10.09
👉 제네릭 기본 및 응용
2022.10.07
👉 Refactoring
2022.08.16
👉 JSP - EL 표현식에서 언제 오류 페이지가 나타날까
2022.05.27
👉 IoC와 DI컨테이너
2022.05.26
👉 DI(의존성 주입) 생성자 주입는 왜 필요한가
2022.05.25
👉 스프링을 왜 사용하는가
2022.05.23
👉 Servlet
2022.02.07
댓글 쓰기