today_is

[ spring 프로젝트 ] 회원가입, 로그인/아웃 - 중복체크(AJAX), hash 본문

project

[ spring 프로젝트 ] 회원가입, 로그인/아웃 - 중복체크(AJAX), hash

ye_rang 2024. 3. 9. 16:57

 

우리 사이트에는 회원의 종류가 총 3가지이다

 

role = 1 role = 2 role = 3
관리자 매장점주 일반회원

 

 

 

 

테이블 내용

create table member(
    idx         number          GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    userid      varchar2(500)   unique not null,
    userpw      varchar2(500)   not null,
    email       varchar2(500)   not null,
    nickname    varchar2(500)   unique not null,
    pnum        varchar2(500)   unique not null,
    role        number          check(role between 1 and 3) not null
        -- 1이면 전체관리자, 2이면 점주, 3이면 일반사용자
);



create table manager (
    idx         number          GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    userid      varchar2(500)    not null,
    name        varchar2(500)    not null,
    store_idx   number          not null,
    status      number          default 0 check(status in (0, 1)),
    -- 기본 '0' , 전체관리자가 확인하면 '1' -> 확인시 member의 role이 3에서 2로 바뀜
    
    constraint manager_member_fk
    foreign key (userid)
    references member(userid) on delete cascade,
    
    constraint manager_store_fk
    foreign key (store_idx)
    references store(idx) on delete cascade
);

 

 

 


 

 join.jsp

: 일반회원가입인지, 매장점주 회원가입인지 선택

 

가입구분 1단계 2단계 3단계
일반회원가입 일반회원 정보만 기입 회원가입 완료  
매장점주 회원가입 일반 회원정보만 기입 매장 정보 기입  회원가입 완료

 

 

 

 

 

 

 


 

 joinStoreMember.jsp

 

: 매장점주가입 - 회원정보 입력

 

 

 

 


 

 storeFormSubmit.jsp

: 매장점주 회원가입 - 매장 정보 입력

 

이때, 이름을 받는건 실제 본명을 입력하기 때문에

중복체크의 과정이 필요없다. (동명이인)

 

 

 

 

 


 

 개선한 부분 ( 중복체크 )

 

 

member 테이블에는 회원 아이디(userid) 와 별명(nickname)이 unique 로 설정되어 있기 때문에

중복된 값이 들어가면 제약조건에 어긋나기 때문에 에러가 난다

 

이를 막아주기 위해서, 아이디와 별명은 중복체크가 되었을때만 회원가입이 되도록 하였다.

 

 

 

 

회원가입 폼이 있는 jsp

  <form method="POST" class="joinInput">
    
      	<div class="title">아이디</div>
      		<div class="flex">
      		<input id="userid" type="text" name="userid" required autofocus>
      		<div class="idCheckPadding">
      			<button type="button" id="checkIdButton">ID 중복확인</button>	
      			<span id="result1"></span>
      		</div>
      </div>
      
      <div class="title">비밀번호</div>
      <input type="password" name="userpw" required>
      <div class="title">이메일</div>
      <input type="email" name="email" value="${oauthUser.email }" required>
      
      
      <div class="title">닉네임</div>
      <div class="flex">
    	<input id="nickname" type="text" name="nickname" value="${oauthUser.name }" required>
      	<div class="idCheckPadding">
      		<button type="button" id="checkNickNameButton">닉네임 중복확인</button>	
      		<span id="result2"></span> 
      	</div>
      </div>
      <div class="title">전화번호</div>
      <input type="text" name="pnum" placeholder="-로 구분하여 입력하세요" required>
      
      <div class="submitPadding">
      	<p><input id="submitButton" type="submit" value="계정 생성하기" disabled="disabled"></p>
      </div>
   	
   
   </form>
	</div>
</div>

 

 

script 로 버튼을 클릭했을때 나온 결과가 만족한다면, 가입버튼이 활성화된다

: disabled 를 이용

 

 

 

하나의 함수가 끝나면 

updateButtonStatus(); 을 통해 다음 단계로 넘어갈 조건을 만족하는지 체크한다.

 

 

<script>

let statusCheck = {
    func1: false,
    func2: false
};

//	아이디 중복체크
const cpath = '${cpath}'
document.addEventListener('DOMContentLoaded', function() {
    document.getElementById("checkIdButton").addEventListener("click", async function(){ 
        const userId = document.getElementById('userid').value
        const url = cpath + '/checkUserid?userid=' + userId
        const text = await fetch(url).then(resp => resp.text())
        document.getElementById("result1").innerText = text // 변환된 텍스트를 화면에 표시
        
        if(text == "사용 가능한 아이디입니다") {
            statusCheck.func1 = true;
        } else {
            statusCheck.func1 = false;
        }
        updateButtonStatus();
        
    })
})


//	닉네임 중복체크
document.addEventListener('DOMContentLoaded', function() {
    document.getElementById("checkNickNameButton").addEventListener("click", async function(){
        const nickName = document.getElementById('nickname').value
        const url = cpath + '/checkNickName?nickname=' + nickName
        const text = await fetch(url).then(resp => resp.text())
        document.getElementById("result2").innerText = text // 변환된 텍스트를 화면에 표시
    	
        if(text == "사용 가능한 닉네임입니다") {
            statusCheck.func2 = true;
        } else {
            statusCheck.func2 = false;
        }
        updateButtonStatus();
        
    })
})

// 두 함수의 결과가 모두 true일 때만 제출 버튼을 활성화
function updateButtonStatus() {

    if(statusCheck.func1 && statusCheck.func2) {
        document.getElementById("submitButton").disabled = false;
    } else {
        document.getElementById("submitButton").disabled = true;
    }
}

</script>

 


 개선한 부분

: 가입시에, 빈 문자열 입력에도 정상작동하는 문제를 발견하여, 수정함.

 

 

 

 

입력값 없이, 중복체크 버튼을 눌렀더니

빈 문자열도 "사용 가능한 아이디 입니다" 라는 문자열이 떴다 

 

 

script 구문에서

결과로 반환되는 text 값이 "사용 가능한 아이디입니다" 일때만,

해당 flag 가 true 로 변경되게 코드를 구성했기 때문에

 

 

입력한 값이 없는 상태로 버튼을 누르면,

"아이디를 입력해주세요" 라는 문자열을 반환하기로 했다

 

 

추가한 코드

if(userid == "") {	
	return "아이디를 입력해주세요";
}

 

 

@RestController

@GetMapping(value = "/checkUserid", produces = "application/json;charset=UTF-8")
	public String checkUserId(String userid) {
		// 사용자 ID의 중복 여부를 확인하는 서비스 로직 호출
		
		if(userid == "") {		//	추가했다
			return "아이디를 입력해주세요";
		}
		
		int isDuplicate = ms.isUseridDuplicate(userid);
		
		// 중복 여부에 따라 메시지 반환
		if (isDuplicate >= 1) {
			return "사용 불가능한 아이디입니다";
		} else {
			return "사용 가능한 아이디입니다";
		}
	}

 

 


 

 MemberRepository 

 

: DB 내용과 입력된 값을 비교하여 결과값은 int 로 반환

 

	@Select("select count(*) from member where userid = #{userid}")
	int useridDuplicate(String userid);

	@Select("select count(*) from member where nickname = #{nickname}")
	int nicknameDuplicate(String nickname);

 

 

 

어차피 아이디와 닉네임은 unique 라서 똑같은 값이 존재한다면 1을 반환

존재하지 않는다면 0을 반환할 것임

 

따라서, RestController에서도 반환값이 1 일때 라는 조건을 이용해도 됨 !!

 

 

if (isDuplicate == 1) {
return "사용 불가능한 아이디입니다";
} else {
return "사용 가능한 아이디입니다";
}

 

 


느낀점

 

블로그에 글을 쓰려고, 코드를 검토하다보니까 

빈문자열 입력시에도 정상작동 되는 것을 알게되었다.

 

프로젝트만 주구장창 본다해서 오류가 다 보이는 것은 아니구나 

 

그치만, 내가 직접 오류를 찾아낸 것에 대해 희열감을 느꼈다 !

 

 

 

사용자가 어떤 입력을 하게될지 모르기 때문에, 

대처를 미리 해두어야한다는 개발자의 역할이 재밌게 느껴진다

 

개발자는 몇 수 앞을 내다보아야 하는 직업인 것 같다 

 

모든 상황에 대응할 수 있도록 여러가지 경우의 수를 생각해보아야겠다.

 

 

 

 

 

 

다음에 해야할 것 (관리자 모드)

 

매장점주 회원은 회원가입 후에 관리자(role == 1) 의 승인을 받아야만

매장점주 회원으로 승격할 수 있다.

 

만약 관리자가 가입 거부를 누른다면, 

일반회원으로 남게된다 

 

 

목록을 띄워서 승인 , 거부 버튼을 만들면 될듯 !!