❤ 김춘장이의 위키백과 - 나만의 공부 기록 Tistory ❤
🙏 양해의 말씀
그동안 포스팅을 잠시 미뤘다.
마지막 프로젝트에 집중하고 싶었고, 이 프로젝트는 이력서에도 포트폴리오에도 첨삭되는 거라
옵시디언에 열심히 중간중간 메모 하며 포스팅만 미루었다.
지금은 최종 PPT가 완료되고, 포트폴리오 정리를 하면서 미루었던 포스팅을 다시 올려 본다
이메일 인증을 구현하기 위해 이제 동작을 만들어 보자!
정의는 이전 포스팅을 참고해 주세요 👇
프로젝트 내에 이메일 인증의 역할
1) 회원가입 시 이메일을 ID로 사용하므로 사용 가능한 email인지 확인해야 한다.
2) 이메일은 DB 테이블에 기본키로 제약조건이 걸려있음으로 중복되지 않아야 한다
인증의 진행
1) 사용자가 이메일을 입력 후 이메일인증 버튼을 클릭 시 이벤트 처리 진행
2) 이메일 양식 유효성 체크
3) 유효성이 정상이라면 DB에 중복이 된 게 있는지 재차 확인
4) 중복도 안되어 있다면 랜덤 6자리 숫자 생성 후 이메일 발송
5) 발송된 점을 사용자에게 알려줌
6) 사용자가 인증번호를 입력함
7) 발송한 랜덤 번호와 일치여부 확인
8) 일치 시 인증 확인 버튼이 비활성화되며 불일치 시 인증 확인 버튼이 활성화되어 있음
* 이러한 과정을 할 때 화면페이지가 바뀌거나 갱신되면 안 된다!
이메일 유효성 리턴
매개변수인 email의 유효성을 검사하는 함수
/^[a-zA-Z0-9._-] : 영문 a-z, A-Z, 0-9, 밑줄 _ , 마침표. , 하이픈 - 으로 시작하며 이 중 하나 포함되어야 힘
@[a-zA-Z0-9.-] : @ 기호 다음 도메인 이름이 오는 곳, 영문자 숫자 마침표 또는 하이픈으로 구성함
\. [a-zA-Z]{2,4}$/ : 최소 2자리, 최대 4자리의 도메인 최상위 도메인이 와야 한다. com이나. net 등
. test 메서드를 사용하며 정규표현식을 담고 있는 regex를 이용하여 email문자열이 정규표현식 패턴에 부합한 지 검사하며
부합한 경우 true를 리턴하고 아닐 경우 false를 리턴함
/**
이메일 유효성 리턴 함수
@param : String
@return : boolean
*/
function isEmail(email) {
var regex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
return regex.test(email);
}
이메일 중복 확인 함수
유효성 체크가 끝났다면 DB에 해당 이메일이 등록된 정보인지 확인하는 작업이 있어야 한다
컨트롤러에게 입력된 이메일을 전달 url을 만든 후 fetch 함수를 통해 컨트롤러에게 전달
controller ➡️ service ➡️ dao ➡️ mybatis ➡️ oracle ➡️ mybatis ➡️ dao ➡️ service ➡️ controller + model ➡️ js
/** 이메일 중복 확인 함수 */
function checkEmailDuplication(email){
// GET 요청 URL 생성
let url = `/emailDuplication?email=${encodeURIComponent(email)}`;
// fetch 사용하여 GET 요청을 보냄
let res = async () => {
try {
await fetch(url)
.then(response => response.json())
.then(data => {
if (data.isDuplicated) {
alert("이메일이 중복됩니다.");
return false;
} else {
return true;
}
})
.catch(error => {
console.error('Error:', error);
});
} catch (error){
console.error('Error : ' , error);
}
}
return res;
}
이메일 중복 컨트롤러 메서드
/**
* 등록된 이메일 중복여부 체크 메서드
* @param : String 사용자가 입력한 email주소가 들어옴
* @return : boolean 중복 여부 반환
* */
@GetMapping(value="/emailDuplication")
public ResponseEntity<?> emailDuplications(@RequestParam String email){
Boolean isDuplicated = emailService.checkEmailDuplication(email);
return ResponseEntity.ok().body("{\"isDuplicated\":" + isDuplicated + "}");
}
}
랜덤 인증번호 생성 후 이메일 발송 함수
이메일 유효성과 중복결과 모두 정상이라면 , 인증번호를 생성하고 이메일을 발송해야 한다
랜덤번호는 어렵지 않기 때문에 크게 설명하진 않겠다.
// 유효성&중복검사 정상 : 랜덤 인증번호 생성
randomNumber = String(Math.floor(Math.random() * 1000000)).padStart(6,'0');
이거 한 줄이면 된다...
padStart를 해준 것은 앞자리가 0으로 떨어지는 경우 6자리가 아닌 6자리 미만으로 숫자가 구성될 수 있어서 사용한다
let randomNumber;
document.getElementById('emailSend').addEventListener('submit', emailVerification)
// 이메일 유효성 검샤 + 이메일 중복 검사 후 발송 로직
async function emailVerification() {
event.preventDefault();
let userEmail = document.getElementById('staffEmail').value;
// 입력된 이메일 유효성 검사 - 정상
if (!isEmail(userEmail)) { return alert("알맞은 이메일방식이 아닙니다.") }
// 가입된 이메일이 있는지 검사
if(!checkEmailDuplication(userEmail)){ return alert("중복된 이메일입니다.")}
// 유효성&중복검사 정상 : 랜덤 인증번호 생성
randomNumber = String(Math.floor(Math.random() * 1000000)).padStart(6,'0');
// 이메일 발송
try {
const emailSent = await sendToEmail(userEmail, randomNumber);
if(emailSent){
alert("이메일 발송 성공");
} else {
alert("이메일 발송 실패");
}
} catch (error) {
console.error('Error during email sending:', error);
}
}
이메일 발송 함수를 별도로 만들어 놨는데 내용은 이러하다
/**
이메일 발송 함수
*/
async function sendToEmail(email, randomNumber) {
let name = document.getElementById('staffName').value;
let data = {
name: name,
email: email,
randomNumber: randomNumber
};
try {
let response = await fetch('/sendMail', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
} else {
let result = await response.json();
if (result === 'true') {
return true;
} else {
console.error('Email sending failed', result);
return false;
}
}
} catch (error) {
console.error('Error:', error);
return false;
}
}
매개변수인 email(사용자가 입력한 email), 생성된 랜덤번호 6자리를 가지고
이메일 발송을 위한 객체를 만든다
이메일을 발송할 때 필요한 데이터는
수신받는 사람의 성함, 수신자의 이메일, 랜덤 인증번호이다
3가지 정보를 매칭하여 JSON포맷형식으로 객체를 구성 후 fetch함수로 컨트롤러에게 전달한다
비동기로 처리한 이유는 이메일 발송을 서버에서 처리하는 동안 다른 코드의 실행이 차단되지 않기 때문에
이런 식으로 진행을 하였다.
이메일 발송 컨트롤러
/**
* 이메일 발송 메서드
* @param : {@link EmailVO} 사용자 이름 , 이메일주소 , 랜덤 인증번호
* @return : boolean 발송 성공 여부 */
@CrossOrigin
@RequestMapping(value = "/sendMail", method = RequestMethod.POST)
@ResponseBody
public ResponseEntity<String> sendEmail(@RequestBody EmailVO emailVO){
try{
// 이메일 발송 서비스단으로 전달
emailService.sendEmailService(emailVO);
return ResponseEntity.ok("true");
} catch (Exception e){
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("false");
}
}
서비스단으로 전달하며 혹시라도 오류가 나타날 경우엔 실패했다는 값을 전달하도록 만들었다.
이메일발송 서비스 처리로직
emailVO 객체는 클라이언트 측에서 보낸 정보를 갖고 있는 객체이다, 컨트롤러가 인자로 전달한 매개변수다
toAddr는 발송하는 서버(회사)측 주소를 뜻한다
메일객체를 생성하고, 어떤 방식으로 메일을 발송할지 구성한 뒤 발송한다
/**
* 이메일 발송 실 처리 로직
*
* @param : {@link EmailVO} 사용자 이름 , 이메일주소 , 랜덤 인증번호
* @return : boolean 이메일 발송 성공 여부 리턴
*/
public boolean sendEmailService(EmailVO emailVO) {
try {
//EMBAD이메일 대입
emailVO.setToAddr(toAddr);
MimeMessage mail = mailSender.createMimeMessage();
MimeMessageHelper mailHelper = new MimeMessageHelper(mail, true, "UTF-8");
// 발송자 이메일(EMBAD이메일)
mailHelper.setFrom(emailVO.getToAddr());
// 수신자 이메일(사용자 이메일주소)
mailHelper.setTo(emailVO.getEmail());
// 메일 제목
mailHelper.setSubject(emailVO.getName() + "님 EMBAD 인증번호 메일입니다 ");
// 메일 내용 : true(html허용)
mailHelper.setText("인증번호 : " + emailVO.getRandomNumber(), true);
// 메일 전송
mailSender.send(mail);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
템플릿을 이쁘게 만든 건 아니지만 , , 이메일 발송은 잘 된다!
인증 확인 성공 시 저렇게 버튼이 비활성 화 된다
만약에 잘못 입력할 경우
이렇게 오류 팝업과 함께 인증 확인 버튼이 활성화 유지 되며 알람창이 뜬다
이메일 인증을 처리하며 배운 점
지금 만든 구현 방식은 화면페이지가 갱신되면 안 되었기 때문에 어떻게 해야 하나 고민했었다.
event.preventDefault();
이 코드를 추가하고 컨트롤러에서도 어떤 식으로 해야 화면 갱신 없이 진행해야 하는 지도 고민했었다.
적절하게 검색도 잘 되었고.. 음 구현시 큰 어려움이라고 하면
앱 키 라던지 비밀번호 같은 부분에 대해서 application.properties 파일로 별도 관리 하다 보니 설정 부분에서 조금 헤매긴 했다
예전처럼 그냥 소스코드에 날것 그대로 앱 키나 비밀번호를 작성했을 텐데
조금이라도 노출이 덜 되도록 신경 써보려고 하다 보니 그 부분이 시간이 걸렸던 것 같다
'👀 Side Project > Eᴍʙᴀᴅ (23.12~24.01)' 카테고리의 다른 글
응급구조사편_의료서비스 검색화면 및 로직2 (0) | 2024.01.31 |
---|---|
응급구조사편_의료서비스 검색화면 및 로직1 (0) | 2024.01.31 |
디자인, 이게 최선이였냐?! , 불호령 떨어진 디자인 개편 (1) | 2024.01.28 |
회원가입 구현 (1) | 2024.01.28 |
Spring email 정의하기 (0) | 2024.01.28 |