쇼핑몰 웹사이트 만들어보기 - 회원탈퇴 기능

Shiba·2024년 8월 26일
0

프로젝트 및 일기

목록 보기
24/29

이제 고쳐야할 오류(오류라기보단 기능 확장)는 다음과 같다.

  1. 회원 탈퇴 기능이 없음
  2. 주문 내역 탭을 구현하지 않아 기능하지 않음
  3. 주문 취소 기능 구현해야됨

여기에 추가적으로 몇가지 기능들을 더 생각해봤다.(시간이 되면 여기까지 다 만들어보자)

  1. 찜한 상품을 볼 수 있는 페이지 만들기
  2. 리뷰를 상품 상세 정보에서 볼 수 있도록 하기
  3. 상품에 평점을 저장해서 상품 검색 시 상품 평점이 보이도록 하기
  4. 검색 후 정렬할 수 있는 기능 추가
  5. 홈 화면에 할인 중인 상품 추가
  6. 이벤트 슬라이드 카테고리 옆에 만들기(배너 삭제)

이번 시간에는 위 3개의 기능 확장을 해보는 것이 목표이다.

회원탈퇴 기능 구현

회원탈퇴 기능 구현은 쉽다. delete메소드를 만들고 컨트롤러로 연결하면 된다.

일줄 알았지만...스프링 시큐리티를 적용했기 때문에 위의 작업만 해서는 회원탈퇴가 원활하게 되지않았다. 코드를 살펴보면서 정리해보자

delete 메소드 작성

먼저, 위에서 말했듯이 delete메소드를 만들어준다.

MemoryUserRepository

@Override
    public boolean deleteUser(Users users) {
        if(users != null) {
            users = em.merge(users);
            em.remove(users);
            return true;
        }
        else return false;
    }

UserService

public boolean delete(Users users) { 
	return userRepository.deleteUser(users); 
}

삭제 함수를 만들었으니 이제 이것을 컨트롤러에 연결해주자.

컨트롤러 작성

UserController

 @GetMapping("/user/quit")
    public String quitPage(){
        return "/user/quit";
    }

    @PostMapping("/quitUser")
    public ResponseEntity<String> quitUser( HttpServletRequest request,
                                            @RequestParam(name = "reason") String reason,
                                            @RequestParam(name = "additional_comments") String comments,
                                            @AuthenticationPrincipal UserDetails userDetails) {
        ResponseEntity response;
        try {
                Users users = userService.findById(userDetails.getUsername());
                if(userService.delete(users)){
                    Complaint complaint = new Complaint();
                    complaint.setReason(reason);
                    complaint.setComments(comments);
                    complaintService.addComplaint(complaint);
                    response = ResponseEntity
                            .status(HttpStatus.CREATED)
                            .body("탈퇴가 완료되었습니다.");
                    // 세션 무효화 및 로그아웃
                    SecurityContextHolder.clearContext();
                    HttpSession session = request.getSession(false);
                    if (session != null) {
                        session.invalidate();
                    }
                }
                else{
                    response = ResponseEntity
                            .status(HttpStatus.CREATED)
                            .body("이미 탈퇴된 아이디입니다.");
                }
        } catch (Exception ex) {
            response = ResponseEntity
                    .status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("An exception occured due to " + ex.getMessage());
        }
        return response;
    }

    @GetMapping("/quitComplete")
    private String quitCompletePage(){
        return "/user/quitComplete";
    }

//세션 무효화 및 로그아웃 부분이 중요하다! 저 부분에서 세션을 무효화해주고 스프링 시큐리티에 저장해둔 내용들을 비움으로서 완벽하게 로그아웃을 시켜주어야 한다! 해주지 않는다면 user가 서버가 닫히기 전까지 살아있는 모습을 볼 수 있다...

또한 코드를 보면 불만 사항을 저장하는 데이터베이스 테이블을 만들어두고 저장을 하는 것을 볼 수 있다. 탈퇴 시에 불만사항을 선택하는 칸과 직접 작성하는 칸을 둠으로서 이를 받아내기 위함이다.(불만사항 엔티티, 리포지토리, 서비스는 생략)

프론트엔드 코드 작성 (feat.ChatGPT)

프론트엔드코드는 조건을 상세히 작성하니 챗 지피티가 아주 잘 만들어주어서 css에서 약간의 수정을 하고 그대로 사용하였다.

quit.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>회원 탈퇴</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0px;
            background-color: #333;
            color: #cccccc;
        }
        /*상단 바*/
        .header {
            background-color: #333;
            color: #fff;
            padding: 10px;
            height: 130px;
            display: flex;
            position: relative;
            min-width: 1200px;
        }

        /*로고가 좌측 상단에 위치하도록 조정*/
        #home_logo {
            display: inline-block;
            width: 270px;
            height: 90px;
        }

        /*선택자를 이용해 로고의 크기 조정*/
        #home_logo > img {
            width: 270px;
            height: 90px;
        }
        .container {
            max-width: 600px;
            margin: 0 auto;
            color: #222222;
            background-color: #ffffff;
            padding: 20px;
            box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
            border-radius: 5px;
        }
        h2 {
            color: #333;
        }
        label {
            display: block;
            margin-bottom: 8px;
            font-weight: bold;
        }
        select, textarea, button {
            width: 100%;
            padding: 10px;
            margin-bottom: 15px;
            border-radius: 5px;
            border: 1px solid #ccc;
        }
        button {
            background-color: #d9534f;
            color: white;
            font-size: 16px;
            border: none;
            cursor: pointer;
        }
        button:hover {
            background-color: #c9302c;
        }
    </style>
    <script>
        function handleSubmit(event) {
            event.preventDefault(); // 기본 폼 제출 동작 방지
            const form = event.target;

            // 폼 데이터를 객체로 생성
            const formData = new FormData(form);

            // Fetch API를 사용하여 비동기 요청 보내기
            fetch(form.action, {
                method: form.method,
                body: formData,
                headers: {
                    'X-Requested-With': 'XMLHttpRequest'
                }
            }).then(response => {
                if (response.ok) {
                    return response.text();
                } else {
                    throw new Error('네트워크 응답이 올바르지 않습니다.');
                }
            }).then(data => {
                alert(data);
                if(data === "탈퇴가 완료되었습니다."){
                    window.location.href = "/quitComplete";
                }
            })
                .catch(error => {
                    console.error('Error:', error);
                    if(error === 'Network response was not ok.')
                        alert('네트워크 오류.');
                });
        }
    </script>
</head>
<body>
<div class="header">
    <a href="/" id="home_logo">
        <img src="/images/icons/logo.png" alt="Home Logo"/>
    </a>
</div>
<div class="container">
    <h2>회원 탈퇴</h2>
    <form action="/quitUser" method="POST" onsubmit="handleSubmit(event)">
        <label for="reason">탈퇴 사유를 선택해 주세요:</label>
        <select id="reason" name="reason" required>
            <option value="">사유를 선택해 주세요</option>
            <option value="서비스가 불만족스러움">서비스가 불만족스러움</option>
            <option value="기능 부족">기능 부족</option>
            <option value="개인정보 보호 우려">개인정보 보호 우려</option>
            <option value="이용 빈도 낮음">이용 빈도 낮음</option>
            <option value="기타">기타</option>
        </select>

        <label for="additional-comments">추가적인 의견을 작성해 주세요:</label>
        <textarea id="additional-comments" name="additional_comments" rows="4" placeholder="여기에 의견을 작성해 주세요..."></textarea>

        <button type="submit">탈퇴하기</button>
    </form>
</div>
</body>
</html>

quitComplete.html

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>탈퇴 완료</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      margin: 0;
      padding: 0px;
      background-color: #333;
      color: #cccccc;
      height: 100vh;
    }

    /*상단 바*/
    .header {
      background-color: #333;
      color: #fff;
      padding: 10px;
      height: 130px;
      display: flex;
      position: relative;
      min-width: 1200px;
    }

    /*로고가 좌측 상단에 위치하도록 조정*/
    #home_logo {
      display: inline-block;
      width: 270px;
      height: 90px;
    }

    /*선택자를 이용해 로고의 크기 조정*/
    #home_logo > img {
      width: 270px;
      height: 90px;
    }
    .container {
      max-width: 400px;
      text-align: center;
      background-color: #ffffff;
      padding: 30px;
      box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
      border-radius: 5px;
      margin: 0 auto;
    }
    h2 {
      color: #333;
      margin-bottom: 20px;
    }
    p {
      color: #555;
      margin-bottom: 30px;
      line-height: 1.6;
    }
    #home {
      display: inline-block;
      padding: 10px 20px;
      background-color: rgba(86, 132, 203, 0.82);
      color: white;
      text-decoration: none;
      border-radius: 5px;
      transition: background-color 0.3s ease;
    }
    #home:hover {
      background-color: #31b0d5;
    }
  </style>
</head>
<body>
<div class="header">
  <a href="/" id="home_logo">
    <img src="/images/icons/logo.png" alt="Home Logo"/>
  </a>
</div>
<div class="container">
  <h2>탈퇴가 완료되었습니다</h2>
  <p>회원 탈퇴가 성공적으로 처리되었습니다.<br>이용해 주셔서 감사합니다.</p>
  <a id="home" href="/">홈으로 돌아가기</a>
</div>
</body>
</html>

테스트 결과!

탈퇴 시, 불만사항을 작성하도록 하고 탈퇴 후에 홈으로 이동할 수 있게 하였다. 탈퇴를 했으니 다시 내 정보를 들어가려고 하면 로그인이 필요하게된다.



회원이 정상적으로 사라졌고, 불만사항 테이블에 불만사항이 저장된 것을 확인할 수 있다.

profile
모르는 것 정리하기

0개의 댓글