JAVA/HIGH JAVA

[JAVA] 서블릿(Servlet)

아잠만_ 2024. 5. 28. 10:10

서블릿(Servlet)

  • 컨테이너(서블릿 엔진)에 의해 관리되는 자바 기반 웹 컴포넌트로서 동적인 웹 컨텐츠 생성을 가능하게 해준다.
  • 자바 플랫폼에서 컴포넌트를 기반으로 한 웹 애플리케이션을 개발할 때 사용하는 핵심기술
  • 동적인 웹 컨텐츠 생성을 가능하게 하는 기술. 즉, JSP + 자바 기술을 사용 가능하게 해주는 기술
  • 클라이언트 요청을 처리하고 그 결과를 다시 클라이언트에게 전송하는 Servlet 클래스의 구현 규칙을 지킨 자바 프로그램

장점

  • 스레드를 기반으로 하므로 웹 애플리케이션 운영에 효율적이다
  • 자바를 기반으로 하므로 자바 API를 모두 사용할 수 있다
  • 운영체제나 하드웨어에 영향을 받지 않으므로, 한 번 개발된 애플리케이션은 다양한 서버환경에서도 실행 가능
  • 웹 애플리케이션에서 효율적으로 자료 공유 방법을 제공한다

서블릿 컨테이너(Servlet Container)

서블릿을 관리, 서블릿 구조와 클라이언트 요청이 있을 때 처리하는 순서

서블릿의 동작 방식

  1. 사용자(클라이언트)가 URL을 클릭하면 HTTP요청(request)를 Servlet Container로
    전송(요청)한다.
  2. 컨테이너는 web.xml에 정의된 'URL패턴'을 확인하여 어느 서블릿을 통해서 처리해야 할지를
    검색한다.
    (이 때 로딩이 안된 경우에는 로딩한다. 처음 로딩시 init()메서드가 호출된다)
    (서블릿 3.0이상에서는 애노테이션(@WebServlet)으로 설정이 가능하다)
  3. 서블릿 컨테이너는 개별 요청을 처리할 스레드를 생성하여 해당 서블릿 객체의 service()메서드를
    호출한다.
    (이 때 HttpServletRequest객체와 HttpServletResponse객체를 매개변수로 넘겨준다)
  4. service()메서드는 전송방식(GET, POST등)을 체크하여 적절한 메서드를 호출한다
    (doGet(), doPost(), doPut(), doDelete() 등)
  5. 요청 및 응답 처리가 완료되면 HttpServletRequest객체와 HttpServletResponse객체는
    자동으로 소멸된다
  6. Servlet Container에서 서블릿이 제거되는 경우에는 destroy()메서드가 호출

※ web.xml : 서블릿을 작성했다면 해당 서블릿을 사용자가 요청한 경로와 맵핑시켜야 WAS에서 맵핑된 정보를 읽어서 브라우저에서 해당 URL로 HTTP요청 시 해당 서블릿으로 요청을 전달해 줄 수 있다. 소스를 분석할 때도 가장 먼저 확인해봐야 할 부분이다. 톰캣을 예로 들면 웹 어플리케이션 서비스 처리에 대해 정의된 환경 설정 파일이 server디렉터리의 web.xml에 있다.

MVC패턴

모델 : 자바 클래스 (Service, DAO, VO)

뷰 : JSP, JSTL

컨트롤러 : 서블릿

메서드 ( HttpServlet 상속)

  • init() 
    서블릿 로딩
    서블릿이 컨테이너에의해 관리되는데
    컨테이너에서 읽어다가 메모리에 있는지 확인하고 없다면 객체화를 시켜야하는데 
    이때 init()메서드가 각종 초기화 작업을 수행
  • service()
    요청 처리 모두 HttpServletRequest와 HttpServletResponse를 매개변수로 전달한다
    • doGet()
    • doPost()
      • setCharacterEncoding("utf-8")
        setContentType("text/html; charset=utf-8")
      • 출력용 스트림 PrintWriter 객체 출력 전송
        • append()
        • print(), println(), printf()
  • destory()
    서블릿 종료
    컨테이너로부터 서블릿 종료 요청

Servlet 클래스

package kr.or.ddit.basic;

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;

/*
	서블릿이란 ==> 컨테이너(서블릿 엔진)에 의해 관리되는 자바 기반 웹 컴포넌트로서
			 	동적인 웹 컨텐츠 생성을 가능하게 해준다.
 */
// 이 예제는 배포 서술자 (web.xml)를 이용해서 실행할 Servlet을 설정하여 처리하는 예제이다

// Servlet클래스는 HttpServlet클래스를 상속해서 작성한다
public class ServletTest01 extends HttpServlet {
	/*
	 	이 영역에서는 service()메서드 또는 doGet()메서드나 doPost()메서드를
	 	재정의해서 작성한다.
	 	
	 	doGet()메서드나 doPost()메서드는 service()메서드를 통해서 호출된다.
	 	이 메서드들의 매개변수로 다음과 같이 2개의 객체를 지정해준다.
	 	- HttpServletRequest객체 => 서비스 요청에 관련된 정보 및 메서드를 관리하는 객체
	 	- HttpServletResponse객체 => 서비스 응답에 관련된 정보 및 메서드를 관리하는 객체
	 */
	
	// doGet() 메서드 ==> GET방식의 요청을 처리하는 메서드
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.setCharacterEncoding("utf-8"); // 응답 문서의 인코딩 방식 지정
		
		// 응답 문서의 ContentType 지정
		resp.setContentType("text/html; charset=utf-8");
		
		// 처리한 결과를 응답으로 보내려면 PrintWriter객체를 생성한다
		// 	==> HttpServletResponse객체의 getWriter()메서드를 이용하여 생성한다
		PrintWriter out = resp.getWriter();
		
		// 처리한 내용을 출력(전송)한다.
		// 방법1) PrintWriter객체의 append()메서드 이용하기
		out.append("<html>")
		.append("<head> <meta charset='utf-8'> "
				+ "<title>첫번째 서블릿</title></head>")
		.append("<body>")
		.append("<h2 style='text-align:center;'>")
		.append("안녕하세요 첫번째 Servlet 프로그램입니다<br>"
				+ "만나서 반갑습니다</h2>")
		.append("</body>")
		.append("</html>");
	}
	
	// doPost() 메서드 ==> POST방식의 요청을 처리하는 메서드
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		super.doPost(req, resp);
	}
	
	
}

web.xml

서블릿이 실행가능 하게 등록+ 매핑

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>webTest</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>
  	<servlet-name>내마음대로이름</servlet-name>
  	<servlet-class>kr.or.ddit.basic.ServletTest01</servlet-class>
  </servlet>
  
  <!-- 요청 URL과 서블릿 매핑(연결)하기 -->
  <!-- 이때 이름은 위의 등록한 값과 동일 -->
  <servlet-mapping>
  	<servlet-name>내마음대로이름</servlet-name>
  	<url-pattern>/servletTest01.do</url-pattern>
  </servlet-mapping>
</web-app>

실행하기위해서 server에 프로젝트 추가

더보기

Add and Remove

add

서버 하위항목에 확인된다면 설정완료

실행

URL주소
http://localhost:80/webTest/servletTest01.do
http localhost 80 /webTest /servletTest01.do
프로토콜 서버의 컴퓨터이름
(도메인명)
또는 서버의 IP주소
포트번호
( 포트번호가
80번일경우에는
생략 가능하다. )
컨텍스트 path
( 보통은 웹 프로젝트
이름으로 지정한다. )
서블릿 요청 URL패턴
(매핑으로
url-pattern
설정해준 값)

@WebServlet 애노테이션

속성들

  1. name : 서블릿 이름을 설정한다. (기본값 : 빈문자열(""))
  2. urlPatterns : 서블릿의 URL패턴의 목록을 설정한다. (기본값 : 빈배열({}))
      예) urlPatterns="/url1" 또는 urlPatterns={"/url1"}
      ==> URL패턴이 1개일 경우
      예) urlPatterns={"/url1", "/url2", ...}
      ==> URL패턴이 2개 이상일 경우
  3. value : urlPatterns와 같다
  4. description : 주석(설명글)을 설정한다.
@WebServlet(
      description = "주석", // 꼭 ,로 구분
      urlPatterns = "/servletTest02.ddit"
)

package kr.or.ddit.basic;

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

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
/*
 	이 예제는 애노테이션(@WebServlet)을 이용하여 Servlet을 설정하여 처리하는 예제
 	( @WebServlet 애노테이션은 Servlet버전 3.0이상에서 사용할 수 있다.)
 */
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//@WebServlet("/servletTest02.ddit") // URL 패턴만 지정할 경우
@WebServlet(
		description = "애노테이션을 이용한 서블릿", //주석글
		urlPatterns = "/servletTest02.ddit"
)
public class ServletTest02 extends HttpServlet {
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.setCharacterEncoding("UTF-8");
		resp.setContentType("text/html; charset=utf-8");
		
		// 출력용 스트림 객체 생성
		PrintWriter out = resp.getWriter();
		
		// 처리한 내용을 출력(전송)한다.
		// 방법2) PrintWriter객체의 print(), println(), printf()를 이용한다.
		out.println("<html>");
		out.println("<head><meta charset='utf-8'>"
				+"<title>두번째 서블릿 연습</title></head>");
		
		out.println("<body>"
				+ "<h2 style='text-align:center; color:maroon;'>"
				+ "두번째 Servlet예제 입니다<br>"
				+ "@WebServlet애노테이션을 이용한 예제입니다<br>"
				+ "ContentextPath "+ req.getContextPath()+"</h2>"
				+ "</body></html>");
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		super.doPost(req, resp);
	}
}

(web.xml을 설정하지 않고 바로 실행이 가능하다)

Servlet로 생성하기

(유의사항)

더보기

생성시 mappings할 이름을 재설정해줄것

JSP로 서블릿 실행

get_Post.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>서블릿 요청 연습</title>
<script>
window.onload = function(){
	document.getElementById("getBtn").addEventListener("click",function(){
		location.href = "/webTest/servletTest03.do";
	});
}
</script>
</head>
<body>
<h1>Servlet 요청 연습</h1>
<br><hr><br>

<h2>Get방식 요청1 ==> 링크 방식</h2>
<!-- localhost 까지 생략가능하다 -->
<a href="/webTest/servletTest03.do">Get방식 요청1</a>
<br><hr><br>

<h2>Get방식 요청2 ==> form태그의 method속성이 생략되거나 'Get'으로 설정한 경우</h2>
<form action="http://localhost/webTest/servletTest03.do">
	<input type="submit" value="Get방식 요청2">
</form>
<br><hr><br>

<h2>Get방식 요청3 ==> JavaScript의 location.href를 이용</h2>
<form>
	<input type="button" value="Get방식 요청3" id="getBtn">
</form>
<br><hr><br>

<h2>Post방식 요청 ==> form태그의 method속성을 'Post'로 설정한 경우</h2>
<form action="http://localhost/webTest/servletTest03.do" method="Post">
	<input type="submit" value="Post방식 요청">
</form>

</body>
</html>

ServletTest03.java

package kr.or.ddit.basic;

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

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

/*
	서블릿의 동작 방식..
	1. 사용자(클라이언트)가 URL을 클릭하면 HTTP요청(request)를 Servlet Container로
		전송(요청)한다.
	2. 컨테이너는 web.xml에 정의된 'URL패턴'을 확인하여 어느 서블릿을 통해서 처리해야 할지를
		검색한다.
		(이 때 로딩이 안된 경우에는 로딩한다. 처음 로딩시 init()메서드가 호출된다)
		(서블릿 3.0이상에서는 애노테이션(@WebServlet)으로 설정이 가능하다)
	3. 서블릿 컨테이너는 개별 요청을 처리할 스레드를 생성하여 해당 서블릿 객체의 service()메서드를
		호출한다.
		(이 때 HttpServletRequest객체와 HttpServletResponse객체를 매개변수로 넘겨준다)
	4. service()메서드는 전송방식(GET, POST등)을 체크하여 적절한 메서드를 호출한다
		(doGet(), doPost(), doPut(), doDelete() 등)
	5. 요청 및 응답 처리가 완료되면 HttpServletRequest객체와 HttpServletResponse객체는
		자동으로 소멸된다
	6. Servlet Container에서 서블릿이 제거되는 경우에는 destroy()메서드가 호출
		
 */
@WebServlet("/servletTest03.do")
public class ServletTest03 extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public void init() throws ServletException {
    	System.out.println("servlet : "+this.getServletName()
    	+ "에서 init()메서드 호출");
    }
     
	@Override
		public void init(ServletConfig config) throws ServletException {
			// TODO Auto-generated method stub
			super.init(config);
		}
	
	// 서블릿이 변경될 때 원래 있던 내용이 삭제되고 재부팅 되면서 destory()호출
    public void destroy() {
    	System.out.println("servlet : "+this.getServletName()
    	+ "에서 destroy()메서드 호출");
    }

    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	System.out.println("service()메서드 시작");
    	
    	// GET방식과 POST방식에 맞는 메서드를 호출하기
    	// 방법1) 부모 클래스인 HttpServlet클래스의 service()메서드로 위임하기
//    	super.service(request, response);
    	
    	// 방법2) 클라이언트의 전송방식 (GET, POST 등)을 구분해서 직접 메서드 호출하기
    	//		HttpServletRequest객체의 getMethod()메서드를 이용하여
    	//		전송 방식을 구해서 처리한다
        String method = request.getMethod();
        System.out.println("method => "+method);
        if ("GET".equalsIgnoreCase(method)) {
            doGet(request, response);
        } else { // get과 post 방식밖에 없다고 가정
            doPost(request, response);
        } 
    }
    
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("doGet()메서드 시작");
		response.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=utf-8");
		PrintWriter out = response.getWriter();
		out.println("<html><head><meta charset='utf-8'></head>");
		out.println("<body style='color:red'><h1>doGet()메서드를 처리한 결과입니다</h2></body></html>");
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("doPost()메서드 시작");
		response.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=utf-8");
		PrintWriter out = response.getWriter();
		out.println("<html><head><meta charset='utf-8'></head>");
		out.println("<body style='color:blue'><h1>doPost()메서드를 처리한 결과입니다</h2></body></html>");
	}

}