세션으로 로그인 유지하기

✒️ 2025-05-26 11:08 내용 수정


실습 목표

실습 흐름

  1. 데이터베이스에 테이블 및 시퀀스, 필요 시 샘플 데이터 추가
  2. 데이터베이스에 연결 : context.xml 파일, 라이브러리(JDBC)
  3. 데이터베이스에서 회원 정보를 조회하는 DAO 클래스 생성
  4. 로그인을 위한 JSP 페이지 생성
  5. 로그인이 정상적으로 되었는지 확인하고, 로그인이 되었을 때만 메인 화면에 접근하도록 하는 중간 다리용 JSP 페이지 생성
  6. 로그인 후 접속 가능한 메인 화면용 JSP 생성
  7. 로그인 정보를 JSP로부터 전달 받아 데이터베이스와 비교하고 Session 객체를 추가하는 Servlet 생성
  8. 로그아웃 요청이 오면 Session을 제거하고 로그인 페이지로 보내는 Servlet 생성

DB에 테이블 추가

-- 시퀀스 생성
CREATE SEQUENCE SEQ_MEMBER_IDX;

--회원테이블
CREATE TABLE MEMBER(
	IDX INT PRIMARY KEY,	-- 번호
	NAME VARCHAR2(100) NOT NULL,	--이름
	ID VARCHAR2(100) NOT NULL,	--아이디
	PWD VARCHAR2(100) NOT NULL,	--비밀번호
	EMAIL VARCHAR2(100) UNIQUE	--이메일
);

--샘플 데이터 추가
INSERT INTO MEMBER VALUES(SEQ_MEMBER_IDX.nextVal,
				 '홍길동', 
				 'aaa',
				 '1234',
				 'aaa@aaaa.com'
				 );

--커밋
COMMIT;

DB 연결

  1. context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context>
	<Resource 
	        auth="Container" 
      		name="jdbc/oracle_test"
      		type="javax.sql.DataSource"
      		driverClassName="oracle.jdbc.driver.OracleDriver"
      		factory="org.apache.commons.dbcp.BasicDataSourceFactory"
      		url="jdbc:oracle:thin:@localhost:1521:xe"
      		username="계정명" password="비밀번호" 
      		maxActive="20" maxIdle="10" maxWait="1"/>
</Context>
  1. 라이브러리
파일
commons-collections-3.2.1.jar
commons-dbcp-1.2.2.jar
commons-pool-1.4.jar
ojdbc8-23.3.0.23.09.jar
cos.jar
  1. service용 DBService.java
package service;

import java.sql.Connection;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

public class DBConnection {

	static DBConnection db = null;
	DataSource ds;

	// singleton pattern으로 생성
	public static DBConnection getInstance() {
		if(db == null) {
			db = new DBConnection();
		}
		return db;
	}

	// 생성자에서 Context 객체와 DataSource 초기화
	public DBConnection() {
		try {
			InitialContext ic = new InitialContext();
			Context ctx = (Context)ic.lookup("java:comp/env");
			ds = (DataSource)ctx.lookup("jdbc/oracle_test");
		
		} catch (NamingException e) {
			e.printStackTrace();
		}
	}

	// 생성자에서 준비한 정보로 DB에 연결하여 Connection 객체 얻기
	public Connection getConnection() {
		Connection connec = null;
		try {
			connec = ds.getConnection();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return connec;
	}
}

Ajax

  1. HttpRequest.js
var xhr = null;

function createRequest() {
	if (xhr != null) {
		return;
	}
	if (window.ActiveXObject) {
		xhr = new ActiveXObject("Microsoft.XMLHTTP"); // IE 환경
	} else {
		xhr = new XMLHttpRequest(); // 기타 브라우저 환경
	}
}

function sendRequest(url, param, callback, method) {

	// HttpRequest 생성
	createRequest();

	// 전송 타입 구분
	var httpMethod = (method != 'POST' && method != 'post') ? 'GET' : 'POST';

	// 파라미터 구분
	var httpParam = (param == null || param == '') ? null : param;

	// 접근 url
	var httpURL = url;

	// 요청 방식이 GET이고 전달할 파라미터가 있다면 새 url 경로 제작
	if (httpMethod == 'GET' && httpParam != null) {
		httpURL = httpURL+'?'+httParam;
	}

	// 서버로 보낼 Ajax 요청 형식
	xhr.open(httpMethod, httpURL, true);

	// requestHeader 설정 : Content-Type 지정
	xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

	// 작업이 완료된 후 호출할 callback 메소드 지정
	xhr.onreadystatechange = callback;

	// Ajax 요청을 서버로 전달
	xhr.send(httpMethod == 'POST' ? httpParam : null);
}

DTO와 DAO

  1. dto
package dto;

import lombok.Data;

@Data
public class MemberDTO {
	private String name, id, pwd;
}
  1. dao
package dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import dto.MemberDTO;
import service.DBService;

public class MemberDAO {
	// single-ton pattern: 
	static MemberDAO single = null;

	public static MemberDAO getInstance() {
		if (single == null)
			single = new MemberDAO();
		return single;
	}
	
	public MemberDTO selectOne(String id) {

		MemberDTO dto = null;

		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = "SELECT * FROM MEMBER WHERE ID=?";

		try {
			//1.Connection얻어온다
			conn = DBService.getInstance().getConnection();
			//2.명령처리객체정보를 얻어오기
			pstmt = conn.prepareStatement(sql);

			//3.pstmt parameter 설정
			pstmt.setString(1, id);
			
			//4.결과행 처리객체 얻어오기
			rs = pstmt.executeQuery();

			if (rs.next()) {
				dto = new MemberDTO();
				dto.setPwd(rs.getString("pwd"));
				dto.setName(rs.getString("name"));
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {

			try {
				if (rs != null)
					rs.close();
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return dto;
	}
}

Servlet

  1. 로그인 Servlet
package action;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import dao.MemberDAO;
import dto.MemberDTO;


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

	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String id = request.getParameter("id");
		String pwd = request.getParameter("pwd");
		
		MemberDTO dto = MemberDAO.getInstance().selectOne(id);
		
		String param = "";
		String resultStr = "";
		
		// dto가 null일 경우 id가 DB 자체에 존재하지 않음
		if(dto == null) {
			param = "no_id";
			resultStr = String.format("[{'param':'%s'}]", param);
			response.getWriter().print(resultStr);
			return;
		}
		
		if(!pwd.equals(dto.getPwd())) {
			param = "no_pwd";
			resultStr = String.format("[{'param':'%s'}]", param);
			response.getWriter().print(resultStr);
			return;
		}
		
		// 아이디와 비밀번호 체크에 문제가 없다면 세션에 바인딩함
		// 세션은 서버의 메모리를 사용하기 때문에 세션을 많이 사용할수록 브라우저가
		// 느려지기 때문에 필요한 곳에서만 사용해야 함
		
		HttpSession session = request.getSession();
		session.setAttribute("dto", dto); // 포워딩 필요 없이 JSP에서 el 표기법으로 접근 가능
		
		// 로그인 성공한 경우
		param = "clear";
		resultStr = String.format("[{'param':'%s'}]", param);
		response.getWriter().print(resultStr);
	}
}
  1. 로그아웃 Servlet
package action;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;


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

	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// Session을 제거
		HttpSession session = request.getSession();
		session.removeAttribute("dto");
		
		response.sendRedirect("login_form.jsp");
	}
}

JSP

  1. 로그인 jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
	<script src="js/HttpRequest.js"></script>
	<script>
		function send(f) {
			var id = f.id.value.trim();
			var pwd = f.pwd.value.trim();
			
			// 유효성 검사
			if (id == '') {
				alert("아이디를 입력해주세요");
				return;
			}
			if (pwd == '') {
				alert("비밀번호를 입력해주세요");
				return;
			}
			
			var url = "login";
			var param = "id="+id+"&pwd="+encodeURIComponent(pwd);
			
			sendRequest(url, param, myCheck, "POST");
		}
		
		function myCheck() {
			if (xhr.readyState == 4 && xhr.status == 200) {
				var data = xhr.responseText;
				
				var json = eval(data);
				
				if(json[0].param == "no_id") {
					alert("아이디가 존재하지 않습니다.");
				} else if (json[0].param == "no_pwd") {
					alert("비밀번호가 일치하지 않습니다.");
				} else if (json[0].param == "clear") {
					alert("로그인에 성공했습니다.");
					location.href = "main_content.jsp";
				}
			}
		}
	</script>
</head>
<body>
	<form>
		<table border="1" align="center">
			<caption>:::로그인:::</caption>
			<tr>
				<th>아이디</th>
				<td><input name="id"></td>
			</tr>
			<tr>
				<th>비밀번호</th>
				<td><input name="pwd" type="password"></td>
			</tr>
			<tr>
				<td colspan="2" align="center">
					<input type="button" value="로그인" onclick="send(this.form)">
				</td>
			</tr>
		</table>
	</form>
</body>
</html>
  1. 로그인 확인용 jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<c:if test="${empty dto}">
	<script>
		alert('로그인 후 이용해주세요');
		location.href='login_form.jsp';
	</script>
</c:if>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

</body>
</html>
  1. 로그인 후 메인 화면 jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<!-- check_login.jsp를 거쳐서 나오도록 설정 -->
	<jsp:include page="check_login.jsp"/> <br>
	메인페이지 <br>
	${dto.name}님 로그인을 환영합니다.
	<input type="button" value="로그아웃" onclick="location.href='logout'">
</body>
</html>

완성된 모습

  1. 아이디를 입력한다.
    로그인 1.png

  2. DB에 존재하지 않는 아이디라면 아이디가 없다고 뜬다.
    로그인 2.png

  3. 아이디는 일치하는데 비밀번호가 일치하지 않으면 비밀번호 불일치로 뜬다.
    로그인 3.png

  4. 아이디와 비밀번호가 모두 맞으면 로그인 성공 메시지가 뜬다.
    로그인 4.png

  5. 로그인 체크 화면을 거쳐 메인 화면으로 온다.
    로그인 5.png

  6. 로그아웃을 했거나 로그인을 안 한 상태로 URL을 변경하여 main_content.jsp에 접근하려고 하면 접근이 막힌다.
    로그인 6.png