티스토리 뷰
이메일 찾기는 이름과 연락처에 해당하는 사용자 입력 값에 대해 일치하는 사용자인 레코드가 있을 경우 해당 레코드의 이메일을 알려주고, 없다면 입력한 정보와 일치하는 사용자가 없다는 응답을 돌려주는 절차이다.
로직 : 전달 받은 이름(name)과 연락처(contact)에 대해 일치하는 회원의 존재 여부 및 존재서의 이메일을 담는 JSON 응답 결과를 처리하기 위한 로직.
서비스 가 넘겨준 결과가 CommonResult.SUCCESS라면 응답 결과로 email 값도 함께 돌려 보낸다.
- MemberController
@RequestMapping(value = "recoverEmail", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView getRecoverEmail() {
ModelAndView modelAndView = new ModelAndView("member/recoverEmail");
return modelAndView;
}
@RequestMapping(value = "recoverEmail", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String postRecoverEmail(UserEntity user) {
Enum<? extends IResult> result = this.memberService.recoverEmail(user);
JSONObject responseObject = new JSONObject();
responseObject.put("result", result.name().toLowerCase());
if(result == CommonResult.SUCCESS) {
responseObject.put("email", user.getEmail());
}
return responseObject.toString();
}
로직
1. 전달 받은 UserEntity 타입의 객체가 가지는 이름(name) 및 연락처(contact)와 일치하는 또 다른 UserEntity 객체를 SELECT 한다.
2. 위 <1>에서 받아온 새로운 UserEntity 객체가 null 이라면 CommonResult.FALURE를 반환하고 메서드 종료.
3. 아니라면, 매개변수로 전달받은 UserEntity 객체의 email 필드 값을 새로 받아온 UserEntity 객체가 가진 email 값으로 지정(set)하고
CommonResult.SUCCESS 반환한다.
- MemberService
public Enum<? extends IResult> recoverEmail(UserEntity user) {
UserEntity existingNameAuth = this.memberMapper.selectUserByNameContact(
user.getName(), user.getContact());
if (existingNameAuth == null) {
return CommonResult.FAILURE;
}
user.setEmail(existingNameAuth.getEmail());
return CommonResult.SUCCESS;
}
로직: 전달된 이름(name)과 연락처(contact)를 가지는 레코드를 선택하여 UserEntity 타입의 객체로 반환한다.
- IMemoMapper
UserEntity selectUserByNameContact(@Param(value = "name") String name,@Param(value = "contact") String contact);
- MemberMapper.xml
<select id="selectUserByNameContact"
resultType="dev.shlee.studymemberbbs.entities.member.UserEntity">
SELECT `email` AS `email`,
`password` AS `password`,
`nickname` AS `nickname`,
`name` AS `name`,
`contact` AS `contact`,
`address_postal` AS `addressPostal`,
`address_primary` AS `addressPrimary`,
`address_secondary` AS `addressSecondary`,
`registered_on` AS `registeredOn`
FROM `study_member`.users
WHERE BINARY `name` = #{name}
AND BINARY `contact` = #{contact}
LIMIT 1
</select>
- recoverEmail.html
<!doctype html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>스터디 - 이메일 찾기</title>
<th:block th:replace="~{fragments/head :: common}"></th:block>
<link rel="stylesheet" th:href="@{/member/resources/stylesheets/recoverEmail.css}">
<script defer th:src="@{/member/resources/scripts/recoverEmail.js}"></script>
</head>
<body>
<th:block th:replace="~{fragments/body :: header}"></th:block>
<th:block th:replace="~{fragments/body :: cover}"></th:block>
<main class="--main main">
<form class="form" id="form" rel="form">
<div class="title-container">
<h1 class="title">이메일 찾기</h1>
</div>
<table class="table">
<tbody>
<tr>
<th>이름</th>
<td>
<label class="label name">
<span hidden>이름</span>
<input class="--object-input input" maxlength="50" name="name"
placeholder="이름을 입력해 주세요" type="text">
</label>
</td>
</tr>
<tr class="contact-row" rel="contactRow">
<th>연락처</th>
<td>
<label class="label contact">
<span hidden>연락처</span>
<input class="--object-input input" maxlength="50" name="contact"
placeholder="가입에 사용하신 연락처를 입력해 주세요." type="tel">
</label>
</td>
</tr>
<tr>
<th></th>
<td>
<input class="--object-button findEmail" name="findEmail" type="button" value="이메일 찾기">
<a th:href="@{/member/login}">
<input class="--object-button goLogin" name="goLogin" type="button" value="로그인 하러가기">
</a>
</td>
</tr>
<tr class="message-row" rel="messageRow">
<th></th>
<td>
<span class="message">
<span class="text"></span>
</span>
</td>
</tr>
<tr class="warning-row" rel="warningRow">
<th></th>
<td>
<span class="warning">
<i class="icon fa-solid fa-triangle-exclamation"></i>
<span class="text">이름을 입력해 주세요.</span>
</span>
</td>
</tr>
</tbody>
</table>
</form>
</main>
<th:block th:replace="~{fragments/body :: footer}"></th:block>
</body>
</html>
- recoverEmail.js
const form = window.document.getElementById('form');
// 주어진 문자열과 일치하는 id 속성을 가진 요소를 찾고, 이를 나타내는 Element 객체를 반환한다.
const Warning = {
getElement: () => form.querySelector('[rel="warningRow"]'), //form안에서 class 찾기
show: (text) => {
const warningRow = Warning.getElement();
warningRow.querySelector('.text').innerText = text; //text를 찾고 text인 값을 innerText 해주기
warningRow.classList.add('visible'); // classList.add를 통해 보여준다
},
hide: () => Warning.getElement().classList.remove('visible')
// hide -> 숨기기
};
const Email = {
getElement: () => form.querySelector('[rel="messageRow"]'),
show: (text) => {
const messageRow = Email.getElement();
messageRow.querySelector('.text').innerText = text;
messageRow.classList.add('visible');
},
hide: () => Email.getElement().classList.remove('visible') // 안보이게 하기
};
form['findEmail'].addEventListener('click', () => {
Warning.hide();
if (form['name'].value === '') {
Warning.show('이름을 입력해 주세요.');
form['name'].focus();
Email.hide();
return;
}
if(form['contact'].value === '') {
Warning.show('전화번호를 입력해 주세요.');
form['name'].focus();
Email.hide();
return;
}
const xhr = new XMLHttpRequest();
const formData = new FormData();
formData.append('name', form['name'].value); // name과 name.value를 추가
formData.append('contact', form['contact'].value);
xhr.open('POST', './recoverEmail')
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
Cover.hide();
if (xhr.status >= 200 && xhr.status < 300) {
const responseObject = JSON.parse(xhr.responseText);
console.log(responseObject);
switch (responseObject['result']) {
case 'success':
form['name'].setAttribute('disabled', 'disabled');
form['contact'].setAttribute('disabled', 'disabled');
form['findEmail'].setAttribute('disabled', 'disabled');
Email.show('입력하신 정보와 일치하는 이메일은'+'\n' + responseObject['email'] +'\n' + '입니다')
form.querySelector('[rel="messageRow"]').classList.add('visible');
form.querySelector('[rel="warningRow"]').classList.remove('visible');
form['goLogin'].classList.add('visible');
break;
default:
Warning.show('입력한 정보와 일치하는 회원이 없습니다.');
form.querySelector('[rel="messageRow"]').classList.remove('visible');
form['goLogin'].classList.remove('visible');
}
} else {
Warning.show('서버와 통신하지 못하였습니다. 잠시 후 다시 시도해 주세요.');
}
}
};
xhr.send(formData);
});
- recoverEmail.css
@charset "UTF-8";
#form {
width: 100%;
max-width: 40rem;
margin: 5rem 2rem;
display: flex;
flex-direction: column;
align-items: stretch;
justify-content: flex-start;
}
#form > .title-container {
margin-bottom: 3rem;
}
#form > .title-container > .title {
font-size: 2rem;
font-weight: 500;
}
#form > .table {
width: 100%;
max-width: 30rem;
align-self: center;
border: none;
border-collapse: collapse;
}
#form > .table th {
white-space: nowrap;
padding-right: 1rem;
}
#form > .table td {
width: 100%;
}
#form > .table [name="recoverEmail"] {
width: 100%;
margin-top: 0.25rem;
}
#form > .table .message-row {
display: none;
}
#form > .table .message-row.visible {
display: table-row;
}
#form > .table .message-row .message {
align-items: center;
background-color: rgb(26, 188, 156);
border-radius: 0.375rem;
color: rgb(255, 255, 255);
display: flex;
flex-direction: row;
font-size: 1rem;
justify-content: center;
margin-top: 0.25rem;
padding: 1rem 1rem;
}
#form > .table .message-row .message > .icon {
font-size: 1.5rem;
margin: 0 1.5rem 0 0.25rem;
}
#form > .table .message-row .message > .text {
text-align: center;
}
#form > .table .warning-row {
display: none;
}
#form > .table .warning-row.visible {
display: table-row;
}
#form > .table .warning-row .warning {
align-items: center;
background-color: rgb(243, 67, 67);
border-radius: 0.375rem;
color: rgb(255, 255, 255);
display: flex;
flex-direction: row;
font-size: 1rem;
justify-content: flex-start;
margin-top: 0.25rem;
padding: 0.75rem 1rem;
}
#form > .table .warning-row .warning > .icon {
font-size: 1.5rem;
margin: 0 1.5rem 0 0.25rem;
}
#form > .table .message-row .warning > .text {
flex: 1;
text-align: justify;
}
#form > .table > .warning-row .warning {
background-color: rgb(231, 76, 60);
color: rgb(255, 255, 255);
margin-top: 0.5rem;
padding: 1rem 1rem;
border-radius: 0.375rem;
font-size: 0.9rem;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
}
#form > table > tbody > tr > td > .findEmail,
#form > table > tbody > tr > td > a > .goLogin {
width: 100%;
margin-top: 0.35rem;
}
#form > table > tbody > tr > td > a {
text-decoration: none;
color: inherit;
}
#form > table > tbody td > a > .goLogin {
display: none;
}
#form > table > tbody td > a > .goLogin.visible {
display: table-row;
}

이메일 찾기 버튼을 클릭하였을 때 이름을 입력하지 않은 경우 '이름을 입력해 주세요'라는 경고 메세지가 표시되게 한다.

이메일 버튼을 클릭하였을 때 입력한 연락처를 입력하지 않은 경우 아래와 같이 '전화번호를 입력해 주세요.' 라는 경고 메세지가 표시되어야 합니다.

이메일 찾기 버튼을 클릭하였을 때 입력한 이름과 연락처를 가지는 회원이 없다면 아래와 같이 '입력한 정보와 일치하는 회원이 없습니다.'라는 경고 메세지가 표시되게 한다.

이메일 찾기 버튼을 클릭하였을 때 입력한 이름과 연락처를 가지는 회원이 있다면 아래와 같이 이름 및 연락처 입력란에 이메일 찾기 버튼이 비활성화 되고, 이메일을 포함하는 메세지와 '로그인하러 가기'라는 버튼이 보여지게 한다.

'웹 개발 > SpringBoot' 카테고리의 다른 글
| [Spring Boot] 게시판 만들기2(게시판 구분) (0) | 2022.11.16 |
|---|---|
| [Spring Boot] 게시판 만들기 (0) | 2022.11.15 |
| [Spring Boot] 로그인 구현 (2) | 2022.11.10 |
| [Spring Boot] Password Reset(2) (3) | 2022.11.09 |
| [Spirng Boot] Password Reset (0) | 2022.11.09 |