[ 진행 과정(흐름) ]
WAS (Web Container)
client(browser) ---> request -----> if (모델과 연동해 아이디 패스워드 일치하면)
HttpSession session = request.getSession( );
: 위 코드는 세션이 없으면 새로 생성, 있으면 기존 세션 리턴
session.setAttribute(name, value) ;
: 위 코드는 로그인 인증 정보(주로 회원 객체)를 주로 할당
WAS 상에서는 클라이언트에 대응하는 세션 객체가 생성되어 있고,
클라이언트에게 응답할 때 생성된 세션 객체의 고유 아이디를 쿠키로 전달
<-- response -- reponse : 즉, 응답 시에 클라이언트에게 쿠키 전달 (쿠키 심기)
cookie가 저장
client(browser) ---> request -----> if ( 로그인 시 발급한 세션 아이디가 기록된 쿠키 정보가 있는지 확인 )
HttpSession session = request.getSession(false);
: 위 코드는 기존 세션이 있으면 -> 기존 세션을 반환 / 없으면 -> null 을 반환
로그인한 사용자인지 여부 확인은 위와 같이 세션이 있는지와
+ 로그인 처리 시 할당한 인증정보가 있는지를 함께 확인한다.
즉, 로그인한 사용자인지 확인하는 방법은
세션이 존재 && 로그인 시 할당한 attribute의 존재
를 확인하고 인증정보가 있으면 로그인 되어있다고 처리하면 된다.
[ 전체 구현 코드 ]
DB Table
Model
/MemberVO.java
package org.kosta.model;
public class MemberVO {
private String id;
private String password;
private String name;
private String address;
@Override
public String toString() {
return "MemberVO [id=" + id + ", password=" + password
+ ", name=" + name + ", adress=" + address + "]";
}
public MemberVO() {
super();
}
public MemberVO(String id, String password) {
super();
this.id = id;
this.password = password;
}
public MemberVO(String id, String password, String name, String address) {
this.id = id;
this.password = password;
this.name = name;
this.address = address;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
/ProductDAO.java
package org.kosta.model;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class MemberDAO {
//singleton 적용
private static MemberDAO instance = new MemberDAO();
//JDBC에 필요한 변수
private String driver = "oracle.jdbc.OracleDriver";
private String url = "jdbc:oracle:thin:@127.0.0.1:1521:xe";
private String username = "scott";
private String userpass = "tiger";
//class 생성 단계에서 singleton으로 한번 생성 + driver loading
//사실 driver loading은 현재 java version에서는 따로 기재해주지 않아도,
//자동으로 loading된다 !
private MemberDAO() {
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//getInstance() method : 생성자 객체 반환용
public static MemberDAO getInstance() {
return instance;
}
//closeAll method 1
public void closeAll(PreparedStatement pstmt, Connection con)
throws SQLException {
if (pstmt != null)
pstmt.close();
if (con != null)
con.close();
}
//closeAll method 2
public void closeAll(ResultSet rs, PreparedStatement pstmt, Connection con)
throws SQLException {
if (rs != null)
rs.close();
//재사용
this.closeAll(pstmt, con);
}
/*
* 1번 기능 : 아이디로 회원정보 조회
* findMemberById(String):MemberVO
*/
public MemberVO findMemberById(String id) throws SQLException {
MemberVO vo = null;
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = DriverManager.getConnection(url, username, userpass);
String sql = "SELECT name, address FROM web_member "
+ "WHERE id = ?";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, id);
rs = pstmt.executeQuery();
if(rs.next()) {
vo = new MemberVO(id, null, rs.getString(1),rs.getString(2));
}
} finally {
closeAll(rs, pstmt, con);
}
return vo;
}
/*
* 2번 기능 : 로그인 기능
* login(MemberVO):MemberVO
*/
public MemberVO login(MemberVO vo) throws SQLException {
MemberVO mvo = null;
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = DriverManager.getConnection(url, username, userpass);
String sql = "SELECT name, address FROM web_member "
+ "WHERE id=? AND password=?";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, vo.getId());
pstmt.setString(2, vo.getPassword());
rs = pstmt.executeQuery();
if(rs.next()){
mvo = new MemberVO(vo.getId(), null,
rs.getString("name"),rs.getString("address"));
}
} finally {
closeAll(rs, pstmt, con);
}
return mvo;
}
}//class
View
/index.jsp
<%@page import="org.kosta.model.MemberVO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" session="false"%>
<!DOCTYPE html>
<html>
<link rel="stylesheet" type="text/css" href="css/mystyle.css">
<head>
<meta charset="UTF-8">
<title>Home</title>
</head>
<body>
<div class="container">
<h4>
<a href="index.jsp"><img class="home-image" src="home.png">Home</a>
</h4>
<hr>
<h3>Model2 회원 관리</h3>
<a href="findmemberbyid.jsp">회원 검색</a><br>
<%
//로그인 여부 확인 방법
//(session 유무 확인 + 로그인 시 할당한 attribute 존재 확인)
HttpSession session = request.getSession(false);
if (session != null && session.getAttribute("mvo") != null) {
MemberVO mvo = (MemberVO) session.getAttribute("mvo");%>
<br><%=mvo.getAddress() %>에 사는 <%=mvo.getName() %>님 로그인 상태<br>
<a href="front?command=logout">로그아웃</a>
<%
} else {
%>
<a href="login.jsp">로그인 페이지로</a>
<%
}
%>
</div>
</body>
</html>
/error.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>
<marquee>
시스템 에러가 발생했습니다. 콘솔을 확인하세요!<br>
<br> <img src="error.jpg">
</marquee>
</body>
</html>
-- 1번 기능 : 아이디를 입력하여 회원 정보 검색
FindMemberByIdController <-----> MemberDAO
findMemberById(String id) : MemberVO
ㅣ forward
findmemberbyid-ok.jsp
아이디와 이름, 주소를 제공한다.
or
findmemberbyid-fail.jsp
javascript alert : [ ] 에 해당하는 회원이 없습니다.
location.href로 index.jsp로 이동한다.
/findmemberbyid.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" session="false"%>
<!DOCTYPE html>
<html>
<link rel="stylesheet" type="text/css" href="css/mystyle.css">
<head>
<meta charset="UTF-8">
<title>회원 검색 Form</title>
</head>
<body>
<div class="container">
<a href="index.jsp">Home</a>
<hr>
<form action="front" method="get">
<input type="hidden" name="command" value="findmemberbyid">
아이디 <input type="text" name="id" required="required">
<input type="submit" value="회원 검색">
</form>
</div>
</body>
</html>
/findmemberbyid-ok.jsp
<%@page import="org.kosta.model.MemberVO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" session="false"%>
<!DOCTYPE html>
<html>
<link rel="stylesheet" type="text/css" href="css/mystyle.css">
<head>
<meta charset="UTF-8">
<title>회원 상세 정보</title>
</head>
<body>
<%
MemberVO vo = (MemberVO) request.getAttribute("vo");
%>
<%=vo.getId()%>님의 회원 정보입니다.<br>
<br>
<table>
<tr>
<td>ID</td>
<td><%=vo.getId()%></td>
</tr>
<tr>
<td>NAME</td>
<td><%=vo.getName()%></td>
</tr>
<tr>
<td>ADDRESS</td>
<td><%=vo.getAddress()%></td>
</tr>
</table>
</body>
</html>
/findmemberbyid-fail.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" session="false"%>
<!DOCTYPE html>
<html>
<link rel="stylesheet" type="text/css" href="css/mystyle.css">
<head>
<meta charset="UTF-8">
<title>오류 페이지</title>
</head>
<body>
<script type="text/javascript">
alert("<%=request.getParameter("id") %>에 해당하는 회원이 없습니다.");
location.href = "index.jsp";
</script>
</body>
</html>
-- 2 + 3번 기능 : 로그인 + 로그아웃 기능
login.jsp -- command=login --> LoginController <-----> MemberController
ㅣ login(MemberVO)
ㅣ
ㅣ ㅣ
login-fail.jsp login-ok.jsp
로그인 실패! alert 후 [name] 님 로그인하셨습니다.
index.jsp로 이동 만약 상단부에 Home 링크를 클릭하면
index.jsp 에서는
login.jsp 으로
-> 링크는 보여주지 않고,
[address]에 사는 [name]님 로그인 상태 + 로그아웃 링크 를 보여준다.
로그아웃 링크를 누르면,
LogoutController가 동작되고,
로그아웃 처리 후, index.jsp로 redirect한다.
로그아웃 처리된 index.jsp는 '다시 로그인 폼으로'라는 링크가 제공된다.
/login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" session="false"%>
<!DOCTYPE html>
<html>
<link rel="stylesheet" type="text/css" href="css/mystyle.css">
<head>
<meta charset="UTF-8">
<title>로그인 form</title>
</head>
<body>
<div class="container">
<a href="index.jsp"><img class="home-image" src="home.png">Home</a>
<hr>
<form action="front" method="POST">
<input type="hidden" name="command" value="login">
아이디 <input type="text" name="id" required="required"><br>
패스워드 <input type="password" name="password" required="required"><br>
<input type="submit" value="로그인">
</form>
</div>
</body>
</html>
/login-ok.jsp
<%@page import="org.kosta.model.MemberVO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" session="false"%>
<!DOCTYPE html>
<html>
<link rel="stylesheet" type="text/css" href="css/mystyle.css">
<head>
<meta charset="UTF-8">
<title>로그인 성공</title>
</head>
<body>
<div class="container">
<a href="index.jsp"><img class="home-image" src="home.png">Home</a>
<hr>
<%
HttpSession session = request.getSession(false);
//로그인 여부 확인 방법
//1단계. 세션이 존재하는지
//session이 null이 아니면(session이 있으면)
if (session !=null) {
//session에서 mvo값 가져오기
MemberVO mvo = (MemberVO) session.getAttribute("mvo");
// 2단계. 로그인 시 할당한 attribute가 존재하는지
//mvo도 null이 아니면
if (mvo !=null) { %>
<h4>
<%=mvo.getName()%>님, 로그인 성공했습니다!
</h4>
<% } %>
<% } else { %>
<a href="login-fail.jsp">로그인 실패</a>
<% } %>
</div>
</body>
</html>
/login-fail.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" session="false"%>
<!DOCTYPE html>
<html>
<link rel="stylesheet" type="text/css" href="css/mystyle.css">
<head>
<meta charset="UTF-8">
<title>로그인 실패</title>
</head>
<body>
<div class="container">
<a href="index.jsp"><img class="home-image" src="home.png">Home</a>
<hr>
<script type="text/javascript">
alert("로그인 실패!");
location.href = "index.jsp";
</script>
</div>
</body>
</html>
Controller
/DispatcherServlet.java
package org.kosta.controller;
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;
/*
* Front Controller Design Pattern이 적용되었음!
* -> 모든 클라이언트의 요청을 한 곳(front)으로 집중시켜,
* 일관성 있는 정책을 이용
*/
@WebServlet("/front")
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
handleRequest(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//POST 방식 한글 처리
request.setCharacterEncoding("utf-8");
handleRequest(request, response);
}
/* handleRequest method()
* 1. 모든 예외는 error.jsp로 응답한다.
* 2. 클라이언트가 전송한 command를 return 받아 온다.
* 3. HanlerMapping에게 command를 전달하여 개발 컨드롤러 객체를 리턴 받는다.
* 4. 개별 Controller 객체를 실행시킨다.
* 5. 실행 후 return 값에 의해 forward와 redirect방식으로 각각 응답한다.
*/
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
//2. 클라이언트가 전송한 command를 return 받아 온다.
String command = request.getParameter("command");
//3. HanlerMapping에게 command를 전달하여 개발 컨드롤러 객체를 리턴 받는다.
Controller controller = HandlerMapping.getInstance().create(command);
//4. 개별 Controller 객체를 실행시킨다.
String url = controller.execute(request, response).trim();
//5. 실행 후 return 값에 의해 forward와 redirect방식으로 각각 응답한다.
if (url.startsWith("redirect:"))
response.sendRedirect(url.substring(9));
else
request.getRequestDispatcher(url).forward(request, response);
} catch (Exception e) {
// 에러 메세지 콘솔에서 확인
e.printStackTrace();
// 1. 모든 예외는 error.jsp로 응답한다.
response.sendRedirect("error.jsp");
}
}
}
/ HandlerMapping.java
package org.kosta.controller;
/*
* 개별 컨트롤러 객체 생성을 전담하는 팩토리 클래스
*/
public class HandlerMapping {
// singleton pattern으로 객체 생성
private static HandlerMapping instance = new HandlerMapping();
private HandlerMapping() { }
public static HandlerMapping getInstance() {
return instance;
}
/* create method() 생성
* command에 따라 개별의 Controller를 만들어주는 기능
*/
public Controller create(String command) {
Controller controller = null;
if(command.contentEquals("findmemberbyid"))
controller = new FindMemberByIdController();
else if(command.contentEquals("login"))
controller = new LoginController();
else if(command.contentEquals("logout"))
controller = new LogoutController();
return controller;
}
}
/controller.java
package org.kosta.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface Controller {
//execute 메서드 생성
public String execute(HttpServletRequest request, HttpServletResponse response)
throws Exception;
}
-- 1번 기능 : 아이디를 입력하여 회원 정보 검색 기능 controller
/FindMemberByIdController.java
package org.kosta.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.kosta.model.MemberDAO;
import org.kosta.model.MemberVO;
public class FindMemberByIdController implements Controller {
@Override
public String execute(HttpServletRequest request, HttpServletResponse response)
throws Exception {
//반환할 url 주소
String url = null;
//View에서 입력값 받아오기
String id = request.getParameter("id");
//Model(MemberDAO)과 연동
MemberVO vo = MemberDAO.getInstance().findMemberById(id);
//연동 결과에 따라 View 화면 이동할 url 제공
if (vo == null) { //아이디에 해당하는 값이 없으면
url = "findmemberbyid-fail.jsp";
} else { //아이디에 해당하는 값이 있으면
url = "findmemberbyid-ok.jsp";
//View에 연동 결과 공유
request.setAttribute("vo", vo);
}
return url;
}
}
-- 2번 기능 : 로그인 기능 controller
/LoginController.java
package org.kosta.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.kosta.model.MemberDAO;
import org.kosta.model.MemberVO;
public class LoginController implements Controller {
@Override
public String execute(HttpServletRequest request, HttpServletResponse response)
throws Exception {
//반환할 url 주소
String url = null;
//JSP에서 입력값 받아오기
String id = request.getParameter("id");
String password = request.getParameter("password");
//Model과 연동
//vo : 입력받은 값으로 만든 MemebrVO 객체
MemberVO vo = new MemberVO(id, password);
//mvo : model과 연동하여 vo를 넣어 결과값으로 받은 MemberVO 객체
MemberVO mvo = MemberDAO.getInstance().login(vo);
//View로 이동 : redirect방식으로
if (mvo == null) { //로그인 실패
url = "redirect:login-fail.jsp";
} else { //로그인 성공
url = "redirect:login-ok.jsp";
//세션 생성
HttpSession session = request.getSession();
//세션에 정보(mvo) 할당 - View에 정보 공유
session.setAttribute("mvo", mvo);
}
return url;
}
}
HttpSession session = requeset.getSession()
→ 세션 생성 이유 : HTTP 는 Stateless(상태 정보 유지 X)하기 때문에, 로그인 (클라이언트) 상태 정보를 유지하기 위해서다!
session.setAttribute( )
→ 세션에 정보 할당 이유 : 세션에 클라이언트의 상세 정보를 담아서 View에 보내주기 위함이다!
-- 3번 기능 : 로그아웃 기능 controller
/LogoutController.java
package org.kosta.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LogoutController implements Controller {
@Override
public String execute(HttpServletRequest request, HttpServletResponse response)
throws Exception {
HttpSession session = request.getSession(false);
//로그인 정보가 있으면 세션정보 초기화
if (session != null)
session.invalidate();
return "redirect:index.jsp";
}
}
브라우저 결과 화면