
[게시판 프로젝트] Spring Security를 이용한 로그인(1) 게시물과 이어서 진행합니다
부트스트랩의 도움을 받아 전체적인 ui를 꾸미기 위해 script와 css추가
thymeleaf도 사용하기 위해 추가
1. 아이디 입력 후 중복체크
2. 패스워드와 패스워드 확인 입력
3. 닉네임 입력 후 중복체크
4. 그 외 성별, 생일 입력
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" >
<head>
<meta charset="utf-8">
<title>회원가입</title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link th:href="@{/css/signin.css}" rel="stylesheet">
<link th:href="@{/css/birth.css}" rel="stylesheet">
<!-- default header name is X-CSRF-TOKEN -->
<meta id="_csrf" name="_csrf" th:content="${_csrf.token}"/>
<meta id="_csrf_header" name="_csrf_header" th:content="${_csrf.headerName}"/>
</head>
<body class="text-center">
<form name="registerForm" class="form-signin" th:action="@{/account/register}" method="post" th:object="${register}" onsubmit="return checkAll();">
<a th:href="@{/}"><img class="mb-4" th:src="@{/image/log_icon.png}" alt="로고" width="72" height="57"></a>
<h1 class="h3 mb-3 fw-normal">회원가입</h1>
<hr>
<label th:for="username" class="form-label">이메일(아이디)</label>
<div class="mb-3 abc">
<input type="email" class="form-control mx-1 overlap" id="username" name="username" placeholder="이메일을 입력해 주세요">
<input class="btn btn-outline-primary btn-sm idCheck mx-1" type="button" id="usernameOverlay" onclick="usernameCheck()" value="중복 체크"/>
<input class="btn btn-outline-success btn-sm reType" type="button" id="resetUsername" onclick="reUsername()" disabled value="다시입력"/>
</div>
<div class="mb-3">
<label th:for="password">패스워드</label>
<input onchange="pwSame()" type="password" class="form-control" th:field="*{password}" placeholder="비밀번호를 입력해 주세요">
</div>
<div class="mb-3">
<label for="password_check">패스워드 확인</label>
<input onkeyup="pwSame()" type="password" class="form-control" id="password_check" name="password_check" placeholder="비밀번호를 입력해 주세요">
<span id="pw_check_msg"></span>
</div>
<label th:for="nickname" class="form-label">이름(닉네임)</label>
<div class="mb-3 abc">
<input type="text" class="form-control mx-1 overlap" id="nickname" name="nickname" placeholder="닉네임을 입력해 주세요">
<input class="btn btn-outline-primary btn-sm idCheck mx-1" type="button" id="nicknameOverlay" onclick="nicknameCheck()" value="중복 체크"/>
<input class="btn btn-outline-success btn-sm reType" type="button" id="resetNickname" onclick="reNickname()" disabled value="다시입력"/>
</div>
<label class="mb-3 form-label" for="birth">생년월일</label>
<div class="mb-3" id="birth" onchange="checkAge()">
<div class="birth dropdown">
<select class="form-control" id="year" name="year">
<option value="">년(YY)</option>
<th:block th:each="a: ${#numbers.sequence(2001,1900)}">
<option th:value="${a}" th:text="${a}"></option>
</th:block>
</select>
</div>
<div class="birth mx-1 dropdown">
<select class="form-control" id="month" name="month">
<option value="">월(mm)</option>
<th:block th:each="month: ${#numbers.listFormatInteger(#numbers.sequence(1,12),2)}">
<option class="dropdown-item" th:value="${month}" th:text="${month}"></option>
</th:block>
</select>
</div>
<div class="birth dropdown">
<select class="form-control" id="day" name="day">
<option value="">일(dd)</option>
<th:block th:each="day: ${#numbers.listFormatInteger(#numbers.sequence(1,31),2)}">
<option class="dropdown-item" th:value="${day}" th:text="${day}"></option>
</th:block>
</select>
</div>
<span id="birth_check_msg"></span>
</div>
<div class="mb-3">
<label class="form-label" for="gen">성별</label>
<div class="dropdown" id="gen">
<select onkeyup="checkGender()" class="form-control" id="gender" name="gender">
<option value="">성별</option>
<option th:each="genderValue : ${T(com.example.CUSHProject.enums.Gender).values()}"
th:value="${genderValue.value}"
th:text="${genderValue.title}"></option>
</select>
</div>
</div>
<div class="mb-3">
<button class="w-100 btn btn-lg btn-primary" type="submit">회원가입</button>
</div>
<div class="mb-3">
<a type="button" style="color:white" class="w-100 btn btn-lg btn-secondary" onclick="window.history.back();">취소</a>
</div>
</form>
<!--<script src="https://code.jquery.com/jquery-3.6.0.js"></script>-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript" src="/js/register.js"></script>
</body>
</html>
중복확인 버튼과 다시입력 버튼을 만들어 다시입력 버튼은 비활성화
사용자가 중복확인버튼을 누를시 ajax를 통해 중복확인
중복이면 중복입니다 라는 alert생성
중복이 아닐 시 confirm으로 사용하시겠습니까를 물어본 후 사용한다면 중복확인버튼 비활성화, 다시입력버튼 활성화, input창 readonly로 수정
다시입력버튼 클릭시 input값 초기화
input을 readOnly로 수정한 이유는 사용자가 사용가능한 아이디를 인가 받은 상태에서 다른 아이디로의 변경을 막기위해
function usernameCheck() {
const username = $("#username").val();
if (username == "") {
alert("아이디를 입력해주세요!. 필수항목입니다.");
$("#username").focus();
return false;
}
$.ajax({
type: "get",
url: "/api/overlap/usernameRegister",
data: {"username": username},
dataType: "JSON",
success: function (result) {
if (result.result == "0") {
if (confirm("이 아이디는 사용 가능합니다. \n사용하시겠습니까?")) {
usernameOverlapCheck = 1;
$("#username").attr("readonly", true);
$("#usernameOverlay").attr("disabled", true);
$("#usernameOverlay").css("display", "none");
$("#resetUsername").attr("disabled", false);
$("#resetUsername").css("display", "inline-block");
}
return false;
} else if (result.result == "1") {
alert("이미 사용중인 아이디입니다.");
$("#username").focus();
} else {
alert("success이지만 result 값이 undefined 잘못됨");
}
},
error: function (request, status,error) {
alert("ajax 실행 실패");
alert("code:" + request.status + "\n" + "error :" + error);
}
});
}
memberEntity에 대해 Repository를 만들어 JPA사용
@Repository
public interface MemberRepository extends JpaRepository<MemberEntity, Long> {
...
//중복가입
boolean existsByUsername(String username);
boolean existsByNickname(String nickname);
}
MemberService
해당 값을 map에 담아 리턴후 해당 값의 결과에 따라 중복여부 체크
//email 중복 검사
public HashMap<String, Object> usernameOverlap(String username) {
HashMap<String, Object> map = new HashMap<>();
map.put("result", memberRepository.existsByUsername(username));
return map;
}
//닉네임 중복 검사
public HashMap<String, Object> nicknameOverlap(String nickname) {
HashMap<String, Object> map = new HashMap<>();
map.put("result", memberRepository.existsByNickname(nickname));
return map;
}

중복일시

사용가능


모든 validate를 통과하고 회원가입 버튼 누를시 해당 form이 post형식으로 전달
BCryptPasswordEncoder를 통해 패스워드를 암호화 하고 기본적으로 Role를 ROLE_MEMBER로 세팅 후 JPA를 이용하여 entity에 저장
@Transactional
public Long singUp(MemberDto memberDto) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
memberDto.setPassword(passwordEncoder.encode(memberDto.getPassword()));
memberDto.setRole(Role.ROLE_MEMBER);
return memberRepository.save(memberDto.toEntity()).getId();
}
패스워드는 아래와 같이 인코딩 된 형태로 DB에 저장

다음 포스트에 이어서 작성!