백엔드/Spring Framework

게시판 구현 / 1. 회원가입 / JsonObject 만들기

maverick11471 2024. 7. 16. 21:04

[요약]

 

[과제]

 - 아이디 중복체크

    * 중복체크 후에 아이디 값이 변경되면 다시 중복체크 버튼을 활성화

 - 닉네임 중복체크

 - 비밀번호 영문자, 숫자, 특수문자 지정 및 알림

 - 비밀번호 일치여부 확인

    * 비밀번호 일치 시, 비밀번호를 변경해도 비밀번호 일치로 나오는 현상

 - 회원가입 submit 

 


[Join.jsp 수정 : 4가지 기능 구현 / script 에서 수정]

 - (1) 아이디 중복체크 여부

 - (2) 닉네임 중복체크 여부

 - (3) 비밀번호 유효성 검사 여부

 - (4) 비밀번호 일치 여부

 - (5) 회원가입 submit

 

우선

 - (1) 아이디 중복체크 여부

 - (2) 닉네임 중복체크 여부 (아이디 중복체크 여부와 동일)

    <script>
    ...
            <div class="container mt-3 mb-5 w-25">
            // #join-form
            <form id="join-form" action="/member/join.do" method="post">
                <div class="form-group">
                    <label for="username">아이디</label>
                                    // #username
                    <input type="text" class="form-control" id="username" name="username" required>
                    <div class="d-flex justify-content-end mt-2">
                        // #btn-id-check
                        <button type="button" class="btn btn-secondary" id="btn-id-check">중복체크</button>
                    </div>
                </div>
    ...

    $(() => {
        // 4가지 변수선언
        // (1) 아이디 중복체크 여부
        let idCheck = false;
        // (2) 닉네임 중복체크 여부
        let nicknameCheck = false;
        // (3) 비밀번호 유효성 검사 여부
        let passwordCheck = false;
        // (4) 비밀번호 일치 여부
        let passwordConfirm = false;


        // (1) ajax를 통한 아이디 중복체크
        $("#btn-id-check").on("click", (e) => {
            // 어떤식으로 구현되는지 확인하기 위해 추가
            console.log($("#join-form").serialize());
            // 중복체크 버튼 클릭 시 아이디값이 비어 있으면
            if($("#username").val() === "") {
                alert("아이디를 입력하세요.");
                $("#username").focus();
                return;
            }

            // ajax를 이용해서 백엔드와 비동기 통신
            $.ajax({
                // controller에서 해당 url 메서드 검색
                url: "/member/usernameCheck.do",
                // post 방식
                type: "post",
                // 유니코드 방식(생략 가능)
                contentType: "x-www-form-urlencoded",
                // serialize(): 선택된 폼 태그의 input들의 name속성을 
                // 키로 입력된 값들을 밸류로 가져오면서 유니코드로 변환한 데이터
                // 형태로 만들어준다.
                data: $("#join-form").serialize(),
                // success: 요청 url로부터 정상적으로 응답을 받았을 때 실행될 내용 정의
                success: (obj) => {

                    // Json String을 Json Object로 변경
                    // JSON.parse()
                    const jsonObj = JSON.parse(obj);

                    console.log(obj);
                    console.log(jsonObj);

                    if(jsonObj.usernameCheckMsg === 'usernameOk') {
                        if(confirm(`사용가능한 아이디입니다. \${\$("#username").val()}를 사용하시겠습니까?`)) {
                            idCheck = true;
                            // 이 코드는 jQuery를 사용하여 HTML 엘리먼트의 속성을 변경하는 것입니다.
                            // $("#btn-id-check"): 이 부분은 jQuery 선택자로, 
                            // ID가 "btn-id-check"인 HTML 엘리먼트를 선택합니다.

                            // .attr("disabled", true): 이 부분은 선택한 엘리먼트의 속성을
                            // 변경하는 것입니다. 여기서는 "disabled" 속성을 
                            // "true"로 설정합니다.
                            // 이렇게 하면 ID가 "btn-id-check"인 버튼 엘리먼트가 
                            // 비활성화됩니다. 사용자가 그 버튼을 클릭할 수 없게 됩니다.
                            $("#btn-id-check").attr("disabled", true);
                        }
                        return;
                    }

                    alert("중복된 아이디입니다.");
                    idCheck = false;
                    $("#username").focus();
                },
                // rror: 요청이 실패했을 때 실행할 내용 정의.
                error: (err) => {
                    console.log(err);
                }
            });
        });

        // 중복체크 후에 아이디 값이 변경되면 다시 중복체크 버튼을 활성화
        $("#username").on("change", (e) => {
            idCheck = false;
            $("#btn-id-check").attr("disabled", false);
        });

 

 - (참고) Sserialize 를 사용해서 객체형태로 저장됨

 - (참고) String이 아닌 JsonSting으로 사용하는 이유는 아래 게시글 참고

2024.07.16 - [분류 전체보기] - ajax에서 return 값이 String이 아닌 JSON 형태여야 하는 이유

 

ajax에서 return 값이 String이 아닌 JSON 형태여야 하는 이유

JSON (JavaScript Object Notation) 문자열은 일반적인 문자열과 몇 가지 차이점이 있습니다.이러한 차이점은 JSON 문자열을 처리하는 데 유용한 기능을 제공합니다.다음은 JSON 문자열에서만 사용할 수 있

maverick11471.tistory.com

 

 - (3) 비밀번호 유효성 검사 여부

 - (4) 비밀번호 일치 여부

<script>
...
                    <div class="form-group mt-3">
                        <label for="password">비밀번호</label>
                        <input type="password" class="form-control" id="password" name="password" required>
                        <p id="password-check" style="color: red; font-size: 0.8rem;">
                            비밀번호는 영문자, 숫자, 특수문자 조합의 9자리 이상으로 설정해주세요.
                        </p>
                    </div>
                    <div class="form-group mt-3">
                        <label for="password-confirm">비밀번호 확인</label>
                        <input type="password" class="form-control" id="password-confirm" name="password-confirm" required>
                        <p id="password-confirm-result" style="font-size: 0.8rem;"></p>
                    </div>
...

            // 비밀번호 유효성 검사 메소드 (정규표현식)
            // .test: 정규 표현식으로 문자열이 해당 패턴과 일치하는지 확인하는 데 사용
            const validatePassword = (pw) => {
                return /^(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[!@#$%^&*+=-]).{9,}$/.test(pw);
            }

            // 비밀번호 input의 내용이 변경되면 validatePassword 메소드로 유효성 검사 진행
            $("#password").on("change", (e) => {
                console.log(validatePassword($("#password").val()));
                // 위의 validatePassword 메서드 이용
               if(validatePassword($("#password").val())) {
                   passwordCheck = true;
                   // 위 password-check 문구 숨기기
                   $("#password-check").hide();
               } else {
                   passwordCheck = false;
                   $("#password-check").show();
               }

               // 비밀번호 일치 시, 비밀번호를 변경해도 비밀번호 일치로 나오는 현상 해결
                if($("#password").val() === $("#password-confirm").val()) {
                    passwordConfirm = true;
                    // 위에 비밀번호 일치여부<p> 내용은 따로 기입하지 않고
                    // 여기서 문구가 나타나도록 한다.
                    $("#password-confirm-result").text("비밀번호가 일치합니다.");
                    $("#password-confirm-result").css("color", "green");
                } else {
                    passwordConfirm = false;
                    $("#password-confirm-result").text("비밀번호가 일치하지 않습니다.");
                    $("#password-confirm-result").css("color", "red");
                }
            });
            
            // 비밀번호 확인
            $("#password-confirm").on("change", (e) => {
                $("#password-confirm-result").show();

                if($("#password").val() === $("#password-confirm").val()) {
                    passwordConfirm = true;
                    $("#password-confirm-result").text("비밀번호가 일치합니다.");
                    $("#password-confirm-result").css("color", "green");
                    return;
                }

                passwordConfirm = false;
                $("#password-confirm-result").text("비밀번호가 일치하지 않습니다.");
                $("#password-confirm-result").css("color", "red");
            });

 

[mapper 수정]

	// 이미 가입되어 있으면 COUNT(*) == 1
    // 가입되어 있지 않으면 COUNT(*) == 0
    <select id="usernameCheck" parameterType="string" resultType="int">
        SELECT COUNT(*)
            FROM MEMBER
            WHERE USERNAME = #{username}
    </select>

 

[Dao 수정]

    public int usernameCheck(String username) {
        return mybatis.selectOne("MemberDao.usernameCheck", username);
    }

 

[service + serviceImpl 수정]

    String usernameCheck(String username);
    @Override
    public String usernameCheck(String username) {
        int usernameCheck = memberDao.usernameCheck(username);

        // String 값을 그대로 리턴하는 경우는 거의 없고
        // 대부분 json 형태의 String을 리턴하여 사용한다.

        // Java에서 Json 데이터 형태로 만드는 방식1 - JsonView
        // Java에서 Json 데이터 형태로 만드는 방식1 - ObjectMapper
        // ObjectMapper 객체를 이용한 json 형태의 데이터 만들기
        ObjectMapper objectMapper = new ObjectMapper();

        // Json 데이터 형태는 키와 밸류로 매핑되어 있는 데이터 형태이기 때문에
        // Map을 사용해서 키와 밸류로 매핑되어 있는 데이터 형태로 만들어준다.
        // (참고) .jsp: Json String을 Json Object로 변경했음
        Map<String, String> jsonMap = new HashMap<>();

        if(usernameCheck == 0) {
            jsonMap.put("usernameCheckMsg", "usernameOk");
        } else {
            jsonMap.put("usernameCheckMsg", "usernameFail");
        }

        String jsonString = "";

        try {
            // writerWithDefaultPrettyPrinter(): 들여쓰기랑 엔터값이 포함하여 시인성이 높은 형태로 데이터를 써주는 writer
            jsonString = objectMapper.writerWithDefaultPrettyPrinter()
                                     .writeValueAsString(jsonMap);
        } catch (JsonProcessingException je) {
            System.out.println(je.getMessage());
        }

        return jsonString;
    }

 

[controller 수정]

    @PostMapping("/usernameCheck.do")
    // Controller 메소드에서 String을 리턴하면 해당 String으로 jsp 파일을 찾게 된다.
    // jsp 파일 자체가 respone(응답 객체)의 body에 담겨서 리턴되는데
    // jsp 파일이나 html 파일이 아닌 리턴할 값을 response(응답 객체)의 body에 담아주려면
    // @ResponseBody 어노테이션을 사용한다. @ResponseBody 어노테이션이 달려있는 메소드에서는
    // viewResolver가 동작하지 않는다.
    @ResponseBody
    public String usernameCheck(MemberDto memberDto) {
        System.out.println(memberService.usernameCheck(memberDto.getUsername()));
        return memberService.usernameCheck(memberDto.getUsername());
    }

 - (5) 회원가입 submit

[join.jsp 수정]

    <script>
				// submit 시 위에 선언한 변수들을 활용하여 미흡한 분야를 보완한다.
                $("#join-form").on("submit", (e) => {
                // id 중복체크가 되지 않았을 때
                if(!idCheck) {
                    // <form> 태그는 제출 시 페이지를 새로 고치는 기본 동작을 하려는데,
                    // e.preventDefault가 HTML 요소의 기본 동작을 방지하는 데 사용
                    e.preventDefault();
                    alert("아이디 중복체크를 진행하세요.");
                    return;
                }

                if(!passwordCheck) {
                    e.preventDefault();
                    alert("비밀번호는 영문자, 숫자, 특수문자 조합의 9자리 이상으로 지정하세요.");
                    return;
                }

                if(!passwordConfirm) {
                    e.preventDefault();
                    alert("비밀번호가 일치하지 않습니다.");
                    return;
                }

                if(!nicknameCheck) {
                    e.preventDefault();
                    alert("닉네임 중복체크를 진행하세요.");
                    return;
                }
            });