<< 학습 목표 >>

1. 500 에러 페이지가 보이는 원인을 찾을 수 있다.

2. 500 에러 페이지가 보이지 않도록 예외 처리를 할 수 있다.

3. 유효성 검증 코드를 작성 할 수 있다.


"열길 물 속은 알아도 한길 사람 속은 모른다" 라는 속담이 있음

여기서 길이란 옛날에 사용하던 길이의 단위로 열길 물 속은 매우 깊은 물 속을 뜻함

그에 비해 사람의 속은 상대적으로 얕지만 알 수 없다는 말

 

갑자기 이 말을 왜 하느냐

이제 우리는 클라이언트가 보낸 값을 서버가 꺼낼 수 있는데

클라이언트가 항상 값을 보낸다고 장담하면 안됨

 

지금 바로 네이버에 로그인을 해보자

일반적으로는 아이디, 비밀번호를 입력하고 로그인하겠지만

고의적으로든 아니면 어떤 실수로든 아이디 또는 비밀번호를 누락하고 로그인을 하려고 할 때도 있었을 것

 

뷰에서는 클라이언트에게 입력을 요구했지만 사용자는 입력하지 않았을 수 있음

서버에서도 이런 상황에 대한 대비가 필요함

이렇게 클라이언트가 값을 보내지 않았을 때를 위한 대비 하는 코드를 "유효성 검증(검사) / Validation" 이라고 함


다시 한번 지금까지 만들었던 계산기 웹 페이지를 만들자

webapp 폴더 안에 chatper03 폴더 안에 calculator.html 에 아래 코드를 입력하자

! 주의 ! 수를 입력하는 input 태그의 type속성이 text임

( form 태그의 method 속성은 GET, POST 둘 중 아무거나 상관 없음 )

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>계산기</title>
</head>
<body>
	<form action="http://localhost:8080/studyProject/chapter03/calculator" method="POST">
		<input type="text" name="firstNumber" placeholder="첫 번째 수">
		<select name="operator">
			<option>+</option>
			<option>-</option>
			<option>*</option>
			<option>/</option>
		</select>
		<input type="text" name="secondNumber" placeholder="두 번째 수">
		<input type="submit" value="결과 보기">
	</form>
</body>
</html>

 

클라이언트의 요청을 받을 서블릿을 추가하자

대신 계산을 하지는 않고 클라이언트가 보낸 값을 꺼내 변환 후 출력만 하고 있음

package chapter03;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/chapter03/calculator")
public class Calculator extends HttpServlet {
	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		int firstNumber = Integer.parseInt(request.getParameter("firstNumber"));
		int secondNumber = Integer.parseInt(request.getParameter("secondNumber"));
		String operator = request.getParameter("operator");
		
		System.out.println("첫 번째 수 => " + firstNumber);
		System.out.println("두 번째 수 => " + secondNumber);
		System.out.println("연산자 => " + operator);
	}

}

 

이제 웹 페이지를 열고 아무 값도 입력하지 않은 채로 [ 결과 보기 ] 를 눌러보자

그럼 이러한 페이지가 보임

 

이 페이지는 서블릿 또는 자바에서 예외가 발생했는데 예외 처리를 하지 않았을 때 보여지는 페이지임

앞으로는 이런 페이지가 보이면 이클립스로 돌아가 [ Console ] 패널을 보자

 

이클립스의 [ Console ] 패널에 예외 메세지가 보임

예외 메세지를 분석해 예외가 발생한 라인 번호와 이유를 찾아보자

 

14번째 줄에서 예외가 발생했고(1) 발생한 이유는 For input String: ""(2) 임

14번째 줄 소스 코드를 보자

예외가 발상한 코드는 14번 째 줄에 Integer.parseInt 메서드 때문에 발생함(1)

 

왜 Integer.parseInt 메서드에서 예외가 발생했는지 좀 더 분석해보면 request.getParameter 메서드로 firstNumber 파라미터의 값을 꺼냈는대 클라이언트가 뷰에서 해당 값을 입력하지 않았음

그래서 firstNumber 파라미터의 값이 비어있어 request.getParameter 메서드가 firstNumber 파라미터의 값을 ""(빈 문자열) 로 반환함(1)

Integer.parseInt 메서드는 숫자처럼 생긴 문자열만 정수로 바꿔줄 수 있음

빈 문자열은 숫자처럼 생긴 문자열이 아니므로 정수로 바꿀 수 없어 예외가 발생하는 것(2)

( 슬라이드 이미지이니 넘기면서 보세요 )

012

 

이와 같이 서버는 "클라이언트가 firstNumber 파라미터의 값을 보낼꺼다" 라는 가정으로 코드를 짰는데 클라이언트가 서버로 firstNumber 파라미터 값을 보내지 않았기 때문에 발생하는 예외임

이럴 때 하는게 뭐다? Validation ( 유효성 검증/검사 )

 

유효성 검증은 특별한게 없음

파라미터의 값을 꺼내서 서버가 원하는 형태의 값을 보냈는지 판단하는게 유효성 검증임

firstNumber 파라미터의 값을 꺼내서 유효성 검증을 하려면 예외가 발생했을 때 firstNumber 파라미터의 값이 어떤 값인지 알아야함

firstNumber 파라미터의 값이 어떤 값인지 알기 위해 이와 같이 다양한 방법을 시도해볼 수 있음

이 외에도 여러분만의 방법도 있을 것

 

서버를 재부팅(Restart) 하고 다시 웹 페이지에서 아무것도 입력하지 않고 [ 결과 보기 ] 를 눌러보자

결과창을 보면 첫 번째 결과는 아무것도 안보임(1) 두 번째 결과는 [] 안에 아무것도 안들어있음(2) 세 번째 결과는 0임

이를 통해서 request.getParameter 메서드로 꺼낸 firstNumber 파라미터의 값이 빈 문자열이라는걸 알 수 있음

 

이제 if문 또는 try ~ catch 문을 사용해서 예외 처리를 하면 됨

먼저 if문으로 예외 처리를 해보자

( doPost 메서드 안에 코드만 붙여 넣었음 )

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String firstNumber_string = request.getParameter("firstNumber");
		String secondNumber_string = request.getParameter("secondNumber");
		if(firstNumber_string.length() == 0) {
			System.out.println("firstNumber 파라미터의 값이 비어있습니다.");
		} else if(secondNumber_string.length() == 0) {
			System.out.println("secondNumber 파라미터의 값이 비어있습니다.");
		} else {
			int firstNumber = Integer.parseInt(request.getParameter("firstNumber"));
			int secondNumber = Integer.parseInt(request.getParameter("secondNumber"));
			String operator = request.getParameter("operator");
			
			System.out.println("첫 번째 수 => " + firstNumber);
			System.out.println("두 번째 수 => " + secondNumber);
			System.out.println("연산자 => " + operator);
		}
	}

 

firstNumber 파라미터 외에도 secondNumber 파라미터의 값도 빈 문자열 일 수 있으므로 두 파라미터의 값 모두 유효성 검증을 했음

두 파라미터의 값이 빈 문자열이 아니라면 else 로 빠져서 사용자가 입력한 값을 꺼내 정수로 변환하고 출력할 것

 

유효성 검증이 정상적으로 동작하는지 확인하자

서버를 재부팅(Restart) 하고

1. 웹 페이지에서 아무것도 입력하지 않고 [ 결과 보기 ] 를 눌러보자

2. 웹 페이지에서 첫 번째 수만 입력하고 [ 결과 보기 ] 를 눌러보자

3. 웹 페이지에서 첫 번째, 두 번째 수 모두 입력하고 [ 결과 보기 ] 를 눌러보자

이제 유효성 검증을 통해 500 에러 페이지가 보이지 않음

 

1, 2 번의 경우 유효성 검증에 걸려 "firstNumber 파라미터의 값이 비어있습니다."와 비슷한 메세지가 출력됨

3 번의 경우 유효성 검증을 통과해 else 로 빠져 사용자가 입력한 값을 출력함

1, 2번의 경우 처럼 유효성 검증을 통과하지 못한 상황을 "유효성 검증에 실패했다" 라고 함

3번의 경우 처럼 유효성 검증을 통과한 상황을 "유효성 검증에 성공했다" 라고 함

 

여기까지 유효성 검증 완료~!

이면 좋겠지만 유효성 검증은 생각만큼 쉽고 간단하지 않음

 

앞서 값을 보내지 않았을 때 500 에러 페이지가 보인 이유는?

서버는 "클라이언트가 firstNumber 파라미터의 값을 보낼꺼다" 라는 가정으로 코드를 짰는데 클라이언트가 서버로 firstNumber 파라미터 값을 보내지 않았기 때문에...

서버에서 또 다른 잘못된 가정을 하고 있음

무엇일까?

더보기

클라이언트가 첫 번째 수(firstNumber)와 두 번째 수(secondNumber)로 정수를 입력할 것이다


웹 페이지를 만들 때 input 태그의 type 속성을 text로 한 이유가 있음

첫 번째 수를 입력하는 input 태그의 type 속성이 text 이므로 사용자는 정수가 아닌 실수값을 입력할 수도 있고 문자열을 입력할 수도 있음

"에이 너무 억지아니야?" 라고 생각할 수 있겠지만 세상에는 생각보다 다른 생각을 가진 사람들이 많음

이렇게 정수가 아닌 값을 입력하고 [ 결과 보기 ] 버튼을 눌러보자

역시나 예외가 발생해 500 에러 페이지가 보임

if문으로 예외 처리하지 않았기 때문에...

 

이를 어떻게 해결할까?

여러분이 먼저 직접 해결해보기

더보기

전달 받은 firstNumber, secondNumber 파라미터 값의 각 자리 값을 chatAt 메서드로 꺼내 숫자가 아니라면 "유효성 검증 실패", 마지막 자리 값까지 모두 숫자였다면 "유효성 검증 성공"

 

이제는 점점 코드가 복잡해지므로 유효성을 검증할 메서드가 필요함

다음과 같이 chapter03 패키지에 어떤 문자열이 숫자인지 판단하는 메서드 추가

isNumeric 은 "숫자인가요?" 라고 번역할 수 있음

이 메서드가 true를 반환하면 어떤 문자열은 정수처럼 생긴 문자열임

이 메서드가 false를 반환하면 어떤 문자열이 정수처럼 생기지 않은 문자열임

 

package chapter03;

public class Validation {
	public boolean isNumeric(String str) {
		boolean isNumeric = false;
		
		if(str.length() != 0) {
			for(int i=0; i<str.length(); i++) {
				char nthNumber = str.charAt(i);
				
				if(nthNumber < '0' || nthNumber > '9') {
					isNumeric = false;
					break;
				}
			}
		}
		
		return isNumeric;
	}
}

 

그리고 서블릿에서는 다음과 같이 Validation 을 사용해 유효성 검증을 하는 코드로 바꾸자

( 서블릿의 doPost 메서드만 옮김 )

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		Validation v = new Validation();

		if(!v.isNumeric(request.getParameter("firstNumber"))) {
			System.out.println("firstNumber 파라미터의 값이 올바르지 않습니다.");
		} else if(!v.isNumeric(request.getParameter("secondNumber"))) {
			System.out.println("secondNumber 파라미터의 값이 올바르지 않습니다.");
		} else {
			int firstNumber = Integer.parseInt(request.getParameter("firstNumber"));
			int secondNumber = Integer.parseInt(request.getParameter("secondNumber"));
			String operator = request.getParameter("operator");
			
			System.out.println("첫 번째 수 => " + firstNumber);
			System.out.println("두 번째 수 => " + secondNumber);
			System.out.println("연산자 => " + operator);
		}
	}

 

유효성 검증은 if문을 사용해야할까? 아님 try ~ catch 를 사용해도됨

또한 이외에 유효성 검증이 더 필요할까?

그건 여러분의 몫 ~~

728x90
LIST