4주차 익셉션, 생명주기

2019. 6. 16. 17:51Java

1. 예외(Exception)처리란?


  • 예외 (Exception) 라는 것은 프로그램 실행중에 발생할 수 있는 가벼운 에러 상태이며 예외 처리는 예외가 발생한 상황에서 프로그램을 종료하지 않고 가능한 한 예외를 핸들링하여 프로그램의 흐름을 복구하고,
    초기에 의도하던 방향으로 프로그램을 수행할 수 있게 하는 것을 의미한다.
  • 예외처리에는 다양한 방법이 있는데 그중에 JSP, Servlet언어의 예외처리를 알아 볼 것이다. 그전에 JSPServlet언어가 무엇인지 차이점은 무엇인지 잠깐 살펴볼필요가있다.

 

1-1) Servlet이란?


  • 웹 기반의 요청에 대한 동적인 처리가 가능한 Server Side에서 돌아가는 Java Program
  • Java 코드 안에 HTML 코드 (하나의 클래스)
  • 웹 개발을 위해 만든 표준

 

1-2) JSP란?


  • Java 언어를 기반으로 하는 Server Side 스크립트 언어
  • HTML 코드 안에 Java 코드
  • Servlet를 보완하고 기술을 확장한 스크립트 방식 표준

 

1-3) Servlet과 JSP의 차이


[ Servlet ]

  • Java 코드 안에 HTML 코드 (하나의 클래스)
  • data processing(Controller)에 좋다.
  • 즉 DB와의 통신, Business Logic 호출, 데이터를 읽고 확인하는 작업 등에 유용하다.
  • Servlet이 수정된 경우 Java 코드를 컴파일(.class 파일 생성)한 후 동적인 페이지를 처리하기 때문에 전체 코드를 업데이트하고 다시 컴파일한 후 재배포하는 작업이 필요하다. (개발 생산성 저하)

 

[ JSP ]

  • HTML 코드 안에 Java 코드
  • presentation(View)에 좋다.
  • 즉 요청 결과를 나타내는 HTML 작성하는데 유용하다.
  • JSP가 수정된 경우 재배포할 필요가 없이 WAS가 알아서 처리한다. (쉬운 배포)

 

결론 : 기능의 차이는 없고 역할의 차이만 있다. (하는 일은 동일)

 

* 예제를 보면서 코드 차이점을 눈으로 확인해 보자.

Servlet 코드

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public ThreeParams extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
        response.setContentType("text/html");
        printWriter out = response.getWriter();
        
        String title = "Reading Three Request Parameters";
        String docType = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n";
        
        out.println(docType + 
            "<HTML>\n" +
            "<HEAD><TITLE>" + title + "</TITLE></HEAD>\n" +
            "<BODY BGCOLOR=\"#FDF5E6\">\n" +  
            "<H1 ALIGN=\"CENTER\">" + title + "</H1>\n" + 
            "<UL>\n" + 
            "<LI><B>param1</B>: " + request.getParameter("param1") + "\n" +
            "<LI><B>param2</B>: " + request.getParameter("param2") + "\n" +
            "<LI><B>param3</B>: " + request.getParameter("param3") + "\n" +
            "</UL>\n" +
            "</BODY></HTML>");
        )
    }
}

JSP 코드

<!DOCTYPE>
<HTML>
<HEAD>
<TITLE>Reading Three Request Parameters</TITLE>
<LINK REL=STYLESHEET HREF="JSP-Styles.css" TYPE="text/css">
</HEAD>

<BODY>
<H1>Reading Three Request Parameters</H1>
<UL>
    <LI><B>param1</B>: <%= request.getParameter("param1") %>
    <LI><B>param2</B>: <%= request.getParameter("param2") %>
    <LI><B>param3</B>: <%= request.getParameter("param3") %>
</UL>
</BODY>
</HTML>

 

 

 

2. 예외(Exception)처리 방법


  • 위에서 JSPServlet의 차이를 살펴보았으니 이제 JSP에서의 예외처리 방법과 Servlet에서의 예외처리방법을 살펴보자.
  • 그전에 Java의 기본적인 예외처리 방법인 try/catch문을 살펴보고 가자.

 

2-1) Java에서 try/catch문을 사용한 예외처리

  • try/catch문을 사용한 예외처리 방법에는 크게 3가지가 있으며 기본 문법은 이렇다.



try{

    예외 발생 가능성이 있는 문장들;

}catch(예외 타입1 매개변수명){

    예외타입1의 예외가 발생할 경우 처리 문장들;

}catch(예외 타입 n 매개변수명){

    예외타입 n의 예외가 발생할 경우 처리 문장들;

}finally{

    항상 수행할 필요가 있는 문장들;

}


출처: http://hyeonstorage.tistory.com/203 [개발이 하고 싶어요]
  • try 블록은 예외가 발생할 가능성이 있는 범위를 지정하는 블록이다. try 블록은 최소한 하나의 catch 블록이 있어야 하며, catch 블록은 try 블록 다음에 위치한다.

  • catch 블록의 매개변수는 예외 객체가 발생했을 때 참조하는 변수명으로 반드시 java.lang.Throwable 클래스의 하위 클래스 타입으로 선언되어야 한다.
    지정된 타입의 예외 객체가 발생하면 try 블록의 나머지 문장들은 수행되지 않고, 자바 가상 머신은 발생한 예외 객체를 발생시키며 발생한 예외 객체 타입이 동일한 catch 블록을 수행한다.

  • finally 블록은 필수 블록은 아니다.

finally 블록이 사용되면 finally 블록의 내용은 예외 발생 유무나 예외 catch 유무와 상관 없이 무조건 수행된다. 따라서, 데이터베이스나 파일을 사용한 후 닫는 기능과 같이 항상 수행해야 할 필요가 있는 경우에 사용한다.

 

 

 

a. 예외(Exception)이 발생한 메소드 내에서 직접 처리 (try-catch-finally)

public class ExceptionTest {

    public static void main(String args[]){
        
        String[] name = new String[2];
        
        try{
            name[0] = "하이언";
            System.out.println("이름 : "+name[0]);
            
            name[1] = "아이유";
            System.out.println("이름 : "+name[1]);
            
            name[2] = "윤하";
            System.out.println("이름 : "+name[2]);
        
        }catch(ArrayIndexOutOfBoundsException e){
            System.out.println("배열 참조 에러 발생");
        }catch(Exception e){
            System.out.println(e.getMessage());
        }finally{
            System.out.println("시스템 종료.");
        }
    }
}

- String[2] 배열을 선언하고, 3번째 배열에 값을 대입할 때, 예외가 발생한다.

- ArrayIndexOutOfBoundsException 이 발생하여 catch에 잡히고 "배열 참조 에러 발생" 이라는 메시지가 출력된다.

- 최종적으로 finally가 실행되며 "시스템 종료." 메시지가 출력된다.



결과화면)

 

 

b. 예외(Exception)이 발생한 메소드를 호출 한 곳으로 예외 객체를 넘기는 방법 (throws)

자바의 예외 처리 방법은 예외가 발생한 지점에서 try-catch 또는 try-catch-finally 블록을 이용하여 직접 처리하지 않아도 예외가 발생한 메소드를 호출한 지점으로 예외를 전달하여 처리하는 방법이 있다.

이때 사용하는 예약어가 throws 이다.

public class ExceptionTest {

    static void callDriver() throws ClassNotFoundException{
        Class.forName("oracle.jdbc.driver.OracleDriver");
        System.out.println("완료");
    }
    
    public static void main(String args[]){
        
        try{
            
            callDriver();
        
        }catch(ClassNotFoundException e){
            System.out.println("클래스를 찾을 수 없습니다.");
        }catch(Exception e){
            System.out.println(e.getMessage());
        }finally{
            System.out.println("시스템 종료.");
        }
        
    }
}

- main 함수에서 callDriver() 함수를 실행시킨다.

- callDriver() 함수에서는 "oracle.jdbc.driver.OracleDriver" 클래스를 가져온다.

- 해당 클래스를 찾지 못하면 ClassNotFoundException이 발생하는데, callDriver()에서는 throws ClassNotFoundException 처리로 호출한 main 함수로 예외를 넘긴다.

- main에서는 ClassNotFoundException을 받아 catch 문에서 잡아서 "클래스를 찾을 수 없습니다." 메시지를 출력한다.

- 마지막으로 finally가 실행되며 "시스템 종료" 를 출력한다.

 

결과화면)

 

 

c. 사용자 정의 예외 생성 (throw)

기존의 예외 클래스로 예외를 처리할 수 없다면 사용자만의 예외 클래스를 작성하여 발생시킬 수 있다.

사용자가 예외 클래스를 정의하려면 예외 클래스의 최상위 클래스인 java.lang.Exception 클래스를 상속받아 클래스를 정의한다.

 

class 예외 클래스 이름 extends Exception

자바 가상 머신은 프로그램 수행중에 예외가 발생하면 자동으로 해당하는 예외 객체를 발생시킨 다음 catch 블록을 수행한다.

하지만 예외는 사용자가 강제적으로 발생시킬 수도 있다. 자바는 예외를 발생시키기 위해 throw 예약어를 사용한다.

 

throw new 예외 클래스 이름(매개변수);

throw를 이용한 예외 발생시에도 try-catch-finally 구문을 이용한 예외 처리를 하거나, throws를 이용하여 예외가 발생한 메소드를 호출한 다른 메소드로 넘기는 예외 처리 방법을 사용해야 한다.

public class MyException extends Exception{
    
    public MyException(){
        super("내가 만든 예외");
    }
}

public class ExceptionTest {

    static void callException() throws MyException{
        
        throw new MyException();
    }
    
    public static void main(String args[]){
        
        try{
               callException();
        
              }catch(MyException e){
                      System.out.println(e.getMessage());
               }catch(Exception e){
                       System.out.println(e.getMessage());
               }finally{
                     System.out.println("시스템 종료.");
              }    
    }
}

- MyException 이라는 Exception을 상속한 예외를 만들었다. 그리고 MyException은 "내가 만든 예외" 라는 메시지를 갖는다.

- ExceptionTest의 main 함수가 실행되면 callException() 함수를 호출한다.

- callException 함수는 MyException() new로 생성한 후 callException() 함수를 호출한 main 함수로 던진다.

- MyException을 받은 main 함수는 catch에서 해당 예외를 받아서, 예외의 메시지를 출력한다. "내가 만든 예외"

- 최종적으로 finally가 실행되어 "시스템 종료"가 출력된다.

 

결과화면)

 

2-2) JSP 예외처리

  • JSP에서의 예외처리 방법에는 3가지가 있다.

          1) page 지시자를 이용한 예외처리
          2) web.xml의 error-code태그사용한 페이지 호출 예외처리
          3) web.xml의 exception-type태그를 이용해 예외타입별로 페이지 호출 예외처리
          4) try/catch문을 이용한 예외처리


1. page 지시자 사용하기

<% @page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<% @page errorPage="errorCheck.jsp" %>
<!DOCTYPE html>
<HTML>
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<TITLE>제목</TITLE>
</HEAD>

<BODY>
<H1>나누기 페이지</H1>
 <%
   int num = 10/0;
 %>
</BODY>
</HTML>
  • 위의 코드를 보면 13번 라인에서 0으로 나누어 예외발생 발생한다.
    이때 톰캣에서 제공하는 딱딱한 에러화면 말고 직접 에러페이지를 만들어서 보여주기 위해 2번라인처럼 page 지시자(Directive)를 이용하였다.
  • 정리 :  page지시자의 errorPage속성을 이용해서 에러가나면 errorCheck.jsp로 이동해라.
<% @page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<% @page isErrorPage="true" %>
<% response.setStatus(200); %>
<!DOCTYPE html>
<HTML>
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<TITLE></TITLE>
</HEAD>
<BODY>
<H2>0으로 나눌수 없습니다!</H2>
 
에러 메시지: <%=exception.getMessage()%>
</BODY>
</HTML>
  • errorCheck.jsp에서 봐야할 코드는 3~4번라인 이다.
    3번라인의 page 지시자의 isErrorPage속성을 true로 해줌으로써 이 페이지는 에러페이지임을 알려주고, 13번라인에서 사용된 exception기본객체를 사용할 수 있게된다.
    13번라인에서 getMessage()를 이용해 에러메시지 출력.
  • 모든 웹 페이지는 status라는 상태값을 가지고 있는데 4번라인의 의미는 상태값을 정상으로 설정하기 위한 코드이다.
    (개발자가 임의로 만든 에러페이지임을 알려주기 위한 정상페이지인데 간혹 status가 500인 상태로 설정이 되는 경우가 있다.[500은 서버내부의 오류])

 

2. web.xml 사용하기(error-code태그이용)


...

	<error-page>
	  <error-code>500</error-code>
	  <location>/error/error500.jsp</location>
	</error-page>

	<error-page>
	  <error-code>404</error-code>
	  <location>/error/error404.jsp</location>
	</error-page>
	
...
  • 위와 같이 error-page태그안에 error-code태그와 location태그를 사용.
  • error-code태그에는 상태값을 설정해주고, location태그에는 해당 상태값일 경우 표시해줄 에러페이지의 위치를 설정해준다.


<% @page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<HTML>
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<TITLE>제목</TITLE>
</HEAD>

<BODY>
<H1>나누기 페이지</H1>
 <%
   int num = 10/0;
 %>
</BODY>
</HTML>

*page지시자는 사용하지 않으므로 지워줘야한다.

 

<% @page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<HTML>
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<TITLE></TITLE>
</HEAD>
<BODY>
	<h1>500에러 페이지 입니다.</h1>
</BODY>
</HTML>

결과화면)

 


<% @page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<HTML>
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<TITLE>제목</TITLE>
</HEAD>
<BODY>
	 <a href="ABC.jsp">ABC.jsp페이지 어딨는지 찾기</a>
</BODY>
</HTML>

 

<% @page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<% response.setStatus(200); %>
<!DOCTYPE html>
<HTML>
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<TITLE></TITLE>
</HEAD>
<BODY>
	<H1>404에러 페이지 입니다.</H1>
</BODY>
</HTML>

결과화면)

 

3. exception-type태그 이용하기


...

	<error-page>
	  <exception-type>java.lang.ArithmeticException</exception-type>
	  <location>/error/error500.jsp</location>
	</error-page>
	
...
  • 두번째 방법과 마찬가지로 web.xml파일에서 작업이 이루어 진다.
  • 위와같이 error-page태그안에 exception-type태그와 location태그를 사용.

 

 

 

 

 

4. try/catch문 이용하기


<%@ page language=“java” contentType=“text/html; charset=EUC-KR”

pageEncoding=“EUC-KR”%>

<%

    int num1 = 0, num2 = 0, result = 0;

    try{

        String str1 = request.getParameter(“NUM1”);
        String str2 = request.getParameter(“NUM2”);

        num1 = Integer.parseInt(str1);//값이 숫자가 아니면 에러가 남
        num2 = Integer.parseInt(str2);

        result = num1 + num2;

    }

    catch(NumberFormatException e){

        RequestDispatcher dispatcher = request.getRequestDispatcher(“DataError.jsp”);
        dispatcher.forward(request, response);

    }

 

%>
  • Adder.jsp라는 숫자를받아 더해주는 페이지에서 인자가 숫자가 아니면 catch문에서 DataError.jsp라는 에러 페이지로 리다이렉트 해주는 예제.

 

정리
1) 별도의 에러페이지가 필요하다면 page지시자를 사용.
2) 자주사용되는 에러코드를 대비하려면 web.xml에서 error-code태크를 사용
3) 따로 처리해주어야할 예외라면 web.xml에서 exception-type태그를 사용.
4) 그때그때 좀더 세밀한 에러 제어시 try/catch문 사용.

 

 

 

 

2-3) Servlet 예외처리

  • Servlet에서의 예외처리 방법

          1) try/catch문을 이용한 예외처리

package com.journaldev.servlet.exception;

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("/MyExceptionServlet")
public class MyExceptionServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		throw new ServletException("GET method is not supported.");
	}

}

결과화면)

3. JSP/Servlet 생명주기


  • 생명주기란, 사람이 살아가면서 태어날 때까지의 과정을 뜻하는것으로 소프트웨어에 적용하면 개발의 초기 단계부터 마지막 출시까지의 모든 단계를 아우르는 개발단계의 총체를 말한다.

 

Servlet생명주기 그림)

Servlet 컨테이너 동작 그림)

 

1) 클라이언트가 웹 브라우저에 URL을 입력하여 요청하면, Servlet 클래스가 로딩되어 요청에 대한 Servlet 객체가 생성된다.
   (이때, Servlet Container는 HttpServletRequest, HttpServletResponse 두 객체를 생성함)

2) 서버는 init() 메소드를 호출해서 Servlet을  초기화 한다.

3) 클라이언트가 요청한 URL을 DD(배포서술자, Deplyment Descriptor)를 참조해서 분석하여 어느 서블릿에 대한 요청인지 찾는다.

4) service() 메소드를 호출해서 Servlet이 브라우저의 요청을 처리하도록 한다.

5) service() 메소드는 특정 HTTP 요청(GET, POST 등)을 처리하는 메서드 (doGet(), doPost() 등)를 호출한다.

6) 서버는 destroy() 메소드를 호출하여 Servlet을 제거한다.


출처: https://victorydntmd.tistory.com/154 [victolee]

 

*DD(Deployment Descriptor : 배포 서술자)

  : 웹 컨테이너에게 사용자가 지금 접근한 URL 주소가 서블릿 요청임을 인식하고 그 서블릿 클래스의 위치는 어디에 있다고

    알려주기 위해 필요한 정보들이 적혀 있는 파일이다. 주로 프로젝트의 WebContent/WEB-INF/web.xml 파일에 작성된다. 

 

 

 

JSP생명주기 그림)

 

*참고 : JSP 페이지도 결국은 Servlet이기 때문에 똑같이 아래의 생명 주기를 갖는다.