<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Page</title>
<link rel="stylesheet" href="/resources/css/myPage/myPage-style.css">
</head>
<body>
<main>
<jsp:include page="/WEB-INF/views/common/header.jsp"/>
<!-- 마이페이지 - 내 정보 -->
<section class="myPage-content">
<!-- 사이드메뉴 include -->
<!-- jsp 액션 태그 -->
<jsp:include page="/WEB-INF/views/myPage/sideMenu.jsp"/>
<!-- 오른쪽 마이페이지 주요 내용 부분 -->
<section class="myPage-main">
<h1 class="myPage-title">회원 탈퇴</h1>
<span class="myPage-subject">현재 비밀번호가 일치하는 경우 탈퇴할 수 있습니다.</span>
<form action="secession" method="POST" name="myPageFrm">
<div class="myPage-row">
<label>비밀번호</label>
<input type="password" name="memberPw" id="memberPw" maxlength="30">
</div>
<div class="myPage-row info-title">
<label>회원 탈퇴 약관</label>
</div>
<pre class="secession-terms">
제1조
이 약관은 샘플 약관입니다.
① 약관 내용 1
② 약관 내용 2
③ 약관 내용 3
④ 약관 내용 4
제2조
이 약관은 샘플 약관입니다.
① 약관 내용 1
② 약관 내용 2
③ 약관 내용 3
④ 약관 내용 4
</pre>
<div>
<input type="checkbox" name="agree" id="agree">
<label for="agree">위 약관에 동의합니다.</label>
</div>
<button class="myPage-submit">탈퇴</button>
</form>
</section>
</section>
</main>
<jsp:include page="/WEB-INF/views/common/footer.jsp"/>
</body>
</html>
// 내 정보(수정)페이지
const memberNickname = document.getElementById("memberNickname");
const memberTel = document.getElementById("memberTel");
const updateInfo = document.getElementById("updateInfo");
// 내 정보 수정 form 태그가 존재할 때(내 정보 페이지)
if(updateInfo != null){
// 전역 변수로 수정 전 닉네임/전화번호를 저장
initNickname = memberNickname.value;
initTel = memberTel.value;
// 닉네임 유효성 검사
memberNickname.addEventListener("input", () => {
// 변경 전 닉네임과 입력값이 같을 경우
if(initNickname == memberNickname.value){
memberNickname.removeAttribute("style");
return;
}
// 정규 표현식으로 유효성 검사
const regEx = /^[가-힣\d\w]{2,10}$/;
if(regEx.test(memberNickname.value)){
memberNickname.style.color="green"
} else {
memberNickname.style.color="red"
}
});
// 전화번호 유효성 검사
memberTel.addEventListener("input", () => {
// 변경 전 전화번호와 입력 값이 같을 경우
if(initTel == memberTel.value){
memberTel.removeAttribute("style");
return;
}
// 정규 표현식으로 유효성 검사
const regEx = /^0(1[01679]|2|[3-6][1-5]|70)\d{3,4}\d{4}$/;
if(regEx.test(memberTel.value)){
memberTel.style.color="green";
} else {
memberTel.style.color="red";
}
});
// form 태그 제출 시 유효하지 않은 값이 있으면 제출 X
updateInfo.addEventListener("submit" ,e => {
// 닉네임이 유효하지 않은 경우
if(memberNickname.style.color == "red"){
alert("닉네임이 유효하지 않습니다.");
memberNickname.focus();
e.preventDefault();
return;
}
// 전화번호가 유효하지 않은 경우
if(memberTel.style.color == "red"){
alert("전화번호가 유효하지 않습니다.");
memberTel.focus();
e.preventDefault();
return;
}
})
} // if문 끝*-
// 비밀번호 변경 제출 시
const changePwFrm = document.getElementById("changePwFrm");
const currentPw = document.getElementById("currentPw");
const newPw = document.getElementById("newPw");
const newPwConfirm = document.getElementById("newPwConfirm");
// 비밀번호 변경 페이지인 경우
if(changePwFrm != null){
changePwFrm.addEventListener("submit", e => {
// 현재 비밀번호 미작성 시
if(currentPw.value.trim() == ""){
alert("현재 비밀번호를 입력해주세요");
e.preventDefault();
currentPw.focus();
currentPw.value = "";
return;
}
// 비밀번호 유효성 검사
const regEx = /^[A-Za-z\d\!\@\#\-\_]{6,20}$/;
if(!regEx.test(newPw.value)){
alert("비밀번호가 유효하지 않습니다.");
e.preventDefault();
newPw.focus();
newPw.value = "";
return;
}
if(newPw.value != newPwConfirm.value ){
alert("비밀번호가 일치하지 않습니다.");
e.preventDefault();
newPwConfirm.focus();
newPwConfirm.value = "";
return;
}
})
} // if문 끝
// 회원탈퇴
const secessionFrm = document.getElementById("secessionFrm");
const memberPw = document.getElementById("memberPw");
const agree = document.getElementById("agree");
// 회원탈퇴 페이지인 경우
if(secessionFrm != null){
secessionFrm.addEventListener("submit", e => {
// 비밀번호 미작성
if(memberPw.value.trim() == ""){
alert("비밀번호를 입력해주세요");
e.preventDefault();
memberPw.focus();
memberPw.value = "";
return;
}
// 동의 체크가 되지 않은 경우
if(!agree.checked){
alert("약관 동의 후 탈퇴 버튼을 눌러주세요");
e.preventDefault();
agree.focus();
return;
}
// 취소 클릭 시
if(!confirm("정말 탈퇴하시겠습니까?")){
alert("탈퇴 취소");
e.preventDefault();
return;
}
});
}
🔑 쿠키 삭제 주의
// 회원 탈퇴
@PostMapping("/secession")
public String secession(String memberPw, @SessionAttribute("loginMember") Member loginMember
, SessionStatus status, HttpServletResponse resp, RedirectAttributes ra) {
// String memberPw : 입력한 비밀번호
// SessionStatus status : session을 관리하는 객체
// HttpServletResponse resp : 서버 -> 클라이언트 응답하는 방법 제공 객체
// RedirectAttributes ra : 리다이렉트 시 request로 값 전달하는 객체
// 1. 로그인한 회원 번호 얻어오기
// @SessionAttribute("loginMember") Member loginMember
int memberNo = loginMember.getMemberNo();
// 2. 회원 탈퇴 service 호출
// - 비번 일치하면 MEMBER_DEL_FL -> Y로 바꾸고 1 반환
// - 비번 일치하지 않으면 0 반환
int result = service.secession(memberPw, memberNo);
String path = "redirect:";
String message = null;
if(result>0) { // 3. 탈퇴 성공 시
// - 로그아웃
status.setComplete();
// + 쿠키 삭제
Cookie cookie = new Cookie("saveId", "");
// 같은 쿠키가 이미 존재하면 덮어쓰기 된다.
cookie.setMaxAge(0); // 0초 생존 -> 삭제
cookie.setPath("/"); // 요청 시 쿠키가 첨부되는 경로 지정
resp.addCookie(cookie); // 요청 객체를 통해서 클라이언트에게 전달
// -> 클라이언트 컴퓨터에 파일로 생성
// - message : 탈퇴되었습니다
message = "탈퇴되었습니다.";
// - 메인페이지로 redirect
path += "/";
} else { // 4. 탈퇴 실패 시
// - message : 현재 비밀번호가 일치하지 않습니다.
message = "현재 비밀번호가 일치하지 않습니다.";
// - 회원 탈퇴 페이지로 redirect
path += "secession";
}
ra.addFlashAttribute("message", message);
return path;
}
/** 회원 탈퇴 서비스
* @param memberPw
* @param memberNo
* @return result
*/
int secession(String memberPw, int memberNo);
// 회원 탈퇴
@Transactional(rollbackFor = {Exception.class})
@Override
public int secession(String memberPw, int memberNo) {
// 회원번호 일치하는 회원의 비밀번호 조회
String encPw = dao.selectEncPw(memberNo);
// 비밀번호 일치하면
if(bcrypt.matches(memberPw, encPw)) {
// MEMBER_DEL_FL -> 'Y'로 바꾸고 1 반환
return dao.secession(memberNo);
}
return 0;
}
/** 회원 탈퇴
* @param memberNo
* @return result
*/
public int secession(int memberNo) {
// sqlSessionTemplate : 마이바티스 + DBCP + close 자동 + 트랜잭션 처리
return sqlSession.update("myPageMapper.secession", memberNo);
}
<!-- 회원 탈퇴 -->
<update id="secession" parameterType="_int">
UPDATE MEMBER SET MEMBER_DEL_FL='Y' WHERE MEMBER_NO = #{memberNo}
</update>