09009

[Spring] 예제 3 - 회원가입 유효성 검사 (AJAX) 본문

Back-End/Spring
[Spring] 예제 3 - 회원가입 유효성 검사 (AJAX)
09009

아이디 중복체크

중복확인 버튼을 눌렀을 때 경고창 띄우기

아이디 중복확인 시에는 자바스크립트로만 할 수 있는 것이 아니라 

회원가입 시 입력한 아이디를 서버로 전송하는 작업이 필요하다.

(입력한 아이디가 DB에 저장된 아이디 중에 같은 것이 있는지 확인해야 하기 때문에)

 

자바스크립트로 request하는 API

:코드 내에서 페이지가 넘어가지 않고 자바스크립트로 request해서 응답하는 api

 

AJAX: 페이지가 넘어가지 않은 채로도 서버와 통신할 수 있는 API (비동기식 통신 방법)

 

호출 방식

	function checkUserId() {
		// AJAX api 활용
	    const xhr = new XMLHttpRequest();
		
		
	    xhr.open("get", "./loginPage"); // 무엇을 호출할 것인지..? requestmapping 된 loginPage 접속
	    xhr.send();
	}

	
	const a = 10;
	
	// 많이 쓰이는 함수 작성법
	function test() {
		alert("ss");
		return 10;
	}
	
	const b = test(); // test 함수 호출하고 return 값 받음
	const c = test; // 변수가 함수 그 자체를 받아들일 수 있다. (변수 c가 test 함수 자체를 받아들임) 함수를 호출한 것이 아니다 !!!
	
	c();
	test(); // c(); == test();
	
	
	// 많이 쓰이는 함수 작성법
	const d = function() { // d라는 변수에 함수를 넣는다. (익명 함수 생성)
		alert("ttt"); 
	}
	
	d(); // 함수 호출 
	
	
	// lo function
	const e = () => alert("ttt");
	
	const e1 = () => {
		alert("ttt")  // e라는 변수에 함수를 넣었다
	};
	
	e();
	e1();
	function checkUserId() {
		// AJAX api 활용
	    const xhr = new XMLHttpRequest();
		
		// 이 값에 function을 넣을 수 있다.
	    xhr.onreadystatechange = function () {
			alert("안녕");			
		};
	    
	    xhr.open("get", "./loginPage"); // 무엇을 호출할 것인지..? requestmapping 된 loginPage 접속
	    xhr.send();
	}

4번째 반응 확인

onreadystatechange : 서버에서 응답이 도착하였을 때 특정한 자바스크립트 함수를 호출할 수 있는 것

XMLHTTP의 상태가 변경될 때마다라는  뜻

	function checkUserId() {
		// AJAX api 활용
	    const xhr = new XMLHttpRequest();
		
		// 이 값에 function을 넣을 수 있다.
	    xhr.onreadystatechange = function () {
	    	alert(xhr.responseText);	
		};
	    
	    xhr.open("get", "./loginPage"); // 무엇을 호출할 것인지..? requestmapping 된 loginPage 접속
	    xhr.send();
	}

 

중복확인 버튼을 클릭하면

ajax: 자바스크립트로 요청하고 응답받는다.

 

ajax가 호출된 쪽(받는 쪽)은 html 코드가 아닌 restapi를 만들어주어야 한다.

	function checkUserId() {
		// AJAX api 활용
		// 코드 실행 흐름 순서 중요
	   const xhr = new XMLHttpRequest(); // (1)
		
		// 이 값에 function을 넣을 수 있다. 콜백함수: 내가 만들었지만 내가 호출한 것이 아님.
	    xhr.onreadystatechange = function () { // (2)
			if(xhr.readyState == 4 && xhr.status == 200) {
				//(5)
				alert(xhr.responseText);
			}		
		};
	    
	    xhr.open("get", "./existsUserId"); // (3)  무엇을 호출할 것인지..? requestmapping 된 loginPage 접속
	    xhr.send(); // 콜백함수를 총 네 번 호출한다. // (4)
	}

 

RestMemberController

package com.ja.finalproject.member.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

// RestAPI용 controller (AJAX용)
@RestController
@RequestMapping("member/*")
public class RestMemberController {
	
	@RequestMapping("existsUserId")
	public String existsUserId() {
		System.out.println("테스트!!!");
		
		return "qwer";
	}
}

중복확인 버튼을 누르면 페이지가 이동이 되지 않고 자바스크립트로 request한다.

서버 쪽은 웹 브라우저가 자바스크립트로 요청했는지 링크를 이용해서 요청했는지는 관심 없다.

 

* 중요 *

RestController는 html로 return하지 않는다 (forwarding 하지 않는다)  = HTML 화면 리턴 X , 값(글자 그대로)을 리턴

 

 

주소 창에 아래 그대로 입력

	function checkUserId() {
		
		const userIdValue = document.getElementById("userId").value;
				
		// AJAX api 활용
		// 코드 실행 흐름 순서 중요
	   const xhr = new XMLHttpRequest(); // (1)
		
		// 이 값에 function을 넣을 수 있다. 콜백함수: 내가 만들었지만 내가 호출한 것이 아님.
	    xhr.onreadystatechange = function () { // (2)
			if(xhr.readyState == 4 && xhr.status == 200) {
				//(5)
				alert(xhr.responseText);
			}		
		};
	    
	    xhr.open("get", "./existsUserId?userId=" + userIdValue);  // (3)  무엇을 호출할 것인지..? requestmapping 된 loginPage 접속
	    xhr.send(); // 콜백함수를 총 네 번 호출한다. // (4)
	}
package com.ja.finalproject.member.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

// RestAPI용 controller (AJAX용)
@RestController
@RequestMapping("/member/*")
public class RestMemberController {
	
	@RequestMapping("existsUserId")
	public String existsUserId(String userId) {
		System.out.println("테스트!!!");
		
		return "qwer";
	}
}

MemberSqlMapper

아래 코드 추가

	public int countByUserId(String userId);

MemberSqlMapper.xml

	<select id="countByUserId" resultType="int">
		SELECT COUNT(*) FROM fp_member WHERE user_id = #{userId}
	</select>

MemberServiceImpl

	public boolean existsUserId(String userId) {
		
		// return memberSqlMapper.countByUserId(userId) > 0 ? true : false; (삼항 연산자)
		
			int count = memberSqlMapper.countByUserId(userId);
			
			if(count > 0 ) { 
				return true;
			} else {
				return false;
			}
		}

RestController

package com.ja.finalproject.member.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.ja.finalproject.member.service.MemberServiceImpl;

// RestAPI용 controller (AJAX용)
// 포워딩하지 않는다. (html 화면 리턴 x), 값을 리턴
// 리턴 타입은 꼭 String이 아니어도 된다.

@RestController
@RequestMapping("/member/*")
public class RestMemberController {
	
	@Autowired
	private MemberServiceImpl MemberService;
	
	@RequestMapping("existsUserId")
	public boolean existsUserId(String userId) {
		System.out.println("테스트");
		
		boolean exists = MemberService.existsUserId(userId);
		
		return exists;
	}
}

 

링크로 테스트할 줄 알아야 한다.

 

 

 

 

----

JSON 변환기 : Object를 JSON 문자열로 변환시켜준다,

 Dto를 출력하면 아래와 같이 나온다.

 

 Dto를 출력하면 아래와 같이JSON 형식으로 나온다.

배열

"aaa"라는 key에 배열

"bbb"라는 key에 Object가 들어있다.

package com.ja.finalproject.member.controller;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.ja.finalproject.member.service.MemberServiceImpl;

// RestAPI용 controller (AJAX용)
// 포워딩하지 않는다. (html 화면 리턴 x), 값을 리턴
// 리턴 타입은 꼭 String이 아니어도 된다.
// 일반적으로 리턴 타입은 객체 혹은 컬렉션을 리턴한다. => JSON 변환해서 리턴함

@RestController
@RequestMapping("/member/*")
public class RestMemberController {
	
	@Autowired
	private MemberServiceImpl MemberService;
	
	@RequestMapping("existsUserId")
	public Map<String, Object> existsUserId(String userId) {
		System.out.println("테스트");
		
		boolean exists = MemberService.existsUserId(userId);
		
		Map<String, Object> map = new HashMap<>();
		map.put("result", "success");
		map.put("data", exists);
		
		return map;
	}
}

registerPage.jsp

	function checkUserId() {
		
		const userIdValue = document.getElementById("userId").value;
				
		// AJAX api 활용
		// 코드 실행 흐름 순서 중요
	   const xhr = new XMLHttpRequest(); // (1)
		
		// 이 값에 function을 넣을 수 있다. 콜백함수: 내가 만들었지만 내가 호출한 것이 아님.
	    xhr.onreadystatechange = function () { // (2)
			if(xhr.readyState == 4 && xhr.status == 200) {
				//(5)
				const response = JSON.parse(xhr.responseText);
				
				// js로 논리 코드 및 DOM 조작
				if(response.data == true) {
					alert("이미 존재하는 아이디입니다.");
				} else {
					alert("사용 가능한 아이디입니다.");
				}
				
			}		
		};
	    
	    xhr.open("get", "./existsUserId?userId=" + userIdValue);  // (3)  무엇을 호출할 것인지..? requestmapping 된 loginPage 접속
	    xhr.send(); // 콜백함수를 총 네 번 호출한다. // (4)
	}

아이디 중복체크 로직 

registerPage.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">
<title>Insert title here</title>
<script>
	function checkValueAndSubmit() {
		const userIdBox = document.getElementById("userId");
		const idValue = userIdBox.value;
		
		const idRegEx = /^[a-zA-Z][a-zA-Z0-9]{4,12}$/;
		
		// idValue가 정규표현식에 적합하지 않으면
		if (!idRegEx.test(idValue)) {
			alert("아이디는 영소문자로 시작해야하고 영소문자, 대문자, 숫자로만 4~12글자이어야 합니다.");
			userIdBox.focus();
			return; // return;을 해줘야 submit이 발동되지 않는다. (주의!)
		}
		
		const userPwBox = document.getElementById("userPw");
		const userPwConfirmBox = document.getElementById("userPwConfirm");
		
		if(userPwBox.value != userPwConfirmBox.value) {
			alert("입력한 비밀번호를 다시 확인해주세요.")
			userPwBox.value = "";
			userPwConfirmBox.value = "";
			userPwBox.focus();
			return;
		}
		
		const pwRegEx = /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[!@#$%^&*()_+])[a-zA-Z\d!@#$%^&*()_+]{8,16}$/;
		
		if(!pwRegEx.test(userPwBox.value)){
			alert("비밀번호는.... 어쩌고 8-16 글짜.. 블라블라..");
			userPwBox.value = "";
			userPwConfirmBox.value = "";
			
			userPwBox.focus();
			return;
		}
		
		if(idChecked == false) {
			alert("아이디 중복확인을 해주세요");
			return;
		}
		
		const frm = document.getElementById("frm");
		frm.submit();
	}
	
	
	// 값이 중간에 바뀔 것이므로 const로 선언하면 안된다.
	let idChecked = false;
	
	function checkUserId() {
		
	    const userIdValue = document.getElementById("userId").value;
				
		// AJAX api 활용
		// 코드 실행 흐름 순서 중요
	    const xhr = new XMLHttpRequest(); // (1)
		
		// 이 값에 function을 넣을 수 있다. 콜백함수: 내가 만들었지만 내가 호출한 것이 아님.
	    xhr.onreadystatechange = function () { // (2)
			if(xhr.readyState == 4 && xhr.status == 200) {
				//(5)
				const response = JSON.parse(xhr.responseText);
				
				// js로 논리 코드 및 DOM 조작
				if(response.data == true) {
					alert("이미 존재하는 아이디입니다.");
					idChecked = false;
				} else {
					alert("사용 가능한 아이디입니다.");
					idChecked = true;
				}
				
			}		
		};
	    
	    xhr.open("get", "./existsUserId?userId=" + userIdValue);  // (3)  무엇을 호출할 것인지..? requestmapping 된 loginPage 접속
	    xhr.send(); // 콜백함수를 총 네 번 호출한다. // (4)
	}
	
</script>
</head>
<body>
<h1>회원 가입</h1>
<form id="frm" action="./registerProcess" method="post">
	ID: <input id="userId" type="text" name="user_id">
	<input onclick="checkUserId()" type="button" value="중복확인">
	<br>
	PW: <input id="userPw" type="password" name="user_pw"><br>
	PW 확인: <input id="userPwConfirm" type="password"><br>
	nickname: <input type="text" name="nickname"><br>
	gender: 
	<input type="radio" name="gender" value="M">남
	<input type="radio" name="gender" value="F">여 <br>
	
	취미: 
	<c:forEach items="${hobbyList}" var="hobby">
		<input type="checkbox" name="hobby_id" value="${hobby.id}"> ${hobby.name}
	</c:forEach>
	
	<br>
	
	email: <input type="text" name="email"><br>
	생년월일: <input type="date" name="birth"><br>
	전화번호: <input type="text" name="phone"><br>
	<input type="button" value="회원가입" onclick="checkValueAndSubmit()">
	
</form>
<a href="./loginPage">로그인 페이지로 이동</a>
</body>
</html>