📗 self-study/📗 KH정보교육원 당산지원

[10/28] 프로젝트 진행 상황 로그인&로그아웃 & 회원가입

천재강쥐 2022. 10. 28. 11:24

서버가 굴러가는 구조란 이런걸가,,,

 

 

<로그인 >

메인 화면 배포 전이라 기존 메인을 로그인폼으로 했었는데 기존 배포된 메뉴바 include 해서 로그인 버튼 이용함

 

1. mainLogin.jsp

경로 노출되면 보안 위험 있으니 form만 띄워 줄 컨트롤러 부르기 위해 하단에 스크립트 구문 넣어 주고

로그인 버튼 onclick 속성 걸고


 

<Controller - Service - Dao - member-mapper - DB까지 갔다가 돌아왔을 때>

 

 loginUser라는 변수에 회원 정보를 담고 있고, 메인 화면에서 닉넴 담긴 알림창 띄워 줘야 하니까

상단 스크립틀릿으로 loginUser 받고, contextPath 알려 주고, alertMsg 받고

login 안 된 상태라면 메뉴바에 로그인/회원가입 ----- login 된 상태라면 마이페이지/로그아웃 뜨도록 조건 넣기


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="com.insertcoin.member.model.vo.Member" %>
<%
	Member loginUser = (Member)session.getAttribute("loginUser");
	String contextPath = request.getContextPath();
	
	String alertMsg = (String)session.getAttribute("alertMsg");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
    <title>메인 화면</title>

    <!-- CSS 스타일시트 -->
    <link href="resources/css/memberLoginForm.css" rel="stylesheet">
    <link href="resources/css/MainCss.css" rel="stylesheet">
    <link href="resources/css/MainContentCss.css" rel="stylesheet">

    <!-- jQuery 라이브러리 연결 -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>

    <!-- Bootstrap 프레임워크 연결 -->
    <!-- Latest compiled and minified CSS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
    <!-- Popper JS -->
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
    <!-- Latest compiled JavaScript -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
</head>

<body>
	<script>
		var msg = "<%= alertMsg %>";
		
		if(msg != "null") {
			alert(msg);
			
			<% session.removeAttribute("alertMsg"); %>
		}
	</script>

    <!-- 전체 영역 -->
    <div class="wrap">

    <!-------------------------------------- 헤더 영역 -------------------------------------->

        <!-- 헤더 영역 -->
        <div class="header_container">

            <!-- 헤더 로고 -->
            <div class="header_logo_container">
                <a href=""><img id="header_logo" src="resources/image/logo/insertcoin_logo.png" width="100%"></a>
            </div>

            <!-- 헤더 메뉴바 -->
            <div id="header_menu">
                <ul>
                    <li><a href="" class="main_menu">게임</a></li>
                    <li>
                        <a href="" class="main_menu">커뮤니티</a>
                        <ul>
                            <li><a href="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;개발자 게시판</a></li>
                            <li><a href="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;자유 게시판</a></li>
                        </ul>
                    </li>
                    <li>
                        <a href="" class="main_menu">고객센터</a>
                        <ul>
                            <li><a href="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;공지사항</a></li>
                            <li><a href="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FAQ</a></li>
                        </ul>
                    </li>
                    <% if (loginUser == null) { %>
	                    <li>
	                        <a id="login_menu" onclick="loginPage();">로그인</a>
	                        <ul>
	                            <li><a onclick="loginPage();">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;로그인</a></li>
	                            <li><a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;회원가입</a></li>
	                        </ul>
	                    </li>
                    <% } else { %>
   	                    <li>
                        <a href="" class="main_menu">
                            <img src="resources/image/profile/profile_default.png" id="header_profile">
                            InsertCoin
                        </a>
                        <ul>
                            <li><a href="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;마이페이지</a></li>
                            <li><a href="<%= contextPath %>/logout.me">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;로그아웃</a></li>
                        </ul>
                    </li>
                    <% } %>
                </ul>
            </div>

            <!-- 헤더 검색 -->
            <div class="header_search_container">
                <form action="" class="header_search-bar">
                    <input type="search" name="search">
                    <button type="submit" id="header_search">
                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-search" viewBox="0 0 16 16">
                            <path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/>
                        </svg>
                    </button>
                </form>
            </div>

        </div>
	
	<div align="center" style="color:white; height:1000px; margin:auto;"><h1>메인 화면 영역</h1></div>
    
    <div> 푸터 </div>

    </div>
    
    <script>
    	function loginPage() {
    		location.href = "<%= contextPath %>/loginForm.me";
    	}
    </script>

</body>
</html>

 

 

2. LoginFormController.jsp

로그인 폼 띄워 주기만 할 controller

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
	    // 단순히 회원가입 폼을 띄워 줄 용도
	    request.getRequestDispatcher("views/member/memberEnrollForm.jsp").forward(request, response);
	}

 

3. memberLoginForm.jsp

로그인 폼

getContextPath만 상단에 선언

로그인 버튼(submit 속성) 눌렀을 때 컨트롤러로 갈 수 있도록 form 태그에 action 속성 걸어 줌

action="<%= contextPath %>/login.me"

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="com.insertcoin.member.model.vo.Member" %>
<%
	String contextPath = request.getContextPath();
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
    <title>로그인 화면</title>

    <!-- CSS 스타일시트 -->
    <link href="resources/css/memberLoginForm.css" rel="stylesheet">
    <link href="resources/css/MainCss.css" rel="stylesheet">
    <link href="resources/css/MainContentCss.css" rel="stylesheet">

    <!-- jQuery 라이브러리 연결 -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>

    <!-- Bootstrap 프레임워크 연결 -->
    <!-- Latest compiled and minified CSS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
    <!-- Popper JS -->
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
    <!-- Latest compiled JavaScript -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
</head>

<body>

        <!-------------------------------------- 컨텐츠 영역 -------------------------------------->

		
        <!-- 컨텐츠 영역 -->
        <div class="content_container">
            <!-- 로그인 창 -->
            <form id="login_form" action="<%= contextPath %>/login.me" method="post">

                <!-- 로고, 이메일, 비밀번호 입력 영역 -->
                <div class="login_content">
                    <!-- 로그인 창 로고 -->
                    <div style="text-align:center;">
                        <img src="resources/image/logo/insertcoin_logo.png" alt="insert_coin_logo" id="login_logo">
                    </div>
                    <!-- 로그인 글자 -->
                    <div id="login_text"><h2>로그인</h2><hr></div>

                    <!-- 로그인 정보 입력 폼 -->
                    <table align="center" id="login_table">
                        
                        <tr>
                            <th>이메일</th>
                        </tr>
                        <tr>
                            <th colspan="3">
                                <input type="email" name="memEmail" required>
                            </th>
                        </tr>
                        <tr>
                            <th>비밀번호</th>

                            </tr>
                        <tr>
                            <th colspan="3">
                                <input type="password" name="memPwd" required>
                            </th>
                        </tr>
                        <tr>
                            <!-- 로그인 버튼 -->
                            <th colspan="3"><button type="submit">로그인</button></th>
                        </tr>
                    </table>
                    <br>
                    <!-- 회원가입, 비밀번호 찾기 -->
                    <div align="center" id="etc">
                        <a onclick="enrollPage();">회원가입</a>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;
                        <a href="">비밀번호 찾기</a>
                    </div>
                </div>
            </form>
        </div>
        
        <script>
    		function enrollPage() {
    			location.href = "<%=contextPath %>/enrollForm.me";
    		}
	    </script>

</body>
</html>

 

4. LoginController

여기서부터 service, dao, member-mapper, DB까지 갔다가 돌아옴

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

	    // 로그인 정보는 POST 방식으로 처리해야 함 => 인코딩 처리
	    request.setCharacterEncoding("UTF-8");
	    
	    // 요청 시 전달값을 꺼내기
	    // memEmail: 아이디 값(이메일)
	    String memEmail = request.getParameter("memEmail");
	    // memPwd: 비밀번호 값
	    String memPwd = request.getParameter("memPwd");
	    // memNickname: 닉네임값 (성공 메시지 표출 때 보여 주고자 함)
	    String memNickname = request.getParameter("memNickname");
	    
	    // 요청 시 전달값들을 VO 객체로 가공
	    Member m = new Member();
	    m.setMemEmail(memEmail);
	    m.setMemPwd(memPwd);
	    
	    // 가공한 VO 객체를 해당 요청을 처리하는 서비스 클래스의 메소드로 넘기기
	    Member loginUser = new MemberService().loginMember(m);
	    
	    // 처리된 결과 응답 뷰 지정
	    if(loginUser == null) { // 로그인 실패 => 에러 문구를 담아서 에러 페이지로 응답하기
	        
	        request.setAttribute("errorMsg", "로그인에 실패했습니다.");
	        RequestDispatcher view = request.getRequestDispatcher("views/common/errorPage.jsp");
	        view.forward(request, response);
	       
	    } else { // 로그인 성공 => 응답 페이지에 loginUser 데이터 전달, 메인 페이지로 응답
	        
	        HttpSession session = request.getSession();
	        session.setAttribute("loginUser", loginUser);
	        
	        session.setAttribute("alertMsg", loginUser.getMemNickname() + "님! 오늘도 즐거운 게임 하세요!");
	        response.sendRedirect(request.getContextPath());
	    }
	    
	}

 

 

 

 

<로그아웃>

1. LogoutController 서블릿 생성 (/logout.me)

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
	    // 잘 가라고 인사하고
        HttpSession session = request.getSession();
	    session.setAttribute("alertMsg", "성공적으로 로그아웃되었습니다. 내일도 게임하러 오세요!");
	    
	    // 사용자의 아이디와 비밀번호는 소중하니까 확실하게 지워봄
	    request.getSession().removeAttribute("loginUser");
	    response.sendRedirect(request.getContextPath());
	}

 

2. main 화면의 로그아웃 버튼에 적용

<li><a href="<%= contextPath %>/logout.me">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;로그아웃</a></li>

 

 

 

 

<회원가입>

 

1. 메인 폼과 로그인 폼 회원가입 버튼 onclick 속성 걸고 script 구문

메인화면 회원가입 버튼, 로그인 폼에서의 회원가입 버튼 모두!

 

🤔 로그인 폼에서 회원가입 버튼 누를 때 밋밋해서 pointer: cursor; font-sylte: underline; 주고 싶은데 안 먹히네,,, 나중에 계속

<li><a onclick="enrollPage();">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;회원가입</a></li>
    <script>  	
    	function enrollPage() {
    		location.href = "<%=contextPath %>/enrollForm.me";
    	}
    </script>

 

2. MemberEnrollFormController 서블릿 생성

회원가입 폼을 띄워 줄 용도

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
	    // 단순히 회원가입 폼을 띄워 줄 용도
	    request.getRequestDispatcher("views/member/memberEnrollForm.jsp").forward(request, response);
	}

 

3. memberEnrollForm.jsp 생성

회원가입 폼 틀 만들어 줌

 

4. MemberEnrollController 서블릿 생성

진짜 회원가입 할 때 쓰일 컨트롤러

뽑아야 할 값 뽑고 멤버 변수에 담기

 

5. 회원가입용 Member 생성자 생성

 

6. 요청값을 Service-> Dao -> member-mapper.xml -> DB 넘긴 뒤에

                      -> Dao -> Service로 다시 가지고 오기

 

 

 

 


lib 폴더에 제이쓴 & 쥐쓴 .jar 추가

 

😱 인증번호 요청 버튼 -> 중복 확인 후 중복 아니면 인증번호 보내기

😱 메일 최대 길이 30자 제한

 

<메일 중복 확인 & 포맷 제한>

 

1. memberEnrollForm.jsp

이메일 30자 제한

회원가입 폼에서 인증번호 요청 버튼을 눌렀을 때 중복확인부터 한 뒤 인증번호 보내기 때문에 onclick 속성에 선언적 함수 걸기

<tr>
    <th>이메일</th>
</tr>
<tr>
    <th colspan="4">
        <input type="email" name="memEmail" maxlength="30" required>
    </th>
    <td><button class="table_button" onclick="emailCheck();">인증번호 요청</button></td>
</tr>


        <script>
        	function emailCheck() {
        		var $memEmail = $("#enroll_table input[name=memEmail]");
        		
        		$.ajax({
        			url : "emailCheck.me",
        			data : {checkEmail : $memEmail.val()},
        			success : function(result) {
        				
        			},
        			error : function () {
        				console.log("이메일 중복 체크용 ajax 통신 실패!");
        			}

        		});
        	}
        </script>

 

script에서 "키 : 밸류"로 이메일창(name: memEmail)에 입력된 데이터를 emailCheck.me(컨트롤러)로 보냈음

 

 

2. EmailCheckController (/emailCheck.me)

니가 보낸 키값에 request.getParameter을 사용해서 밸류 넣어 줄게!

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
	    // checkEmail이라는 변수에 든 value값 뽑기
	    String checkEmail = request.getParameter("checkEmail");
	    
	    // 전달값인 밸류를 서비스로 넘겨서 요청 처리 후 결과 받기
        // 응답 데이터는 1개만 넘기기 때문에 JSON 필요 없이 Ajax로 해결 가능
        // 넘겨 주기
	    int count = new MemberService().emailCheck(checkEmail);
	    
	    // 응답 데이터에 한글이 있다면 깨질 수도 있으니 문서 타입과 인코딩 방식 알려 주기
	    response.setContentType("text/html; charset=UTF-8");
	    
	    // DB까지 다녀온 count에 중복 이메일 값이 있다면 1, 없다면 0이 담겨 있을 것 
	    if(count > 0) {
	        response.getWriter().print("possible");
	    } else {
	        response.getWriter().print("impossible");
	    }
	    
	}

 

3. MemberService

    // 이메일 중복체크용 서비스
    public int emailCheck(String emailCheck) {
        
        Connection conn = JDBCTemplate.getConnection();
        
        int count = new MemberDao().emailCheck(conn, emailCheck);
        
        JDBCTemplate.close(conn);
        
        return count;
        
    }

 

4. MemberDao

    public int emailCheck(Connection conn, String checkEmail) {
        
        // SELECT문 => ResultSet 객체 (숫자 1개)
        
        // 필요한 변수 세팅
        int count = 0;
        PreparedStatement pstmt = null;
        ResultSet rset = null;
        
        String sql = prop.getProperty("emailCheck");
        
        try {
            pstmt = conn.prepareStatement(sql);
            
            pstmt.setString(1, checkEmail);
            
            rset = pstmt.executeQuery();
            
            if(rset.next()) {
                count = rset.getInt("COUNT(*)");
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            
            JDBCTemplate.close(rset);
            JDBCTemplate.close(pstmt);
            
        }
        
        return count;
        
    }

 

5. member-mapper.xml

	<entry key="emailCheck">
		SETLECT COUNT(*)
		FROM MEMBER
		WHERE MEM_EMAIL = ?
	</entry>

 

 

 

 

 

😱 인증 버튼 => 일치하면 submit

<인증...어케하지>

 

😱 비밀번호.val() == 비밀번호 확인.val() 일 때만 넘어가게 조건 걸기

😱  비밀번호 8~16자리 영어 대소문자, 숫자, 특수문자

<비밀번호 일치 확인>

 

 

 

😱 닉네임 중복 확인

😱  닉네임 2~10자리의 한글, 영문, 숫자, 특수문자

<닉네임 중복 확인 & 포맷 제한>