기록

*78일차 (비밀번호 변경 / 관리자회원 조회 / 권한변경 / 검색) 본문

학원/강의

*78일차 (비밀번호 변경 / 관리자회원 조회 / 권한변경 / 검색)

pringspring 2022. 5. 18. 18:33

@비밀번호 변경

 

1. 비번변경 버튼 추가 (memberView.jsp)

<input type="button" value="비밀번호수정" onclick="location.href='<%= request.getContextPath() %>/member/passwordUpdate';"/>

 

2.비번 서블릿 생성 (PasswordUpdateServlet.java)

  • doGet | doPost 사용
package 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 common.HelloMvcUtils;
import member.model.dto.Member;
import member.model.service.MemberService;

/**
 * Servlet implementation class PasswordUpdateServlet
 */
@WebServlet("/member/passwordUpdate")
public class PasswordUpdateServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private MemberService memberService = new MemberService();
	
	/**
	 * 패스워드 수정폼 요청
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.getRequestDispatcher("/WEB-INF/views/member/passwordUpdate.jsp")
			.forward(request, response);
	}

	/**
	 * 패스워드 수정 요청
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try {
			// 1. 사용자입력값 처리
			String memberId = request.getParameter("memberId");
			String oldPassword = HelloMvcUtils.encrypt(request.getParameter("oldPassword"), memberId);
			String newPassword = HelloMvcUtils.encrypt(request.getParameter("newPassword"), memberId);
			
			System.out.println("memberId = " + memberId);
			System.out.println("oldPassword = " + oldPassword);
			System.out.println("newPassword = " + newPassword);
			
			// 2. 업무로직 - 기존비밀번호가 일치하는 경우에만 비밀번호를 수정
			Member member = memberService.findByMemberId(memberId);
			String msg = "";
			String location = request.getContextPath();
			if(member != null && oldPassword.equals(member.getPassword())) {
				// 비밀번호 수정
				Member updateMember = new Member();
				updateMember.setMemberId(memberId);
				updateMember.setPassword(newPassword);
				int result = memberService.updatePassword(updateMember);
				msg = "비밀번호를 성공적으로 변경했습니다.";
				location += "/member/memberView";
			}
			else {
				msg = "기존 비밀번호가 일치하지 않습니다.";
				location += "/member/passwordUpdate";
			}
			
			// 3. 리다이렉트처리
			request.getSession().setAttribute("msg", msg);
			response.sendRedirect(location);
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
		
	}

}

 

3.비번 jsp 생성 (PasswordUpdate.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/views/common/header.jsp" %>

	<section id=enroll-container>
		<h2>비밀번호 변경</h2>
		<form 
			name="passwordUpdateFrm" 
			action="<%=request.getContextPath()%>/member/passwordUpdate" 
			method="post" >
			<table>
				<tr>
					<th>현재 비밀번호</th>
					<td><input type="password" name="oldPassword" id="oldPassword" required></td>
				</tr>
				<tr>
					<th>변경할 비밀번호</th>
					<td>
						<input type="password" name="newPassword" id="newPassword" required>
					</td>
				</tr>
				<tr>
					<th>비밀번호 확인</th>
					<td>	
						<input type="password" id="newPasswordCheck" required><br>
					</td>
				</tr>
				<tr>
					<td colspan="2" style="text-align: center;">
						<input type="submit"  value="변경" />
					</td>
				</tr>
			</table>
			<input type="hidden" name="memberId" value="<%= loginMember.getMemberId() %>" />
		</form>
	</section>
	<script>
	newPasswordCheck.onblur = () => {
		if(newPassword.value !== newPasswordCheck.value){
			alert("두 비밀번호가 일치하지 않습니다.");
			return false; // 폼 유효성 검사에서 사용
		}	
		return true;
	};
	
	document.passwordUpdateFrm.onsubmit = () => {
		// password 영문자/숫자/특수문자!@#$%^&*()
		if(!/^[A-Za-z0-9!@#$%^&*()]{4,}$/.test(oldPassword.value)){
			alert("기존 비밀번호는 영문자/숫자/특수문자!@#$%^&*()로 4글자 이상이어야 합니다.");
			return false;
		}
		if(!/^[A-Za-z0-9!@#$%^&*()]{4,}$/.test(newPassword.value)){
			alert("새 비밀번호는 영문자/숫자/특수문자!@#$%^&*()로 4글자 이상이어야 합니다.");
			return false;
		}
		if(!newPasswordCheck.onblur()){
			return false; // 폼 제출을 방지
		}
	}	
	</script>
<%@ include file="/WEB-INF/views/common/footer.jsp" %>

 

  • id는 노출할 필요없어서 hidden
  • 평문으로는 비교불가라 암호화함

 

4. updatePassword 생성 (MemberService.java)

	public int updatePassword(Member member) {
		int result = 0;
		Connection conn = getConnection();
		try {
			result = memberDao.updatePassword(conn, member);
			commit(conn);
		} catch (Exception e) {
			rollback(conn);
			throw e;
		} finally {
			close(conn);
		}
		return result;
	}
  • alt + shift + z → try~catch

 

 

 

5. updatePassword 생성 (MemberDAO)

	public int updatePassword(Connection conn, Member member) {
		int result = 0;
		PreparedStatement pstmt = null;
		String sql = prop.getProperty("updatePassword");
		try {
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, member.getPassword());
			pstmt.setString(2, member.getMemberId());
			result = pstmt.executeUpdate();
		} catch (Exception e) {
			throw new MemberException("비밀번호 수정 오류!", e);
		} finally {
			close(pstmt);
		}
		return result;
	}
  • 6번에서 ?가 2개이므로 2개 채워줌

 

6.properties에 관련 작성

updateMemberRole = update member set member_role = ? where member_id = ?
  • 홍길동 비번 2345

 

 

 

 

@관리자의 회원조회

  • 관리자일때 할 수 있는 기능들

 

1.header.jsp

<% if(loginMember != null && loginMember.getMemberRole() == MemberRole.A) { %>
<li class="admin"><a href="<%= request.getContextPath() %>/admin/memberList">회원관리</a></li>
<% } %>
  • admin일때만 회원관리가 보임

 

 

2.admin은 별개의 package에서 관리할 것

  • AdminMemberListServlet
  • doGet
		try {
			// 1. 업무로직
			List<Member> list = memberService.findAll();
			System.out.println("list = " + list);
			
			// 2. view단 처리
			request.setAttribute("list", list);
			request.getRequestDispatcher("/WEB-INF/views/admin/memberList.jsp")
				.forward(request, response);
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}

 

 

3. findAll 생성 (MemberService.java)

	public List<Member> findAll() {
		Connection conn = getConnection();
		List<Member> list = memberDao.findAll(conn);
		close(conn);
		return list;
	}

 

4. findAll 생성 (MemberDao.java)

public List<Member> findAll(Connection conn) {
		PreparedStatement pstmt = null;
		ResultSet rset = null;
		List<Member> list = new ArrayList<>();
		String sql = prop.getProperty("findAll");
		
		try {
			pstmt = conn.prepareStatement(sql);
			rset = pstmt.executeQuery();
			while(rset.next()) {
				Member member = handleMemberResultSet(rset);
				list.add(member);
			}
		} catch (Exception e) {
			throw new MemberException("관리자 회원목록 조회 오류", e);
		} finally {
			close(rset);
			close(pstmt);
		}
		return list;
	}
  • 1건 조회시 member객체 하나 or null 리턴
  • n건 조회시 여러건의 member객체를 가진 list or 빈 list

 

*ResultSet을 받아서 맴버객체로 반환 (리팩토리)

  • 우클릭 - Refactor - Extract Method

 

5.memberList.jsp

<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/views/common/header.jsp" %>
<%
	List<Member> list = (List<Member>) request.getAttribute("list");
%>
<!-- 관리자용 admin.css link -->
<link rel="stylesheet" href="<%=request.getContextPath()%>/css/admin.css" />
<style>
div#search-container {width: 100%; margin:0 0 10px 0; padding:3px; background-color: rgba(0, 188, 212, 0.3);}
div#search-memberId {display: inline-block;}
div#search-memberName{display:none;}
div#search-gender{display:none;}
</style>
<section id="memberList-container">
	<h2>회원관리</h2>	
	<div id="search-container">
    	<label for="searchType">검색타입 :</label> 
        <select id="searchType">
            <option value="member_id">아이디</option>		
            <option value="member_name">회원명</option>
            <option value="gender">성별</option>
        </select>
        <div id="search-memberId" class="search-type">
            <form action="<%=request.getContextPath()%>/admin/memberFinder">
                <input type="hidden" name="searchType" value="member_id"/>
                <input type="text" name="searchKeyword"  size="25" placeholder="검색할 아이디를 입력하세요."/>
                <button type="submit">검색</button>			
            </form>	
        </div>
        <div id="search-memberName" class="search-type">
            <form action="<%=request.getContextPath()%>/admin/memberFinder">
                <input type="hidden" name="searchType" value="member_name"/>
                <input type="text" name="searchKeyword" size="25" placeholder="검색할 이름을 입력하세요."/>
                <button type="submit">검색</button>			
            </form>	
        </div>
        <div id="search-gender" class="search-type">
            <form action="<%=request.getContextPath()%>/admin/memberFinder">
                <input type="hidden" name="searchType" value="gender"/>
                <input type="radio" name="searchKeyword" value="M" checked> 남
                <input type="radio" name="searchKeyword" value="F"> 여
                <button type="submit">검색</button>
            </form>
        </div>
    </div>
	
	<table id="tbl-member">
		<thead>
			<tr>
				<th>아이디</th>
				<th>이름</th>
				<th>회원권한</th>
				<th>성별</th>
				<th>생년월일</th>
				<th>이메일</th>
				<th>전화번호</th>
				<th>주소</th>
				<th>취미</th>
				<th>가입일</th>
			</tr>
		</thead>
		<tbody>
<%
		if(list != null && !list.isEmpty()){
			for(Member member : list){
%>			
			<tr>
				<td><%= member.getMemberId() %></td>
				<td><%= member.getMemberName() %></td>
				<td>
					<select class="member-role" data-member-id="<%= member.getMemberId() %>">
						<option value="<%= MemberRole.A %>" <%= member.getMemberRole() == MemberRole.A ? "selected" : "" %>>관리자</option>
						<option value="<%= MemberRole.U %>" <%= member.getMemberRole() == MemberRole.U ? "selected" : "" %>>일반회원</option>
					</select>
				</td>
				<td><%= member.getGender() != null ? member.getGender() : "" %></td>
				<td><%= member.getBirthday() != null ? member.getBirthday() : "" %></td>
				<td><%= member.getEmail() != null ? member.getEmail() : "" %></td>
				<td><%= member.getPhone() %></td>
				<td><%= member.getAddress() != null ? member.getAddress() : "" %></td>
				<td><%= member.getHobby() != null ? member.getHobby() : "" %></td>
				<td><%= member.getEnrollDate() %></td>
			</tr>			
<%
			}
		}
		else {
%>			
			<tr>
				<td colspan="10">조회된 회원이 없습니다.</td>
			</tr>
<%
		}
%>		
		</tbody>
	</table>
</section>
<form 
	action="<%= request.getContextPath() %>/admin/memberRoleUpdate" 
	name="updateMemberRoleFrm"
	method="POST">
	<input type="hidden" name="memberId" />
	<input type="hidden" name="memberRole" />
</form>

<script>
searchType.addEventListener('change', (e) => {
	const {value} = e.target; // 구조분해할당
	console.log(value);
	
	document.querySelectorAll(".search-type").forEach((div) => {
		div.style.display = "none";
	});
	let id = "";
	switch(value){
		case "member_id": id = "search-memberId"; break; 
		case "member_name": id = "search-memberName"; break; 
		case "gender": id = "search-gender"; break; 
	}
	document.querySelector(`#\${id}`).style.display = "inline-block";
});


document.querySelectorAll(".member-role").forEach((select) => {
	select.addEventListener('change', (e) => {
		// console.dir(e.target);
		// console.log(e.target.dataset.memberId); // key값을 조회시에는 camelcasing으로 참조 
		// console.log(e.target.value); // "U" "A"
		const memberId = e.target.dataset.memberId;
		const memberRole = e.target.value;
		
		// jsp에서 js의 Template String문법 사용시 반드시 escaping처리할 것
		// (jsp의 EL문법과 충돌)
		if(confirm(`[\${memberId}]의 권한을 [\${memberRole}]로 변경하시겠습니까?`)){
			const frm = document.updateMemberRoleFrm;
			frm.memberId.value = memberId;
			frm.memberRole.value = memberRole;
			frm.submit();
		}
		else {
			e.target.querySelector("[selected]").selected = true;
		}
		
	});
});
</script>
<%@ include file="/WEB-INF/views/common/footer.jsp" %>

 

 

@권한변경

document.querySelectorAll(".member-role").forEach((select) => {
	select.addEventListener('change', (e) => {
		// console.dir(e.target);
		// console.log(e.target.dataset.memberId); // key값을 조회시에는 camelcasing으로 참조 
		// console.log(e.target.value); // "U" "A"
		const memberId = e.target.dataset.memberId;
		const memberRole = e.target.value;
		
		// jsp에서 js의 Template String문법 사용시 반드시 escaping처리할 것
		// (jsp의 EL문법과 충돌)
		if(confirm(`[\${memberId}]의 권한을 [\${memberRole}]로 변경하시겠습니까?`)){
			const frm = document.updateMemberRoleFrm;
			frm.memberId.value = memberId;
			frm.memberRole.value = memberRole;
			frm.submit();
		}
		else {
			e.target.querySelector("[selected]").selected = true;
		}
		
	});
  • 각각의 태그에 대해 배열이 넘어옴

 

@검색

1.검색기능추가 form (memberList.jsp)

<div id="search-container">
    	<label for="searchType">검색타입 :</label> 
        <select id="searchType">
            <option value="member_id">아이디</option>		
            <option value="member_name">회원명</option>
            <option value="gender">성별</option>
        </select>
        <div id="search-memberId" class="search-type">
            <form action="<%=request.getContextPath()%>/admin/memberFinder">
                <input type="hidden" name="searchType" value="member_id"/>
                <input type="text" name="searchKeyword"  size="25" placeholder="검색할 아이디를 입력하세요."/>
                <button type="submit">검색</button>			
            </form>	
        </div>
        <div id="search-memberName" class="search-type">
            <form action="<%=request.getContextPath()%>/admin/memberFinder">
                <input type="hidden" name="searchType" value="member_name"/>
                <input type="text" name="searchKeyword" size="25" placeholder="검색할 이름을 입력하세요."/>
                <button type="submit">검색</button>			
            </form>	
        </div>
        <div id="search-gender" class="search-type">
            <form action="<%=request.getContextPath()%>/admin/memberFinder">
                <input type="hidden" name="searchType" value="gender"/>
                <input type="radio" name="searchKeyword" value="M" checked> 남
                <input type="radio" name="searchKeyword" value="F"> 여
                <button type="submit">검색</button>
            </form>
        </div>
    </div>

 

 

2. AdminMemberFinderListServlet

  • /admin/memberFinder
  • doGet
  • 결과를 html로 반환 → jsp에서 처리
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 1. 사용자입력값처리
		String searchType = request.getParameter("searchType"); // member_id member_name gender
		String searchKeyword = request.getParameter("searchKeyword");
		Map<String, String> param = new HashMap<>();
		param.put("searchType", searchType);
		param.put("searchKeyword", searchKeyword);
		System.out.println("param = " + param);
		
		// 2. 업무로직
		List<Member> list = memberService.findBy(param);
		System.out.println("list = " + list);
		
		// 3. view단처리
		request.setAttribute("list", list);
		request.getRequestDispatcher("/WEB-INF/views/admin/memberList.jsp")
			.forward(request, response);
	
	}
  • select * from member where member_id like '%abc%'
  • select * from member where member_name like '%박%'
  • select * from member where gender like 'M'
  •  
  • select * from member where # like ?
  • jdbc에는 테이블명/컬럼명을 대체해주는 기능이 없음 
  • #을 이용한 이유 : 문자열의 replace를 이용하여 값을 대체함

 

 

3.MemberDao

public List<Member> findBy(Connection conn, Map<String, String> param) {
		PreparedStatement pstmt = null;
		ResultSet rset = null;
		List<Member> list = new ArrayList<>();
		String sql = prop.getProperty("findBy");
		sql = sql.replace("#", param.get("searchType"));
		System.out.println("sql = " + sql);
		try {
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, "%" + param.get("searchKeyword") + "%");
			rset = pstmt.executeQuery();
			while(rset.next()) {
				Member member = handleMemberResultSet(rset);
				list.add(member);
			}
		} catch (Exception e) {
			throw new MemberException("관리자 회원검색 오류", e);
		} finally {
			close(rset);
			close(pstmt);
		}
		return list;
	}