글쓰기

개인 공부 상자/Spring 실습

스프링 로그인 실습[스마트인재개발원]

RSpring41 2021. 8. 31. 15:24

이전 환경 구성에 이어서 로그인 실습을 진행하겠다!!

'스마트인재개발원'에서 진행했던 게시글 작성 및 조회 실습 내용을 떠올려 보면서 실습해보았다.

 

[3편] 스프링 환경 구성[스마트인재개발원]

저번 1편에서 프로젝트를 생성하고 2편에서는 DB를 구성해봤다. 이제 이 둘을 연동해보자! [1편] 스프링 환경 구성[스마트인재개발원] 이 글은 Spring이라는 것을 처음 사용해 보거나 중간에 어려움

rspring41.tistory.com

 

 

먼저 부트스트랩을 이용해 간단한 회원가입 페이지를 만들고 추가로 중복 확인 기능을 넣기 위해 JSP파일을 만들었다.

('스마트인재개발원'에서 교육받으면서 부트스트랩을 처음 알았는데 정말 편하다.)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- 부트스트랩 사용 -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"></script>


<title>사용자 등록</title>
<style type="text/css">
@font-face {
	font-family: 'Gmarket Bold';
	font-style: normal;
	font-weight: 700;
	src: local('Gmarket Sans Bold'), local('GmarketSans-Bold'), url('http://script.ebay.co.kr/fonts/GmarketSansBold.woff2') format('woff2'),
		url('http://script.ebay.co.kr/fonts/GmarketSansBold.woff') format('woff');
}

@font-face {
	font-family: 'Gmarket mid';
	font-style: normal;
	font-weight: 500;
	src: local('Gmarket Sans Medium'), local('GmarketSans-Medium'), url('http://script.ebay.co.kr/fonts/GmarketSansMedium.woff2') format('woff2'),
		url('http://script.ebay.co.kr/fonts/GmarketSansMedium.woff') format('woff');
}

@font-face {
	font-family: 'Gmarket Lite';
	font-style: normal;
	font-weight: 300;
	src: local('Gmarket Sans Light'), local('GmarketSans-Light'), url('http://script.ebay.co.kr/fonts/GmarketSansLight.woff2') format('woff2'),
		url('http://script.ebay.co.kr/fonts/GmarketSansLight.woff') format('woff');
}

* {
	font-family: 'Gmarket mid', serif;
}

.container {
	width: 400px;
	margin-top: 100px;
	padding: 30px 50px;
	border: 1px solid #8bec95;
	border-radius: 25px;
	background-color: #8bec95;
}

.input-group {
	margin-bottom: 5%;
}
</style>
</head>
<body>


	<script src="${pageContext.request.contextPath}/resources/js/jquery-3.6.0.min.js"></script> 
	<script type="text/javascript">
	
	
	
		// 아이디 중복 체크
		function id_check() {
			 
			var input_id = + $('#input_id').val();

			$.ajax({
				url : 'user_id_check',
				type : 'get',
				success : function(data) {
					alert("성공");
				},
				error : function() {
					alert("실패");
				}
			});
		} 
		
	</script>





	<div class="container">
		<h2>회원 등록 ${login_result}</h2>
		<h5 style="color: red; display: none;">중복된 아이디가 존재합니다.</h5>

		<c:set var="data" value="${loginResult}" />
		<c:choose>
			<c:when test="${data eq '1'}">
				<!-- <h2>회원가입 성공</h2> -->
			</c:when>
			<c:when test="${data eq '0'}">
				<!-- <h2>회원가입 실패</h2> -->
			</c:when>
			<c:otherwise>
				<h2></h2>
			</c:otherwise>
		</c:choose>


		<form action="post_user_add" method="post">

			<div class="input-group mb-3">
				<span class="input-group-text"><i class="bi bi-person-plus-fill" style="line-height: 0px"></i></span>
				<input name="input_id" id="input_id" type="text" class="form-control" placeholder="Username" autocomplete="username">
				<button class="btn btn-success" type="button"  onclick="id_check()">중복확인</button>
			</div>


			<div class="input-group mb-3">

				<span class="input-group-text"><i class="bi bi-lock-fill" style="line-height: 0px"></i></span>				
				<input name="input_pw" id="input_pw" type="password" class="form-control" placeholder="Password" autocomplete="current-password">
			</div>
			<button type="submit" class="btn btn-primary" style="width: 100%;">등록</button>
		</form>
	</div>






</body>
</html>

CSS분리 안해서 엄청 길다;;

 

- 결과

 

 

이제 아이디 중복 확인을 위한 ajax기능 구현하겠다!!

(사실 하루종일 이것 때문에 힘들었다 ㅠㅠ)

 

 

 

1. Jquery경로 설정

'스마트인재개발원'에서 Spring 수업 당시에 jQuery에 관한 내용은 교육하지 않아서 일단 일반적인 웹 프로젝트처럼 경로를 설정했는데 jQuery파일을 찾지 못하는 상황이 발생했다.

 

Spring에서 JQuery나 js파일 경로 설정은 다음 게시글을 참조하면 된다.

 

Spring Legacy Project Jquery경로 설정

이전에 사용했던 Dynamic Web Project에서 Spring Legacy Project로 변경된 환경에서 실습 진행시 Jquery를 사용하기 위해 파일을 경로를 아래와 같이 설정해 주었지만 계속하여 콘솔창에 'net::ERR_ABORTED 404'..

rspring41.tistory.com

 

2. @RequestMapping만 사용하는 게 아닌 @ResponseBody를 추가로 사용

여기도 '스마트인재개발원'에서 진행했던 교육 내용이 아니라서 많이 찾아봤다. 먼저 페이지를 전환할때@RequestMapping를 하고 jsp파일 이름을 반환하면 페이지 전환이 일어난다.

 

하지만 Ajax는 페이지 전환이 아닌 데이터만 넘겨주어야 한다. My-SQL에서 select문에 결과로 단일 값이 아니라면 JSON형태로 값을 받아오게 된다. 이때 @RequestMapping를 이용하게 된다면 JSON형태에 데이터를  'jsp파일 이름'으로 인식하기 때문에 오류가 발생한다.

 

따라서 @ResponseBody를 이용하여 데이터를 반환 해주어야 Ajax에서 결과값을 정상적으로 받을 수 있다.

 

 

3. 로그인 중복확인 기능 구현 

- JSP ajax부분

	<script src="${pageContext.request.contextPath}/resources/js/jquery-3.6.0.min.js"></script> 
	<script type="text/javascript">
	
	
	
		// 아이디 중복 체크
		function id_check() {
			 
			var input_id = $('#input_id').val();
			console.log(input_id);

			$.ajax({
				url : 'user_id_check',
				type : 'get',
				data:{
					input_id : input_id
				},
				success : function(data) {
					if (data == 'Yes') {
						alert("사용 가능한 아이디 입니다.");
					}else{
						alert("이미 존재하는 아이디 입니다.");
					}
				},
				error : function() {
					alert("서버연결 실패");
				}
			});
		} 
		
	</script>

 

- Controller부분

	// 아이디 중복 확인
	@RequestMapping(value = "/user_id_check")
	@ResponseBody
	public String user_id_sheck(Model model, HttpServletRequest request) {
		String result_idCheck = "Yes";
		String input_id = request.getParameter("input_id");
		
		System.out.println(input_id);
		
		if (input_id.equals("ps")) {
			result_idCheck = "No";
		}
		
		return result_idCheck;
		
		 
	}

 

- 테스트

이렇게 간단하게 'ps'라는 아이디만 확인하게 만들었다. 이제 DB와 연동하여 실제로 Table에 아이디가 존재한다면 경고 메시지를 출력해보자

 

1. DB에서 아이디가 존재 하는지 확인하는 SQL문을 작성해보고 테스트해보자!

(My-SQL서버 실행 까먹지 말자!)

예전에 만들어 뒀던 sql_test.SQL파일에서 테스트를 진행했다.

 

 

사용한 SQL문 : select * from users where id = 'ps';

id칼럼이 '1'인 행을 잘 찾았다! 

 

 

 

 

>>> 팁!!

'스마트인재개발원'에서 프로젝트를 진행할 때 DB내용을 계속 확인해야 하는데 그때마다 Select문을 실행시켜 위에 사진과 같은 형태로 확인하니 너무 불편해다. 또한, 값을 바꿔야 하는데 그때마다 Update문을 이용해서 수정하는 게 손이 너무 많이 갔다. 그래서 다른 방법을 찾았다

 

여기서 추가, 변경, 삭제 이후 저장을 하게 되면 자동으로 SQL문이 실행되어 DB에 반영된다.

 

다음으로

'0'개 이면 중복된 아이디 없음

'1'개 이면 중복된 아이디 있음

개수 카운터로 구현하면 : select count(id) from users where id = '1';

 

이제 이 결과를 처리하여 아이디 중복 검사 기능을 구현해보자

 

 

2. mapper.xml mapper.java 파일 수정

 

3. Controller 추가

4. 테스트

 

5. 중복확인이 완료되면 회원가입이 가능하게 input에 hidden과 Controller에 회원가입 기능을 수정하자

 

- Controller 중복검사 부분

	// 아이디 중복 확인
	@RequestMapping(value = "/user_id_check")
	@ResponseBody
	public String user_id_sheck(Model model, HttpServletRequest request) {
		
		// result_idCheck = [상태값]
		// 0(중복 없음)
		// 1(중복 발생)
		// 2(DB 오류)

		int result_idCheck = 3;
		String input_id = request.getParameter("input_id");
		
		
		// id 중복 검사
		try {
			result_idCheck = homeMapper.id_check(input_id);
		} catch (Exception e) {
			System.out.println("아이디 중복검사 오류 발생 Controller-user_id_check참고");
			e.printStackTrace();
		}
		
		return String.valueOf(result_idCheck);
		
		 
	}

 

- JSP 아이디 중복검사와 로그인 기능 구현(JavaScript)

		// 아이디 중복 체크
		function id_check() {

			var input_id = $('#input_id').val();

			if (input_id) {
				$
						.ajax({
							url : 'user_id_check',
							type : 'get',
							data : {
								input_id : input_id
							},
							success : function(data) {
								if(data == 3){
									alert("서비스 오류");
								} else if (data == 1) {
									alert("이미 존재하는 아이디 입니다.");
									// 0 : 중복 아이디로 인하여 가입 불가 상태
									$('#id_check_result').attr('value', '0');
								} else {
									var user_id_use
									user_id_use = confirm('사용 가능한 아이디이며 이 아이디로 사용 하시겠습니까?');

									if (user_id_use) {
										// 1 : 가입 가능 상태
										$('#id_check_result')
												.attr('value', '1');
										// 사용 가능 하다면 사용할지 선택
										$('#input_id').attr('readonly',
												'readonly');
									} else {
										$('#input_id').val('');
									}

								}
							},
							error : function() {
								alert("서버연결 실패");
							}
						});
			} else {
				alert("아이디를 입력해주세요");
			}

		}

		// 회원가입 진행
		function user_add() {

			var input_id = $('#input_id').val();
			var input_pw = $('#input_pw').val();
			var id_check_result = $('#id_check_result').attr('value')

			// 3 : 아이디 중복확인을 하기 전 기본 상태
			if (id_check_result != 3) {
				// 0 : 불가능 , 1: 가능
				if (id_check_result == 1) {
					// 비밀번호 입력 했는지 검사
					if (input_pw) {

						$.ajax({
							url : 'post_user_add',
							type : 'post',
							data : {
								input_id : input_id,
								input_pw : input_pw
							},
							success : function(data) {
								if (data == 1) {
									alert("회원가입이 완료 되었습니다.");
									location.replace('user_add');
								} else {
									alert("회원가입에 실패 하였습니다. 관리자게 문의 하세요");
								}
							},
							error : function() {
								alert("서버연결 실패");
							}
						});
					} else {
						alert("비밀번호를 입력해 주세요");
					}

				} else {
					alert("다른 아이디를 이용해 주세요");
				}
			} else {
				alert("아이디 중복확인을 해주세요");
			}
		}

 

- 테스트

 

이제 로그인 기능을 구현해보자!!

 

회원 등록 JSP를 복사해서 로그인 페이지를 하나 만들고 Controller에서 URL 매핑해주자!

 

- user_login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- 부트스트랩 사용 -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"></script>


<title>PS 로그인</title>
<style type="text/css">
@font-face {
	font-family: 'Gmarket Bold';
	font-style: normal;
	font-weight: 700;
	src: local('Gmarket Sans Bold'), local('GmarketSans-Bold'), url('http://script.ebay.co.kr/fonts/GmarketSansBold.woff2') format('woff2'),
		url('http://script.ebay.co.kr/fonts/GmarketSansBold.woff') format('woff');
}

@font-face {
	font-family: 'Gmarket mid';
	font-style: normal;
	font-weight: 500;
	src: local('Gmarket Sans Medium'), local('GmarketSans-Medium'), url('http://script.ebay.co.kr/fonts/GmarketSansMedium.woff2') format('woff2'),
		url('http://script.ebay.co.kr/fonts/GmarketSansMedium.woff') format('woff');
}

@font-face {
	font-family: 'Gmarket Lite';
	font-style: normal;
	font-weight: 300;
	src: local('Gmarket Sans Light'), local('GmarketSans-Light'), url('http://script.ebay.co.kr/fonts/GmarketSansLight.woff2') format('woff2'),
		url('http://script.ebay.co.kr/fonts/GmarketSansLight.woff') format('woff');
}

* {
	font-family: 'Gmarket mid', serif;
}

.container {
	width: 400px;
	margin-top: 100px;
	padding: 30px 50px 20px 50px;
	border: 1px solid #8bec95;
	border-radius: 25px;
	background-color: #8bec95;
}

.input-group, .btn-primary {
	margin-bottom: 5%;
}
</style>
</head>
<body>


	<div class="container">
		<h2>PS 로그인</h2>

		<div class="input-group mb-3">
			<span class="input-group-text"><i class="bi bi-person-plus-fill" style="line-height: 0px"></i></span>
			<input name="input_id" id="input_id" type="text" class="form-control" placeholder="Username" autocomplete="username">
		</div>


		<div class="input-group mb-3">

			<span class="input-group-text"><i class="bi bi-lock-fill" style="line-height: 0px"></i></span>
			<input name="input_pw" id="input_pw" type="password" class="form-control" placeholder="Password" autocomplete="current-password">
		</div>
		<button type="button" class="btn btn-primary" style="width: 100%;" onclick="user_login()">로그인</button>
		<button type="button" class="btn btn-primary" style="width: 100%;" onclick="user_add()">회원가입</button>

	</div>


	<script src="${pageContext.request.contextPath}/resources/js/jquery-3.6.0.min.js"></script>
	<script type="text/javascript">
	
	
		// 로그인
		function user_login() {

			var input_id = $('#input_id').val();
			var input_pw = $('#input_pw').val();

			// 아이디 입력 했는지 검사
			if (input_id) {
				// 비밀번호 입력 했는지 검사
				if (input_pw) {

					$.ajax({
						url : 'user_login',
						type : 'post',
						data : {
							id : input_id,
							pw : input_pw
						},
						success : function(data) {
							if (data.id == 'error' && data.pw == 'error') {
								alert("서비스 오류 발생");
							} else if (data) {
								alert("로그인 성공");
								// 로그인 성공한 데이터 처리
								
								
								location.replace('home');
							} else {
								alert("아이디 또는 비밀번호가 틀렸습니다.");
							} 
						},
						error : function() {
							alert("서버연결 실패");
						}
					});
				} else {
					alert("비밀번호를 입력해 주세요");
				}
			} else {
				alert("아이디를 입력해 주세요");
			}
		}
		
		
		
		// 회원가입 페이지 이동
		function user_add() {
			location.assign('user_add');
		}
	</script>


</body>
</html>

# alert("서비스 오류 발생");

DB서버가 실행되고 있지 않다면 'error'값을 이용하여 서비스 오류 문구를 출력하게 하였다.

 

 

- Mapper 추가

	<!-- 로그인 -->
	<select id="user_login" parameterType="UserInfoVO" resultType="UserInfoVO">
		select * from users where id = #{id} and pw = #{pw};
	</select>

# 여기서 UserInfoVO은 config.xml에서 지정해준 "level_1.level_2.VO.UserInfoVO"에 별칭이다.

 

 

- Config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
 
    <!-- 패키지 경로 별칭 설정 -->
    <!-- 여기서  VO에 모든 경로를 적으면서 사용하면 불편하니까 별칭을 설정해준다 -->
    <typeAliases>
        
       <!--  <typeAlias type="level_1.level_2.level_3.연결할 파일 이름 " alias="사용할 별칭"/> -->
       <typeAlias type="level_1.level_2.VO.UserInfoVO" alias="UserInfoVO"/>
       
        
    </typeAliases>

</configuration>

이렇게 하면 VO파일에 경로와 파일 이름을 별칭으로 사용 가능하다.

UserInfoVO = "level_1.level_2.VO.UserInfoVO" 

 

- Controller 추가 부분

		/* =================================== 로그인 페이지 =================================== */  
		
		// 로그인 페이지로 이동
		@RequestMapping(value = "/user_login", method = RequestMethod.GET)
		public String user_login() {
			return login_functionn + "user_login";
		}
		
		// 로그인 DB연동
		@RequestMapping(value = "/user_login", method = RequestMethod.POST)
		@ResponseBody
		public UserInfoVO user_login(HttpServletRequest request, UserInfoVO userInfoVO){
			UserInfoVO userLogin_ok = new UserInfoVO(null, null);
		
			// DB에 데이터 insert
			try {
				userLogin_ok = homeMapper.user_login(userInfoVO);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				System.out.println("아이디 : " + userInfoVO.getId() + "\t 비밀번호 : " + userInfoVO.getPw());
				System.out.println("회원 로그인 오류 발생 - controller user_login()참고");
				//e.printStackTrace();
			}
			return userLogin_ok;
		}

 

- 테스트

 

 

이렇게 회원가입, 로그인 기능이 끝이 났다.

추가로 DB에 패스워드를 저장하기 위해서는 암호화 작업이 필요한데 이것은 나중에 따로 작성해서 올려야겠다.

 

다음은 게시글 기능을 주제로 글을 작성하겠다!

 

스마트인재개발원

4차산업혁명시대를 선도하는 빅데이터, 인공지능, 사물인터넷 전문 '0원' 취업연계교육기관

www.smhrd.or.kr