Study Web Development

1월 10일

이전으로

Servlet & JSP

3. JSP

3-8 세션

  1. 새 폴더 ch08-session 생성하고 새 JSP 파일 s01_sessionInfo.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.util.Date" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%
	Date time = new Date();
	SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>세션 정보</title>
</head>
<body>
세션 ID : <%= session.getId() %><br>

세션 생성 시간 : <%= session.getCreationTime() %><br> <%-- getCreationTime() 메서드는 1970년 1월 1일부터 세션 생성 시간까지의 경과 시간을 밀리초 단위, long 자료형의 값으로 반환 --%>
<%
	// long 자료형의 시간을 Date 객체가 표시하는 연, 월, 일, 시, 분, 초로 변환
	time.setTime(session.getCreationTime());
%>
세션 생성 시간 : <%= sf.format(time) %><br>

최근 접근 시간 : <%= session.getLastAccessedTime() %><br> <%-- getLastAccessedTime() 메서드는 1970년 1월 1일부터 세션 생성 시간까지의 경과 시간을 밀리초 단위, long 자료형의 값으로 반환 --%>
<%
	time.setTime(session.getLastAccessedTime());
%>
최근 접근 시간 : <%= sf.format(time) %><br>

세션 유지 시간 변경하기(기본값: 30분)<br>
<%
	// JSP 페이지 내에서 지정한 값은 web.xml에서 지정한 값보다 우선하며, 서버를 재시작하지 않아도 바로 적용됨
	session.setMaxInactiveInterval(60*20); // 초 단위로 지정
%>
세션 유지 시간 : <%= session.getMaxInactiveInterval() %></body>
</html>
  1. WEB-INF 폴더의 web.xml를 열고, 왼쪽 하단의 Source 탭 선택 후 <web-app> 태그 사이에 다음의 내용을 추가
  <!-- 세션 유지 시간 지정 시작 -->
  <session-config>
  	<session-timeout>50</session-timeout> <!-- 분 단위로 지정 -->
  </session-config>
  <!-- 세션 유지 시간 지정 끝 -->
  1. 새 JSP 파일 s02_loginForm.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>
<form action="s03_login.jsp" method="post">
	아이디 <input type="text" name="id" size="10"><br>
	비밀번호 <input type="password" name="password" size="10"><br>
	<input type="submit" value="로그인">
</form>
</body>
</html>
  1. 새 JSP 파일 s03_login.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.setCharacterEncoding("UTF-8");

	String id = request.getParameter("id");
	String password = request.getParameter("password");
	
	// 테스트용으로 ID와 비밀번호가 서로 같으면 로그인 처리
	if(id.equals(password)) { // 로그인 성공
		session.setAttribute("user_id", id);
%>
	<%= id %>님이 로그인했습니다.<br>
	<input type="button" value="로그인 여부 체크" onclick="location.href='s04_loginCheck.jsp'">
	<input type="button" value="로그아웃" onclick="location.href='s05_logout.jsp'">
<%
	}
	else { // 로그인 실패
%>
	<script type="text/javascript">
		alert('로그인에 실패했습니다!');
		history.go(-1);
	</script>
<%
	}
%>
</body>
</html>
  1. 새 JSP 파일 s04_loginCheck.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>
<%
	String user_id = (String)session.getAttribute("user_id"); // getAttribute() 메서드는 속성 값을 Object 자료형으로 반환하므로 다운캐스팅 필요
	if(user_id!=null) { // 로그인된 경우
%>
	아이디 [ <%= user_id %> ]로 로그인한 상태!<br>
	<input type="button" value="로그아웃" onclick="location.href='s05_logout.jsp'">
<%		
	}
	else { // 로그인되지 않은 경우
%>
	로그인하지 않은 상태<br>
	<input type="button" value="로그인" onclick="location.href='s02_loginForm.jsp'">
<%	
	}
%>
</body>
</html>
  1. 새 JSP 파일 s05_logout.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>
<%
	// 세션의 모든 속성을 제거해서 세션을 갱신
	session.invalidate();
%>
로그아웃했습니다.<br>
<input type="button" value="로그인" onclick="location.href='s02_loginForm.jsp'">
<input type="button" value="로그인 여부 체크" onclick="location.href='s04_loginCheck.jsp'">
</body>
</html>

7. 파일 업로드

COS 라이브러리

다운로드

http://www.servlets.com/

  1. 좌측 메뉴에서 COS File Upload Library 선택하고 Download에서 cos-20.08.zip 선택
  2. 압축 해제 후 lib 폴더의 cos.jarC:\javaWork\workspace_jsp\jspMain\src\main\webapp\WEB-INF\lib로 이동
  3. webapp 폴더 오른쪽 클릭 후 새 폴더 upload 생성
사용
  1. 새 폴더 ch09-fileupload 생성하고 새 JSP 파일 s01_fileForm.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>
<form action="s02_fileUpload.jsp" method="post" enctype="multipart/form-data"> <!-- 파일 업로드시 method를 post로 지정하지 않으면 파일의 경로와 이름만 전송되고 내용은 전송되지 않으며, enctype을 multipart/form-data로 지정하지 않으면 파일을 업로드해도 인식하지 못함 -->
	작성자 <input type="text" name="user"><br>
	제목 <input type="text" name="title"><br>
	파일명 <input type="file" name="uploadFile"><br>
	<input type="submit" value="파일 전송">
</form>
</body>
</html>
  1. 새 JSP 파일 s02_fileUpload.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="com.oreilly.servlet.MultipartRequest" %>
<%@ page import="com.oreilly.servlet.multipart.DefaultFileRenamePolicy" %>
<%@ page import="java.io.File" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>파일 업로드 처리</title>
</head>
<body>
<%
	// 파일 업로드 경로
	String saveFolder = "/upload";
	// 인코딩 타입
	String encType = "UTF-8";
	// 파일의 최대 업로드 사이즈
	int maxSize = 5*1024*1024; // 바이트 단위 
	
	// 파일 업로드 절대 경로 구하기
	String realFolder = application.getRealPath(saveFolder); // 다이나믹 웹 프로젝트에서는 이클립스가 publish하는 경로를 반환; C:/javaWork/workspace_jsp/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/jspMain/upload
	
	out.println("파일 업로드 절대 경로 : " + realFolder + "<br>");
	out.println("--------<br>");
	
	// 파일 업로드 작업을 위해서 MultipartRequest 객체 생성
	MultipartRequest multi = new MultipartRequest(request, // 파일 정보 제공
			realFolder, // 절대 경로
			maxSize, // 전송 전에 파일의 최대 업로드 사이즈를 초과하지 않는지 확인
			encType, // 인코딩 타입
			new DefaultFileRenamePolicy()); // 이미 업로드된 파일명과 동일한 파일명을 업로드하는 경우 덮어씌우지 않도록 파일명을 교체
	
	out.println("작성자 : " + multi.getParameter("user") + "<br>"); // enctype="multipart/form-data"으로 전송시 request 객체에서는 파라미터 값을 얻을 수 없음 
	out.println("제목 : " + multi.getParameter("title") + "<br>");
	out.println("--------<br>");
	
	// 파일 정보 처리
	// 전송된 원래의 파일명
	String original = multi.getOriginalFileName("uploadFile"); // 파라미터명(<input type="file"> 태그의 name 속성 ) 전달
	// 서버에 저장된 파일명
	String filename = multi.getFilesystemName("uploadFile");
	// 전송된 파일의 컨텐트 타입
	String type = multi.getContentType("uploadFile");
	
	out.println("전송 전 원래의 파일명 : " + original + "<br>");
	out.println("서버에 저장된 파일명 : " + filename + "<br>");
	out.println("컨텐트 타입 : " + type + "<br>");
	
	// 파일의 용량 구하기
	File file = multi.getFile("uploadFile");
	out.println("파일의 용량 : " + file.length() + " bytes");
%>
</body>
</html>
  1. 새 JSP 파일 s03_fileMultiForm.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>
<form action="s04_fileMultiUpload.jsp" method="post" enctype="multipart/form-data">
	이름 <input type="text" name="name"><br>
	제목 <input type="text" name="title"><br>
	이미지1 <input type="file" name="uploadFile1" accept="image/gif,image/png,image/jpeg"><br>
	이미지2 <input type="file" name="uploadFile2" accept="image/gif,image/png,image/jpeg"><br>
	<input type="submit" value="전송">	
</form>
</body>
</html>
  1. 새 JSP 파일 s04_fileMultiUpload.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="com.oreilly.servlet.MultipartRequest" %>
<%@ page import="com.oreilly.servlet.multipart.DefaultFileRenamePolicy" %>
<%@ page import="java.net.URLEncoder" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>파일 다중 업로드 처리</title>
</head>
<body>
<%
	String saveFolder = "/upload"; // 파일 업로드 경로
	String encType = "UTF-8"; // 인코딩 타입
	int maxSize = 5*1024*1024; // 최대 업로드 파일 크기
	// upload의 절대 경로
	String realFolder = application.getRealPath(saveFolder);
	
	// 파일 업로드를 하기 위해 MultipartRequest 객체 생성
	MultipartRequest multi = new MultipartRequest(request, realFolder, maxSize, encType, new DefaultFileRenamePolicy());	
	
	out.println("이름 : " + multi.getParameter("name") + "<br>");
	out.println("제목 : " + multi.getParameter("title") + "<br>");
	out.println("--------<br>");
	
	String img1 = multi.getFilesystemName("uploadFile1");
	String img2 = multi.getFilesystemName("uploadFile2");
%>
<%-- 파일명에 괄호, 공백 등 특수문자가 사용된 경우 퍼센트 인코딩해야 서버에서 파일을 불러올 수 있음; URLEncoder의 경우 공백을 +로 변환하므로 %20으로 일괄 치환 필요 --%>
<img src="/jspMain/upload/<%= URLEncoder.encode(img1, "UTF-8").replace("+", "%20") %>"><br>
<img src="/jspMain/upload/<%= URLEncoder.encode(img2, "UTF-8").replace("+", "%20") %>"><br>
</body>
</html>
  1. 새 JSP 파일 s05_profileForm.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>프로필 사진 업로드 폼</title>
<script type="text/javascript">
	window.onload = function() {
		var file = document.getElementById('file');
		// 파일을 선택할 때 이벤트 연결
		file.onchange = function() {
			if(file.files && file.files[0]) { // 파일이 선택되어 files 배열의 인덱스 0에 File 객체가 저장되어 있는 경우
				var reader = new FileReader();
				// 이미지 파일 읽기
				reader.readAsDataURL(file.files[0]);
				// 이미지 파일을 모두 읽어들이면 이벤트 발생
				reader.onload = function() {
					var image = document.getElementById('image');
					var submit_btn = document.getElementById('submit_btn');
					// 이미지 미리 보기 처리
					image.src = reader.result;
					image.style.display = '';
					submit_btn.style.display = '';
				};
			}
		};
	};
</script>
</head>
<body>
<h2>프로필 사진 업로드하기</h2>
<img id="image" width="100" height="100" alt="Image Preview" style="display: none;">
<form action="s06_profile.jsp" method="post" enctype="multipart/form-data">
	<input type="file" name="file" id="file" accept="image/png,image/jpeg,image/gif">
	<input type="submit" value="전송" style="display: none;" id="submit_btn">
</form>
</body>
</html>
  1. 새 JSP 파일 s06_profile.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="com.oreilly.servlet.MultipartRequest" %>
<%@ page import="com.oreilly.servlet.multipart.DefaultFileRenamePolicy" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>프로필 사진 업로드 처리</title>
</head>
<body>
<h2>저장된 프로필 사진</h2>
<%
	String saveFolder = "/upload"; // 파일 업로드 경로
	String encType = "UTF-8"; // 인코딩 타입
	int maxSize = 5*1024*1024; // 최대 업로드 파일 크기
	// upload 절대 경로
	String realFolder = application.getRealPath(saveFolder);
	
	// 파일 업로드를 처리하기 위해 MultipartRequest 객체 생성
	MultipartRequest multi = new MultipartRequest(request, realFolder, maxSize, encType, new DefaultFileRenamePolicy());
	String file = multi.getFilesystemName("file");
%>
<img src="/jspMain/upload/<%= file %>">
</body>
</html>

5. JSP와 DB 연동

5-1 JDBC

  1. C:\javaWork\apps에서 ojdbc8.jar를 복사하여 C:\javaWork\workspace_jsp\jspMain\src\main\webapp\WEB-INF\lib에 붙여넣기
  2. 새 폴더 ch10-jdbc 생성하고 새 JSP 파일 connectionTest.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.sql.DriverManager" %>
<%@ page import="java.sql.Connection" %>
<%@ page import="java.sql.SQLException" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>연동 테스트</title>
</head>
<body>
<%
	String driverName = "oracle.jdbc.OracleDriver";
	String jdbcUrl = "jdbc:oracle:thin:@localhost:1521:xe";
	String dbId = "scott";
	String dbPass = "tiger";
	
	Connection conn = null;
	try {
		// JDBC 수행 1단계 : 드라이버 로드
		Class.forName(driverName);
		// JDBC 수행 2단계 : Connection 객체 생성
		conn = DriverManager.getConnection(jdbcUrl, dbId, dbPass);
		
		out.println("정상적으로 연결되었습니다.");
	}
	catch(Exception e) {
		e.printStackTrace();
	}
	finally {
		// 자원 정리
		if(conn!=null) try {conn.close();} catch(SQLException e) {}
	}
%>
</body>
</html>
  1. 새 JSP 파일 dbinfo.jspf 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
String driverName = "oracle.jdbc.OracleDriver";
String jdbcUrl = "jdbc:oracle:thin:@localhost:1521:xe";
String dbId = "scott";
String dbPass = "tiger";
%>
  1. 새 SQL 파일 table.sql 생성
CREATE TABLE tboard(
	num NUMBER PRIMARY KEY,
	name VARCHAR2(30) NOT NULL,
	title VARCHAR2(150) NOT NULL,
	passwd VARCHAR2(10) NOT NULL,
	content VARCHAR2(4000) NOT NULL,
	reg_date DATE NOT NULL
);

CREATE SEQUENCE tboard_seq;
  1. 새 CSS 파일 style.css 생성
@charset "UTF-8";

body {
	padding: 0;
	margin: 0;
}
.page-main {
	width: 800px;
	margin: 0 auto; /* 중앙 정렬 */
}
.result-display {
	width: 400px;
	height: 200px;
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	border: 1px solid #000;
	display: flex; /* 하위 요소를 수직으로 쌓을 수 있는 공간을 만듦 */
	align-items: center; /* 세로 정렬 */
	justify-content: center; /* 가로 정렬 */
}
.align-center {
	text-align: center;
}
.align-right {
	text-align: right;
}

/* 등록, 수정 폼 */
form {
	width: 500px;
	margin: 0 auto;
	border: 1px solid #000;
	padding: 10px 10px 10px 30px;
}
ul {
	list-style: none;
}
label {
	width: 100px;
	float: left;	
}
  1. 새 JSP 파일 insertTestForm.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시판 글 등록</title>
<link rel="stylesheet" href="style.css">
<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 title = document.getElementById('title');
			if(title.value.trim()=='') {
				alert('이름을 입력하세요!');
				title.focus();
				title.value = '';
				return false;
			}
			var passwd = document.getElementById('passwd');
			if(passwd.value.trim()=='') {
				alert('이름을 입력하세요!');
				passwd.focus();
				passwd.value = '';
				return false;
			}
			var content = document.getElementById('content');
			if(content.value.trim()=='') {
				alert('이름을 입력하세요!');
				content.focus();
				content.value = '';
				return false;
			}
			/*
			list = document.getElementsByTagName('li');
			for(let i=0;i<list.length;i++) {
				let input = list[i].querySelector('input,textarea');
				if(input.value.trim()=='') {
					alert(list[i].querySelector('label').innerHTML + '을/를 입력하세요!');
					input.focus();
					input.value = '';
					return false;
				}
			}
			*/
		};
	};
</script>
</head>
<body>
<div class="page-main">
	<h2>글쓰기</h2>
	<form id="myForm" action="insertTest.jsp" method="post">
		<ul>
			<li>
				<label for="name">이름</label>
				<input type="text" name="name" id="name" size="20" maxlength="10"> <!-- 관리하기 편하게 식별자를 SQL 테이블의 컬럼명과 통일시킴 -->
			</li>
			<li>
				<label for="title">제목</label>
				<input type="text" name="title" id="title" size="30" maxlength="50">
			</li>
			<li>
				<label for="passwd">비밀번호</label>
				<input type="password" name="passwd" id="passwd" size="20" maxlength="10">
			</li>
			<li>
				<label for="content">내용</label>
				<textarea rows="5" cols="40" name="content" id="content"></textarea>
			</li>
		</ul>
		<div class="align-center">
			<input type="submit" value="전송">
			<input type="button" value="목록" onclick="location.href='selectTest.jsp'">
		</div>
	</form>
</div>
</body>
</html>
  1. 새 JSP 파일 insertTest.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.sql.DriverManager" %>
<%@ page import="java.sql.Connection" %>
<%@ page import="java.sql.PreparedStatement" %>
<%@ page import="java.sql.SQLException" %>
<%@ include file="dbinfo.jspf" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글 등록 처리</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<%
	// 전송된 데이터 인코딩 처리
	request.setCharacterEncoding("UTF-8");

	// 전송된 데이터 반환
	String name = request.getParameter("name");
	String title = request.getParameter("title");
	String passwd = request.getParameter("passwd");
	String content = request.getParameter("content");
	
	// DB 연동
	Connection conn = null;
	PreparedStatement pstmt = null;
	String sql = null;
	
	try {
		// JDBC 수행 1단계 : 드라이버 로드
		Class.forName(driverName);
		// JDBC 수행 2단계 : Connection 객체 생성
		conn = DriverManager.getConnection(jdbcUrl, dbId, dbPass);
		
		// SQL문 작성
		sql = "INSERT INTO tboard (num, name, title, passwd, content, reg_date) "
			+ "VALUES (tboard_seq.NEXTVAL, ?, ?, ?, ?, SYSDATE)";
		
		// JDBC 수행 3단계 : PreparedStatement 객체 생성
		pstmt = conn.prepareStatement(sql);
		// ?에 데이터를 바인딩
		pstmt.setString(1, name);
		pstmt.setString(2, title);
		pstmt.setString(3, passwd);
		pstmt.setString(4, content);
		
		// JDBC 수행 4단계 : SQL문 실행
		pstmt.executeUpdate();
%>
	<div class="result-display">
		<div class="align-center">
			글 등록 성공<br>
			<input type="button" value="목록 보기" onclick="location.href='selectTest.jsp'">
		</div>
	</div>
<%
	}
	catch(Exception e) {
		e.printStackTrace();
%>
	<div class="result-display">
		<div class="align-center">
			오류 발생! 글 등록 실패!<br>
			<input type="button" value="글쓰기" onclick="location.href='insertTestForm.jsp'">
		</div>
	</div>
<%
	}
	finally {
		// 자원 정리
		if(pstmt!=null) try {pstmt.close();} catch(SQLException e) {}
		if(conn!=null) try {conn.close();} catch(SQLException e) {}
	}
%>
</body>
</html>

다음으로