Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

승띵이의 개발일지

[Spring Boot] 회원 가입 사이트 만들기 1 본문

언어/Spring Boot

[Spring Boot] 회원 가입 사이트 만들기 1

승띵이 2022. 11. 2. 21:43
회원 가입 사이트 만들기

 

오늘은 Spring 한다면 당연히 만들줄 알아야 하는 '회원 가입'을 만들어 보려고 한다. 

험난한 여정이 예상된다........ 그래도 Let's go

 

결과

 

일단 다짜고짜 결과 화면부터 보여주고 시작할게요

 

뭔가 그럴듯하지 않나요

 

소개 시작

 

 

  • STEP 1 페이지

로고는 구글 뒤지다가 뭔가 간지나는 페브리즈 로고로 결정.

뭔가 힙하지 않나요

 

 

아래 "위 서비스... 머시기" 체크박스를 체크하지 않고 다음 버튼을 클릭하면 아래와 같이 경고창이 나타나고 넘어가지 않는다.

 

 

체크를 하고 다음 버튼을 클릭하면 STEP2 화면으로 넘어간다. 

 

 

  • STEP 2 페이지

회원 가입을 위한 개인정보 기입창이다.

 

너무나도 자주본 낯익은 녀석

 

이메일을 적지 않고 인증번호 전송을 클릭하면 이메일 주소를 입력하라는 경고 문구가 나타난다.

 

이메일이 정상적인지 확인하는 동안 해당 화면이 나온다.

 

주소 찾기 클릭 시 연동시켜놓은 주소 찾기 API가 나타난다.

 

개발자 모드로 확인하면 선택한 주소의 값을 확인할 수 있다.

 

주소를 선택하면 우편번호와 주소 칸에 해당 값이 할당된다.

 

 

  • STEP 3

아무것도 없다. 왜냐면 아직 안만들었기 때문

 

회원가입 사이트 만들기 2탄 혹은 3탄에서 계속... (많관부) 

 

휑~

 

 

자 이제 진짜로 만들기 시작 

 

프론트 & 백 작업 드가자~

 

프로젝트 생성

 

일단 프로젝트 생성 고고씽

 

 

On 'Updata' action과 On frame deactivation을 둘 다 Update classes and resources로 설정해 준다.

run을 하지 않아도 자동으로 업데이트해주는 설정이다. (개편함)

 

 

의존성 추가

 

필요한 의존성을 추가해준다. 

우리가 오늘 회원가입 사이트를 만들기 위해 필요한 의존성은 

 

springframework.boot

mariadb.jdbc

mybatis.spring.boot

 

의존성 추가 3개 가보자고

 

메이븐 공개 저장소 : Maven Repository: Search/Browse/Explore (mvnrepository.com)

 

DB 연결

 

DB를 연결해 준다. 

 

 

* 여기서 뜬금없는 중간 꿀팁 *

 

내가 진~~짜 맞는데 안될때 reload All Maven Projects 하기

이거마저도 안되면 File - Invalidate Cashes - 모두 선택 -OK 하면 인텔리제이가 재시작하고 오류가 사라진다.

 

application.properties 설정

 

application.properties 설정해준다. 

 

spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://localhost:12602/
spring.datasource.username=study
spring.datasource.password=test1234

mybatis.mapper-locations=classpath:mappers/**/*.xml

#server.servlet.context-path=/abc 무적권 도메인 뒤에 붙이는 경로

 

경로

 

 

경로 설정 잘하자. 골통 깨지기 싫으면.

 

프론트 엔드

 

  • html 파일 생성

 

html로 해당 사이트의 뼈대를 생성하였다.  class와 id, rel 설정을 알아보기 쉽게 잘하는 것이 중요하다. 

 

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>스터디 :: 회원가입</title>
    <link rel="stylesheet" th:href="@{/resources/stylesheets/common.css}">
    <link rel="stylesheet" th:href="@{/member/resources/stylesheets/register.css}">
    <script src="https://kit.fontawesome.com/282afddd53.js" crossorigin="anonymous"></script>
    <script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
    <script defer th:src="@{/resources/scripts/common.js}"></script>
    <script defer th:src="@{/member/resources/scripts/register.js}"></script>
</head>
<body>
<header class="--header">
    <div class="--content">
        <a class="--logo-container" th:href="@{/}">
            <img class="--logo" th:src="@{/resources/images/logo.png}">
        </a>
        <ul class="--menu --main">
            <li class="--item">
                <a class="--link" href="#">공지사항</a>
            </li>
            <li class="--item">
                <a class="--link" href="#">자유게시판</a>
            </li>
            <li class="--item">
                <a class="--link" href="#">Q&A</a>
            </li>
        </ul>
        <ul class="--menu">
            <li class="--item">
                <a class="--link" href="#">로그인</a>
            </li>
            <li class="--item">
                <a class="--link" href="#">회원가입</a>
            </li>
        </ul>
    </div>
</header>
<div class="--cover" id="cover">
    <img alt="" class="--icon" th:src="@{/resources/images/loading.png}">
    <span class="--text" rel="text">무언가를 불러오고 있습니다. 잠시만 기다려 주세요.</span>
</div>
<main class="--main main">
    <div class="--content content">
        <form class="form step2" id="form">
            <div class="title-container">
                <h2 class="title">회원가입</h2>
                <div class="step-container">
                    <span class="text" rel="stepText">약관 동의 및 개인정보 처리방침</span>
                    <span class="step step1">1</span>
                    <span class="line"></span>
                    <span class="step step2">2</span>
                    <span class="line"></span>
                    <span class="step step3">3</span>
                </div>
            </div>
            <div class="step step1">
                <label class="label">
                    <h2 class="title">서비스 이용약관</h2>
                    <textarea class="--object-input term" readonly>서비스 이용약관</textarea>
                </label>
                <label class="label">
                    <h2 class="title">개인정보 처리방침</h2>
                    <textarea class="--object-input term" readonly>개인정보 처리방침</textarea>
                </label>
                <label class="--object-check">
                    <input name="termAgree" type="checkbox">
                    <span class="--checkbox">
                        <i class="--icon fa-solid fa-check"></i>
                    </span>
                    <span class="--text">위 서비스 이용약관 및 개인정보 처리방침을 읽어보았고 이해하였으며 동의합니다.</span>
                </label>
            </div>
            <div class="step step2">
                <table class="table">
                    <tbody>
                    <tr>
                        <th>이메일</th>
                        <td>
                            <label class="label email">
                                <span hidden>이메일</span>
                                <input autofocus class="--object-input input" maxlength="50" name="email" placeholder="이메일 주소를 입력해 주세요." type="email">
                                <input class="--object-button" name="emailSend" value="인증번호 전송" type="button">
                            </label>
                            <label class="label email">
                                <span hidden>인증번호</span>
                                <input autofocus class="--object-input input" disabled maxlength="6" name="emailAuthCode" placeholder="인증번호를 입력해 주세요." type="text">
                                <input class="--object-button" name="emailVerify" disabled value="인증번호 확인" type="button">
                            </label>
                            <span class="warning" rel="emailWarning">이메일 주소를 입력해 주세요.</span>
                        </td>
                    </tr>
                    <tr>
                        <th>비밀번호</th>
                        <td>
                            <label class="label password">
                                <span hidden>비밀번호</span>
                                <input autofocus class="--object-input input" maxlength="50" name="password" placeholder="비밀번호를 입력해 주세요." type="password">
                            </label>
                            <label class="label password">
                                <span hidden>비밀번호 재입력</span>
                                <input autofocus class="--object-input input" maxlength="50" name="passwordCheck" placeholder="비밀번호를 한 번 더 입력해 주세요." type="password">
                            </label>
                        </td>
                    </tr>
                    <tr>
                        <th>닉네임</th>
                        <td>
                            <label class="label">
                                <span hidden>닉네임</span>
                                <input autofocus class="--object-input input" maxlength="10" name="nickname" placeholder="닉네임을 입력해 주세요." type="text">
                            </label>
                        </td>
                    </tr>
                    <tr>
                        <th>이름</th>
                        <td>
                            <label class="label">
                                <span hidden>이름</span>
                                <input autofocus class="--object-input input" maxlength="5" name="name" placeholder="이름을 입력해 주세요." type="text">
                            </label>
                        </td>
                    </tr>
                    <tr>
                        <th>연락처</th>
                        <td>
                            <label class="label">
                                <span hidden>연락처</span>
                                <input autofocus class="--object-input input" maxlength="12" name="contact" placeholder="연락처를 ' - ' 없이 입력해 주세요." type="text">
                            </label>
                        </td>
                    </tr>
                    <tr>
                        <th>주소</th>
                        <td>
                            <label class="label address">
                                <span hidden>우편번호</span>
                                <input autofocus class="--object-input input" maxlength="6" name="addressPostal" placeholder="우편번호" readonly type="text">
                                <input class="--object-button" name="addressFind" value="주소 찾기" type="button">
                            </label>
                            <label class="label address">
                                <span hidden>기본 주소</span>
                                <input autofocus class="--object-input input" maxlength="100" name="addressPrimary"  readonly placeholder="주소 찾기를 통해 주소를 입력해 주세요." type="text">
                            </label>
                            <label class="label address">
                                <span hidden>상세 주소</span>
                                <input autofocus class="--object-input input" maxlength="100" name="addressSecondary" placeholder="상세 주소를 입력해 주세요." type="text">
                            </label>
                            <div class="panel address" rel="addressFindPanel">
                                <div class="dialog" rel="addressFindPanelDialog"></div>
                            </div>
                        </td>
                    </tr>
                    </tbody>
                </table>
            </div>
            <div class="warning" rel="warning">
                <i class="icon fa-solid fa-triangle-exclamation"></i>
                <div class="text" rel="warningText"></div>
            </div>
            <div class="button-container">
                <div class="button green" rel="nextButton">
                    <span class="text">
                        다음 <i class="fa-solid fa-chevron-right"></i>
                    </span>
                </div>
            </div>
        </form>
    </div>
</main>
<footer class="--footer">
    <div class="--content">
        발
    </div>
</footer>
</body>
</html>

 

  • CSS 파일 생성

 

1. common.css

 

공통으로 적용되는 css 파일이다. 

@charset "UTF-8";

@import url("https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.6/dist/web/static/pretendard.css");

html {
    font-family: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif;
    font-weight: 400;
}

h1, h2, h3, h4, h5, h6 {
    font: inherit;
    margin: unset;
    padding: unset;
}

input, select, textarea {
    appearance: none;
    background-color: unset;
    border: unset;
    color: unset;
    font: inherit;
    margin: unset;
    outline: none;
    padding: unset;
}

.--object-input {
    width: 100%;
    background-color: rgb(255, 255, 255);
    border: 0.0625rem solid rgb(213, 216, 220);
    border-radius: 0.375rem;
    box-sizing: border-box;
    padding: 0.625rem 0.875rem;
}

.--object-input:disabled {
    background-color: rgb(234, 236, 238);
    color: rgb(171, 178, 185);
}

.--object-check {
    align-items: center;
    cursor: pointer;
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
    user-select: none;
}

.--object-check > input[type=checkbox] {
    display: none;
}

.--object-check > .--checkbox {
    width: 1rem;
    height: 1rem;
    align-items: center;
    background-color: rgb(255, 255, 255);
    border-radius: 0.25rem;
    border: 0.0625rem solid rgb(213, 216, 220);
    color: rgb(255, 255, 255);
    display: flex;
    flex: 0 0 1.125rem;
    /*flex-grow: 0;*/
    /*flex-shrink: 0;*/
    /*flex-basis: 1.125rem;*/
    flex-direction: row;
    justify-content: center;
    margin-right: 0.75rem;
    overflow: hidden;
}

.--object-check > input[type=checkbox]:checked ~ .--checkbox {
    background-color: #0b65cc;
}

.--object-check > .--checkbox > .--icon {
    top: 0.0625rem;
    font-size: 0.8rem;
    position: relative;
}

.--object-button {
    background-color: #0b65cc;
    border-radius: 0.5rem;
    box-sizing: border-box;
    color: rgb(255, 255, 255);
    cursor: pointer;
    padding: 0.625rem 0.875rem;
}

.--object-button:hover {
    background-color: #0b5db9;
}

.--object-button:active {
    background-color: #0a52a4;
}

.--object-button:disabled {
    background-color: rgb(171, 178, 185);
    color: rgb(128, 139, 150);
    cursor: default;
    pointer-events: none;
}

.--cover {
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 80%);
    display: none;
    align-items: center;
    flex-direction: column;
    justify-content: center;
    position: fixed;
    z-index: 9;
    color: rgb(255, 255, 255);
}

.--cover.visible {
    display: flex;
}

.--cover > .--icon {
    width: 4rem;
    height: 4rem;
    animation-name: anim-cover-icon;
    animation-duration: 1500ms;
    animation-iteration-count: infinite;
    animation-timing-function: linear;
    animation-play-state: running;
    pointer-events: none;
    user-select: none;
    -webkit-user-drag: none;
}

@keyframes anim-cover-icon {
    0% {
        transform: rotate(0deg);
    }
    100% {
        transform: rotate(360deg);
    }
}

.--cover > .--text {
    max-width: 25rem;
    font-size: 1.375rem;
    line-height: 150%;
    margin-top: 2.5rem;
    pointer-events: none;
    text-align: center;
    user-select: none;
    white-space: pre-wrap;
}

body {
    top: 0;
    left: 0;
    width: 100%;
    background-color: rgb(234, 236, 238);
    color: rgb(23, 32, 42);
    align-items: stretch;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    line-height: 125%;
    font-size: 1rem;
    min-height: 100%;
    margin: unset;
    overflow: hidden auto;
    position: absolute;
}

.--header,
.--main,
.--footer {
    align-items: flex-start;
    display: flex;
    flex-direction: row;
    justify-content: center;
}

body > .--header > .--content,
body > .--main > .--content,
body > .--footer > .--content {
    width: 100%;
    max-width: 70rem;
    margin: 0 2rem;
}

body > .--header {
    background-color: rgb(255, 255, 255);
    border-bottom: 0.0625rem solid rgb(213, 216, 220);
    box-shadow: 0 0 0.75rem 0.0625rem rgba(0, 0, 0, 10%);
}

body > .--header > .--content {
    align-items: center;
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
    padding: 1rem 0;
}

body > .--header > .--content > .--logo-container > .--logo {
    height: 5rem;
}

body > .--header > .--content > .--menu {
    align-items: center;
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
    list-style-type: none;
    margin: unset;
    padding: unset;
}

body > .--header > .--content > .--menu.--main {
    flex: 1;
    font-size: 1.5rem;
    margin-left: 2.5rem;
}

body > .--header > .--content > .--menu > .--item + .--item {
    margin-left: 1rem;
}

body > .--header > .--content > .--menu > .--item > .--link {
    color: rgb(128, 139, 150);
    text-decoration: none;
}

body > .--header > .--content > .--menu > .--item > .--link:hover {
    color: rgb(86, 101, 115);
}

body > .--header > .--content > .--menu > .--item > .--link:active {
    color: rgb(44, 62, 80);
}

body > .--main {
    flex: 1;
}

body > .--footer {
    background-color: rgb(255, 255, 255);
    border-bottom: 0.0625rem solid rgb(213, 216, 220);
    box-shadow: 0 0 0.5rem 0.0625rem rgba(0, 0, 0, 10%);
}

 

 

2. register.css

 

회원가입 창에서 사용되는 css 파일이다. 

 

@charset "UTF-8";

body > .main > .content {
    align-items: center;
    display: flex;
    flex-direction: column;
    justify-content: center;
    margin-top: 5rem;
    margin-bottom: 5rem;
}

body > .main > .content > .form {
    width: 100%;
    max-width: 40rem;
    align-items: stretch;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
}

body > .main > .content > .form > .title-container {
    align-items: center;
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
    margin-bottom: 3.75rem;
}

body > .main > .content > .form > .title-container > .title {
    flex: 1;
    font-size: 2rem;
    font-weight: 500;
}

body > .main > .content > .form > .title-container > .step-container {
    align-items: center;
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
}

body > .main > .content > .form > .title-container > .step-container > .step {
    width: 2rem;
    height: 2rem;
    align-items: center;
    border: 0.125rem solid rgb(213, 216, 220);
    border-radius: 50%;
    box-sizing: border-box;
    color: rgb(128, 139, 150);
    display: flex;
    flex-direction: row;
    font-size: 0.95rem;
    font-weight: 600;
    justify-content: center;
}

body > .main > .content > .form.step1 > .title-container > .step-container > .step.step1,
body > .main > .content > .form.step2 > .title-container > .step-container > .step.step2,
body > .main > .content > .form.step3 > .title-container > .step-container > .step.step3 {
    background-color: #0b65cc;
    color: rgb(255, 255, 255);
}

body > .main > .content > .form.step2 > .title-container > .step-container > .step.step1,
body > .main > .content > .form.step3 > .title-container > .step-container > .step.step1,
body > .main > .content > .form.step3 > .title-container > .step-container > .step.step2 {
    background-color: rgb(117, 141, 218);
    border: 0.125rem solid rgb(213, 216, 220);
    color: rgb(171, 178, 185);
}

body > .main > .content > .form.step2 > .title-container > .step-container > .step.step1 + line,
body > .main > .content > .form.step3 > .title-container > .step-container > .step.step1 + line,
body > .main > .content > .form.step3 > .title-container > .step-container > .step.step2 + line {
    background-color: rgb(213, 216, 220);
}

body > .main > .content > .form > .title-container > .step-container > .line {
    width: 0.375rem;
    height: 0.125rem;
    background-color: rgb(171, 178, 185);
}

body > .main > .content > .form > .title-container > .step-container > .text {
    color: rgb(86, 101, 115);
    font-size: 0.95rem;
    margin-right: 0.75rem;
}

body > .main > .content > .form > .step {
    align-items: stretch;
    display: none;
    flex-direction: column;
    justify-content: flex-start;
}

body > .main > .content > .form.step1 > .step.step1,
body > .main > .content > .form.step2 > .step.step2,
body > .main > .content > .form.step3 > .step.step3 {
    display: flex;
}

body > .main > .content > .form > .step.step1 > .label {
    margin-bottom: 1.5rem;
}

body > .main > .content > .form > .step.step1 > .label > .title {
    font-size: 1.5rem;
    font-weight: 500;
    margin-bottom: 0.75rem;
}

body > .main > .content > .form > .step.step1 > .label > .title::before {
    top: 0.0625rem;
    width: 1rem;
    height: 1rem;
    background-color: rgb(171, 178, 185);
    border-radius: 50%;
    content: '';
    display: inline-block;
    margin-right: 0.625rem;
    position: relative;
}

body > .main > .content > .form > .step.step1 > .label > .term {
    height: 17.5rem;
    resize: none;
}

body > .main > .content > .form > .step.step2 > .table {
    /*max-width: 40rem;*/
    /*align-self: center;*/
}

body > .main > .content > .form > .step.step2 > .table > tbody > tr > th {
    padding-right: 1rem;
    text-align: right;
    white-space: nowrap;
}

body > .main > .content > .form > .step.step2 > .table > tbody > tr:not(:last-child) > th,
body > .main > .content > .form > .step.step2 > .table > tbody > tr:not(:last-child) > td {
    padding-bottom: 1rem;
}

body > .main > .content > .form > .step.step2 > .table > tbody > tr > td > .label.email,
body > .main > .content > .form > .step.step2 > .table > tbody > tr > td > .label.address {
    align-items: stretch;
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
}

body > .main > .content > .form > .step.step2 > .table > tbody > tr > td > .label {
    display: block;
}

body > .main > .content > .form > .step.step2 > .table > tbody > tr > td > .label.email + .label.email,
body > .main > .content > .form > .step.step2 > .table > tbody > tr > td > .label.password + .label.password,
body > .main > .content > .form > .step.step2 > .table > tbody > tr > td > .label.address + .label.address {
    margin-top: 0.375rem;
}

body > .main > .content > .form > .step.step2 > .table > tbody > tr > td > .label > input + input {
    margin-left: 0.5rem;
}

body > .main > .content > .form > .step.step2 > .table > tbody > tr > td > .warning {
    color: rgb(231,76,60);
    display: none;
    font-size: 90%;
    margin-top: 0.5rem;
}

body > .main > .content > .form > .step.step2 > .table > tbody > tr > td > .warning.visible {
    display: block;
}

body > .main > .content > .form > .step.step2 > .table > tbody > tr > td > .panel.address {
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 70%);
    display: none;
    position: fixed;
}

body > .main > .content > .form > .step.step2 > .table > tbody > tr > td > .panel.address.visible {
    display: block;
}

body > .main > .content > .form > .step.step2 > .table > tbody > tr > td > .panel.address > .dialog {
    top: 50%;
    left: 50%;
    width: 100%;
    height: 100%;
    max-width: 30rem;
    max-height: 40rem;
    background-color: rgb(255,255,255);
    position: absolute;
    transform: translate(-50%, -50%);
                                                                                            }

body > .main > .content > .form > .warning {
    background-color: rgb(231, 76, 60);
    border-radius: 0.5rem;
    color: rgb(255, 255, 255);
    margin-top: 2.5rem;
    padding: 1rem 1.25rem;
    align-items: center;
    display: none;
    flex-direction: row;
    justify-content: center;
}

body > .main > .content > .form > .warning.visible {
    display: flex;
}

body > .main > .content > .form > .warning > .text {
    flex: 1;
    margin-left: 0.875rem;
}

body > .main > .content > .form > .button-container {
    align-items: center;
    display: flex;
    flex-direction: row;
    justify-content: center;
}

body > .main > .content > .form > .button-container > .button {
    background-color: rgb(128, 139, 150);
    border-radius: 0.5rem;
    color: rgb(255, 255, 255);
    cursor: pointer;
    padding: 1rem 4rem;
    user-select: none;
}

body > .main > .content > .form > .button-container > .button:hover {
    background-color: rgb(44, 62, 80);
}

body > .main > .content > .form > .button-container > .button:active {
    background-color: rgb(86, 101, 115);
}

body > .main > .content > .form > .button-container > .button.green {
    background-color: #0b65cc;
    margin-top: 2rem;
}

body > .main > .content > .form > .button-container > .button.green:hover {
    background-color: #0b5db9;
}

body > .main > .content > .form > .button-container > .button.green:active {
    background-color: #0a52a4;
}

 

백엔드 

 

  • Java

 

MemberController 클래스

package com.smchoi.studymemberbbs.controllers;

import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;


@Controller
@RequestMapping(value = "/member")
public class MemberController {
    @RequestMapping(value = "register",
            method = RequestMethod.GET,
            produces = MediaType.TEXT_HTML_VALUE)
    public ModelAndView getRegister() {
        ModelAndView modelAndView = new ModelAndView("member/register");

        return modelAndView;
    }

    @RequestMapping(value = "email",
            method = RequestMethod.POST,
            produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody //경로를 입력해도 걍 문자열 그대로 받는 놈
    public String postEmail(@RequestParam(value = "email") String email) {
        System.out.println(email);
        return "";
    }
}

 

  • Javascript

1. register.js

const form = window.document.getElementById('form');

form.querySelector('[rel="nextButton"]').addEventListener('click', () => {
    form.querySelector('[rel=warning]').classList.remove('visible'); //체크하고 다음하면 visible 클래스 삭제
    if (form.classList.contains('step1')) {
        if (!form['termAgree'].checked) {
            form.querySelector('[rel="warningText"]').innerText = '서비스 이용약관 및 개인정보 처리방침을 읽고 동의해 주세요.';
            form.querySelector('[rel="warning"]').classList.add('visible');
            return;
        }
        form.querySelector('[rel="stepText"]').innerText = '개인정보 입력';
        form.classList.remove('step1');
        form.classList.add('step2');
    } else if (form.classList.contains('step2')){
        form.querySelector('[rel="stepText"]').innerText = '회원가입 완료';
        form.querySelector('[rel="nextButton"]').innerText = '로그인하러 가기';
        form.classList.remove('step2');
        form.classList.add('step3');
    } else if (form.classList.contains('step3')) {
        window.location.href = 'login';
    }
});

//인증번호 전송 클릭 시
form['emailSend'].addEventListener('click', () => {
    form.querySelector('[rel="emailWarning"]').classList.remove('visible');

    if(form['email'].value === '') {
        form.querySelector('[rel="emailWarning"]').innerText = '이메일 주소를 입력해 주세요.'
        form.querySelector('[rel="emailWarning"]').classList.add('visible');
        form['email'].focus();
        return;
    }
    //email 확인 정규식(몰라도 그만)
    if(!new RegExp('^(?=.{7,50})([\\da-zA-Z_.]{4,})@([\\da-z\\-]{2,}\\.)?([\\da-z\\-]{2,})\\.([a-z]{2,10})(\\.[a-z]{2})?$').test(form['email'].value)) {
        form.querySelector('[rel="emailWarning"]').innerText = '올바른 이메일 주소를 입력해 주세요.'
        form.querySelector('[rel="emailWarning"]').classList.add('visible');
        form['email'].focus();
        return;
    }

    //ajax 를 활용한 인증번호 전송 요청 & 대기
    Cover.show('인증번호를 전송하고 있습니다.\n잠시만 기다려 주세요.');
    const xhr = new XMLHttpRequest();
    const formData = new FormData();    //요청시 같이 전송할 데이터
    formData.append('email', form['email'].value);
    xhr.open('POST', './email');
    xhr.onreadystatechange = () => {
        if (xhr.readyState === XMLHttpRequest.DONE) {
            Cover.hide();
            if(xhr.status >= 200 && xhr.status < 300) {

            } else {
                form.querySelector('[rel="emailWarning"]').innerText = '서버와 통신하지 못하였습니다. 잠시 후 다시 시도해 주세요.';
                form.querySelector('[rel="emailWarning"]').classList.add('visible');
            }
        }
    }
    xhr.send(formData);
});

//주소찾기 창 띄우기
form['addressFind'].addEventListener('click', () => {
    new daum.Postcode({
        oncomplete: e => {
            form.querySelector('[rel="addressFindPanel"]').classList.remove('visible');
            form['addressPostal'].value = e['zonecode'];
            form['addressPrimary'].value = e['address'];
            form['addressSecondary'].value = '';
            form['addressSecondary'].focus();
        },
        width: '100%',
        height: '100%'
    }).embed(form.querySelector('[rel="addressFindPanelDialog"]'));
    form.querySelector('[rel="addressFindPanel"]').classList.add('visible');
});

//배경 클릭시 주소찾기 창 없어지기
form.querySelector('[rel="addressFindPanel"]').addEventListener('click', () => {
    form.querySelector('[rel="addressFindPanel"]').classList.remove('visible');
});

 

2. common.js

const Cover = {
    show: (text) => {
        const cover = window.document.getElementById('cover');
        cover.querySelector('[rel="text"]').innerText = text;
        cover.classList.add('visible');
    },
    hide: () => {
        window.document.getElementById('cover').classList.remove('visible');
    }
}

 

 

마치며

 

일단 회원가입 사이트 만들기 1은 여기까지 구현하였다. 몇 탄까지 나올지는 모르겠지만 2탄에서는 인증메일 전송, 인증메일 확인, STEP 3 페이지 등등..의 기능들을 추가해보려한다.

 

골통 깨지겠구만

Comments