요약
회원 가입 리팩토링 및 기능 추가
- 핸드폰 인증 문자 만료 시간 표시
- 아이디 입력 조건, 비밀번호 입력 조건 추가
- 비밀번호 암호화
리팩토링 :
1.핸드폰 인증 문자 만료시간 표시
인증 번호를 포함한 메세지를 발송할 때, 만료 시간도 함께 반환하도록 수정하였다.
반환 데이터는 message와 expirationTime 두 가지 값이다.
서비스에서 private static final로 설정된 AUTH_CODE_EXPIRATION_TIME에 접근하기 위해 getter 메서드 생성했다.
getAuthCodeExpirationTime() 메서드를 통해 만료 시간을 외부에서 가져올 수 있게 한 것이다.
인증 번호를 포함한 메세지를 발송하는 메서드에서 서비스를 호출해 인증번호를 전송하고 만료 시간을 가져오도록 했다.
반환 데이터는 JSON 형식으로, Map을 사용하여 키-값 형태로 클라이언트에 전달하도록 하였다.
ResponseEntity<?>를 사용해 유연한 반환 타입으로 처리 하였다.
이제 프론트엔드에서 남은 시간을 expirationTime을 이용해 표시할 수 있도록 할 것이다.
먼저, 흐름으로는 사용자가 전화번호를 입력하고 발송 버튼을 클릭하면 서버에 요청을 보내서 인증 번호를 발송한다.
발송 후, 서버로부터 가져온 메세지는 출력될 것이고, 만료 시간(expirationTime)을 기반으로 타이머가 시작될 것이다.
타이머는 사용자에게 익숙한 MM:SS 형식으로 표시할 것이고, 시간이 만료되면 '시간 초과' 메세지를 보여줄 것이다.
타이머를 표시할 영역을 HTML에 추가한다.
인증 번호를 포함하여 발송하는 sendSmsAuthCode 함수를 수정해보도록 한다.
변경된 부분은 서버 응답에서 단순 문자열만 받았다가, 추가로 만료 시간도 받는 것으로 수정하였다. 때문에 response.text() → response.json()으로 변경하여 JSON 데이터를 객체로 변환하였다.
서버에서 받은 expirationTime 값을 새로 추가한 startTimer() 함수에 전달한다.
// 인증 번호를 포함한 메시지 발송 함수
function sendSmsAuthCode() {
const toInput = document.getElementById('phone').value.trim();
const phoneVerificationResult = document.getElementById('phoneVerificationResult');
const timerDisplay = document.getElementById('timerDisplay'); // 타이머 표시 영역
// 서버에 요청 보내기
fetch("/api/sms/sendSmsWithAuthCode", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
to: toInput
})
})
.then(response => response.json())
.then(data => {
console.log("서버 응답:", data); // 서버 응답 확인
const remainingTime = Math.floor(data.expirationTime / 1000); // 밀리초 → 초 변환
startTimer(timerDisplay, remainingTime); // 타이머 시작
setResultMessage(phoneVerificationResult, "인증 번호가 전송되었습니다!", true);
})
.catch(error => {
console.error("Error:", error);
setResultMessage(phoneVerificationResult, "인증 번호 전송에 실패했습니다.", false);
});
}
서버에서 반환한 JSON 객체인 data =>
data.expirationTime은 서버에서 전달한 만료 시간이며, SmsService에서 설정한 대로 5분, 300,000 밀리초이다.
1초는 1,000 밀리초이기 때문에 300,000 밀리초는 5분이고, 이는 300초이다. 이렇게 설정한 이유는 Java에서는 시간 단위를 밀리초(ms)로 처리하는 경우가 많기 때문이다. 정밀한 시간 표현이 가능하여, 시간 계산이나 비교를 일관되게 처리할 수 있어서 기본 단위로 사용하는 것 같다. 그러나 클라이언트는 초 단위로 사용하는 것이 익숙하므로, JavaScript 에서 다시 /1000으로 변환하여 사용해야 한다.
서버에서 받은 expirationTime을 const remainingTime = Math.floor(data.expirationTime / 1000); 남은 시간으로 설정한다.
Math.floor()는 소수점 이하를 버림처리 해서 정확한 초 단위의 값을 만드는 것이다.
그리고 startTimer() 함수를 호출해서 타이머를 시작한다. 파라미터로는 남은 시간을 표시할 HTML요소와 남은 시간이다.
그리고 setResultMessage(phoneVerificationResult, "인증 번호가 전송되었습니다!", true); 발송 결과 메세지를 표시한다.
// 타이머 시작 함수
function startTimer(timerDisplay, remainingTime) {
// 밀리초를 초 단위로 변환
remainingTime = Math.floor(remainingTime);
const interval = setInterval(() => {
if (remainingTime <= 0) {
clearInterval(interval);
timerDisplay.innerText = "시간 초과"; // 만료 시 메시지 표시
return;
}
// 남은 시간 계산 및 포맷
const minutes = ('0' + Math.floor(remainingTime / 60)).slice(-2);
const seconds = ('0' + (remainingTime % 60)).slice(-2);
timerDisplay.innerText = `${minutes} : ${seconds}`;
remainingTime--;
}, 1000);
}
startTimer() 함수는 남은 시간을 화면에 표시하고, 시간이 0이 되면 종료하는 함수로 설계하였다.
혹시라도 remainTime에 소수점이 들어올 경우를 대비하여 Math.floor()로 소수점을 버리고 정수로 만든다.
남은 시간을 분과 초로 나누고, 항상 두 자리 숫자로 표시하게 설정하였다.
Math.floor(remainingTime / 60) → 남은 시간을 분 단위로 변환.
remainingTime % 60 → 남은 초를 계산.
'0' + 값 → 한 자리 숫자 앞에 0을 추가..slice(-2) → 문자열 끝에서 두 자리만 가져옴.
예시: 299초 → 04 : 59, 59초 → 00 : 59
"서버를 올리고 직접 회원가입 페이지에서 전화번호를 입력 후 발송해 보았다. 성공!" 🎉
그런데 인증 완료가 되면, 타이머가 멈추어야 하는데 그대로 작동하는 것을 확인하였다.
자바스크립트에 필요한 로직을 추가하자.
let timerInterval; // 타이머 interval 전역 변수 선언
// 기존 타이머가 있으면 멈춤
if (timerInterval) {
clearInterval(timerInterval);
timerInterval = null;
}
})
.then(data => {
setResultMessage(phoneVerificationResult, data, true);
// 인증 성공 시 타이머 멈춤
clearInterval(timerInterval);
const timerDisplay = document.getElementById('timerDisplay');
timerDisplay.innerText = "인증 완료"; // 시간 대신 '인증 완료' 표시
})
// 타이머가 '인증 완료' 상태인지 확인
if (timerDisplay.innerText === "인증 완료") {
clearInterval(timerInterval);
timerInterval = null; // 타이머 중지 및 초기화
return;
}
먼저 기존 타이머를 중지하고 초기화하도록 했다.
타이머를 시작할 때 timerInterval이 이미 존재하면 clearInterval(timerInterval)을 호출해 기존 타이머를 중지하고, timerInterval 값을 null로 초기화한다.
이로써 사용자가 인증번호 발송 버튼을 여러 번 눌러도 타이머가 충돌하지 않도록 방지했다.
또한, 인증 성공 후 타이머를 멈추는 로직을 추가했다.
인증 확인 함수의 .then 블록에서 clearInterval(timerInterval)을 호출해 타이머를 중지하고, 타이머 표시 영역에 "인증 완료" 메시지를 출력하도록 했다.
마지막으로, 타이머 실행 중 '인증 완료' 상태를 확인하는 로직을 추가했다.
타이머가 갱신될 때 timerDisplay.innerText가 **"인증 완료"**인지 확인하고, 즉시 clearInterval(timerInterval)을 호출해 타이머를 중지하도록 처리하였다.
이렇게 수정함으로써 타이머가 중복 없이 정상적으로 종료되도록 개선하였다.
휴 이로써 정말 인증 완료다!
'Spring Boot Projects > community website' 카테고리의 다른 글
회원 관리 시스템 구현: 회원 가입 기능추가 -3. 비밀번호 암호화 (0) | 2024.12.18 |
---|---|
회원 관리 시스템 구현: 회원 가입 리팩토링 -2. 아이디 입력 조건(regexp)과 비밀번호 입력 조건 (2) | 2024.12.18 |
회원 관리 시스템 구현: 회원 가입 데이터 전송과 DTO 설계 및 이해 (0) | 2024.12.17 |
회원 가입 핸드폰 인증: coolSMS를 활용한 SMS 인증 시스템 (0) | 2024.12.13 |
회원 가입 이메일 인증: SMTP와 JavaMailSender를 활용하여 인증 구현 (0) | 2024.12.11 |