2. HttpSession의 활용 - 로그인
HttpSession 객체는 클라이언트 당 한개가 생성된다. 웹 브라우저로부터 요청이 들어오면, 그 웹 브라우저를 위한 HttpSession 객체가 있는지 검사하고, 없다면 새로 HttpSession 객체를 만든다. 이렇게 생성된 HttpSession 객체는 그 웹 브라우저로부터 일정 시간 동안 Timeout 요청이 없으면, 삭제된다. 따라서 로그인되어 있는 동안 지속적으로 사용할 데이터를 HttpSession 객체에 저장한다.
HttpSession 객체를 활용하는 상황을 실습한다. 다음 그림은 로그인을 수행하는 시나리오다(그림 1).
① 웹 브라우저에서 '/auth/login' 서블릿을 요청한다.
② LogInServlet 클래스는 LogInForm.jsp로 화면 출력 작업을 위임한다.
③ LogInForm.jsp는 로그인 입력폼을 만들어 출력한다.
④ 사용자가 입력한 정보를 가지고 다시 '/auth/login' 서블릿을 요청한다. 단 이번에는 POST 요청이다.
⑤ LogInServlet 클래스는 이메일과 암호가 일치하는 회원 정보를 데이터베이스에서 찾아서 값 객체 'Member'에 담는다. 또한, 다른 서블릿들도 참조할 수 있도록 HttpSession 객체에 보관한다. 만약 이메일과 암호가 일치하는 회원을 찾지 못한다면, LogInFail.jsp로 작업을 위임한다.
⑥ 로그인 성공일 때, 회원 목록 페이지로 리다이렉트 한다. 로그인 실패일 때, 로그인 실패 메시지를 출력한 후 다시 로그인 입력폼으로 리프래시 한다.
- 로그인 컨트롤러 만들기
로그인 입력 화면을 만들고 로그인 정보를 처리할 서블릿을 만든다. 지금까지 배운 MVC 구조를 일부 적용한다.
spms.servlets 패키지에 LogInServlet 클래스를 생성한다.
package spms.servlets;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
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 spms.vo.Member;
@WebServlet("/auth/login")
public class LogInServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//로그인 페이지로 포워딩
RequestDispatcher rd = request.getRequestDispatcher("/auth/LogInForm.jsp");
rd.forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
ServletContext sc = this.getServletContext();
conn = (Connection)sc.getAttribute("conn");
stmt = conn.prepareStatement(
"SELECT MNAME,EMAIL FROM MEMBERS"
+ " WHERE EMAIL=? AND PWD=?");
stmt.setString(1, request.getParameter("email"));
stmt.setString(2, request.getParameter("password"));
rs = stmt.executeQuery();
if(rs.next()) {//이메일, 암호 일치하는 회원 있을때 - 로그인 성공
Member member = new Member().setEmail(rs.getString("EMAIL"))
.setName(rs.getString("MNAME"));
HttpSession session = request.getSession();
session.setAttribute("member", member);
//회원 목록 페이지로 리다이렉트
response.sendRedirect("../member/list");
}else {//이메일, 암호 일치하는 회원 없을때 - 로그인 실패
//로그인 실패 페이지로 포워딩
RequestDispatcher rd = request.getRequestDispatcher("/auth/LogInFail.jsp");
rd.forward(request, response);
}
}catch(Exception e) {
throw new ServletException(e);
}finally {
try {if (rs != null) rs.close();} catch (Exception e) {}
try {if (stmt != null) stmt.close();} catch (Exception e) {}
}
}
}
웹 브라우저로부터 GET 요청이 들어오면 doGet()이 호출되어 LogInForm.jsp로 포워딩한다.
//로그인 페이지로 포워딩
RequestDispatcher rd = request.getRequestDispatcher("/auth/LogInForm.jsp");
rd.forward(request, response);
JSP에서 다시 서블릿으로 돌아올 필요가 없기 때문에 인클루딩 대신 포워딩으로 처리한다.
사용자가 이메일과 암호를 입력한 후 POST 요청을 하면 doPost()가 호출된다. doPost()에서는 데이터베이스로부터 회원 정보를 조회한다. 만약 이메일과 암호가 일치하는 회원을 찾는다면 값 객체 Member에 회원 정보를 담는다.
Member member = new Member().setEmail(rs.getString("EMAIL"))
.setName(rs.getString("MNAME"));
그리고 Member 객체를 HttpSession 에 보관한다.
HttpSession session = request.getSession();
session.setAttribute("member", member);
로그인 성공이면, /member/list로 리다이렉트 한다.
//회원 목록 페이지로 리다이렉트
response.sendRedirect("../member/list");
여기서 '../'는 현재 위치의 상단폴더라는 뜻이다.
'/'는 루트를 의미하면 './'는 현재 위치, '../'는 현재 위치의 상단 폴더를 의미한다.
예시) File.xxx가 /web05/member/list에 위치하면 '/'는 web05, './'는 list, '../'는 member 이다.
즉, '/'는 가장 최상의 폴더로 이동하고(웹 애플리케이션 루트), './'는 파일의 현재 폴더, '../'는 파일이 존재하는 폴더의 상위 폴더로 이동한다. '../../'는 두 단계 상위 폴더로 이동한다.
출처 : https://88240.tistory.com/122
절대경로와 상대경로
참말로... 소스코드 짜다보면 절대경로와 상대경로. 너무헷갈린다! 학교나 학원이나 또는 혼자 공부로 경로에 대해서 수없이 공부해도 매번 쓸때마다 헷갈리는 경로. 개념은 숙지했어도 실천에
88240.tistory.com
로그인에 실패하면, /auth/LogInFail.jsp로 포워딩 한다.
//로그인 실패 페이지로 포워딩
RequestDispatcher rd = request.getRequestDispatcher("/auth/LogInFail.jsp");
rd.forward(request, response);
- 로그인 입력폼 만들기
web05 프로젝트의 webapp 폴더에 auth 폴더를 생성하고, LogInForm.jsp를 만든다.
<%@ page
language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>로그인</title>
</head>
<body>
<h2>사용자 로그인</h2>
<form action="login" method="post">
이메일: <input type="text" name="email"><br>
암호: <input type="password" name="password"><br>
<input type="submit" value="로그인">
</form>
</body>
</html>
로그인 입력폼의 값을 서버에 전달할 때 POST 요청을 하도록 <form> 태그를 설정했다. 요청 URL은 입력폼 요청할 때의 URL과 같다. 이렇게 로그인 입력폼의 URL과 로그인 처리를 하는 URL이 같더라도, 서버에서는 GET 요청과 POST 요청을 구분하여 처리하기 때문에 상관없다.
<form action="login" method="post">
...
</form>
- 로그인 실패 시 출력작업을 수행할 JSP 만들기
web05 프로젝트의 webapp 폴더의 auth 폴더에 LogInFail.jsp를 작성한다. 이 JSP는 로그인에 실패했을 때 알림 문구를 출력한다.
<%@ page
language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Refresh" content="1;url=login">
<title>로그인 실패</title>
</head>
<body>
<p>로그인 실패입니다. 이메일 또는 암호가 맞지 않습니다.!<br>
잠시 후에 다시 로그인 화면으로 갑니다.</p>
</body>
</html>
여기서 중요한 것은, 로그인 실패에 대한 안내 문구를 출력한 후, 1초가 지난 다음에 다시 서버에 로그인 입력폼을 요청하도록 설정했다는 것이다.
<meta http-equiv="Refresh" content="1;url=login">
<head> 태그를 보면 리프래시를 설정한 <meta> 태그를 볼 수 있는데, 1초 후에 /auth/login을 다시 요청하라고 웹 브라우저에게 내리는 명령이다.
톰캣 서버를 시작한 후, 웹 브라우저에서 http://localhost:9999/web05/auth/login을 요청한다(그림 2).
로그인 실패를 먼저 테스트한다. 데이터베이스에 등록되지 않은 임의의 이메일과 암호를 입력하여 '로그인' 버튼을 클릭한다(그림 3).
그림 3과 같은 화면을 출력한 후 1초 후에 다시 로그인 입력폼이 출력될 것이다.
로그인 성공을 테스트한다. 데이터베이스에 등록된 회원의 이메일과 암호를 사용하여 로그인한다(그림 4).
회원 목록이 정상적으로 출력되는 것을 확인할 수 있다. 하지만, 화면 상단에 로그인한 회원의 이름이 출력되지 않았다. 이 부분을 처리해 보겠다.
참고도서 : https://freelec.co.kr/book/1674/
[열혈강의] 자바 웹 개발 워크북
[열혈강의] 자바 웹 개발 워크북
freelec.co.kr
'교재 실습 > 자바 웹 개발 워크북' 카테고리의 다른 글
49. 데이터 보관소 (5) (0) | 2022.06.20 |
---|---|
48. 데이터 보관소 (4) (0) | 2022.06.19 |
46. 데이터 보관소 (2) (0) | 2022.06.16 |
45. 데이터 보관소 (1) (0) | 2022.06.15 |
44. 포워딩과 인클루딩 (2) (0) | 2022.06.14 |
댓글