웹에서 이벤트가 사용되는 경우는 다음과 같다.

  • 세션의 생성, 소멸
  • 속성 변경
  • 컨텍스트 초기화


web.xml 에 <listener>에 등록해주면 웹 서버가 자동으로 이벤트를 감지하여 지정한 클래스 메서드를 실행시켜 준다.

<listener> 태그는 최상위에 넣는다.

  <listener>
    <display-name>이벤트 리스너 명</display-name>
    <listener-class>리스너클래스</listener-class>
  </listener>
  
  <filter>
    ....
  </filter>
  
  <filter-mapping>
    ....
  </filter-mapping>
  
  <servlet>
    ....
  </servlet>
  
  <servlet-mapping>
    ....
  </servlet-mapping>


설정할 수 있는 이벤트는 다음과 같다.

 이벤트

 ServletContextListener 

 발생시점 

 ServletContext 객체의 초기화 또는 소멸 시 발생

 메서드

 contextInitialized() 

 contextDestroyed()

 이벤트

 ServletContextAttributeListener

 발생시점

 ServletContext 객체에 속성이 추가, 삭제, 수정될 때 발생

 메서드

 attributeAdded()

 attributeRemoved()

 attributeReplaced()

 이벤트

 HttpSessionListener

 발생시점

 HttpSession 객체가 생성되거나 소멸될 때 발생

 메서드

 sessionCreated()

 sessionDestroyed()

 이벤트

 HttpSessionAttributeListener

 발생시점

 HttpSession 객체에 속성이 추가, 삭제, 수정될 때 발생

 메서드

 attributeAdded()

 attributeRemoved()

 attributeReplaced()

 이벤트

 ServletRequestListener

 발생시점

 ServletRequest 객체의 초기화 또는 소멸 시 발생 

 메서드

 requestInitialized()

 requestDestroyed()

 이벤트

 ServletRequestAttributeListener

 발생시점

 ServletRequest 객체에 속성이 추가, 삭제, 수정될 때 발생

 메서드

 attributeAdded()

 attributeRemoved()

 attributeReplaced()


앞서 작성한 서블릿 필터의 예제 소스에 추가해서 테스트한다.

예제) 세션에 속성 추가 시 이벤트 발생을 확인한다.

web.xml

<servlet> 태그보다 앞에 추가한다.

  ....
  <listener>
    <display-name>SessionListener</display-name>
    <listener-class>com.study.SessionListener</listener-class>
  </listener>
  ....


SessionListener.java

리스너 클래스를 생성한다.

package com.study;

import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

public class SessionListener implements HttpSessionAttributeListener {
  public void attributeAdded(HttpSessionBindingEvent _evt) {
    System.out.println("Event (attributeAdded)");
    System.out.println("  => Name: " + _evt.getName());
    System.out.println("  => Value: " + _evt.getValue());
  }
  
  public void attributeRemoved(HttpSessionBindingEvent _evt) {
  }

  public void attributeReplaced(HttpSessionBindingEvent _evt) {
  }
}


확인~


Posted by 후니아부지
:

서블릿 필터

웹 상에서 사용자 요청 페이지가 실행하기 전이나 후에 동작이나 데이터를 가로채서 어떠한 작업을 해주고 해당 페이지로 넘어갈 수 있도록, 혹은 넘어갈 수 없도록 막는 등의 작업을 할 때 사용한다.

예를 들면 이벤트나 공지 등의 팝업을 추가하거나 전달 받은 데이터를 인코딩하는 경우, 세션 데이터를 인증하는 등의 작업에 사용될 수 있다.


Filter 인터페이스를 구현하는 클래스 작성 후

class 클래스명 implements Filter {
    public void init(FilterConfig fc) throws ServletExeption {
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
              throws IOEXception, ServletException {
        // 필터 작업
        
        chain.doFilter(request, response); // '가던 길로 가세요~' 라는 의미 :)
    }

    public void destroy() {
    }
}

web.xml에 등록하여 사용한다. (서블릿 보다 위에 작성한다.)

<filter>
  <filter-name>필터명</filter-name>
  <filter-class>필터클래스</filter-class>
  <init-param>
    <param-name>매개변수명</param-name>
    <param-value>값</param-value>
  </init-param> 
</filter>

<filter-mapping>
  <filter-name>필터명</filter-name>
  <url-pattern>필터패턴</url-pattern>
</filter-mapping>


예제) 로그인 페이지에서 로그인 후 메인 페이지로 이동

login.htm


LoginProcessServlet.java

 

web.xml


MainServlet.java


이때 문제가 되는 것이, 로그인 후 메인 페이지의 주소를 복사한 후 서버 재시작 후 복사한 주소를 넣고 이동하면 메인 페이지로 바로 갈 수 있다. 로그인 과정을 거치지도 않았는데도 메인 페이지를 볼 수 있다는 것이다.

이를 방지하기 위해 필터를 사용해본다.

 

Filter 클래스를 생성하고 web.xml에 등록해준다.

 

web.xml

<servlet> 태그 보다 위에 작성해야 한다. '.do'로 서블릿을 호출할 때 LoginFilter 필터가 적용되도록 설정한다. 

 

LoginFilter.java

세션에 ID가 있는지 확인해서 없다면 로그인 화면으로 가도록 한다.

LoginProcessServlet 에서 세션에 ID를 저장하도록 할 것이므로 필터 처리에 예외가 되도록 한다. LoginProcessServlet 를 거치지 않고서는 ID가 세션에 없으므로 무조건 로그인 화면으로 가버리게 되기 때문이다.

 

LoginProcessServlet.java

로그인 처리 서블릿에서는 세션에 ID를 저장하고 Main.do를 호출한다.


 

MainServlet.java



로그인 후 세션이 생성되었을 때의 주소를 복사 후, 서버를 재시작하고 앞에 복사한 주소로 직접 접근해본다.

이제는 Main.do 로 접근 시 필터에 걸려서 (세션에 ID가 없으므로) 로그인 화면으로 이동될 것이다.

 

Posted by 후니아부지
:

MIME은 Multipurpose Internet Mail Extensions 의 약자로 메일을 확장한 인터넷 표준이라 할 수 있다.

웹에서 데이터를 상대방에게 보낼 때 헤더에 MIME을 지정하고, 상대방은 받은 데이터를 화면에 보여줄 때 MIME 형식에 따라 처리한다.

자주 사용하는 MIME 형식 종류는 다음과 같다.

 분류

 종류

 설명

 이미지 관련

 image/bmp

 BMP 파일의 MIME

 image/gif

 GIF 파일의 MIME

 image/jpeg

 JPG, JPEG, JPE 파일의 MIME

 image/png

 PNG 파일의 MIME

 image/x-icon

 ICO 파일의 MIME

 ....

 

 응용 프로그램 관련

 application/msword

 워드 파일의 MIME

 application/vnd.ms-excel

 엑셀 파일의 MIME

 application/vnd.ms-powerpoint

 파워포인트 파일의 MIME

 .... 

 기타

 application/octet-stream

 파일 다운로드 MIME

 .... 


예제) 파일 종류 별로 몇 가지 업로드해서 화면에 보여지도록 해본다.

web.xml


FileUploadServlet.java


fileUploadPage.htm


파일 업로드 후, 이미지 파일의 경우 웹 페이지에 보여질 것이고, 

응용프로그램 관련 파일은 '열기'를 선택하면 해당 응용프로그램이 실행되어 파일을 볼 수 있을 것이다. (웹 페이지에 안 열리고??????)

그러나 응용프로그램 관련 MIME 형식을 설정하지 않아도 '열기'가 된다?!?!?!?!?!?!?

기타 파일의 경우 다운로드 할 수 있다.


왜 이러나?????



Posted by 후니아부지
:

웹 프로그램에서는 데이터베이스의 환경 설정과 연결 관리등을 XML 파일이나 속성 파일을 사용하여 관리하고 특정 이름을 사용하여 이 정보를 얻어온다. 

웹에서 불특정 다수의 사용자가 DB연결을 요청한다고 무작정 허용한다면 DBMS는 부하를 감당할 수 없을 것이다.

따라서 연결 개수를 설정하여 현재 연결된 사용자가 더 이상 Connection 객체를 사용하지 않을 경우 해당 Connection 객체를 반환받아서 다른 사용자에게 할당해야 한다. 이런 작업을 Connection Pooling이라 하고 DBCP(Database Connection Pooling)이라 부른다. 


여기서는 톰캣의 DBCP(Database Connection Pool)를 사용하여 DBMS Connection 객체를 생성, 사용하는 방법에 대해 알아본다.


프로젝트의 META-INF 디렉터리 내에 Context.xml을 생성한다.

Context.xml은 해당 Context에서 사용할 리소스를 등록하는 곳이다. 

다음과 같이 작성한다.

<?xml version="1.0" encoding="UTF-8"?>
<Context>
  <Resource name="jdbc/myconn"
            auth="Container"
            type="javax.sql.DataSource"
            factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"
            driverClassName="org.gjt.mm.mysql.Driver"
            url="jdbc:mysql://localhost:3306/데이터베이스명?AutoReconnect=true"
            username="계정"
            password="암호"
            maxActive="100"
            maxIdle="30"
            maxWait="60"
            removeAbandoned="true"
            removeAbandonedTiemout="60"/>
</Context>

속성

설명 

 name

 JNDI로 호출될 이름

 auth

 DBCP를 관리할 관리자. Container or Application 

 type

 해당 리소스의 Return Type. DataSource는 Connection 객체를 반환할 수 있다.

 factory

 DBCP를 관리하는 클래스

 driverClassName

 JDBC를 이용하기 위한 드라이버 클래스

 url

 DB 접속 URL. 해당 속성으로 자동 재접속을 설정했다.

 username

 DB 계정명

 password

 계정 비밀번호

 maxActive

 최대 접속 허용 개수

 maxIdle

 DB Pool에 여분으로 남겨질 최대 Connection 개수

 maxWait

 DB 연결이 반환되는 Timeout 최대 시간

 removeAbandoned

 Connection이 잘못 관리되어 버려진 연결을 찾아 재활용할 것인지 여부 설정

 removeAbandonedTimeout

 버려진 연결로 인식할 기본 시간 설정. 초 단위.


이렇게 설정된 정보 객체를 이름으로 얻으려면 자바의 네이밍 API를 사용해야 한다. 이를 JNDI라고 하는데 

JNDI(Java Naming and Directory Interface)는 이름을 사용하여 데이터 및 객체를 찾을 수 있도록 도와주는 디렉토리 서비스에 대한 Java API이다. 


web.xml에 JNDI로 정의할 이름을 등록한다. <welcome-file-list> 태그 위에 작성한다.

  <resource-ref>
    <description>MySQL Resource</description>
    <res-ref-name>jdbc/myconn</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>


서블릿을 작성하고 web.xml에 매핑해준다.

ConnectionServlet.java

package com.study;

import java.io.IOException;
import java.sql.Connection;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

public class ConnectionServlet extends HttpServlet {
	public void service(HttpServletRequest _request, HttpServletResponse _response) 
			throws IOException, ServletException {
		try {
			Context context = new InitialContext();
			/* JNDI 이름은 java:comp/env에 등록되어 있다. 
			   따라서 예약어로 "java:comp/env"가 오고 그 다음 
			   Context.xml의 name으로 설정한 내용을 쓰면 된다. */
			DataSource ds = (DataSource)context.lookup("java:comp/env/jdbc/myconn");
			Connection conn = ds.getConnection();
			
			System.out.println("conn: " + conn);			
		} catch(Exception _ex) {
			System.out.println("Error: " + _ex.getLocalizedMessage());			
		}
	}
}

web.xml

  <servlet>
    <servlet-name>ConnectionServlet</servlet-name>
    <servlet-class>com.study.ConnectionServlet</servlet-class>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>ConnectionServlet</servlet-name>
    <url-pattern>/DBConnect.do</url-pattern>
  </servlet-mapping>  


실행해서 Connection 객체 정보를 확인하자.



Posted by 후니아부지
:

서블릿 클래스의 상속 관계


사용하는 패키지는 다음과 같다.

javax.servlet.*

javax.servlet.http.*


Servlet 인터페이스


ServletConfig 인터페이스


GenericServlet 클래스


HttpServlet 클래스


ServletRequest 클래스


HttpServletRequest 클래스


ServletResponse 클래스


HttpServletResponse 클래스


Posted by 후니아부지
:


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <display-name>프로젝트명</display-name>
  
  <filter>
  	<filter-name>필터 닉네임</filter-name>
  	<filter-class>패키지명을 포함한 필터 클래스 풀 네임</filter-class>
  	<init-param>
  		<param-name>매개변수명</param-name>
  		<param-value>값</param-value>
  	</init-param>
  </filter>

  <filter>....</filter>
  <filter>....</filter>
  
  <filter-mapping>
  	<filter-name>필터 닉 네임</filter-name>
  	<url-pattern>필터 클래스가 실행될 위치</url-pattern>
  </filter-mapping>
  
  <filter-mapping>....</filter-mapping>
  <filter-mapping>....</filter-mapping>

  <servlet>
  	<servlet-name>서블릿 닉네임</servlet-name>
  	<servlet-class>패키지명을 포함한 서블릿 클래스 풀 네임</servlet-class>
  	<init-param>
  		<param-name>매개변수명</param-name>
  		<param-value>값</param-value>
  	</init-param>
  	<load-on-startup>실행 순서(숫자, 0은 서버 임의 실행)</load-on-startup>
  </servlet>
  
  <servlet>....</servlet>
  <servlet>....</servlet>
  
  <servlet-mapping>
  	<servlet-name>서블릿 닉 네임</servlet-name>
  	<url-pattern>URL 패턴</url-pattern>
  </servlet-mapping>
  
  <servlet-mapping>....</servlet-mapping>
  <servlet-mapping>....</servlet-mapping>
  
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
</web-app>


Posted by 후니아부지
:

웹 서버 구동은 아래의 순서로 진행된다.

순서

 처리 내용

 해당 파일 및 폴더

 1

 웹서버 구동에 필요한 포트 및 설정 정보를 인식한다.

 [톰캣폴더]\conf\server.xml

 2

 모든 프로젝트에 공통으로 적용되는 설정 정보 인식한다.

 [톰캣폴더]\conf\web.xml

 3

 모든 프로젝트에 공통으로 적용되는 라이브러리 파일을 인식한다. 더불어 %JAVA_HOME%\lib , %JAVA_HOME%\jre\lib\ext 폴더 내의 jar 파일들도 자동으로 인식한다.

 [톰캣폴더]\common\lib

 4

 프로젝트별 환경 정보를 인식한다.

 [프로젝트이름]\WEB-INF\web.xml

 5

 프로젝트별 라이브러리를 인식한다.

 [프로젝트이름]\WEB-INF\lib

 6

 프로젝트별로 적용되는 서블릿 파일을 인식한다. 설정에 따라 init()을 실행한다.(<load-on-startup> 태그 사용)

 [프로젝트이름]\WEB-INF\classes


웹 서버 종료 시 아래의 순서로 진행된다.

 순서

 처리 내용 

 해당 파일 및 폴더 

 1

 프로젝트별로 적용되는 서블릿 파일을 인식하고 destroy()를 실행하여 메모리를 해제한다.

 [프로젝트이름]\WEB-INF\classes

 2

 프로젝트별로 환경 설정에 사용된 메모리를 해제한다.

 

 3

 모든 프로젝트에 공통적인 환경을 설정하기 위해 사용된 메모리를 해제한다.

 

 4

 웹 서버를 구동하기 위해 열어둔 포트를 닫는다.

 


서블릿라이프 사이클은 다음과 같다

 순서

 처리 내용

 1

 public void init() 또는 public void init(ServletConfig sc) {....} 에 의한 초기화 코드가 실행된다. 

 이는 web.xml 인식 시 <load-on-startup> 태그에 의해 실행되거나, 최초 접속하는 클라이언트에 의해 실행된다.

 2

 public void service(HttpServletRequest request, httpServletResponse response) throws IOException, ServletException {....}

 클라이언트의 요청에 의해 실행되는 메서드로 콘솔 프로그램의 main() 과 같은 역할을 한다.

 3

 public void destroy() {....} 에 의한 메모리 해제

 웹 서버가 종료될 때 실행되어 메모리를 해제한다.


간단한 코드로 서블릿의 라이프 사이클을 확인해보자.

ServeletLifeCycleTest.java

package com.study;

import java.io.IOException;

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


public class ServeletLifeCycleTest extends HttpServlet {
	private int callCount;
	public void init() {
		this.callCount = 0;
		System.out.println("Servlet init() called....");
	}
		
	public void service(HttpServletRequest _request, HttpServletResponse _response) 
		throws ServletException, IOException{
		System.out.println("Servlet service() called (" + (++(this.callCount)) + ")....");
	}
		
	public void destory() {
		System.out.println("Servlet destroy() called....");
	}
}	


web.xml

  ....
  <servlet>
  	<servlet-name>ServletLifeCycle</servlet-name>
  	<servlet-class>com.study.ServeletLifeCycleTest</servlet-class>
  </servlet>
  
  <servlet-mapping>
  	<servlet-name>ServletLifeCycle</servlet-name>
  	<url-pattern>/test</url-pattern>
  </servlet-mapping>
  ....


서버에 올리고 주소창에 URL을 입력하면 다음과 같이 init(), service()가 실행됨을 볼 수 있다.


해당 페이지를 리로딩하면 카운트가 계속 올라가며 service()가 호출됨을 확인할 수 있다.


서버 종료 시 destory()가 호출 되어야 하는데 왜 안나오나????




' > web' 카테고리의 다른 글

[Servlet] 서블릿 주요 클래스  (0) 2014.03.04
[Servlet] web.xml 설정 파일  (0) 2014.03.04
[Servlet] 웹 프로그램의 파일 구조  (0) 2014.02.27
[Servlet] MVC 패턴  (0) 2014.02.26
자바 입출력(I/O) - 객체(Obejct) 입출력  (0) 2014.02.24
Posted by 후니아부지
:

자바로 작성하는 웹 프로그램은 어떤 웹 컨테이너를 사용하든지 다음과 같은 구조를 가진다.

웹 프로그램의 파일 구조


그러나 이클립스에서는 작성이나 관리의 효율성을 위해 조금 변형된 구조를 가진다.

물론, 실제 웹 프로그램이 실행될 때는 다시 원래의 구조로 바뀐다.

이클립스의 웹 프로그램 파일 구조

 

Posted by 후니아부지
:

[Servlet] MVC 패턴

앎/web 2014. 2. 26. 15:47 |
  • Model

데이터를 담거나 DB로 데이터를 보내는 작업을 하는 객체를 말한다.

View 상의 사용자 입력을 담아 가지고 있는 역할을 하며, Controller에서 상태 변화를 알려주면 자기자신의 상태를 변경하여 View에게 알려주는 역할을 한다. 

DTO를 통해 상태를 주고 받으며 DB와의 데이터 통신을 위해 DAO를 사용한다.


  • View

Model을 화면상에 보여주는 부분을 말한다. 

Model의 변화된 상태를 가져와서 보여준다.

View에서의 데이터 입력을 Controller에 전달한다. 

Controller가 선택한 View를 보여준다.


  • Controller

Model과 View간의 데이터 전달 및 결과에 대한 View를 선택하여 응답하는 역할을 한다.


 

MVC 구조 활용 예시

사용자 등록하는 기능 구현해본다.

0. 사용자 정보를 관리하기 위한 DB 테이블을 생성한다.


1. 사용자 등록을 위한 html 페이지를 작성한다. (View)

MVC_Test_Register.htm


2. 사용자 페이지에서 넘어오는 데이터 저장을 위한 DTO 클래스를 작성한다. (Model)

MVC_Test_MemberDTO.java


3. DTO에 저장된 데이터를 DB로 저장하는 작업을 하는 DAO 클래스를 작성한다. (Model)

MVC_Test_MemberDAO.java


4. 사용자 페이지에서 넘어온 데이터를 DTO에 넣고 DAO 클래스의 관련 메서드에 전송하는 작업을 하고, 그 작업 결과에 따라 이동할 페이지를 결정하는 클래스를 작성한다. (Controller)

MVC_Test_MemberProcess.java


5. 서블릿 정보를 등록한다.

web.xml


6. 처리 결과에 따른 뷰 페이지를 작성한다. (View)

MVC_Test_Success.htm

 

MVC_Test_Failure.htm

서버에 올려 확인해보자.

 

MVC_Test.rar


 

Posted by 후니아부지
: