[23/06/30] 서블릿 (1)

yeju·2023년 6월 30일
0

Servlet

목록 보기
1/6
post-thumbnail

📖 5. 서블릿 이해하기

📌 서블릿(Servlet)이란?

클라이언트(웹 브라우저)의 요청에 따라 동적으로 서비스를 제공하는 자바 클래스

  • 서버 쪽에서 실행되면서 동적으로 여러 기능을 수행함
  • 톰캣과 같은 서블릿 컨테이너에서 실행됨
  • 스레드 방식(병렬 처리) 으로 실행됨

서블릿 동작 과정

📌 서블릿 API 계층 구조와 기능

웹 브라우저의 요청을 처리하는 서블릿은 HttpServlet 이고, 이 클래스를 상속받으면 웹 브라우저에서 받은 요청을 처리하는 서블릿을 작성할 수 있다.
GenericServlet 추상 클래스가 Servlet 인터페이스, ServletConfig 인터페이스를 구현했고, HttpServlet 클래스는 GenericServlet 클래스를 상속받아 해당 메서드를 모두 사용할 수 있다.

📌 서블릿의 생명주기 메서드

서블릿은 자바 클래스이므로 초기화 과정, 인스턴스 생성 과정, 소멸 과정을 거치며, 각각의 과정마다 호출되어 기능을 수행하는 메서드를 서블릿 생명주기 메서드라고 한다.

init() : 서블릿 요청 시 처음 한 번만 호출됨, 초기 설정 작업을 주로 수행
doGet() , doPost() : 서블릿 요청 시 매번 호출됨, 클라이언트가 요청한 핵심 기능을 수행
destroy() : 서블릿이 메모리에서 소멸될 때 호출됨, 마무리 작업을 주로 수행

📌 서블릿을 만들고 실행하는 과정

  1. 원하는 내용의 서블릿 클래스 생성하고 생명주기 메서드 구현하기
  2. 서블릿 매핑 작업하기
  3. 웹 브라우저에서 서블릿 매핑 이름으로 요청하기

1. 서블릿 클래스 생성, 생명주기 메서드 구현

package sec01.ex01;

import java.io.IOException;

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

public class FirstServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("doGet 메서드 호출");
	}

	@Override
	public void destroy() {
		System.out.println("destroy 메서드 호출");
	}

	@Override
	public void init() throws ServletException {
		System.out.println("init 메서드 호출");
	}
	
}

2. 서블릿 매핑 작업

파일명 : web.xml

<web-app>
...
  <!-- 서블릿 매핑 하기 -->
  <servlet>
  	<servlet-name>first</servlet-name>
  	<servlet-class>sec01.ex01.FirstServlet</servlet-class>
  </servlet>
  <servlet>
  	<servlet-name>second</servlet-name>
  	<servlet-class>sec01.ex01.SecondServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>first</servlet-name>
  	<!-- 컨텍스트명 뒤에 올 url을 입력  -->
  	<url-pattern>/first</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
  	<servlet-name>second</servlet-name>
  	<url-pattern>/second</url-pattern>
  </servlet-mapping>
...
</web-app>

3. 웹 브라우저에서 서블릿 매핑 이름으로 요청

주소창에 http://IP주소:포트번호/컨텍스트(프로젝트)명/first 입력
콘솔에 'init 메서드 호출' , 'doGet 메서드 호출' 메세지 출력 확인

📌 애너테이션을 이용한 서블릿 매핑

애너테이션이란?
web.xml 에서 서블릿 설정을 작성하지 않고 각 서블릿 클래스에 기호(@)를 이용하여 서블릿 표시를 하는 것, 가독성을 높일 수 있음
서블릿 클래스 위에 @WebServlet("/서블릿매핑이름") 을 입력하여 사용

package sec01.ex01;

import java.io.IOException;
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;

// 에너테이션 사용
@WebServlet("/third")
public class ThirdServlet extends HttpServlet {

	public void init(ServletConfig config) throws ServletException {
		System.out.println("init 메서드 호출");
	}

	public void destroy() {
		System.out.println("destroy 메서드 호출");
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("doGet 메서드 호출");
	}

}

📖 6. 서블릿 기초

📌 서블릿의 세 가지 기본 기능

  1. 클라이언트로부터 요청 받기
  2. 비즈니스 로직 처리하기
  3. 처리 결과를 클라이언트에 돌려주기(응답)

📝 서블릿 요청과 응답 수행 API

요청과 관련된 API : HttpServletRequest 클래스
응답과 관련된 API : HttpServletResponse 클래스

서블릿에 요청이 들어오면 웹 애플리케이션 서버가 HttpServletRequest 객체와 HttpServletResponse 객체를 만들고, 해당 객체를 doGet() , doPost() 등의 매개변수로 사용한다. 이로써 넘어온 요청과 응답을 서블릿에서 처리할 수 있다.

📝 서블릿에서 요청 처리하기

파일명 : login.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인</title>
</head>
<body>
  	<!-- 제출 시 서블릿 매핑 이름이 login인 서블릿으로 전송 -->
	<form name="frmLogin" method="post" action="login" encType="UTF-8">
		아이디 : <input type="text" name="user_id"><br>
		비밀번호 : <input type="password" name="user_pw"><br>
		<input type="submit" value="로그인"> <input type="reset" value="초기화">
	</form>
</body>
</html>
...

@WebServlet("/login")
public class LoginServlet extends HttpServlet {

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		String user_id = request.getParameter("user_id");
		String user_pw = request.getParameter("user_pw");
		
		System.out.println("아이디 : "+user_id);
		System.out.println("비밀번호 : "+user_pw);
	}
	
	...

}

url에 데이터를 붙여 전송하려면 get 방식, 숨겨서 전송하려면 post 방식 사용

getParameterValues() : 한 name 에 여러 값이 들어 있을 경우 (ex. 체크박스) getParameterValues() 메서드를 사용해 배열로 받기

getParameterNames() : 전송된 데이터 종류가 많을 경우 getParameterNames() 메서드로 모든 키(name) 이름을 Enumeration 객체로 받아옴

파일명 : input.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>여러 가지 input</title>
</head>
<body>
	<form name="frmInput" method="get" action="input2">
		아이디 : <input type="text" name="user_id"><br>
		비밀번호 : <input type="password" name="user_pw"><br>
		<input type="checkbox" name="subject" value="java" checked> 자바
		<input type="checkbox" name="subject" value="C언어"> C언어
		<input type="checkbox" name="subject" value="JSP"> JSP
		<input type="checkbox" name="subject" value="안드로이드"> 안드로이드
		<br><br>
		<input type="submit" value="전송">
		<input type="reset" value="초기화">
	</form>
</body>
</html>
package sec01.ex01;

import java.io.IOException;
import java.util.Enumeration;

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;

@WebServlet("/input2")
public class InputServlet2 extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public void init(ServletConfig config) throws ServletException {
		System.out.println("init 메서드 호출");
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		
		Enumeration enu = request.getParameterNames();
		// hasMoreElements(), nextElement() 로 안에 있는 name값 가져오기
		while(enu.hasMoreElements()) {
			String name = (String) enu.nextElement();
			// 해당 name에 있는 모든 값 가져와 배열에 담기
			String[] values = request.getParameterValues(name);
			// foreach문으로 배열 요소 출력하기
			for(String value : values) {
				System.out.println(name+" : "+value);
			}
		}
	}

	public void destroy() {
		System.out.println("destroy 메서드 호출");
	}

}

📝 서블릿에서 응답 처리하기

HttpServletResponse 객체와 자바 IO 스트림 을 이용해 클라이언트(웹 브라우저) 에 원하는 내용을 출력할 수 있다.

응답 처리 방법
1. setContentType() 메서드로 MIME-TYPE 지정
2. 데이터를 출력할 PrintWriter 객체 생성
3. 출력 데이터를 HTML로 입력
4. PrintWriter의 print() 메서드를 이용해 데이터 출력

MIME-TYPE이란?
서버에서 웹 브라우저로 데이터를 전송할 때 지정하는 전송 데이터의 종류
톰캣 컨테이너에 미리 설정되어 있는 여러 값 중 하나를 선택, 웹 브라우저는 기본적으로 HTML만 인식하므로 서블릿에서 전송하는 대부분의 데이터는 text/html로 지정함

📄 [예제] 서블릿을 이용한 환율 계산기

package sec02.ex01;

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;

// url-pattern이 /calc일 때 다음 서블릿 실행
@WebServlet("/calc")
public class CalcServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	// 환율 설정
	private static float USD_RATE = 1124.70F;
	private static float JPY_RATE = 10.113F;
	private static float CNY_RATE = 163.30F;
	private static float GBP_RATE = 1444.35F;
	private static float EUR_RATE = 1295.97F;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		// html에 내용을 입력하기 위한 준비
		response.setContentType("text/html; charset=utf-8");
		PrintWriter pw = response.getWriter();
		
		// 수행할 요청(command)
		String command = request.getParameter("command");
		// 변환할 원화
		String won = request.getParameter("won");
		// 변환할 외화 종류
		String operator = request.getParameter("operator");
		
		if (command != null && command.equals("calculate")) {
			// command 값이 calculate면 해당 내용 실행하고 웹 브라우저로 return
			String result = calculate(Float.parseFloat(won), operator);
	        pw.print("<html><font size=10>변환결과</font><br>");
	        pw.print("<html><font size=10>" + result + "</font><br>");
	        pw.print("<a href='calc'>환율 계산기</a>");
	        return;
		}
		
		// if문이 실행되지 않으면 아래 내용 실행
		pw.print("<html><title>환율계산기</title>");
	    pw.print("<font size=5>환율 계산기</font><br>");
	    pw.print("<form name='frmCalc' method='get' action='calc'/>  ");
	    pw.print("원화: <input type='text' name='won' size=10/> ");
	    pw.print("<select name='operator'>");
	    pw.print("<option value='dollar'>달러</option>");
	    pw.print("<option value='en'>엔화</option>");
	    pw.print("<option value='wian'>위안</option>");
	    pw.print("<option value='pound'>파운드</option>");
	    pw.print("<option value='euro'>유로</option>");
	    pw.print("</select>");
	    pw.print("<input type='hidden' name='command' value='calculate'  />  ");
	    pw.println("<input type='submit' value='변환'/>");
	    pw.println("</form>");
	    pw.print("</html>");
	    pw.close();
	}
	
	// 환율대로 계산해 금액을 반환하는 메서드
	private static String calculate(float won, String operator) {
		String result = null;
		
		if(operator.equals("dollar")) {
			result = String.format("%.6f", won / USD_RATE);
		} else if(operator.equals("en")) {
			result = String.format("%.6f", won / JPY_RATE);
		} else if(operator.equals("wian")) {
			result = String.format("%.6f", won / CNY_RATE);
		} else if(operator.equals("pound")) {
			result = String.format("%.6f", won / GBP_RATE);
		} else if(operator.equals("euro")) {
			result = String.format("%.6f", won / EUR_RATE);
		}
		return result;
	}
}

📝 GET 방식과 POST 방식 요청 동시에 처리하기

doGet() , doPost() 메서드에서 doHandle() 메서드를 호출해 전송 방식에 상관없이 같은 내용을 실행한다.

...

@WebServlet("/login4")
public class LoginServlet4 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doHandle(request, response);
	}
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doHandle(request, response);
	}
	private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 실행할 내용
	}
}

📄 [예제] 구구단 출력하기

입력 페이지
파일명 : /test01/gugu.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>단수 입력창</title>
</head>
<body>
	<form method="get" action="../guguTest">
		출력할 구구단 : <input type="text" name="dan"><br>
		<input type="submit" value="구구단 출력">
	</form>
</body>
</html>
package sec04.ex01;

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;

@WebServlet("/guguTest")
public class GuguTest extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public void init(ServletConfig config) throws ServletException {
		System.out.println("init 메서드 호출");
	}

	public void destroy() {
		System.out.println("destroy 메서드 호출");
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		
		// 받아온 단수를 int 타입으로 캐스팅
		int dan = Integer.parseInt(request.getParameter("dan"));
		
		String data = "<table border=1 width=800 align=center style=border-collapse:collapse>";
		data += "<tr align=center bgcolor='#FFFF66'>";
		data += "<td colspan=2>" + dan + " 단 출력</td>";
		data += "</tr>";
		// 1단부터 9단까지 내용 입력
		for (int i=1; i<10; i++) {
			if(i%2 == 0) {
				data += "<tr align=center bgcolor='#ACFA58'>";
			}
			else {
				data += "<tr align=center bgcolor='#81BEF7'>";
			}
			data += "<td width=400>";
			data += dan + "*" + i;
			data += "</td>";
			data += "<td width=400>";
			data += dan * i;
			data += "</td>";
			data += "</tr>";
		}
		data += "</table>";
		
		out.print(data);
	}
}

profile
🌱

0개의 댓글