SpringBoot 프로젝트

Spring Boot - 관리자 페이지 (2)

orin602 2024. 11. 25. 15:10

저번글의 관리자 로그인 및 로그아웃 구현에 이어서 이번 글에서는 회원관리에 대해서 기능을 구현하고, 설명하려고 합니다. 부족해도 좋게 봐주세요 :)

 

adminMain.html에서 작성해 놓은

<!-- 회원관리 섹션 -->
<div class="admin-section">
    <h3 class="clickable" onclick="toggleContent(this)">회원 관리</h3>
    <div class="content-list" style="display: none;">
        <a th:href="@{/admin-customer-list}">회원리스트</a><br>
    </div>
</div>

<a th:href="@{/admin-customer-list}">회원리스트</a> a링크를 통해서 /admin-customer-list URL로 GET 요청이 전송됩니다.

 

// 회원관리 페이지
@GetMapping("/admin-customer-list")
public String allCustomerList(HttpSession session, Model model) {
    Member admin = (Member)session.getAttribute("admin");
    if(admin == null) {
        model.addAttribute("message", "로그인 페이지로 이동");
        model.addAttribute("text", "회원관리를 위해 로그인해주세요.");
        model.addAttribute("messageType", "info");

        return "admin/admin_login";
    }
    // 회원 목록을 가져오는 로직 구현
    List<Member> members = memberService.getAllMembers();
    model.addAttribute("members", members);
    return "admin/section/customer_list"; // 뷰 이름
}
  • Member admin = (Member)session.getAttribute("admin"); : session 객체에서 현재 로그인된 관리자의 정보를 admin 변수에 저장합니다.
  • List<Member> members = memberService.getAllMembers(); : 전체 회원 목록을 가져오고, 반환된 members 리스트를 model.addAttribute("members", members); 를 통해 모델에 추가합니다.

 -- getAllMembers() 메서드 (repository, serviceimpl)

- Repository
// 전체 회원목록 조회
@Query(value="SELECT * FROM member ORDER BY signup_date DESC", nativeQuery=true)
List<Member> getAllMember();

- ServiceImpl
// 관리자용
@Override
public List<Member> getAllMembers() {
    return memberRepo.getAllMember();
}

 

customer_list.html

<div class="all-container">
	<h1>회원 관리</h1>
	<label for="searchMember"></label>
    <input type="text" id="searchMember" placeholder="회원 검색 ( ID를 입력하세요 )">
	<div class="customer-list">
		<table border="1">
		    <thead>
		        <tr>
		            <th>ID</th>
		            <th>Email</th>
		            <th>이름</th>
		            <th>회원코드</th>
		            <th>가입일</th>
		            <th>회원 탈퇴 여부</th>
		        </tr>
		    </thead>
		    <tbody id="memberTableBody">
		        <!-- 전체 회원 리스트를 여기에 동적으로 채웁니다 -->
		        <tr th:each="member : ${members}">
		            <td th:text="${member.id}"></td>
		            <td th:text="${member.email}"></td>
		            <td th:text="${member.name}"></td>
		            <td>
		                <span th:text="${member.membercode}"></span>
		                <button class="update-btn" type="button" th:alt="${member.membercode}" 
		                	th:data-memberid="${member.id}" th:data-membercode="${member.membercode}" 
		                	onclick="updateMemberCode(this)">수정</button>
		            </td>
		            <td th:text="${member.signupDate}"></td>
		            <td>
		            	<span th:text="${member.withdrawalRequest == 0 ? 'X' : 'O'}"></span>
		                <button class="delete-btn" type="button" th:alt="${member.withdrawalRequest}"
		                	th:data-memberid="${member.id}" th:data-withdrawalRequest="${member.withdrawalRequest}"
		                onclick="deleteMember(this)">회원탈퇴</button>
		            </td>
		        </tr>
		    </tbody>
		</table>
	</div>
</div>

html

+ 회원 검색을 실시간으로 필터링

<label for="searchMember"></label>
<input type="text" id="searchMember" placeholder="회원 검색 ( ID를 입력하세요 )">
// 검색 입력에 따른 실시간 필터링 기능
$(document).ready(function() {
    $('#searchMember').on('input', function() {
        const searchValue = $(this).val().toLowerCase();
        $('#memberTableBody tr').filter(function() {
            $(this).toggle($(this).find('td:first').text().
            	toLowerCase().indexOf(searchValue) > -1);
        });
    });
});
  • $(document).ready(function() {... : 문서가 완전히 로드된 후에 코드를 실행합니다. jQuery로 DOM을 조작할 때 필수적으로 사용되는 구문입니다.
  • $('#searchMember').on('input', function() {... : #searchMember(검색 입력 필드)에 사용자가 글자를 입력할 때마다 input 이벤트가 발생합니다. on('input', : 입력 필드에 변화가 있을 때마다 호출됩니다.
  • const searchValue = $(this).val().toLowerCase(); : 현재 입력 필드에 있는 텍스트 $(this).val()를 가져옵니다. .toLowerCase();를 사용하여 대소문자 구분 없이 검색할 수 있도록 변환합니다.
  • $('#memberTableBody tr').filter(function() {... : #memberTableBody는 회원 목록이 포함된 테이블의 tbody 요소로 가정됩니다. tr은 테이블의 각 행(row)을 나타내며, filter()는 각 행에 대해 조건을 검사하는 함수입니다.
  • $(this).toggle($(this).find('td:first').text().toLowerCase().indexOf(searchValue) > -1); : $(this)는 현재 행(tr)을 참조하고, .find('td:first')는 그 행에서 첫 번째 td 요소를 찾습니다..text()는 해당 셀의 텍스트(회원 ID)를 추출합니다 .toLowerCase()를 사용하여 대소문자 구분 없이 비교합니다. .indexOf()는 텍스트 내에서 searchValue가 포함된 위치를 찾습니다.(-1은 찾을 수 없음 >>>  searchValue가 해당 텍스트에 포함된 경우로 간주하여 true를 반환.)

 

 

+ 회원코드 수정

<button class="update-btn" type="button" th:alt="${member.membercode}" 
    th:data-memberid="${member.id}" th:data-membercode="${member.membercode}" 
    onclick="updateMemberCode(this)">수정</button>

버튼 클릭 시 updateMemberCode(button)함수 호출

// 회원코드 수정 함수
function updateMemberCode(button) {
    const memberId = button.getAttribute('data-memberid'); 
    const currentMemberCode = button.getAttribute('th:alt'); 

    Swal.fire({
        title: '회원코드를 수정합니다.',
        input: 'number',
        inputLabel: '새로운 회원코드를 입력하세요.',
        inputPlaceholder: '0 또는 1을 입력하세요.',
        showCancelButton: true,
        confirmButtonText: '수정',
        cancelButtonText: '취소',
        preConfirm: (newMemberCode) => {
            if (!newMemberCode || newMemberCode < 0 || newMemberCode > 1) {
                Swal.showValidationMessage('올바른 회원코드를 입력하세요. (0 또는 1)');
                return false; // 유효성 검사 실패 시 false 반환
            }
            return newMemberCode; // 유효성 검사 통과 시 새로운 회원코드 반환
        }
    }).then((result) => {
        if (result.isConfirmed) {
            // AJAX 요청을 통해 서버에 업데이트 요청을 보냄
            $.ajax({
                url: `/update-membercode`,
                type: 'post',
                data: { 
                    id: memberId, // 회원 ID 추가
                    newMemberCode: result.value // 새로운 회원코드를 포함
                },
                success: function(response) {
                    Swal.fire({
	                    title: '성공',
	                    text: response,
	                    icon: 'success'
	                }).then(() => {
	                    location.reload(); // 확인 버튼 클릭 시 페이지 새로고침
	                });
                },
                error: function(xhr) {
                    // 오류 발생 시 처리
	                console.error('Error details:', xhr.status, xhr.statusText); // 오류 로그
	                if (xhr.status === 401) {
	                    Swal.fire({
	                        title: '권한 오류',
	                        text: '로그인 후 다시 시도하세요.',
	                        icon: 'warning'
	                    }).then(() => {
	                        window.location.href = '/admin/admin_login'; // 관리자 로그인 페이지로 리다이렉트
	                    });
	                } else {
	                    Swal.fire('오류', '회원코드 수정에 실패했습니다. 다시 시도해주세요.', 'error');
	                }
                }
            });
        }
    });
}

 

  • button.getAttribute() : 버튼에 포함된 th:data-memberid th:data-membercode, th:alt속성을 가져와 해당 정보를 memberId와 currentMemberCode 변수에 저장합니다.
  • input: 'number', : 숫자만 입력되도록 합니다.
  • preConfirm: (newMemberCode) => {...} : if (!newMemberCode || newMemberCode < 0 || newMemberCode > 1) { 함수에서 새로운 회원코드가 0 또는 1인지 확인합니다. 그렇지 않으면 유효성 검사 메시지를 표시하고, 올바른 값을 입력할 때까지 수정이 이루어지지 않도록 합니다.

 

repository, controller, service 메서드

/* Repository */
// 특정 회원 조회
@Query(value="SELECT * FROM member WHERE id =:id", nativeQuery=true)
Member findMemberById(@Param("id") String id);

/* ServiceImpl */
// 회원코드 수정 메서드
@Override
public void updateMemberCode(String id, int memberCode) {
    Member member = memberRepo.findMemberById(id);
    if (member != null) {
        member.setMembercode(memberCode);
        memberRepo.save(member); // 변경된 회원 정보를 저장
    }
}

/* Controller */
// 회원코드 수정
@PostMapping("/update-membercode")
public ResponseEntity<String> updateMemberCode(HttpSession session, @RequestParam String id,
        @RequestParam int newMemberCode, Model model) {
    Member admin = (Member) session.getAttribute("admin");

    if (admin == null) {
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                .body("로그인후 가능한 기능입니다."); // 401 Unauthorized 응답
    }

    memberService.updateMemberCode(id, newMemberCode); // 서비스 메서드 호출
    return ResponseEntity.ok("회원코드가 수정되었습니다."); // 성공 메시지 반환
}
  • memberService.updateMemberCode(id, newMemberCode); 메서드를 호출하여 실제로 회원의 회원코드를 수정합니다. 이 메서드는 @RequestParam String id@RequestParam int newMemberCode를 통해 받아온 값을 받아 해당 회원의 정보를 업데이트하는 로직을 처리합니다

잘못된 숫자를 입력했을 경우
hello를 관리자(membercode = 1)로 수정
db에도 반영된 결과