본문 바로가기

컴퓨터 프로그래밍/수업

2020.06.03

WAS가 하는일

1. web.xml(Deployee Descriptor)을 읽어들입니다. DD파일(servlet 정의, Initialization 정보)

2. servlet 생성-> 기본생성자 호출

3. ServletConfig 객체-> WAS가 알아서 만들어 줍니다. 

4. init() 호출 servletConfig를 인자값 들어갑니다. 

 


위에 상태가 Ready-on 상태->only one: 한번만됨

최초의 요청이 있어야지 Ready-on상태로 됩니다. 

그 다음 요청은 Ready-on 상태에서 아래가 실행됩니다.

이를 해결하기 위해서는 아래오 같이 해줘야합니다. 

lazzy loading이 default로 되어 있습니다. 이것을 free loading으로 해야하는데 이 옵션이 

web.xml에 load-on-startup입니다.

1은 순번을 의미합니다.


5. 클라이언트가 요청을 하면 Request와 Response 객체가 생성이 되고 service()(get, post에 따라서 doGet() 또는 doPost() 재호출됨) 메소드가 호출 됩니다. 이때, service의 인자값으로 request와 response가 parsing into 됩니다. 이때 thread 하나가 생성이 됩니다. 

6. service(){} 실행이 끝나면 응답을 합니다. 

7. request와 response 객체와 thread가 death됩니다. 


5-7 repeat

 


8. server를 shut-down->destroy() 호출, 이때 객체들 다 사라집니다. 

 

servlet life-cycle관련 메소드

1. init(): 기본생성자 밖에는 호출을 못하니까, 필드 초기화를 이 메소드를 통해서 해줍니다.

2. service()

3. destroy(): 서버를 끄면 무조건 호출이 됩니다.

 

 

life cycle 알아봅시다. 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>lifeCycle</title>
</head>
<body>
<h2 align="center">LifeCycle....CallBack Method Test...</h2>
<a href="life">LifeCyle Test...click</a>
</body>
</html>

 

package servlet.life;

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

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * Servlet implementation class ServletLifeCyleTest1
 */
public class ServletLifeCyleTest1 extends HttpServlet {
	private static final long serialVersionUID = 1L;
     private int count = 0;//field  
    /**
     * @see HttpServlet#HttpServlet()
     */
    public ServletLifeCyleTest1() {
        super();
        System.out.println("1. ServletLifeCyleTest1...call by container(WAS)");
    }

	/**
	 * @see Servlet#init(ServletConfig)
	 */
	public void init() throws ServletException {
		System.out.println("2. init...call by container(WAS)");
	}

	/**
	 * @see Servlet#destroy()
	 */
	public void destroy() {
		System.out.println("4. destroy...call by container(WAS)");
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doProcess(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doProcess(request, response);
	}
	protected void doProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("3. service...call by container(WAS)");
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		//web browser로 출력
		out.println("<html><body bgcolor='yellow'>");
		out.println("<h3>LifeCycle CallBack Method...</h3>");
		out.println("<b>Count::"+ ++count+"</b>");
		out.println("</body></html>");
		out.close();
	}
	

}

 

이렇게 되면, 1,2번은 한번만 실행이 되고 요청을 할 때 마다 3번만 실행이 반복됩니다. 4번은 서버를 끄면 실행이 됩니다. 3번이 실행이 될때마다 count값이 올라갑니다. 서버가 꺼지면 count값도 초기화 됩니다. 

 

servlet의 필드 최종 값을 프로그래밍이 꺼질때 DB 저장(destroy())해야하고, 다시 DB에서 가져와야(init())합니다.  

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>lifeCycle</title>
</head>
<body>
<h2 align="center">LifeCycle....CallBack Method Test...</h2>
<a href="life3">LifeCyle Test...click</a>
</body>
</html>
/*
 * 서블릿 필드값 count값을 영구적으로 보관할 수 있는 방법은 지금으로서는 없다.
 * 왜냐하면 서버가 stop되는 순간 destroy() callback 함수가 자동으로 호출되어 지고, 
 * 서블릿 인스턴스를 메모리에서 unbound 시켜버리기 때문이다. 
 * 
 * 서버가 내려가더라도 서비스를 수행한 후 필드에 저장시킨 값을 영구적으로 보관하려면 
 * 1) DB
 * 2) file(수업은 이것으로 합니다)
 * 이때 서블릿 라이프 사이클 메소드가 중요하게 사용되어 진다.
 * 1) 해당 필드값을 파일로 출력 : destroy()
 * 2) 파일에 저장된 값을 읽음:  init()
 */
package servlet.life;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

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

public class ServletLifeCyleTest3 extends HttpServlet {
	private static final long serialVersionUID = 1L;
    private int count = 0;
    private String path="c:\\filestore\\life\\count.txt";//컴퓨터는 이것을 디렉토리로 구분합니다. 
    
    
    public ServletLifeCyleTest3() {
        super();
        System.out.println("1. ServletLifeCyleTest1...call by container(WAS)");
    }

	public void init() throws ServletException {
		System.out.println("2. init...call by container(WAS)");
		//서버가 다시 시작되리 때 init()에서 파일에 저장된 내용을 읽어서 필드 count에 다시 할당
		//0이 아닌 해당 숫자 이후부터 카운팅이 진행된다.
		try {
			BufferedReader br = new BufferedReader(new FileReader(path));
			String str=br.readLine();
			count=Integer.parseInt(str);
			System.out.println("count.txt 파일의 내용을 읽어들임 count:: "+count);
			br.close();
		}catch(IOException e){
			System.out.println("파일을 읽어들이는데 실패했습니다. ");
		}
	}

	public void destroy() {
		System.out.println("4. destroy...call by container(WAS)");
		//필드에 저장된 값을 파일로 뿌리고..... 서버가 내려질 것입니다. 
		File file = new File(path);
		//출력용 파일이 출력스트림에서 자동적으로 생선되려면 그전에 반드시 디렉토리는 먼저 만들어져 있어야합니다. 
		file.getParentFile().mkdirs();//"c:\\filestore\\life\\count.txt"에서 count.text를 제외 하고 만든다.getParentFile()을 해주고 .mkdirs를 쓰는게 안전합니다. 
								// 이렇게 해서 파일을 제외한 디렉토리를 만들어 줍니다. 
		try {
			PrintWriter pw = new PrintWriter(new FileWriter(file));
			//PrintWriter pw = new PrintWriter(new FileWriter(file, true(append)), true(autoflush);
			pw.println(count);
			pw.close();
			System.out.println(path+"count 값:: "+count +" 파일에 영구적으로 저장됨....");
		}catch(IOException e) {
			System.out.println("스트림 생성 실패....");
		}
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doProcess(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doProcess(request, response);
	}
	protected void doProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("3. service...call by container(WAS)");
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		//web browser로 출력
		out.println("<html><body bgcolor='yellow'>");
		out.println("<h3>LifeCycle CallBack Method...</h3>");
		out.println("<b>Count::"+ ++count+"</b>");
		out.println("</body></html>");
		out.close();
	}
	

}

서블릿은 로직중심의 기술입니다. 서블릿에는 tag가 들어가면 안됩니다. PrintWriter가 나오면 안됩니다. 지금까지는 화면 출력까지 담당합니다. 서블릿의 원래의 로직중심으로 가기 위해서 출력을 담당하는 JSP를 사용합니다. 서블릿(로직, 프로그래밍)과 jsp(script 중심, presentation, 결과물 출력)의 역할을 나눕니다.   

 

 

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>lifeCycle</title>
</head>
<body>
<h2 align="center">LifeCycle....CallBack Method Test...</h2>
<a href="life2">LifeCyle Test...click</a>
</body>
</html>

 

package servlet.life;
/*
 * ServletLifeCyleTest1로 복사해서 했는데, sevlet으로 만들지 않아서 xml을 직접 작성해 줘야합니다. 
 * 또한, load-on-startup은 servlet으로 만들던, 복붙해서 만들던 중복없이 직접 써줘야합니다. 
 */
import java.io.IOException;
import java.io.PrintWriter;

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

public class ServletLifeCyleTest2 extends HttpServlet {
	private static final long serialVersionUID = 1L;
     private int count = 0;//field  

    public ServletLifeCyleTest2() {
        super();
        System.out.println("1. ServletLifeCyleTest2...call by container(WAS)");
    }

	public void init() throws ServletException {
		System.out.println("2. init...call by container(WAS)");
	}

	public void destroy() {
		System.out.println("4. destroy...call by container(WAS)");
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doProcess(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doProcess(request, response);
	}
	protected void doProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("3. service...call by container(WAS)");
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		
		count=100;
		out.println("<a href=life2.jsp?cnt="+count+">life2.jsp로 이동</a>");
	}
	

}

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body bgcolor='cyan'>>
<h3>LifeCycle CallBack Method...</h3>
<b>Count::</b>
<%=request.getParameter("cnt") %>
</body>
</html>

아직까지 servlet에 PrinterWriter가 있습니다. 

또한, 이렇게 a 태그로 해서 정보를 전달하는 것은 get방식으로 하는 것이기 때문에 대용량의 data 즉, Object는 전달 할 수 없습니다. 

 

JSP는 script 언어이기 때문에 배포 위치는 web-INF 상위 폴더에 위치하게 됩니다. 

JSP파일을 WAS가 servlet으로 고칩니다. 컴파일해서 실행파일을 만들고, 객체 생성하고 init호출하고 service 호출합니다. jsp로 만들면 WAS가 servlet로 컨버팅 하는 작업이 추가 됩니다. 이 작업 한것을 아래 work 디렉토리에서 확인 할 수 있습니다. 


servletConfig

=>

1) A Servlet Instance Initialization(A servlet A servletConfig 입니다. )

: application, 즉 컨테이너 차원의 global한 initialization이 있고, 위와같이 각각의 instance마다의 initialization이 있습니다. 

2) Container차원에서의 값으로 초기화

-> Extra Resource

: 값을 받아오는 통로는 클라이언트(form)에서 오는 방법 밖에 없는데 WAS가 읽을 수 있는 언어인 XML에 값을 저장하는 방법을 알아야 합니다. 아직 클라이언트의 요청을 받기 이전 시점인데, 필드 초기화를 하려면 클라이언트가 제공하는 값을 통해서 초기화 할 수 없습니다. 아직 ready-on 전입니다. 그래서 컨테이너 차원에서의 값을 통해서 필드 초기화를 합니다. 

클라이언트가 아닌 web.xml에 설정된 값(외부자원, Extra Resource)을 받습니다.

<init-param>

            <param-name> 별

            <param-value> *

</init-param>

ex) String 별 = getInstanceParameter("별");

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<marquee bgcolor="orange"><h1>ServletConfig를 이용한 servlet Initialization.....</h1></marquee>
<a href="SC1">Here Click</a>
</body>
</html>

 

package servlet.config;

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

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

public class ServletConfigTest1 extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private String name, addr;
	
    public ServletConfigTest1() {
        super();
        System.out.println("생성자 호출.......");

    }

	public void init() throws ServletException {
		System.out.println("init 호출......");
		name = getInitParameter("name");
		addr = getInitParameter("addr");
		System.out.println(name+", "+addr);
	}


	public void destroy() {

	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doProcess(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doProcess(request, response);
	}
	protected void doProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("doProcess");
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out=response.getWriter();
		
		out.println("<h2>A Servlet Instance Initialization...Using ServletConfig</h2><p>");
		
		out.println("당신의 이름: "+name+"</br>");
		out.println("당신이 사는 곳: "+addr+"</br>");
		out.close();
	}

}

 

<?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" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>web05_ServletConfig</display-name>
  <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>
  <servlet>
    <description></description>
    <display-name>ServletConfigTest1</display-name>
    <servlet-name>ServletConfigTest1</servlet-name>
    <servlet-class>servlet.config.ServletConfigTest1</servlet-class>
    <init-param>
    	<param-name>name</param-name>
    	<param-value>하바리</param-value>
    </init-param>
    <init-param>
    	<param-name>addr</param-name>
    	<param-value>서현동</param-value>
    </init-param> 
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>ServletConfigTest1</servlet-name>
    <url-pattern>/SC1</url-pattern>
  </servlet-mapping>
</web-app>

 

xml에 정보를 넣는 방법

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2 align="center">Using config...Store log file</h2>
<form action="SC2" method="post">
	UserName:<input type="text" name="userName" placeholder="사용자이름 입력">
	<input type="submit" value="send">
</form>
</body>
</html>

 

package servlet.config;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;

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

public class ServletConfigTest2 extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private String path;
	private int count=0;
    public ServletConfigTest2() {
        super();

    }

	public void init() throws ServletException {
		//1.ServletConfig의 기능을 사용해서 path에 연결된 값을 받아 온다.
		path = getInitParameter("path");
		
		
		
		try {
			//2. BufferedReader를 사용해서 파일을 읽어들입니다. 
			BufferedReader br = new BufferedReader(new FileReader(path));
			String str = br.readLine();
			//3. count값으로 필드 초기화
			count = Integer.parseInt(str);
			br.close();
			System.out.println("count 값: "+count);
			}catch(Exception e){
			System.out.println("파일을 읽어들이는데 실패....");
			
		}
	}
	public void destroy() {
	
	}


	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doProcess(request, response);
	}
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doProcess(request, response);
	}
	protected void doProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//로직은 여기에
		//4. 폼에 입력된 값을 받아서 
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out=response.getWriter();
		String name = request.getParameter("userName");
		out.println("<h2>"+name+", "+count+"번째 고객님이십니다.!!");
	}
}

 

'컴퓨터 프로그래밍 > 수업' 카테고리의 다른 글

2020.06.05  (0) 2020.06.05
2020.06.04  (0) 2020.06.04
2020.06.02  (0) 2020.06.02
2020.06.1_1  (0) 2020.06.01
2020.05.29_2  (0) 2020.05.29