JSP/서블릿 흝어 보기

예외 처리

서블릿에서 고려할 수 있는 오류 처리방법으로 다음의 방법들이 있다.

  • 실행코드를 try-catch 블록으로 구성한다.
  • 메소드 선언부에 throws 절을 선언한다.
  • 강제로 예외를 발생시키기
  • 사용자 예외를 생성하여 처리
  • web.xml에 오류 처리 설정을 한다.

우선 다음의 코드를 작성해 보자. 이 코드는 몇가지 문제가 존재한다.

ErrorTestServlet.java

package job.study.web;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class ErrorTestServlet
 */
@WebServlet("/errorTest")
public class ErrorTestServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public ErrorTestServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @throws IOException 
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
	throws IOException {
		// TODO Auto-generated method stub
		response.setContentType("text/html; charset=UTF-8");
		PrintWriter out = response.getWriter();
		
		String getquery = request.getQueryString();
		
		try {
			out.println("Query : " + getquery + "<br>");
			out.println("Query길이 : " + getquery.length() + "<br>");
			out.println("Done!");
		} catch(NullPointerException e) {
			out.println("요청을 처리하는 동안 오류가 발생하였습니다 : "+e);
		}
		
		out.close();
		
	}


}

첫번째 문제는 이클립스에서 이 코드를 보면 다음과 같은 getWriter( ) 메소드에 대해서 "Unhandled exception type IOException"이라는 메시지가 나타난다. 그 이유는 getWriter( ) 메소드 호출시 getWriter( ) 메소드 내부에서 발생 가능성이 이는 IOException 예외처리를 메소드 내부에서 처리하지 않고 getWriter( ) 메소드를 호출하는 곳에서 처리하도록 자체에서 throws 절을 정의하고 있기 때문이다. 

이에 대해 이클립스에서 두가지 방법을 권고하고 있다.

 

  • doGet( ) 메소드에 throws 절을 선언하는 것,
  • 또는 해당하는 코드를 try-catch 블록으로 감싸는 것이다.

 

doGet( )에 throws 절을 선언하자

IOException에 대한 예외처리를 아래처럼 doGet( ) 메소드에 IOException을 throws하는 정의를 추가해보자 그럼 권고와 관련된 메시지가 사라진 것을 알 수 있다. 편집기에서는 더이상 문제가 발생할 부분은 보이지 않는다. doPost( ) 메소드를 사용한다면 이 경우에도 마찬가지로 throws 절 선언이 가능하다.

주의할 것은! 재정의한 메소드라면 선언부를 변경할 수 없어서 원래 메소드에서 선언하고 있는 Exception 외에는 추가로 선언할 수 없습니다. 이럴 때는 반드시 try-catch 문으로 오류 처리를 구현해 주어야 한다.

    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
    throws IOException {
		// TODO Auto-generated method stub
		response.setContentType("text/html; charset=UTF-8");
		PrintWriter out = response.getWriter();
		
		String getquery = request.getQueryString();
		out.println("Query : " + getquery + "<br>");
		out.println("Query길이 : " + getquery.length() + "<br>");
		out.println("Done!");
		
		out.close();
		
	}

그렇지만 아직 문제가 있다. 일단 실행 결과를 보자.

실행 중 NullPointerException 예외 오류가 발생하는 것을 확인할 수 있다.

그이유는 코드를 살펴보면 GET으로 전달된 질의 문자열(QueryString)의 문자열 길이를 구하는 메소드를 실행하고 있다. 여기에 두번째 문제가 있다. ErrorTestServlet에 접근할 때 전달된 질의 문자열이 없으므로 getQueryString( ) 메소드의 리턴값은 null이다.

그리고 이 null을 참조하여 문자열의 길이를 구하려 하는데, 이때 JVM에 의해 NullPointerException 이 생성되며, JVM은 오류에 대응하는 코드가 구현되어 있는지 검사합니다. 만일 오류 처리가 구현되어 있지 않다면 실행 중이던 프로그램을 강제로 중단합니다. 앞에서의 실행 결과에서 프로그램이 강제로 중단된 모습을 확인할 수 있습니다.

try-catch 를 이용해 오류를 처리해보자

try-catch는 오류가 발생했을 때 프로그램 실행이 강제로 중단되지 않도록, 프로그램 내에서 발생한 오류를 적적하게 처리할 수 있게 해준다.

가장 명심해야 할 것은 서블릿을 벗어나면 우리가 이 예외처리의 흐름을 제어하여 에러를 적절하게 처리 수 있는 곳이 없다. 또는 진입부를 작성하는 코드 역시나 이를 벗어나면 예외를 처리할 수 있는 곳이 없다. 이러한 곳을 최후의 보류라 볼 수 있다. 그렇기 떄문에 이런 경우는내부에서 처리할 수 밖에 없다. 

그럼 위의 코드에서 try-catch를 이용해 doGet( ) 메소드 내부에서 NullPointerException 처리할 수 있도록 보완해보자.

ErrorTestServlet.java

다음의 코드에서는 NullPointerException이 발생하면 이를 try-catch 문으로 내부에서 처리하고 있다. 이때 catch 문 순서대로 발생한 오류 객체와 일치하는 타입의 변수를 살펴봅니다. 

protected void doGet(HttpServletRequest request, HttpServletResponse response) 
    throws IOException {
		// TODO Auto-generated method stub
		response.setContentType("text/html; charset=UTF-8");
		PrintWriter out = response.getWriter();
		
		String getquery = request.getQueryString();
		
		try {
			out.println("Query : " + getquery + "<br>");
			out.println("Query길이 : " + getquery.length() + "<br>");
			out.println("Done!");
		}catch(NullPointerException e) {
			out.println("전달된 질의문자열이 없습니다. : "+e);
		}catch(Exception e) {
			//catch문은 처음 부터 검색하여 예외가 일치하는 catch문의 블록을 실행한다.
		}finally {
			//try-catch 문을 끝마치면 반드시 실행딘다.
			
		}
				
		out.close();
	}

실행결과

catch문을 작성할 때 주의할 것은 Exception은 모든 예외 객체의 최상의 객체이므로 일치하는 타입의 catch문이 없을 경우 Exception 타입으로 선언된 catch문이 동작하게 끔 마지막에 정의해줍니다.

그렇지 않으면 다음의 그림처럼 Exception 객체 이후의 예외 catch문에 도달할 수 없다고 표시되면서 에러가 발생합니다.

사용자 예외 클래스를 작성하고 강제로 예외를 발생시켜보자.

이번에는 사용자 예외를 생성하고 전달된 질의문자열이 없을 때 getQueryString( )메소드의 값이 null인 경우 강제로 사용자 예외를 발생시키도록 해보자

사용자 예외 클래스 생성하기 - QueryStringNullException.java

package job.study.web;

public class QueryStringNullException extends ServletException {

    public QueryStringNullException() {
		// TODO Auto-generated constructor stub
		super("전달된 질의 문자열이 없습니다.");
	}
}

ErrorTestServlet.java

doGet( ) 메소드에서 질의문자열 값이 null이면 를 예외강제로 발생하도록 수정한다.

    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
	throws IOException {
		// TODO Auto-generated method stub
		response.setContentType("text/html; charset=UTF-8");
		PrintWriter out = response.getWriter();
		
		String getquery = request.getQueryString();
		
		try {
			out.println("Query : " + getquery + "<br>");
			
			//질의문자열 값이 null이면 사용자예외를 강제로 발생시킨다.
			if(getquery==null ) throw new QueryStringNullException();
				
			out.println("Query길이 : " + getquery.length() + "<br>");
			out.println("Done!");
		}catch(QueryStringNullException e) {
			out.println("요청을 처리하는 동안 오류가 발생하였습니다 : <br/>");
			out.println(e);
		}catch(Exception e) {
			//catch문은 처음 부터 검색하여 예외가 일치하는 catch문의 블록을 실행한다.
		}finally {
			//try-catch 문을 끝마치면 반드시 실행딘다.
			
		}
				
		out.close();
	}

실행결과 

마지막으로, web.xml을 이용해 웹 애플리케이션에서 발생하는 오류를 처리하는 페이지를 지정할 수도 있다.

web.xml

  <error-page>
    <error-code>405</error-code>
    <location>/errorHandle</location>
  </error-page>
  <error-page>
    <exception-type>job.study.web.QueryStringNullException</exception-type>
    <location>/errorHandle</location>
  </error-page>

ErrorHandleServlet.java

package job.study.web;

import java.io.IOException;
import java.io.PrintWriter;

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

/**
 * Servlet implementation class ErrorHandleServlet
 */
@WebServlet("/errorHandle")
public class ErrorHandleServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public ErrorHandleServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.setContentType("text/html; charset=UTF-8");
		PrintWriter out = response.getWriter();
		
		//발생된 오류의 코드정보
		Integer code = (Integer) request.getAttribute("javax.servlet.error.status_code");
		//발생된 오류 객체의 타입 정보를 가지고 있는 Class형 객체
		String message = (String) request.getAttribute("javax.servlet.error.message");
		//발생된 오류의 메시지 정보
		Object type = request.getAttribute("javax.servlet.error.exception_type");
		//발생된 오류 객체
		Throwable exception = (Throwable) request.getAttribute("javax.servlet.error.exception");;
		//오류가 발생된 페이지의 URI정보
		String uri = (String) request.getAttribute("javax.servlet.error.request_uri");
		
		out.println("<h2>Error Code     : " + code + "</h2>");
		out.println("<h2>Error Message  : " + message + "</h2>");
		out.println("<h2>Error Type     : " + type + "</h2>");
		out.println("<h2>Error Object   : " + exception + "</h2>");
		out.println("<h2>Error URI      : " + uri + "</h2>");
		
		out.close();
		
	}

}

ErrorTestServlet.java의 doGet() 을 다음와 같이 수정하자. 

참고할 것은 doGet( ) 메소드의 throws 정의에 ServletException이 추가되었고 코드를 보면 ServletException을 상속 받아 구현한 QueryStringNullException 예외 객체를 throw하고 있는 것을 볼 수 있다. 

    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
	throws IOException,ServletException {
		// TODO Auto-generated method stub
		response.setContentType("text/html; charset=UTF-8");
		PrintWriter out = response.getWriter();
		
		String getquery = request.getQueryString();
		
		out.println("Query : " + getquery + "<br>");
		
		//질의문자열 값이 null이면 사용자예외를 강제로 발생시킨다.
		if(getquery==null ) throw new QueryStringNullException();
			
		out.println("Query길이 : " + getquery.length() + "<br>");
		out.println("Done!");
				
		out.close();
	}

실행결과

 

댓글

댓글 본문
작성자
비밀번호
버전 관리
DongHyun Kim
현재 버전
선택 버전
graphittie 자세히 보기