Study Web Development

1월 4일

이전으로

Servlet & JSP

2. Servlet

2-1 서블릿의 개요

  1. 패키지 kr.web.ch01에 새 클래스 MyInfoServlet 생성
package kr.web.ch01;

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

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

@WebServlet("/myInfo")
public class MyInfoServlet extends HttpServlet { // HttpServlet을 상속받아야 서블릿이 됨(=요청을 받아 HTML을 생성)
	// HttpServlet의 doGet() 메서드를 재정의
	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String name = "너굴";
		int age = 20;
		String job = "학생";
		String address = "서울시";
		
		// 문서 타입 및 캐릭터셋 지정
		response.setContentType("text/html;charset=utf-8");
		
		// HTML 생성을 위해 출력 스트림 생성
		PrintWriter out = response.getWriter();
		out.println("<html>");
		out.println("<head><title>개인 정보</title></head>");
		out.println("<body>");
		out.println("이름 : " + name + "<br>");
		out.println("나이 : " + age + "<br>");
		out.println("직업 : " + job + "<br>");
		out.println("주소 : " + address);
		out.println("</body>");
		out.println("</html>");
		out.close();
	}
}

2-2 HTTP 프로토콜과 HTTP 메서드

GET 방식
  1. src/main/webapp 폴더 오른쪽 클릭하고 새 폴더 views 생성 후 새 HTML 파일 gugu.html 생성
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>구구단 입력</title>
</head>
<body>
<h1>구구단의 단 입력</h1>
<form action="/servletMain/gugudan" method="get"> <!-- action 속성에는 호출할 서버 프로그램의 주소(Context Root부터)를 명시, method 속성에는 전송 방식(get 방식은 클라이언트의 데이터를 URL에 ?name=value 형식으로 붙여서 보냄)을 명시 --><input type="number" name="dan" min="2" max="9"><br>
	<input type="submit" value="전송">
</form>
</body>
</html>
  1. 패키지 kr.web.ch01에 새 클래스 GugudanServlet 생성
package kr.web.ch01;

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

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

@WebServlet("/gugudan")
public class GugudanServlet extends HttpServlet {
	// HttpServlet의 doGet() 메서드를 재정의
	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 클라이언트가 전송한 데이터 반환
		int dan = Integer.parseInt(request.getParameter("dan")); // getParameter() 메서드는 인자로 전달된 식별자에 대응하는 값을 문자열로 반환
		
		// 문서 타입 및 캐릭터셋 지정
		response.setContentType("text/html;charset=utf-8");
		
		// HTML 생성을 위해서 출력 스트림 생성
		PrintWriter out = response.getWriter();
		out.println("<html>");
		out.println("<head><title>구구단</title></head");
		out.println("<body>");
		out.println(dan + "단<br>");
		for(int i=1;i<=9;i++) {
			out.println(dan + " * " + i + " = " + dan * i + "<br>");
		}
		out.println("</body>");
		out.println("</html>");
		out.close();
	}
}
  1. views 폴더에 새 HTML 파일 add.html 생성
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>[실습] 덧셈</title>
</head>
<body>
<form action="/servletMain/add" method="get"> <!-- 전송되는 데이터가 2개 이상인 경우, ?name=value&name2=value2와 같이 &를 구분자로 하여 연결 -->
	첫 번째 정수 : <input type="number" name="num1"><br>
	두 번째 정수 : <input type="number" name="num2"><br>
	<input type="submit" value="더하기">
</form>
</body>
</html>
  1. 패키지 kr.web.ch01에 새 클래스 AddServlet 생성
package kr.web.ch01;

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;

@WebServlet("/add")
public class AddServlet extends HttpServlet {
	/*
	 * [실습 문제] 전송된 두 개의 정수를 덧셈하여 결과 값을 표시하시오.
	 * [출력 예시] 5 + 6 = 11
	 */
	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		int num1 = Integer.parseInt(request.getParameter("num1"));
		int num2 = Integer.parseInt(request.getParameter("num2"));
		
		response.setContentType("text/html;charset=utf-8");
		
		PrintWriter out = response.getWriter();
		out.println("<html>");
		out.println("<head><title>덧셈 결과</title></head>");
		out.println("<body>");
		out.println(num1 + " + " + num2 + " = " + (num1 + num2));
		out.println("</body>");
		out.println("</html>");		
		out.close();
	}
}
POST 방식
  1. views 폴더에 greeting.html 생성
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Greeting Form</title>
</head>
<body>
<form action="/servletMain/greeting" method="post"> <!-- post 방식은 클라이언트의 데이터를 URL에 표시하지 않고 HTTP 패킷의 body에 담아 보냄 -->
	당신의 이름은? <input type="text" name="name"><br>
	<input type="submit" value="전송">
</form>
</body>
</html>
  1. 새 패키지 kr.web.ch02 생성하고 새 클래스 GreetingServlet 생성
package kr.web.ch02;

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;

@WebServlet("/greeting")
public class GreetingServlet extends HttpServlet {
	// 클라이언트가 데이터 전송 방식을 post로 지정하고 데이터를 전송할 경우, 서블릿에서 doPost() 메서드를 재정의해야 메서드가 구동됨
	@Override
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 전송된 데이터 인코딩 처리
		request.setCharacterEncoding("utf-8"); // (get 방식과 달리) post 방식의 경우 명시적으로 인코딩 처리를 하지 않으면 한글이 깨짐
		
		String name = request.getParameter("name");
		
		// 문서 타입 및 캐릭터셋 지정
		response.setContentType("text/html;charset=utf-8");
		
		// HTML 생성을 위해서 출력 스트림을 생성
		PrintWriter out = response.getWriter();
		out.println("<html>");
		out.println("<head><title>Greeting</title></head>");
		out.println("<body>");
		out.println(name + "님의 방문을 환영합니다.");
		out.println("</body>");
		out.println("</html>");		
		out.close();
	}
}
  1. views 폴더에 새 HTML 파일 board_write.html 생성
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시판 글쓰기</title>
</head>
<body>
	<h2>글쓰기</h2>
	<form action="/servletMain/board" method="post">
		이름 : <input type="text" name="name"><br>
		제목 : <input type="text" name="title"><br>
		내용 : <textarea rows="5" cols="50" name="content"></textarea><br>
		<input type="submit" value="전송">
	</form>
</body>
</html>
  1. 패키지 kr.web.ch02에 새 클래스 BoardServlet 생성
package kr.web.ch02;

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;

@WebServlet("/board")
public class BoardServlet extends HttpServlet {
	// HttpServlet의 doPost() 메서드를 재정의
	@Override
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 전송된 데이터 인코딩 처리
		request.setCharacterEncoding("utf-8");
		
		String name = request.getParameter("name");
		String title = request.getParameter("title");
		String content = request.getParameter("content");
		
		// 문서 타입 및 캐릭터셋 지정
		response.setContentType("text/html;charset=utf-8");
		
		// HTML 생성을 위해 출력 스트림을 생성
		PrintWriter out = response.getWriter();
		out.println("<html>");
		out.println("<head><title>글쓰기 완료</title></head>");
		out.println("<body>");
		out.println("이름 : " + name + "<br>");
		out.println("제목 : " + title + "<br>");
		content = content.replaceAll("\n", "<br>"); // 전송받은 문자열의 줄바꿈을 유지한 채 출력하기
		out.println("내용 : " + content);
		out.println("</body>");
		out.println("</html>");
		out.close();
	}
}
  1. views 폴더에 새 HTML 파일 score_form.html 생성
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>실습</title>
</head>
<body>
	<!-- 국어(korean), 영어(english), 수학(math)을 입력받아 성적 처리 -->
	<form action="/servletMain/score" method="post">
	<label>국어 : <input type="number" name="korean" min="0" max="100" required></label>
	<label>영어 : <input type="number" name="english" min="0" max="100" required></label>
	<label>수학 : <input type="number" name="math" min="0" max="100" required></label>
	<input type="submit" value="성적 처리">
	</form>
</body>
</html>
  1. 패키지 kr.web.ch02에 새 클래스 ScoreServlet 생성
package kr.web.ch02;

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;

@WebServlet("/score")
public class ScoreServlet extends HttpServlet {
	@Override
	public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		/*
		 * [실습 문제] 전송된 국어, 영어, 수학 점수를 이용해서 총점과 평균(정수), 등급을 구하고 출력하시오.
		 * [출력 예시]
		 * 국어 : 90
		 * 영어 : 90
		 * 수학 : 90
		 * 총점 : 270
		 * 평균 : 90
		 * 등급 : A
		 */

		req.setCharacterEncoding("utf-8"); // 전송받은 데이터가 영문과 숫자로만 구성되어 있는 경우 생략 가능
		
		int korean = Integer.parseInt(req.getParameter("korean"));
		int english = Integer.parseInt(req.getParameter("english"));
		int math = Integer.parseInt(req.getParameter("math"));
		
		// 서블릿에서 만든 메서드는 다른 서블릿에서 호출할 수 없기 때문에, 재사용성을 높이기 위해 메서드를 만들고자 한다면 별도의 클래스에 만들어야 함
		int sum = korean + english + math;		
		int avg = sum / 3;
		String grade = "";
		if(avg>=90) grade = "A";
		else if(avg>=80) grade = "B";
		else if(avg>=70) grade = "C";
		else if(avg>=60) grade = "D";
		else grade = "F";
		
		resp.setContentType("text/html;charset=utf-8");
		
		PrintWriter out = resp.getWriter();
		out.println("<html>");
		out.println("<head><title>성적 처리 결과</title></head>");
		out.println("<body>");
		out.println("국어 : " + korean + "<br>");
		out.println("영어 : " + english + "<br>");
		out.println("수학 : " + math + "<br>");
		out.println("총점 : " + sum + "<br>");
		out.println("평균 : " + avg + "<br>");
		out.println("등급 : " + grade);
		out.println("</body>");
		out.println("</html>");
		out.close();
	}
}
  1. views 폴더에 lunch.html 생성
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>점심 선택</title>
</head>
<body>
	<h3>오늘 점심은 무엇을 먹을까?(2개 이상 선택)</h3>
	<form action="/servletMain/todayMenu" method="post"> <!-- 체크박스의 경우, 파라미터명 하나에 여러 값을 전송할 수 있음 -->
		<label><input type="checkbox" name="lunch" value="미트치즈피자">미트치즈피자</label>
		<label><input type="checkbox" name="lunch" value="매콤크림파스타">매콤크림파스타</label>
		<label><input type="checkbox" name="lunch" value="카츠카레">카츠카레</label>
		<label><input type="checkbox" name="lunch" value="마늘간장치킨">마늘간장치킨</label>
		<label><input type="checkbox" name="lunch" value="비프칠리버거">비프칠리버거</label>
		<input type="submit" value="전송">
	</form>
</body>
</html>
  1. 패키지 kr.web.ch02에 새 클래스 TodayMenu 생성
package kr.web.ch02;

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;

@WebServlet("/todayMenu")
public class TodayMenu extends HttpServlet {
	@Override
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 전송된 데이터 인코딩 처리
		request.setCharacterEncoding("utf-8");
		
		// 문서 타입 및 캐릭터셋 지정
		response.setContentType("text/html;charset=utf-8");
		
		// HTML 생성을 위한 출력 스트림 생성
		PrintWriter out = response.getWriter();
		out.println("<html>");
		out.println("<head><title>Lunch Menu</title></head>");
		out.println("<body>");
		out.println("<h3>오늘의 점심</h3>");
		
		String[] values = request.getParameterValues("lunch"); // 체크박스의 경우 복수의 값이 전송될 수 있으므로 getParameterValues() 메서드를 이용해 배열로 반환받음
		if(values!=null) {
			for(int i=0;i<values.length;i++) {
				out.println(values[i] + "<br>");
			}
		}
		else {
			out.println("점심 메뉴를 선택하지 않았습니다. 3초 후 이전 페이지로 돌아갑니다.");
			out.println("<script type=\"text/javascript\">setTimeout(function() {history.back();}, 3000);</script>");
		}
		out.println("</body>");
		out.println("</html>");
		out.close();
	}
}
  1. views에 새 HTML 파일 travel.html 생성
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>실습</title>
<script type="text/javascript">
	window.onload = function() {
		var myForm = document.getElementById('myForm');
		// 이벤트 연결
		myForm.onsubmit = function() {
			var name = document.getElementById('name');
			if(name.value.trim()=='') { // 아무것도 입력하지 않거나 공백만 입력한 경우
				alert('이름을 입력하세요!');
				name.focus();
				name.value = '';
				return false;
			}
			
			var cities = document.getElementsByClassName('cb-city');
			var num = 0;
			for(var i=0;i<cities.length;i++) {
				if(cities[i].checked) { // 체크박스가 선택된 경우
					num++;
				}
			}
			if(num<2) {
				alert('여행지를 2개 이상 선택해야 합니다!');
				return false;
			}
		};
	};
</script>
</head>
<body>
	<!-- 이름(name), 여행지 선택(city: 서울, 뉴욕, 런던, 파리) -->
	<h3>여행지를 선택하세요(2개 이상 선택)</h3>
	<form id="myForm" method="post" action="/servletMain/travel">
		이름 : <input type="text" name="name" id="name">
		<br>
		여행지 : 
		<label><input type="checkbox" name="city" value="서울" class="cb-city">서울</label>
		<label><input type="checkbox" name="city" value="뉴욕" class="cb-city">뉴욕</label>
		<label><input type="checkbox" name="city" value="런던" class="cb-city">런던</label>
		<label><input type="checkbox" name="city" value="파리" class="cb-city">파리</label>
		<br>
		<input type="submit" value="전송 w/ JavaScript">
		<button type="button">전송 w/o JavaScript</button> <!-- <button> 태그의 type 속성 기본값은 submit으로, <form> 태그 내부에 있는 <button> 태그에 type을 명시하지 않으면 해당 버튼 클릭시 자신이 포함된 <form> 태그의 submit 이벤트를 발생시킴 -->
	</form>
	
	<script type="text/javascript">
		document.getElementsByTagName('button')[0].onclick = function() {
			document.querySelector('form').submit(); // <form> 요소의 submit() 메서드는 submit 이벤트를 발생시키지 않고(=onsubmit 이벤트 핸들러를 실행하지 않고) JavaScript로 직접 <form> 서버에 전송
		};
	</script>
</body>
</html>
  1. 패키지 kr.web.ch02에 새 클래스 TravelServlet 생성
package kr.web.ch02;

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;

@WebServlet("/travel")
public class TravelServlet extends HttpServlet {
	/*
	 * [실습 문제] 이름과 선택한 여행지를 출력
	 * [출력 예시]
	 * 이름 : 홍길동
	 * 선택한 여행지 : 서울, 뉴욕
	 * 				선택한 여행지가 없습니다! 
	 */
	@Override
	public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.setCharacterEncoding("utf-8");
		
		resp.setContentType("text/html;charset=utf-8");
		
		PrintWriter out = resp.getWriter();
		out.println("<html>");
		out.println("<head><title>여행지 선택</title></head>");
		out.println("<body>");
		out.println("이름 : " + req.getParameter("name") + "<br>");
		out.println("선택한 여행지 : ");
		String[] cities = req.getParameterValues("city");
		if(cities!=null) {
			for(int i=0;i<cities.length;i++) {
				out.print(cities[i]);
				if(i<cities.length-1) out.print(", ");
			}
		}
		else {
			out.println("선택한 여행지가 없습니다!");
		}
		out.println("</body>");
		out.println("</html>");
		out.close();
	}
}

2-4 서블릿 동작 원리

다음으로