본문 바로가기

Sever

6. 이메일 중복 검사 및 인증번호 이메일 보내기 기능 구현하기

이메일 중복 검사 

1. Servlet 

package edu.kh.community.member.controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import edu.kh.community.member.model.service.MemberService;

//----------------------------------------------------------

@WebServlet("/member/emailDupCheck")
public class EmailDupCheckServlet extends HttpServlet {
	
	// 이메일 중복 검사(비동기 통신) 
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		
		// 비동기 통신으로 전달된 파라미터(data 속성의 key값) 얻어오기 
		String memberEmail = req.getParameter("memberEmail");
		
		// service 호출 -> dao -> db -> dao -> service -> servlet 
		// Exception을 던지면서 이동하기 때문에 Servlet엔 반드시 try~catch가 있어야 함. 
		try {
			
			// 이메일 중복 검사 서비스 호출 후 결과 반환 받기 
			MemberService service = new MemberService();
			
			int result = service.emailDupCheck(memberEmail);
			
			// 보통 동기식 코드 작성 시, forward or redirect를 이용하여 새로운 페이지를 보이게 함 
			// 비동기 통신 시 응답은 응답은 화면이 아닌 '데이터'로 (데이터: String, int, JSON, XML...) 
			// 응답용 스트림을 이용하여 단순 데이터 전달만 하면 된다. 
			resp.getWriter().print(result);
			// 응답용 스트림을 이용하여 result 출력 
			
			
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
}

 

2. Service

package edu.kh.community.member.model.service;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

import static edu.kh.community.common.JDBCTemplate.*;
import edu.kh.community.member.model.dao.MemberDAO;
import edu.kh.community.member.model.vo.Member;

// -----------------------------------

public class MemberService {
	
	private MemberDAO dao = new MemberDAO();

	/** 이메일 중복 검사 Service
	 * @author memberEmail 
	 * @return
	 */
	public int emailDupCheck(String memberEmail) throws Exception {
		
		Connection conn = getConnection();
		
		int result = dao.emailDupCheck(conn, memberEmail);

		close(conn);
		
		return result;
	}	
}

 

3. DAO 

package edu.kh.community.member.model.dao;

import java.io.FileInputStream;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import static edu.kh.community.common.JDBCTemplate.*;

import edu.kh.community.member.model.vo.Member;

// --------------------------------

public class MemberDAO {
	
	private Statement stmt;		    
	private PreparedStatement pstmt; 
	private ResultSet rs;
	private Properties prop;
	
	public MemberDAO() {
		try {
			prop = new Properties();
			
			String filePath = MemberDAO.class.getResource("/edu/kh/community/sql/member-sql.xml").getPath();
			
			prop.loadFromXML( new FileInputStream(filePath) );
			
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	
    
	/** 이메일 중복검사 DAO 
	 * @param conn
	 * @param memberEmail
	 * @return
	 *
	 */
	public int emailDupCheck(Connection conn, String memberEmail) throws Exception{
		
		// 결과 저장용 변수 선언 
		int result = 0; 
		
		try {
			
			// SQL 얻어오기 
			String sql = prop.getProperty("emailDupCheck");
			
			//psmt 생성 
			pstmt = conn.prepareStatement(sql);
			
			// 위치 홀더에 알맞은 값 세팅
			pstmt.setString(1, memberEmail); // sql ?에 들어갈 값 
            
			/* 실행한 SQL 
				<entry key="emailDupCheck">
				SELECT COUNT(*) FROM MEMBER 
				WHERE MEMBER_EMAIL = ?
				AND SECESSION_FL = 'N'
				</entry>
			*/
			
			// sql 실행 후 결과 반환 받기 
			rs = pstmt.executeQuery();
			
			if(rs.next()) {
				result = rs.getInt(1); // COUNT(*)
			}
			
		} finally {
			close(rs);
			close(pstmt);
		}
		
		return result;
	}

 


이메일 인증번호 보내기 

1. Servlet

package edu.kh.community.member.controller;

import java.io.IOException;
import java.util.Properties;

import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;
import javax.mail.internet.MimeMultipart;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import edu.kh.community.member.model.service.MemberService;

// -------------------------------------

@WebServlet("/member/sendEmail")
public class SendEmailServlet extends HttpServlet{

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		// 입력받은 이메일 얻어오기 
		String inputEmail = req.getParameter("inputEmail"); 
		
		// -------------- 라이브러리 이용 -------------------
        
		String subject = "[Commnity 프로젝트] 회원 가입 이메일 인증번호"; // 메일 제목
		
		String fromEmail = "kdavin1221@gmail.com"; // 보내는 사람으로 표시될 이메일 (이메일 따라서 안될수도 있음)
		String fromUsername = "관리자"; // 보내는 사람 이름
		String toEmail = inputEmail; // 받는사람, 콤마(,)로 여러개 나열 가능
		
		
		// 구글 이메일을 이용한 메일 보내기 (SMTP..기술 이름)
		// 1. 구글 계정 생성(기존 이메일 사용해도됨)
		// 2. 계정 -> 보안 설정 진행
		// 1) 2단계 인증 추가
		// 2) 앱 비밀번호 생성(메일, 서버컴퓨터 OS) -> 저장해두기 ( pbbnnudxezjycopr ) // 발급 받은 비밀번호.... 보안 주의!!!!!!!!!!!!
			
		final String smtpEmail = "kdavin1221@gmail.com"; // 이메일
		final String password = "pbbnnudxezjycopr"; // 발급 받은 비밀번호.... 보안 주의!!!!!!!!!!!!
		
		// 메일 옵션 설정
		Properties props = new Properties();
		
		// 중요
		props.put("mail.transport.protocol", "smtp");
		props.put("mail.smtp.host", "smtp.gmail.com");
		props.put("mail.smtp.port", "587"); //465, 587
		props.put("mail.smtp.auth", "true");
		
		// 추가 옵션
		props.put("mail.smtp.quitwait", "false");
		props.put("mail.smtp.socketFactory.port", "587");
		props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
		props.put("mail.smtp.socketFactory.fallback", "true");
		props.put("mail.smtp.starttls.enable", "true");
		
		try {
			// 메일 세션 생성
			Session session = Session.getDefaultInstance(props);
			// 메일 송/수신 옵션 설정(1명 보내기)
			Message message = new MimeMessage(session);
		
			message.setFrom(new InternetAddress(fromEmail, fromUsername)); 	// 송신자(보내는 사람) 지정
			
			message.addRecipient(RecipientType.TO, new InternetAddress(toEmail)); // 수신자(받는사람) 지정
			
			message.setSubject(subject); // 이메일 제목 지정
			
			
			
			// 메일 콘텐츠 설정
			Multipart mParts = new MimeMultipart();
			MimeBodyPart mTextPart = new MimeBodyPart();
			
			// 인증번호 6자리 생성코드(영어 대/소문 + 숫자)
			String cNumber = "";
			for(int i=0 ; i< 6 ; i++) {
				
				int sel1 = (int)(Math.random() * 3); // 0:숫자 / 1,2:영어
				
				if(sel1 == 0) {
					
					int num = (int)(Math.random() * 10); // 0~9
					cNumber += num;
					
				}else {
					
					char ch = (char)(Math.random() * 26 + 65); // A~Z
					
					int sel2 = (int)(Math.random() * 2); // 0:소문자 / 1:대문자
					
					if(sel2 == 0) {
						ch = (char)(ch + ('a' - 'A')); // 대문자로 변경
					}
					
					cNumber += ch;
				}
				
			}
			
			
			// 메일에 출력할 텍스트
			StringBuffer sb = new StringBuffer(); // 가변성 문자열 저장 객체
			sb.append("<h3>[Community 프로젝트] 회원 가입 인증 번호입니다.</h3>\n");
			sb.append("<h3>인증 번호 : <span style='color:red'>"+ cNumber +"</span></h3>\n");
			
			//sb.append("<img src='https://cdn.wikifarmer.com/wp-content/uploads/2022/02/%ED%94%8C%EB%9F%BC%EB%B0%94%EA%B3%A0.jpg'>");
			
			String mailContent = sb.toString(); // 문자열로 반환
			
			// 메일 콘텐츠 - 내용 , 메일인코딩, "html" 추가 시 HTML 태그가 해석됨
			mTextPart.setText(mailContent, "UTF-8", "html");
			mParts.addBodyPart(mTextPart);
			
			// 메일 콘텐츠 지정
			message.setContent(mParts);
			
			
			// MIME 타입 설정 (이메일 내용이 깨질 때 사용)
			/*MailcapCommandMap MailcapCmdMap = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
			MailcapCmdMap.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
			MailcapCmdMap.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
			MailcapCmdMap.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
			MailcapCmdMap.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
			MailcapCmdMap.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
			CommandMap.setDefaultCommandMap(MailcapCmdMap);*/
			
			// 메일 발송
			Transport t = session.getTransport("smtp");
			t.connect(smtpEmail, password);
			t.sendMessage(message, message.getAllRecipients());
			t.close();
			
			
			// -------------- 라이브러리 이용 -------------------								
			// 인증번호를 받은 이메일, 인증번호난수(cNumber), 인증번호 발급 시간(sysdate)
			//  -> DB '삽입->INSERT->행의 개수'
			int result = new MemberService().insertCertification(inputEmail, cNumber);
			resp.getWriter().print(result);
			
		} catch (Exception e) {
			e.printStackTrace();
			
			// ajax error 속성 활용을 위한 500에러를 응답으로 전달.
			resp.setStatus(500);
			resp.getWriter().print(e.getMessage());
		}		
	}
}

* resp.getWriter().print(result)

 - resp: HttpServlerResponse 객체로 클라이언트로부터의 요청에 대한 응답 

 - getWriter(): 텍스트 데이터를 출력하기 위한 클래스인 PrintWriter 객체를 반환 

 - print(result): result의 값을 PrintWriter를 통하여 출력, 코드 HTTP 응답 본문에 result 변수 값을 출려 ㄱ

 - 즉, 클라이언트에게 result 볌수의 값을 포함하는 HTTP 응답 전송

 

 

2. Service

package edu.kh.community.member.model.service;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

import static edu.kh.community.common.JDBCTemplate.*;
import edu.kh.community.member.model.dao.MemberDAO;
import edu.kh.community.member.model.vo.Member;



public class MemberService {
	
	private MemberDAO dao = new MemberDAO();

	/** 인증번호 DB 추가 Service 
	 * @param inputEmail
	 * @param cNumber
	 * @return
	 */
	public int insertCertification(String inputEmail, String cNumber) throws Exception{
		
		Connection conn = getConnection();
		
		//1. 입력한 이메일과 일치하는 값이 있으면(기존에 있음) 수정(UPDATE) 
		int result = dao.updateCertification(conn, inputEmail, cNumber);

		//2. 입력한 이메일이 없으면(처음으로 발급) 삽입(INSERT) 
		if(result == 0) {
			result = dao.insertCertification(conn, inputEmail, cNumber);
		}
		
		// DML 구문은 commit, rollback... 트랜잭션 제어 필요!! 
		if(result > 0) commit(conn);
		else		   rollback(conn);
		
		// 커넥션 반환
		close(conn);
		
		return result;
	}
}

 

3. DAO 

package edu.kh.community.member.model.dao;

import java.io.FileInputStream;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import static edu.kh.community.common.JDBCTemplate.*;

import edu.kh.community.member.model.vo.Member;

//------------------------------------------

public class MemberDAO {
	
	private Statement stmt;		    
	private PreparedStatement pstmt; 
	private ResultSet rs;
	private Properties prop;
	
	public MemberDAO() {
		try {
			prop = new Properties();
			
			String filePath = MemberDAO.class.getResource("/edu/kh/community/sql/member-sql.xml").getPath();
			
			prop.loadFromXML( new FileInputStream(filePath) );
			
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	

	/** 인증번호, 발급일 수정 DAO(result가 1일 때 UPDATE)
	 * @param conn
	 * @param inputEmail
	 * @param cNumber
	 * @return
	 */
	public int updateCertification(Connection conn, String inputEmail, String cNumber) throws Exception {
		
		int result = 0; 
		
		try {
			String sql = prop.getProperty("updateCertification");
			
			pstmt = conn.prepareStatement(sql); 
			
			pstmt.setString(1, cNumber);
			pstmt.setString(2, inputEmail);

			result = pstmt.executeUpdate(); // 업데이트가 이루어지면 1 or 0
			
		} finally {
			close(pstmt);			
		}
		
		
		return result;
	}


	/** 인증번호 생성 DAO (result가 0이면 INSERT)
	 * @param conn
	 * @param inputEmail
	 * @param cNumber
	 * @return
	 */
	public int insertCertification(Connection conn, String inputEmail, String cNumber) throws Exception {
		
		int result = 0;
		
		try {
			String sql = prop.getProperty("insertCertification");
			
			pstmt = conn.prepareStatement(sql);
			
			pstmt.setString(1, inputEmail);
			pstmt.setString(2, cNumber);
			
			result = pstmt.executeUpdate();
			
		} finally {
			close(pstmt);
		}
		return result;
	}

 

* XML 

	<!-- UPDATE: 이미 있는 이메일.. 인증번호, 발급일 수정 -->
	<entry key="updateCertification">
		UPDATE CERTIFICATION SET
		C_NUMBER = ?,
		ISSUE_DT = SYSDATE
		WHERE EMAIL = ?
	</entry>
	
	
	<!-- INSERT: 인증번호 보내기 -->
	<entry key="insertCertification">
		INSERT INTO CERTIFICATION VALUES(?,?,SYSDATE)
	</entry>

 

 

'Sever' 카테고리의 다른 글

5. 로그인 기능 구현하기  (1) 2023.04.05
4. JDBC - 연결 생성부터 자원반환까지  (0) 2023.04.04
3. JDBC의 흐름 및 JDBC Tamplate  (0) 2023.04.04
2. JSP? + AJAX?  (0) 2023.03.28
1. Sevlet?  (0) 2023.03.27