프로젝트[종료]

11.회원가입 기능 만들기(1)

알렉스 페레이라 2023. 4. 26. 20:11

회원가입 기능을 추가하려고 한다!!!! Spring Boot와 ThymeLeaf, JPA이 세가지를 동시에 사용해서 만드는 회원가입은 처음이라 서툴지만,, 열심히 해봐야지

 

1.오른쪽 상단에 두 버튼을 달았다. 둘다 Modal로 만들 생각이었지만 스타일의 충돌 및 기타 사유로 취소.

2. 로그인버튼에 thymeleaf를 활용하여 onclick시 location.href를 지정해준다.

<li>
	<a href="#" class="button" th:onclick="|location.href='@{/signUp}'|" th:text="#{signUp}" data-toggle="modal" data-target="#signUp">Sign Up</a>
</li>

 

3.회원가입전용 SignUpController를 만들어 /signUp 요청이 왔을시에 회원가입 html파일로 이동시킨다

package com.project.domain.login;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequiredArgsConstructor
@RequestMapping("/signUp")
@Slf4j
public class SignUpController {
    @GetMapping
    public String getSignUp(Model model) {
        SignUpForm signUpForm = new SignUpForm();
        model.addAttribute("signUpForm", signUpForm); //기본 객체를 하나 넣어주어 thymeleaf object기능을 사용한다.
        
        return "/login/signUp";
    }
}

 

html경로 templates > login> signUp.html

 

정상적으로 이동한다.

 

 

 

4.회원가입 Form을 위한 객체를 만든다. Bean Validation기능을 사용하기 위해

아래와 같은 의존성을 build.gradle에 추가한다.

 

package com.project.domain.signup;

import com.project.domain.user.SexType;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class SignUpForm {
    @NotBlank(message = "아이디는 필수입력 입니다.")
    private String loginId;

    @NotBlank(message = "사용자 이름을 입력해주세요.")
    private String userName;

    @NotBlank
    @Pattern(regexp="^(?=.*[a-zA-Z])(?=.*\\d)(?=.*\\W).{8,20}$", message = "비밀번호는 영어와 숫자로 포함해서 8~20자리 이내로 입력해주세요.")
    private String password;

    @NotBlank
    @Pattern(regexp="^(?=.*[a-zA-Z])(?=.*\\d)(?=.*\\W).{8,20}$", message = "비밀번호는 영어와 숫자로 포함해서 8~20자리 이내로 입력해주세요.")
    private String passwordCheck;

    @Email(message = "유효하지 않은 이메일입니다.")
    @NotBlank(message = "이메일을 입력해주세요.")
    private String email;

    @NotBlank(message = "전화번호를 입력해 주세요.")
    private String phone;

    @NotBlank(message = "주소를 입력해 주세요.")
    private String address;

    @NotNull(message = "성별을 선택해주세요.")
    @Enumerated(value = EnumType.STRING)
    private SexType sex;
}

UserRepository에서는 User객체를 사용하지만, 김영한 선생님의 가르침에 따라 회원가입 전용 SignUpForm객체를 만들어서 사용할 예정이다.

 

5.회원가입 HTML을 작성한다..

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="~{/fragment/meta-fragment :: meta}"></head>
<body class="is-preload">
<div id="wrapper">
    <header id="header" th:replace="~{/fragment/logoMenu-fragment :: logoMenu}"></header>
    <nav id="menu" th:replace="~{/fragment/menu-fragment :: menu}"></nav>
    <div id="main">
        <div class="inner">
            <h1 th:text="#{signUp}">회원가입</h1>
<!--            <span class="image main"><img src="images/pic13.jpg" alt="" /></span>-->
            <form method="post" th:action th:object="${signUpForm}"> <!-- th:action을 입력하지않으면 현재 url(/add)로 method(POST)를 요청한다.-->
                <div class="row gtr-uniform">                        <!-- th:object는 빈 객체값이다. 각각의 field의 name, id 등을 넣어주기 위해, 그리고 Validation에서 튕겨나갔을시 기본 입력정보는 유지하기 위하여 사용.-->

                    <!--로그인 아이디-->
                    <div class="col-3">
                        <label class="signup-label" for="loginId" th:text="#{signUp.form.loginId}"></label>
                    </div>
                    <div class="col-9"> <!-- th:errorclass를 입력하면 해당 필드에서 error가 발생했을시 입력한 class를 추가해준다. 나같은 경우에는 border를 주기위해 새로 추가하였다.-->
                        <input class="signup-text" th:errorclass="error" type="text" name="loginId" id="loginId" th:field=*{loginId} value="" th:placeholder="#{signUp.form.loginId.placeholder}" placeholder="로그인 아이디를 입력하세요" />
                        <div class="signup-text-error" th:errors="*{loginId}"></div> <!-- th:errors를 사용하면 해당 필드에 에러가 있을시 bindingResult가 message를 해당 태그에 입력해준다!-->
                    </div>

                    <!--사용자 이름-->
                    <div class="col-3">
                        <label class="signup-label" for="userName" th:text="#{signUp.form.userName}"></label>
                    </div>
                    <div class="col-9">
                        <input class="signup-text" th:errorclass="error" type="text" name="userName" id="userName" th:field=*{userName} value="" th:placeholder="#{signUp.form.userName.placeholder}" placeholder="이름을 입력하세요" />
                        <div class="signup-text-error" th:errors="*{userName}"></div>
                    </div>

                    <!--비밀번호-->
                    <div class="col-3">
                        <label class="signup-label" for="password" th:text="#{signUp.form.password}"></label>
                    </div>
                    <div class="col-9">
                        <input class="signup-text" th:errorclass="error" type="password" name="password" id="password" th:field=*{password} value="" th:placeholder="#{signUp.form.password.placeholder}" placeholder="비밀번호를 입력하세요" />
                        <div class="signup-text-error" th:errors="*{password}"></div>
                    </div>

                    <!--비밀번호 확인-->
                    <div class="col-3">
                        <label class="signup-label" for="passwordCheck" th:text="#{signUp.form.passwordCheck}"></label>
                    </div>
                    <div class="col-9">
                        <input class="signup-text" th:errorclass="error" type="password" name="passwordCheck" id="passwordCheck" th:field=*{passwordCheck} value="" th:placeholder="#{signUp.form.passwordCheck.placeholder}" placeholder="비밀번호확인을 입력하세요" />
                        <div class="signup-text-error" th:errors="*{passwordCheck}"></div>
                    </div>

                    <!--이메일-->
                    <div class="col-3">
                        <label class="signup-label" for="email" th:text="#{signUp.form.email}"></label>
                    </div>
                    <div class="col-9">
                        <input class="signup-text" th:errorclass="error" type="text" name="email" id="email" th:field=*{email} value="" th:placeholder="#{signUp.form.email.placeholder}" placeholder="이메일을 입력하세요" />
                        <div class="signup-text-error" th:errors="*{email}"></div>
                    </div>

                    <!--전화번호-->
                    <div class="col-3">
                        <label class="signup-label" for="phone" th:text="#{signUp.form.phone}"></label>
                    </div>
                    <div class="col-9">
                        <input class="signup-text" th:errorclass="error" type="text" name="phone" id="phone" th:field=*{phone} value="" th:placeholder="#{signUp.form.phone.placeholder}" placeholder="전화번호를 입력하세요" />
                        <div class="signup-text-error" th:errors="*{phone}"></div>
                    </div>

                    <!--주소-->
                    <div class="col-3">
                        <label class="signup-label" for="phone" th:text="#{signUp.form.address}"></label>
                    </div>
                    <div class="col-9">
                        <input class="signup-text" th:errorclass="error" type="text" name="address" id="address" th:field=*{address} value="" th:placeholder="#{signUp.form.address.placeholder}" placeholder="클릭하여 주소를 선택하세요" />
                        <div class="signup-text-error" th:errors="*{address}"></div>
                    </div>

                    <!--성별-->
                    <div class="col-3">
                        <label class="signup-label" th:text="#{signUp.form.sex}"></label>
                    </div>

                    <div class="col-9">
                        <div th:each="sexType : ${sexTypes}" class="col-6">
                            <input type="radio" th:field="*{sex}" th:value="${sexType.name()}">
                            <label th:for="${#ids.prev('sex')}" th:text="${sexType.sex}"></label>
                        </div>
                        <div class="signup-text-error" th:errors="*{sex}"></div>
<!--                        <div class="col-6">-->
<!--                            <input type="radio" class="signup-text" th:errorclass="signup-text-error" name="sexM" id="sexM" th:field=*{sex} value="" />-->
<!--                            <label class="signup-label" for="sexM" th:text="#{signUp.form.sexM}"></label>-->
<!--                        </div>-->
<!--                        <div class="col-6">-->
<!--                            <input type="radio" class="signup-text" th:errorclass="signup-text-error" name="sexF" id="sexF" th:field=*{sex} value="" />-->
<!--                            <label class="signup-label" for="sexF" th:text="#{signUp.form.sexF}"></label>-->
<!--                        </div>-->
                    </div>
                </div>

                <div style="width:50%;margin:0 auto;">
                    <ul class="actions fit">
                        <li><button type="submit" class="button fit" th:text="#{signUp}">회원가입</button></li>
                        <li><button type="button" th:onclick="|location.href='/'|" class="button fit" th:text="#{goHome}">홈으로</button></li>
                    </ul>
                </div>
            </form>
        </div>

    </div>
    <footer id="footer" th:replace="~{/fragment/contactMe-fragment :: contactMe}"></footer>
</div>
<div th:replace="~{fragment/script-fragment :: script}"></div>
</body>
</html>

 

실행화면!

.

@ModelAttribute("sexTypes")
    public SexType[] sexTypes(){
        return SexType.values();
    }

위 기능을 사용하여 sexTypes이라는 이름으로 View화면으로 전송하였고 해당 html을 손쉽게 그릴 수 있었다.

<div th:each="sexType : ${sexTypes}" class="col-6">
	<input type="radio" th:field="*{sex}" th:value="${sexType.name()}">
    <label th:for="${#ids.prev('sex')}" th:text="${sexType.sex}"></label>
</div>