▸JSP & Servlet/기본 문법

MCV 패턴의 자동 로그인, 회원가입 만들기 [1/3]

코데방 2020. 2. 24.
728x90

JSP와 서블릿을 이용한 간단한 로그인, 자동로그인 및 회원가입, 회원 정보조회 기능이 있는 웹페이지 만들기입니다. 컨트롤러와 뷰에 대한 코드입니다. DAO, DTO와 Command 역할의 클래스들은 다음글들을 참조하시면 됩니다.

 

[· JSP & Servlet/- 기본 문법] - MCV 패턴의 자동 로그인, 회원가입 만들기 [2/3]

[· JSP & Servlet/- 기본 문법] - MCV 패턴의 자동 로그인, 회원가입 만들기 [3/3]

 

 

전체 코드는 깃허브에 올려놨습니다. 게시판 로직을 추가할 예정이라 commit 코멘트가 "First commit"인 부분으로 되돌리면 현재 코드로 돌아옵니다.

https://github.com/codevang/hssweb.git

 

 


 

 

[ /layout/headLayout.jspf - View, 공통부분 ]

 

모든 화면에서 공유하는 가장 윗부분의 레이아웃입니다. 모든 페이지에서 include해줄거고 단독으로 쓰이지 않으므로 jspf 확장자로 지정했습니다. 'web.xml'파일에서 매핑된 JSP의 확장자에 등록돼 있지 않으므로, 해당 파일로 접근하더라도 디폴트 서블릿("/" 매핑)으로 지정된 컨트롤러로 가게 됩니다.

 

[· JSP & Servlet/- 기본 문법] - URL 매핑_'/' 와 '/*' 의 차이점

 

 

세션과 쿠키를 체크해 로그인 했을 때와 로그아웃 했을 때의 화면을 달리 출력해줍니다. 이곳에서 모두 로그인 여부를 체크 해주므로 다른 페이지에서는 이 파일을 include만 해주면 됩니다. 액션 테그 사용법은 아래 링크글을 참조하시면 됩니다. HTML이나 CSS 등을 잘 몰라서 대충 짰습니다. ㅎㅎ

 

[· JSP & Servlet/- 기본 문법] - JSP 태그의 종류와 사용법

 

 

로그인 하기 전

 

로그인한 뒤 페이지

<%@page import="login.SessionCheck"%>
<%@ 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>

<!-- form 태그 줄바꿈 제거 -->
<style>
	form {
	display: inline;
	}
</style>

<%
	// 세션과 쿠키 체크
	Cookie[] cookie = request.getCookies();
	boolean check = SessionCheck.loginCheck(session, cookie);
	// true를 받았을 경우 (로그인 된 상태) 
	if (check) {
%>

<p>
	<form action="/hssweb/etc" method="post">
		&nbsp<input type="submit" value="홈으로가기" /> 
	</form>
	<form action="/hssweb/logout" method="post">
		&nbsp<input type="submit" value="로그아웃" /> 
	</form>
	<form action="/hssweb/getUserInfo" method="post">
		&nbsp<input type="submit" value="회원정보보기"/><br><br>
		&nbsp <%=session.getAttribute("userID")%>님 안녕하세요. 로그인 되셨습니다.
	</form>
</p>	
<hr />

<%
	// false를 받았을 경우 (로그인 안된 상태)
	} else {
%>

<p>
	<form action="/hssweb/etc" method="post">
		&nbsp<input type="submit" value="홈으로가기" /> 
	</form>
	<form action="/hssweb/login" method="post">
		&nbsp<input type="submit" value="로그인" /> 
	</form>
	<form action="/hssweb/register" method="post">
		&nbsp<input type="submit" value="회원가입"/><br><br>
		&nbsp 로그인 또는 회원가입을 해주세요.
	</form>
</p>	
<hr />

<%
	}
%>

</body>
</html>

 

 

 


 

 

[ /login/SessionCheck.java -  세션/쿠키 체크 ]

 

세션에 로그인한 정보가 있으면 true, 쿠키 정보가 있다면 세션을 다시 생성해주고 true를 반납하고 둘 다 없으면 false를 반납합니다. 사실 이 클래스를 사용하는 jspf 파일은 컴파일되어 계속 메모리에 로드돼 있으므로, 굳이 별도로 static메소드로 지정하지 않아도 무방합니다. 

 

여기서 쿠키를 다루다가 좀 헤맸는데 로그인할 때 생성하는 쿠키의 저장 경로 탓이었습니다. 폴더 구조가 복합한 경우 쿠키의 저장 경로가 꼬여서 원하는 쿠기를 get하고 set하는데 문제가 생길 수 있습니다. 아래 글을 참조 부탁드립니다.

 

[· JSP & Servlet/- 기본 문법] - 쿠키 이용 시 유의 사항 (자동로그인 로직 구현 등)

 

package login;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;

public class SessionCheck {

	public static boolean loginCheck(HttpSession session, Cookie[] cookie) {

		// user_id가 등록된 세션인 경우 (이미 로그인 돼 있음) true 반환
		if (session.getAttribute("userID") != null) {
			return true;

		// 세션이 없을 경우 쿠키 정보를 확인
		} else if (cookie != null) {

			// 쿠키 확인
			for (int i = 0; i < cookie.length; i++) {

				// userID라는 이름을 가진 쿠키가 있다면 true 반환
				if (cookie[i].getName().equals("userID")) {
					
					System.out.println(cookie[i].getPath());
					// 쿠키에 들어있는 userID를 세션에 추가해줌
					session.setAttribute("userID", cookie[i].getValue());
					return true;
				}
			}
		}

		// 세션도 없고 쿠키도 없는 경우
		return false;
	}
}

 

 


 

 

[ /control/Ctrl.java - 컨트롤러 서블릿 ]

 

프레임워크 없이 MVC 패턴으로 구성했기 때문에, 서블릿은 하나만 사용했습니다. 컨트롤러 역할을 하고 있고 각 기능을 수행할 Command(자바 클래스)와 뷰 역할의 JSP 파일로 분배만 해주게 됩니다. 

 

또한 상수를 지정해서 Command를 수행하고 리턴된 결과값에 따라 출력할 페이지를 설정해줍니다. boolean 타입으로 리턴받을 수 있겠지만 DB 작업을 실행하다가 예외가 발생된 경우 별도의 예외 페이지로 넘겨주기 위해 3가지 리턴 타입을 지정했습니다.

 

패키지와 폴더 구조가 복잡해질 수록 경로 설정이 어려우니 절대 경로로 모두 설정해주는 것이 보기도 좋고 헷갈리지 않을 것 같습니다. 또한 MVC 패턴에서 리다이렉트 기능을 활용하려면 sendRedirect()의 동작 방식을 알고 있어야 합니다. 그렇지 않으면 중복 리다이렉트를 시켜 예외가 발생할 수 있습니다. 아래 글을 참조 부탁드립니다.

 

[· JSP & Servlet/- 기본 문법] - sendRedirect 작동 방식 및 예외 처리에서의 사용

 

package control;

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 login.LoginAction;
import login.LogoutAction;
import login.RegisterAction;
import userInfo.GetUserInfo;

@WebServlet("/")
public class Ctrl extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	// command에서 리턴받을 종류
	public static final int TRUE = 0;
	public static final int FALSE = 1;
	public static final int EXCEPT = 2;

	public Ctrl() {
		super();
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		doAction(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doAction(request, response);
	}

	protected void doAction(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		request.setCharacterEncoding("UTF-8");
		// 프로젝트 이름 뒤의 URI만 남기도록 잘라줌 (프로젝트/페이지 - 프로젝트 = /페이지)
		String uri = request.getRequestURI().substring
				(request.getContextPath().length());
		
		String page = null;  // 리다이렉트할 페이지 넣을 문자열
		Command command = null; // 실행할 커멘드 클래스를 담아줄 인터페이스 객체 
		
		/* 메인에서 로그인 버튼 눌렀을 때 */
		if(uri.equals("/login")) {
			page = "/join/login.jsp";
	
		/* 메인에서 회원가입 버튼 눌렀을 때 */
		} else if(uri.equals("/register")) {
			page = "/join/register.jsp";		

		/* join/login.jsp에서 계정 넣고 로그인 요청 했을 때 */
		} else if(uri.equals("/join/loginAsk")) {
			command = new LoginAction(request, response);
			int result = command.execute();
			
			// TRUE일 경우 메인 화면으로
			if(result == Ctrl.TRUE) {
				page = "/main.jsp";
			// FALSE일 경우 다시 로그인 페이지로
			} else if(result == Ctrl.FALSE) { 
				page = "/join/login.jsp";
			// EXCEPT일 경우 에러 페이지로
			} else {
				page = "/exception/exception.jsp";
			}			
			
		/* join/register.jsp에서 회원가입 폼 작성하고 가입 눌렀을 때 */
		} else if(uri.equals("/join/registerAsk")) {
			command = new RegisterAction(request);
			int result = command.execute();
			
			// TRUE일 경우 로그인 페이지로
			if (result == Ctrl.TRUE) {
				page = "/join/login.jsp";
			// FALSE일 경우 회원가입 페이지로 (session에 추가된 메세지 출력) 
			} else if(result == Ctrl.FALSE){
				page = "/join/register.jsp";
			// EXCEPT일 경우 에러 페이지로 
			} else {
				page = "/exception/exception.jsp";
			}

		/* 메인에서 로그아웃 버튼 눌렀을 때 세션 및 쿠키 제거 */
		} else if(uri.equals("/logout")) {
			command = new LogoutAction(request, response);
			command.execute();
			page = "/main.jsp";
			
		/* 메인에서 회원정보조회 버튼 눌렀을 때 */
		} else if(uri.equals("/getUserInfo")) {
			command = new GetUserInfo(request);
			int result = command.execute();
			
			if(result == Ctrl.TRUE) {
				page = "/userInfo/getUserInfo.jsp";
			// FALSE일 경우 로그인 페이지로
			} else if(result == Ctrl.FALSE) {
				page = "/join/login.jsp";
			} else {
				page = "/exception/exception.jsp";
			}
			
		/* 작업 시 예외 발생할 경우 */
		} else if(uri.equals("/exception")) {
			page = "/exception/exception.jsp";
			
		/* 그 외 URI일 경우 메인 첫화면으로 돌려줌  */
		} else {
			page = "/main.jsp";
		}
		
		response.sendRedirect("/hssweb" + page);
	}
}

 

 


 

 

[ /main.jsp ]

 

그냥 내용이 없어서 그냥 TOP 레이아웃을 include만 하고 있습니다.

 

<%@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>
	
<!-- 헤드 레이아웃 include -->
<jsp:include page = "/layout/headLayout.jspf" flush = "false"/>
	
</body>
</html>

 

 

 


 

 

[ /join/login.jsp ]

 

로그인 입력을 받는 화면입니다. 이미 로그인이 돼 있을 경우라면 로그인 버튼이 없지만, 혹시 직접 URL로 접속하는 경우를 대비해 로그인이 돼 있는 경우 입력폼을 띄우지 않도록 합니다.

 

또한 세션 객체에 로그인화면에서 띄워줄 메세지가 있다면 추가로 띄워주고 없으면 무시합니다. 이 부분은 로그인 시도 시 실패할 경우나, 회원가입에 성공해서 로그인 페이지로 넘어왔을 때 메세지를 출력해주기 위함입니다. 출력 후에는 바로 지워서 두 번 출력되는 일이 없도록 합니다.

 

로그인 실패 시

 

회원가입 직후

<%@ page import="login.SessionCheck" 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>

<!-- 헤드 레이아웃 include -->
<jsp:include page = "/layout/headLayout.jspf" flush="false"/>

<!-- 세션에 정보가 없을 경우에만 로그인 창 보여주기 -->
<% if (session.getAttribute("userID") == null) { %>
	<p>
	<form action="loginAsk" method="post">
		ID : <input type="text" name="userID" size="10" required/><br> 
		PW : <input type="password" name="userPW" size="10" required/>
		<input type="submit" value="로그인"> <br>
		<input type = "checkbox" name = "isAutoLogin" value = "true"> 자동 로그인
	</form>	
	</p>
<% } %>

<%
	// 회원가입 성공, 로그인 실패 등 메세지가 있으면 출력 후 삭제
	Object obj = session.getAttribute("loginMsg");
	if(obj != null) {
		String msg = (String)obj;
		out.println(msg);
		session.removeAttribute("loginMsg");
	}
%>

</body>
</html>

 

 


 

 

 

[ /join/register.jsp ]

 

회원가입 페이지입니다. 마찬가지로 TOP 레이아웃을 include 한 뒤, 한번 더 로그인 여부를 체크해서 돼있지 않은 경우에만 입력 폼을 출력합니다.

 

로그인 페이지와 마찬가지로 회원가입 시 문제가 발생할 경우의 메세지를 세션의 Attribute에서 찾아 출력해주고 바로 지워줍니다. 이 메세지는 회원가입을 처리하는 클래스에서 문제 발생 시 Session 객체에 담아줍니다. 

 

기존 계정 있을 경우

 

패스워드 확인이 틀렸을 경우

<%@ 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>

<!-- 헤드 레이아웃 include -->
<jsp:include page = "/layout/headLayout.jspf" flush="false"/>

<!-- 회원가입 (페이지 직접 접속할 경우에도 세션에 로그인 값 있으면 안보여줌)  -->
<% if (session.getAttribute("userID") == null) { %>
<p>
<form action = "registerAsk" method = "post">
	ID : <input type="text" name="userID" size="10" required/><br>
	패스워드 : <input type="password" name="userPW" size="12" required/><br>
	패스워드 확인 : <input type="password" name="userPW2" size="12" required/><br>
	이름 : <input type="text" name="userName" size="10" required/><br>
	이메일 : <input type="text" name="userEmail" size="30" required/><br>
	전화번호 : <input type="text" name="userPhone" size="15" required/><br>
	성별 : <input type="radio" name="userGender" value="men" required/>남 
	<input type="radio" name="userGender" value="women">여<br>
	<input type="submit" value="가입하기">
</form>
</p>
<% } %>

<%
	// 회원가입 체크에서 실패 했을 경우 실패 메세지를 받아서 출력해줌
	Object obj = session.getAttribute("formMsg");
	if(obj != null) {
		String msg = (String)obj;
		out.println(msg);
		session.removeAttribute("formMsg");
	}
%>

</body>
</html>

 

 


 

 

일단 컨트롤러와 뷰의 구성 작업이 완료됐습니다. 다음 글들에서 DAO, DTO, Command 클래스를 추가하도록 하겠습니다. 

728x90

댓글

💲 추천 글