Study Web Development

1월 7일

이전으로

Servlet & JSP

3. JSP

3-1 디렉티브

include 디렉티브
  1. 새 폴더 ch04-include 생성하고 새 JSP 파일 main.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="include.jspf" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>include 디렉티브</title>
</head>
<body>
이미지 경로 : <%= img_path %><br> <%-- include한 jspf 코드는 같은 파일 내에 있는 코드로 인식되기 때문에, jspf에서 만든 변수를 직접 읽어올 수 있음 --%>
파일 경로 : <%= file_path %>
</body>
</html>
  1. 새 JSP 파일 include.jspf 생성
    • 확장자가 jsp여도 다른 JSP 파일에 include될 수 있지만, 확장자를 jspf로 지정하면 해당 파일이 단독으로 사용되지 않음을 나타냄
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%> <%-- 한글로 주석 작성하는 경우, jspf 파일 내에서도 page 디렉티브로 인코딩 방식을 (include되는 JSP 파일과 동일하게) 설정해야 함 --%>
<%
String img_path = "/image";
String file_path = "/file";
%>

3-5 액션 태그

<jsp:include> 액션 태그
<jsp:include> include 디렉티브
처리 시간 요청 시간에 처리 JSP 파일을 자바 소스로 변환할 때 처리
변수 공유 불가능 가능
기능 별도의 파일로 요청 처리 흐름을 이동 현재 파일에 삽입시킴
데이터 전달 방법 request 기본 객체나 <jsp:param/>을 이용한 파라미터 전달 페이지 내에 변수를 선언한 후, 변수 값 지정
용도 화면 레이아웃의 일부분을 모듈화할 때 주로 사용 다수의 JSP 페이지에서 공통으로 사용되는 변수를 지정하는 코드나 저작권과 같은 문장을 포함
  1. 새 폴더 ch05-actionTag 생성하고 하위 폴더로 module 생성 후 module 폴더에 새 JSP 파일 top.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%> <%-- 한글이 포함되면 반드시 page 디렉티브로 인코딩 방식을 설정해야 함 --%>
<%-- 다른 페이지에 삽입될 것이므로 전체적인 <HTML> 구조는 중복되지 않게 삭제해야 함 --%>
<% String company = request.getParameter("company"); %>
<b><%= company %></b>
상단 메뉴 :
<a href="#">HOME</a>
<a href="#">INFO</a>
  1. module 폴더에 새 JSP 파일 left.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
좌측 메뉴<br>
<a href="#">상품 소개</a><br>
<a href="#">판매처</a><br>
<a href="#">상담실</a><br>
  1. module 폴더에 새 JSP 파일 bottom.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
하단 메뉴 : 소개 | 도움말 | 약관 | 사이트맵
  1. ch05-actionTag 폴더에 새 JSP 파일 s01_layout.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<% request.setCharacterEncoding("UTF-8"); %> <%-- <jsp:param/>으로 파라미터 전송시, request에 처음 액세스하는 것은 include된 JSP 파일이 아니라 include하는 JSP 파일이므로 인코딩 방식 설정도 include하는 JSP 파일에서 해야 전송되는 파라미터 값이 깨지지 않음 --%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>페이지 모듈화</title>
<style type="text/css">
	table {
		border:solid 1px #000;
		border-collapse: collapse;
		width: 500px;
		margin: 0 auto;
	}
	td {
		border: solid 1px #000;
		text-align: center;
		vertical-align: middle;
		height: 40px;
	}
	td.td-middle {
		text-align: left;
		vertical-align: top;
		height: 200px;
	}
	td.td-width {
		width: 100px;
	}
</style>
</head>
<body>
<table>
	<tr>
		<td colspan="2">
			<%-- <jsp:include> 시작 태그와 끝 태그 사이에는 HTML 주석과 JSP 주석 모두 사용 불가하고, 태그만 내용으로 들어갈 수 있음 --%>
			<jsp:include page="/ch05-actionTag/module/top.jsp">
				<jsp:param value="서울" name="company"/>
			</jsp:include>
		</td>
	</tr>
	<tr>
		<td class="td-middle td-width">
			<jsp:include page="module/left.jsp"/>
		</td>
		<td class="td-middle">
			<!-- 내용 부분 : 시작 -->
			레이아웃 1
			<!-- 내용 부분 : 끝 -->
		</td>
	</tr>
	<tr>
		<td colspan="2">
			<jsp:include page="module/bottom.jsp"/>
		</td>
	</tr>
</table>
</body>
</html>
<jsp:forward> 액션 태그
<jsp:forward> response.sendRedirect()
호출 대상 같은 웹 서버, 같은 웹 애플리케이션 디렉토리에 속하는 웹 자원만 호출 가능 다른 서버에 있는 웹 자원도 호출 가능
전달 방식 request 내장 객체를 통해 데이터를 전달 호출할 JSP 페이지의 URL 뒤에 데이터를 붙여서 전달
  1. ch05-actionTag 폴더에 새 JSP 파일 s02_forwardA.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	// 전송된 데이터 인코딩 처리; <jsp:param/>으로 파라미터 전송시, request에 처음 액세스하는 것은 forward된 JSP 파일이 아니라 forward하는 JSP 파일이므로 인코딩 방식 설정도 forward하는 JSP 파일에서 해야 전송되는 파라미터 값이 깨지지 않음
	request.setCharacterEncoding("UTF-8");
%>
<%-- 포워드시 생략 가능한 영역 시작 --%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>포워드 테스트</title>
</head>
<body>
forwardA.jsp 페이지! 화면은 보여지지 않습니다.
</body>
</html>
<%-- 포워드시 생략 가능한 영역 끝 --%>
<jsp:forward page="s03_forwardB.jsp">
	<jsp:param value="오렌지" name="color"/>
</jsp:forward>
  1. ch05-actionTag 폴더에 새 JSP 파일 s03_forwardB.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>s03_forwardB.jsp</title>
</head>
<body>
forwardB.jsp 페이지<br>
request에 파라미터로 전송된 데이터 = <%= request.getParameter("color") %>
</body>
</html>

3-6 에러 처리

page 디렉티브를 이용한 에러 처리
  1. 새 폴더 ch06-errorPage 생성하고 하위 폴더로 error 생성 후 error 폴더에 새 JSP 파일 viewErrorMessage.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page isErrorPage="true" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>예외 발생</title>
</head>
<body>
요청 처리 과정에서 예외가 발생했습니다.<br>
빠른 시간 내에 문제를 해결하도록 하겠습니다.
<p> <!-- 단독 <p> 태그는 <br><br>과 같음 -->
에러 타입 : <%= exception.getClass().getName() %><br> <%-- exception 객체는 에러 페이지(isErrorPage="true")에서만 호출 가능 --%>
에러 메시지 : <b><%= exception.getMessage() %></b>
</body>
</html>
  1. ch06-errorPage 폴더에 새 JSP 파일 readParameter.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page errorPage="/ch06-errorPage/error/viewErrorMessage.jsp" %> <%-- 생략시 에러가 발생하면 컨테이너가 만든 에러 페이지를 호출 --%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>파라미터 출력</title>
</head>
<body>
name 파라미터 값 : <%= request.getParameter("name").toUpperCase() %> <%-- 없는 파라미터를 호출하면 null이 반환되는데, null에서 메서드를 호출하여 NPE를 발생시킴 --%>
</body>
</html>
응답 상태 코드별 에러 페이지 지정
Code Status
200 OK 에러 없이 전송 성공
403 Forbidden 서버가 허용하지 않는 웹 페이지나 미디어를 사용자가 요청할 때
404 Not Found 클라이언트가 요청한 문서를 찾지 못했을 때
500 Internal Server Error 웹 서버가 요청 사항을 수행할 수 없을 때
  1. error 폴더에 새 JSP 파일 error404.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>404 에러 발생</title>
</head>
<body>
<h1>404</h1>
<strong>요청한 페이지는 존재하지 않습니다.</strong>
<br><br>
주소를 올바르게 입력했는지 확인해보시기 바랍니다.
</body>
</html>
  1. error 폴더에 새 JSP 파일 error500.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>500 에러 발생</title>
</head>
<body>
<h1>500</h1>
<strong>페이지 호출시 오류가 발생했습니다.</strong>
<br><br>
잠시 후에 다시 사용하시기 바랍니다.
</body>
</html>
  1. WEB-INF 폴더의 web.xml를 열고, 왼쪽 하단의 Source 탭 선택 후 <web-app> 태그 사이에 다음의 내용을 추가
  <!-- 응답 상태 코드별 에러 페이지 지정 시작 -->
  <error-page>
  	<error-code>404</error-code>
  	<location>/ch06-errorPage/error/error404.jsp</location>
  </error-page>
  <error-page>
  	<error-code>500</error-code>
  	<location>/ch06-errorPage/error/error500.jsp</location>
  </error-page>
  <!-- 응답 상태 코드별 에러 페이지 지정 끝 -->
  1. ch06-errorPage 폴더에 새 JSP 파일 readParameter2.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>파라미터 출력</title>
</head>
<body>
파라미터 출력 : <%= request.getParameter("name").toUpperCase() %>
</body>
</html>
예외 타입별 에러 페이지 지정
  1. error 폴더에 새 JSP 파일 errorNullPointer.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>NULL 에러 발생</title>
</head>
<body>
<h1>NULL 에러</h1>
<strong>서비스 처리 과정에서 NULL 예외가 발생했습니다.</strong>
<br><br>
잠시 후에 다시 사용하시기 바랍니다.
</body>
</html>
  1. WEB-INF 폴더의 web.xml를 열고, 왼쪽 하단의 Source 탭 선택 후 <web-app> 태그 사이에 다음의 내용을 추가
  <!-- 예외 타입별 에러 페이지 지정 시작 -->
  <error-page>
  	<exception-type>java.lang.NullPointerException</exception-type>
  	<location>/ch06-errorPage/error/errorNullPointer.jsp</location>
  </error-page>
  <!-- 예외 타입별 에러 페이지 지정 끝 -->
에러 페이지 우선 순위
  1. page 디렉티브의 errorPage 속성에서 지정한 에러 페이지
  2. web.xml에서 <exception-type>이 발생한 예외 타입과 일치하는 에러 페이지
  3. web.xml에서 <error-code>가 발생한 응답 상태 코드와 일치하는 에러 페이지
  4. 웹 컨테이너가 제공하는 기본 에러 페이지

3-7 쿠키

구성 요소
쿠키 생성하기
  1. 새 폴더 ch07-cookie 생성하고 새 JSP 파일 s01_makeCookie.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.net.URLEncoder" %>
<%
	// 쿠키 생성; Cookie 클래스는 서블릿에 포함되어 있어 별도로 import할 필요 없음
	Cookie cookie = new Cookie("name", URLEncoder.encode("너굴", "UTF-8")); // 생성자의 첫 번째 인자는 쿠키명, 두 번째 인자는 쿠키 값이며 한글 포함시 깨지지 않게 인코딩해서 인자로 전달해야 함
	
	// 쿠키 유효 시간 지정(단위: 초)
	// cookie.setMaxAge(30*60); // 쿠키 유효 시간을 지정하면 클라이언트 영역에 파일을 생성해서 쿠키 정보 보관
	// cookie.setMaxAge(-1); // 쿠키 유효 시간을 지정하지 않거나 -1로 지정시 메모리에 쿠키 정보 보관(=브라우저 종료시 쿠키 만료)
	
	// 생성된 쿠키를 클라이언트에 전송
	response.addCookie(cookie);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>쿠키 생성</title>
</head>
<body>
<%= cookie.getName() %> 쿠키의 값은 <%= cookie.getValue() %>
</body>
</html>
쿠키 정보 읽기
  1. 새 JSP 파일 s02_viewCookies.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.net.URLDecoder" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>쿠키 목록</title>
</head>
<body>
<h1>쿠키 목록</h1>
<%
	// 클라이언트로부터 전송된 쿠키 정보를 반환
	Cookie[] cookies = request.getCookies();
	if(cookies!=null && cookies.length>0) {
		for(int i=0;i<cookies.length;i++) {
%>
			<%= cookies[i].getName() %> = 
			<%= URLDecoder.decode(cookies[i].getValue(), "UTF-8") %><br>
<%
		}
	}
	else {
%>
		쿠키가 존재하지 않습니다.
<%		
	}
%>
</body>
</html>
  1. 새 JSP 파일 s03_modifyCookie.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.net.URLEncoder" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>쿠키 값 변경</title>
</head>
<body>
<%
	// 쿠키 정보 읽기
	Cookie[] cookies = request.getCookies();
	if(cookies!=null && cookies.length>0) {
		for(int i=0;i<cookies.length;i++) {
			// 쿠키 값을 변경할 쿠키가 존재하는지 확인
			if(cookies[i].getName().equals("name")) { // 쿠키명이 name인 쿠키 검색
				// 동일한 이름으로 쿠키 생성
				Cookie cookie = new Cookie("name", URLEncoder.encode("JSP 프로그래밍", "UTF-8"));
				// 생성한 쿠키를 클라이언트에 전송
				response.addCookie(cookie);
				
				out.println("name 쿠키의 값을 변경합니다.");
			}
		}
	}
	else {
		out.println("쿠키가 존재하지 않습니다.");
	}
%>
</body>
</html>
  1. 새 JSP 파일 s04_deleteCookie.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>쿠키 삭제</title>
</head>
<body>
<%
	// 쿠키 읽기
	Cookie[] cookies = request.getCookies();
	// 쿠키 존재 여부 확인
	if(cookies!=null && cookies.length>0) {
		for(int i=0;i<cookies.length;i++) {
			// 삭제할 쿠키가 있는지 확인
			if(cookies[i].getName().equals("name")) {
				// 삭제할 쿠키와 동일한 이름의 쿠키를 생성
				Cookie cookie = new Cookie("name", ""); // 삭제할 것이므로 value는 어떤 값이든 무관
				cookie.setMaxAge(0); // 쿠키 정보 제거
				
				// 생성된 쿠키를 클라이언트로 전송
				response.addCookie(cookie);
				
				out.println("name 쿠키를 삭제하였습니다.");
			}
		}
	}
	else {
		out.println("쿠키가 존재하지 않습니다"); // 쿠키 배열이 만들어지지 않았거나, 쿠키 배열이 만들어졌지만 배열 안에 쿠키가 없는 경우
	}
%>
</body>
</html>

3-3 기본 객체

request
  1. ch03-nestedObject 폴더에 새 JSP 파일 s20_orderForm2.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>실습</title>
<style type="text/css">
	table {
		border-collapse: collapse;
		border: 1px solid gray;
	}
	td {
		border: 1px solid gray;
		height: 30px;
	}
	td.title {
		text-align: right;
		background-color: ivory;
		font-weight: bold;
		color: #f60;
		padding: 0 10px;
	}
	input[type="number"] {
		text-align: right;
		width: 50px;
		height: 19px;	
	}
	ul {
		list-style: none;
		padding: 0 10px;
		margin: 5px;
	}
	ul li {
		display: inline;
	}
</style>
</head>
<body>
<h2>주문서</h2>
<form action="s21_order2.jsp" method="post" id="myForm">
	<table>
		<tr>
			<td class="title">식사류</td>
			<td>
				<ul>
					<li>
						<label for="c0">짜장면</label>
						<input type="number" name="food_c0" id="c0" min="0" max="99" value="0">
					</li>
					<li>
						<label for="c1">짬뽕</label>
						<input type="number" name="food_c1" id="c1" min="0" max="99" value="0">
					</li>
					<li>
						<label for="c2">볶음밥</label>
						<input type="number" name="food_c2" id="c2" min="0" max="99" value="0">
					</li>
				</ul>
			</td>
		</tr>
		<tr>
			<td colspan="2" align="center">
				<input type="submit" value="전송">
			</td>
		</tr>
	</table>
</form>
<script type="text/javascript">
	document.getElementById('myForm').onsubmit = function() {
		
		let c0 = document.getElementById('c0');
		if(c0.value=='') { // number 필드는 숫자 및 공백 입력 가능; 사용자가 기본값 0을 지우고 공백만 입력한 경우
			alert('짜장면의 수량을 입력하세요!');
			c0.focus();
			c0.value = 0;
			return false;
		}
		let c1 = document.getElementById('c1');
		if(c1.value=='') {
			alert('짬뽕의 수량을 입력하세요!');
			c1.focus();
			c1.value = 0;
			return false;
		}
		let c2 = document.getElementById('c2');
		if(c2.value=='') {
			alert('볶음밥의 수량을 입력하세요!');
			c2.focus();
			c2.value = 0;
			return false;
		}
		if(c0.value==0 && c1.value==0 && c2.value==0) { // 아무것도 주문하지 않는 경우
			alert('세 가지 음식 중 하나는 꼭 주문해야 합니다!');
			return false;
		}

		/*
		let nums = document.querySelectorAll('input[type="number"]');
		let count = 0;
		for(let i=0;i<nums.length;i++) {
			if(!nums[i].value.trim()) { // 아무것도 입력하지 않거나 공백만 입력한 경우
				nums[i].value = 0; // 입력된 값을 0으로 변경하여 JSP에서 NumberFormatException 발생을 방지
			}
			count += Number(nums[i].value); // HTML의 <input> 요소에서 입력받는 값은 문자열로 인식되며, type="number"는 사용자가 입력할 수 있는 값을 제한할 뿐 입력된 값의 자료형을 변경하지 않음; 즉, <input type="number">의 value 속성은 string을 반환하므로, 연산하기 위해서는 숫자로 변환해야 함
		}
		if(count===0) {
			alert('1개 이상 주문해주세요!')
			return false;
		}
		*/
	};
</script>
</body>
</html>
  1. 새 JSP 파일 s21_order2.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>실습</title>
</head>
<body>
<!-- 
[실습 문제] 짜장면 4,000원, 짬뽕 5,000원, 볶음밥 6,000원
[출력 예시]
[주문 음식]
짜장면 2개
짬뽕 1개
총 지불 금액 : 13,000원
 -->
<h2>주문서 확인</h2>

<%
	// 전송된 데이터 인코딩 처리
	request.setCharacterEncoding("UTF-8");
	
	int[] orderArray = {4000, 5000, 6000};
	
	int total = 0;
	String orderName = "";
	
	int food_c0 = Integer.parseInt(request.getParameter("food_c0"));
	int food_c1 = Integer.parseInt(request.getParameter("food_c1"));
	int food_c2 = Integer.parseInt(request.getParameter("food_c2"));

	if(food_c0>0) {
		total += orderArray[0] * food_c0;
		orderName += "짜장면 " + food_c0 + "<br>";
	}
	if(food_c1>0) {
		total += orderArray[1] * food_c1;
		orderName += "짬뽕 " + food_c1 + "<br>";
	}
	if(food_c2>0) {
		total += orderArray[2] * food_c2;
		orderName += "볶음밥 " + food_c2 + "<br>";
	}
%>
[주문 음식]<br>
<%= orderName %>
총 지불 금액 : <%= String.format("%,d원", total) %>

<%--
<%
	String[] food = {"짜장면", "짬뽕", "볶음밥"};
	int[] price = {4000, 5000, 6000};
	int[] count = new int[food.length];
	for(int i=0;i<count.length;i++) {
		count[i] = Integer.parseInt(request.getParameter("food_c" + i));
	}
%>
[주문 음식]<br>
<%
	int sum = 0;
	for(int i=0;i<count.length;i++) {
		if(count[i]>0) {
%>
<%= food[i] %> <%= count[i] %>개<br>
<%
		}
		sum += price[i] * count[i];
	}
%>
총 지불 금액 : <%= String.format("%,d원", sum) %>
 --%>
</body>
</html>

다음으로