프로젝트/기능 정리

[Java] SpringBoot 프로젝트 : 회원가입 기능 구현 - 아이디 중복확인

민뇌 2023. 6. 29. 14:27

목적

  • 게시판 형식 웹사이트 개발 시 회원가입 기능 구현 정리
  • 아이디 중복확인, 비밀번호 확인, 이메일 인증번호 등 세부 기능 정리

 

지난 글에서는 전체적인 회원가입 과정 흐름과 가입 폼 태그 및 세부사항 등을 살펴봤다.

 

이번엔 회원가입 시 입력한 아이디 중복체크 과정을 알아보자.

 

[데이터 흐름도] 

데이터 흐름도는 다음과 같다.

 

회원가입 데이터 흐름도

 

[JSP]

다시 아이디 부분 태그를 보면 아래와 같다.

<form:form action="registerUser.do" id="register_form" modelAttribute="memberVO">
    <ul>
        <li>
            <label for="mem_id"><small>아이디</small></label>
            <form:input path="mem_id" class = "align-left" autocomplete="off" placeholder = "아이디를 입력하세요"/>
            <input type="button" id="confirmId" class = "checkSome" value="중복체크">
            <div id="message_id"></div>
            <form:errors path="mem_id" cssClass="error-color"/> <!-- 에러문구 -->
        </li>
<!-- 이하 코드 생략-->

 

간단히 흐름을 먼저 설명하자면,

 

  1. 회원이 아이디 입력 후 "중복체크" 버튼 클릭
  2. JS에서 Ajax로 서버에 회원이 입력한 아이디 전달
  3. 요청 받은 컨트롤러는 회원이 입력한 아이디가 DB에 있는지 확인
  4. 아이디 유무에 따라 문자열을 담은 Map 객체 반환

 

정도로 볼 수 있다.

 

일단 버튼 태그는 아래와 같았다.

<input type="button" id="confirmId" class = "checkSome" value="중복체크">

id로 confirmId를 지정했는데 이것만 기억하면 된다. 클래스는 디자인을 위해 둔 것으로 여기선 무시해도 된다.

 

[JS]

이제 JS에서 어떤 처리가 일어나는지 보도록 하자.

$(function(){
    let checkId = 0;
    //이하 코드 생략

가장 먼저 jQuery를 이용했기 때문에 $(function(){}); 을 적어줬다.

 

이건 그냥 JS로 치면 window.onload = function(){}과 비슷한 것인데, 실행되는 순서가 조금 다르다.

 

간단히 설명하면 $(function(){}) 또는 $(document).ready(function(){})이 먼저 실행되고, window.onload = function(){}이 조금 늦게 실행되는데, 

 

여기서는 그냥 간단히 둘 다 페이지가 로딩되고 나면 {}안에 코드를 실행시켜달라는 의미로 알면 된다.

 

궁금하다면 아래 포스트를 참고하거나 다른 정보를 찾아보길 바란다.

 

참고 : https://velog.io/@dydgjs7878/Javascript-문법-공부-window.onload-document.ready-차이

 

다음으로 checkId라는 변수를 선언해두고 0으로 초기화 했는데, 이 변수는 회원이 작성한 아이디가 중복체크 되었는지 확인하기 위한 용도로 사용한다.

 

중복체크가 되었다면 1, 되지 않았다면 0이라고 생각하면 된다.

 

다음 코드를 보자.

    $('#confirmId').click(function(){
        if($('#mem_id').val().trim()==''){
            $('#message_id').css('color','#fba082').text('아이디를 입력하세요');
            $('#mem_id').val('').focus();
            return;
        }
	//이하 코드 생략

회원가입 과정에서 선택 정보의 경우 상관없지만 필수 입력 사항의 경우 위와 같은 코드로 입력 여부를 체크해야 한다.

 

물론 이전 포스트에서 설명했던 validation을 이용해도 된다.

 

submit이 될 때 확인하는 것이 보통이겠지만, 이건 중복체크 과정이므로 중복체크 버튼이 클릭됐을 때 실행되도록 했다.

 

간단하게, 중복체크 버튼 클릭 시 ID를 입력한 <input> 태그의 value의 공백을 제거한 값이 비어있으면, 즉 아무것도 적지 않았으면 "아이디를 입력하세요" 라는 문구가 뜨도록 하고, return하여 이하 코드는 실행하지 않게 한 것이다.

 

아이디 미입력 후 중복체크

 

만약 회원가입자가 어떤 값이라도 입력한 상태라면 아래 코드가 실행된다.

        $.ajax({
            url : '/member/confirmId.do',
            type : 'post',
            data : {mem_id : $('#mem_id').val()},
            dataType : 'json',
            success : function(param) {
                if (param.result == 'idNotFound'){
                    $('#message_id').text('사용가능합니다.');
                    checkId = 1;	
                }else if (param.result == 'idDuplicated'){
                    $('#message_id').text('존재하는 아이디입니다.');
                    checkId = 0;
                }else if (param.result == 'notMatchPattern'){
                    $('#message_id').text('4~12자의 영문 소문자, 숫자만 사용 가능합니다.');
                    checkId = 0;
                }else {
                    checkId = 0;
                    alert('아이디 중복체크 오류');
                }
            },
            error : function(){
                checkId = 0;
                alert('네트워크 오류 발생');
            }
        });	
    });

Ajax 파라미터 관련 내용은 이전 글에서 다룬 적이 있는데(여기) 간단히 위 코드를 설명하면,

 

confirmId.do라는 주소로 매핑된 컨트롤러에 요청을 보낼 건데, post방식으로 mem_id라는 이름에 데이터를 담아 전송하고, json형식으로 리턴 받겠다는 뜻이다.

 

[Controller - confirmId]

그럼 이제 호출받은 컨트롤러를 보자.

@RequestMapping("/member/confirmId.do")
@ResponseBody
public Map<String, String> process(@RequestParam String mem_id){

    Map<String, String> mapAjax = new HashMap<String, String>();

    MemberVO member = memberService.selectCheckMember(mem_id);

    if (member != null) {
        mapAjax.put("result", "idDuplicated");
    }else {
        if(!Pattern.matches("^[a-z0-9]{4,12}$", mem_id)) {
            mapAjax.put("result", "notMatchPattern");
        }else {
            mapAjax.put("result", "idNotFound");
        }
    }
    return mapAjax;
}

@ResponseBody와 @RequestParam도 이전 글에서 간단히 설명했는데(@ResponseBody, @RequestParam),

 

 @ResponseBody는 Map객체 데이터 자체를 리턴하기 위해 사용하는 것이고, @RequestParam은 클라이언트가 주소를 호출하면서 같이 보낸 데이터를 매핑된 메소드의 파라미터에 전달 받기 위해 사용하는 것으로 생각하면 된다.

 

흐름을 보면, 다음과 같다.

 

  1. Map 객체 생성
  2. 주입 받은 서비스에 전달 받은 파라미터인 mem_id를 넘겨주고 MemberVO에 데이터를 저장
  3. member가 null이 아니면, 즉 DB에서 무언가 데이터를 꺼내왔다면, 아이디가 중복된 것이니 "idDuplicated" 저장
  4. null이면서 mem_id의 패턴이 4~12자 소문자 및 숫자인지 검사, 아니면 "notMatchPattern" 저장
  5. null이면서 패턴이 일치하면 "idNotFound" 저장
  6. 저장된 Map 객체 리턴

 

[Mapper.java]

이제 mapper에 작성한 sql문을 보자.

@Select("SELECT m.mem_num, m.mem_id, m.mem_auth, d.mem_pw, d.mem_email FROM member m LEFT OUTER JOIN member_detail d ON m.mem_num = d.mem_num WHERE m.mem_id = #{mem_id}")
public MemberVO selectCheckMember(String mem_id);

기본적으로 DB에 회원 기본 정보 테이블과 회원 상세 정보 테이블을 따로 두어 JOIN하여 사용했다.

 

회원 탈퇴시 상세 정보 테이블은 지우지만 회원 기본 정보(회원 번호, 아이디, 권한번호)는 지우지 않고 두기 때문에 LEFT OUTER JOIN을 통해 상세 정보 테이블에 데이터가 없어도 NULL로 불러올 수 있게 했다.

 

마지막 WHERE절을 보면 회원이 입력한 아이디가 조건으로 들어가 있어 해당 아이디로 등록되었던 계정이 있는지 탐색한다.

 

위 쿼리문에서는 회원번호, 아이디, 권한, 비밀번호 등의 정보도 가져오고 있는데, 다른 곳에서 사용하기 위해 저렇게 작성한 듯 하다.

 

아이디 중복체크만을 위해 작성한다면, 회원 테이블에 해당 아이디 열만 검색해도 충분할 것 같다(아마도..).

 

[Service]

public interface MemberService {
    public MemberVO selectCheckMember(String mem_id);
}

[ServiceImpl]

@Service
@Transactional
public class MemberServiceImpl implements MemberService{
    @Autowired
    private MemberMapper memberMapper;

    @Override
    public MemberVO selectCheckMember(String mem_id) {
        return memberMapper.selectCheckMember(mem_id);
    }
}

[Controller]

@Controller
public class MemberController {
    @Autowired
    private MemberService memberService;

 

이렇게 컨트롤러에서 DB에 해당 아이디가 있는지 여부에 따라 Map 객체에 다음 세 가지 문자열 중 하나를 담았다.

mapAjax.put("result", "idDuplicated");
mapAjax.put("result", "notMatchPattern");
mapAjax.put("result", "idNotFound");

 

다시 ajax 결과부분을 보자.

success:function(param){
    if(param.result == 'idNotFound'){
        $('#message_id').text('사용가능합니다.');
        checkId = 1;	
    }else if(param.result == 'idDuplicated'){
        $('#message_id').text('존재하는 아이디입니다.');
        checkId = 0;
    }else if(param.result == 'notMatchPattern'){
        $('#message_id').text('4~12자의 영문 소문자, 숫자만 사용 가능합니다.');
        checkId = 0;
    }else{
        checkId = 0;
        alert('아이디 중복체크 오류');
    }
},

콜백으로 param에 Ajax 결과 데이터가 담겨오고 result라는 key에 값을 담았으므로 param.result를 통해 값을 꺼내온다.

 

중복되거나 패턴에 맞지 않는 경우 checkId는 0으로 뒀다(원래 0이라 사실 안써도 된다).

 

모든 조건을 충족하는 경우, 즉 아이디가 사용가능 할 때 사용가능하다는 문구를 출력하고, checkId를 1로 바꿔줬다.

 

이 checkId는 위에서도 언급했지만, 회원가입자가 가입하기 버튼을 눌렀을 때, 중복확인을 했는지 여부를 확인할 때 사용한다.

 

여기서 한 가지 과정이 더 필요하다.

 

만약 회원이 가입 가능한 아이디를 입력해 중복체크를 완료하고 일부러 아이디를 다른 것으로 바꾸었다면, 지금 코드로는 확인이 불가능하다.

 

따라서 아래 과정을 하나 추가해주자.

$('#mem_id').keydown(function(){
    checkId = 0;
    $('#message_id').text('');
});

간단하게 아이디 입력 <input>태그에 keydown 이벤트가 발생하면, checkId 값을 0으로 바꾸고, "사용가능합니다" 메시지 등이 있다면 지워준다는 것이다.

 

작성되어 있던 코드를 그대로 가져와서 리뷰하는 것이라 썼지만, 저 코드도 살짝 문제가 있을 수 있다.

 

만약 다른 마음을 품은 아이디(?)를 미리 복사해두고 가입 가능한 아무 아이디를 입력해 중복체크를 한 뒤, 마우스 클릭으로만 복사 붙여넣기 할 경우 checkId가 1로 남아서 오류가 나게된다.

 

따라서 값이 변하는지 자체를 검사하는 것이 가장 좋아보이는데 대안은 아래와 같다.

$('#mem_id').change(function(){
    checkId = 0;
    $('#message_id').text('');
});

change로 바꿔주는 것이다.

 

뭐.. 이게 완벽한가 확신할 수는 없으나 아마 이게 더 괜찮지 않을까 싶어 적어봤다.

 

이렇게 해서 아이디 중복체크 과정을 살펴봤다.

 

다음 글에서는 비밀번호 재확인 과정과 전화번호 입력 과정을 알아보도록 하겠다.