본문 바로가기
05_Server (04. JSP 프로그래밍 구현)

[1-5] 회원서비스 마이페이지요청, 정보변경요청

by moca7 2024. 9. 9.

 

 

 

ㅁ 회원서비스

- 회원서비스 개발 세팅         

- 회원서비스_로그인          
- 회원서비스_로그아웃          
- 회원서비스_회원가입페이지로이동 

 

- 회원서비스_회원가입요청  <- 여기까지 했음.
- 회원서비스_마이페이지요청
- 회원서비스_정보변경요청
- 회원서비스_비번변경요청
- 회원서비스_회원탈퇴요청

 

 

 

 

ㅁ header.jsp에서 마이페이지로 이동 요청한다.

 

 
<%@ page import="com.br.web.member.model.vo.Member" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
   
<!-- Bootstrap 사용을 위한 CDN -->
<!-- ------------------------- -->
   
<style>
  header{height: 150px}
  header a{color:black;}
</style>

<%
  String contextPath = request.getContextPath();    //    "/web"
 
  Member loginUser = (Member)session.getAttribute("loginUser");
  // 해당 구문이 실행되는 시점
  // 로그인 요청 전 페이지 로드시 : null
  // 로그인 성공 후 페이지 로드시 : 조회된 데이터가 담겨있는 Member객체
 
  String alertMsg = (String)session.getAttribute("alertMsg");
  // 해당 구문이 실행되는 시점
  // 특정 서비스 요청 전 페이지 로드시 : null
  // 특정 서비스 요청 성공 후 페이지 로드시 : alert로 띄워줄 메세지
%>
 

<% if(alertMsg != null) { %>
<script>
  alert('<%=alertMsg%>');
</script>
<% session.removeAttribute("alertMsg"); } %>
 

<header class="row m-3">
  <div class="col-3 d-flex justify-content-center align-items-center">
    <a href="<%=contextPath%>"><img src="<%= contextPath %>/assets/image/goodee_logo.png"></a>
  </div>
  <div class="col-6"></div>
  <div class="col-3 d-flex justify-content-center align-items-center">

    <% if(loginUser == null) { %>
    <!-- case1. 로그인전 -->
    <form action="<%= contextPath %>/login.me" method="post">
      <table>
        <tr>
          <th>ID</th>
          <td><input type="text" name="userId" class="form-control form-control-sm" placeholder="Enter Your ID" required></td>
        </tr>
        <tr>
          <th>PWD</th>
          <td><input type="password" name="userPwd" class="form-control form-control-sm" placeholder="Enter Your PWD" required></td>
        </tr>
        <tr>
          <td colspan="2" align="center">
            <button type="submit" class="btn btn-secondary btn-sm">로그인</button>
            <button type="button" class="btn btn-secondary btn-sm" id="signup-btn">회원가입</button>
            <script>
              document.getElementById("signup-btn").addEventListener("click", () => {
                location.href = "<%=contextPath%>/signup.me";
              })
            </script>
          </td>
        </tr>
      </table>
    </form>
    <% }else { %>
    <!-- case2. 로그인후 -->
    <div>
      <b><%= loginUser.getUserName() %></b>님 환영합니다. <br><br>

      <a href="<%=contextPath%>/myinfo.me">마이페이지</a>
      <a href="<%=contextPath%>/logout.me">로그아웃</a>
    </div>
    <% } %>

  </div>
</header>
<nav class="navbar m-3 navbar-expand-sm bg-dark navbar-dark d-flex justify-content-center">
  <ul class="navbar-nav">
    <li class="nav-item">
      <a class="nav-link" href="#">Home</a>
    </li>
    <li class="nav-item">
      <a class="nav-link" href="#">공지사항</a>
    </li>
    <li class="nav-item">
      <a class="nav-link" href="#">일반게시판</a>
    </li>
    <li class="nav-item">
      <a class="nav-link" href="#">사진게시판</a>
    </li>
  </ul>
</nav>
 

 

 

- 로그인 후 보여지는 '마이페이지' 링크를 클릭하면 "/myinfo.me"라는 url mapping 값을 가지는 서블릿 클래스가 호출되게끔 작성한다.

 

 

 

 

ㅁ /webApp/src/main/java/com/br/web/member/controller에 MemberInfoController.java라는 서블릿을 만든다.

 

 
package com.br.web.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;


@WebServlet("/myinfo.me")
public class MemberInfoController extends HttpServlet {
 
    private static final long serialVersionUID = 1L;
       

    public MemberInfoController() {
        super();
    }


    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
   
        // 응답페이지 : /web/views/member/myInfo.jsp
        // 응답데이터 : 로그인한 회원 데이터 (HttpSession에 이미 담겨있음)
        request.getRequestDispatcher("/views/member/myInfo.jsp").forward(request, response);
   
    }


    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}
 

 

 

- 요청시 전달한 값이나 실행할 쿼리는 없다. 응답만 하면 된다.

- 마이페이지 요청을 보낸다는 것은 현재 로그인이 되어있다는 뜻이다.

header.jsp에서 '로그인 후'에 '마이페이지' 링크가 보여지기 때문이다.

- 마이페이지에서 응답할 데이터는 로그인한 회원 데이터인데,

로그인을 하면서 이미 session에 loginUser라는 key 값으로 로그인한 회원 객체가 담겨있다.

그래서 db에서 조회할 필요가 없다.

 

- 응답페이지로 /web/views/member/myInfo.jsp를 띄워준다.

이 페이지를 응답하는 url은 따로 존재하지 않는다. 최초로 이동할 때는 무조건 포워딩 방식으로 이동해야 한다.

- 이 응답페이지에서 필요한 응답데이터인 로그인한 회원 데이터는 session에 이미 담겨있다.

응답페이지에 가서 session에서 데이터를 꺼내서 각각의 영역에 출력만 해주면 된다.

 

 

 

 

ㅁ src/main/webapp/views/member에 myInfo.jsp를 만든다.

 

 

 

 

 

 

- 아래는 myInfo.jsp다.

 
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

  <div class="container p-3">

    <!-- Header, Nav start -->
    <%@ include file="/views/common/header.jsp" %>
    <!-- Header, Nav end -->

    <!-- Section start -->
    <section class="row m-3" style="min-height: 500px">

      <div class="container border p-5 m-4 rounded">
        <h2 class="m-4">마이페이지</h2>
       
        <form action="" method="" class="m-4">
          <table class="table">
            <tr>
              <th>* 아이디</th>
              <td><input type="text" class="form-control" placeholder="Enter Your ID" name="userId" value="<%= loginUser.getUserId() %>" readonly></td>
              <td></td>
            </tr>
            <tr>
              <th>* 이름</th>
              <td><input type="text" class="form-control" placeholder="Enter Your Name" name="userName" value="<%= loginUser.getUserName() %>" required></td>
              <td></td>
            </tr>
            <tr>
              <th>&nbsp;&nbsp;전화번호</th>
              <td><input type="text" class="form-control" placeholder="Enter Your Phone (- include)" name="phone" value='<%= loginUser.getPhone() == null ? "" : loginUser.getPhone() %>'></td>
              <td></td>
            </tr>
            <tr>
              <th>&nbsp;&nbsp;이메일</th>
              <td><input type="text" class="form-control" placeholder="Enter Your Email (@ include)" name="email" value='<%= loginUser.getEmail() == null ? "" : loginUser.getEmail() %>'></td>
              <td></td>
            </tr>
            <tr>
              <th>&nbsp;&nbsp;주소</th>
              <td><input type="text" class="form-control" placeholder="Enter Your Address" name="address" value='<%= loginUser.getAddress() == null ? "" : loginUser.getAddress() %>'></td>
              <td></td>
            </tr>
            <tr>
              <th>&nbsp;&nbsp;관심분야</th>
              <td>
                <input type="checkbox" name="interest" value="운동" id="sports">
                <label for="sports">운동</label>
                <input type="checkbox" name="interest" value="등산" id="climibing">
                <label for="climibing">등산</label>
                <input type="checkbox" name="interest" value="낚시" id="fishing">
                <label for="fishing">낚시</label>
                <input type="checkbox" name="interest" value="요리" id="cooking">
                <label for="cooking">요리</label>
                <input type="checkbox" name="interest" value="게임" id="game">
                <label for="game">게임</label>
                <input type="checkbox" name="interest" value="영화" id="movie">
                <label for="movie">영화</label>
              </td>
 
              <script>
                $(function() {
 
                  let interest = '<%=loginUser.getInterest() == null ? "" : loginUser.getInterest()%>' //  ""  |  "운동,등산"
                 
                  $(":checkbox").each(function(idx, el) {        // el : 순차적으로 접근되는 체크박스 요소 객체
                                                                                     // el.value : 접근되는 체크박스의 value값("운동", "등산", "낚시", ...)
                    if(interest.indexOf(el.value) != -1){
                      $(el).prop("checked", true);
                    }                                    
 
                  })      
                 
                })
              </script>
 
              <td></td>
            </tr>
          </table>
          <br>
          <div align="center">
            <button type="submit" class="btn btn-outline-primary btn-sm">정보변경</button>
            <button type="button" class="btn btn-outline-warning btn-sm" data-toggle="modal" data-target="#changePwdModal">비밀번호변경</button>
            <button type="button" class="btn btn-outline-danger btn-sm" data-toggle="modal" data-target="#resignModal">회원탈퇴</button>
          </div>
        </form>
      </div>

    </section>
    <!-- Section end -->

    <!-- Footer start -->
    <%@ include file="/views/common/footer.jsp" %>
    <!-- Footer end -->

  </div>

  <!-- 비밀번호 변경용 Modal -->
  <div class="modal" id="changePwdModal">
    <div class="modal-dialog">
      <div class="modal-content">
 
        <!-- Modal Header -->
        <div class="modal-header">
          <h4 class="modal-title">비밀번호 변경</h4>
          <button type="button" class="close" data-dismiss="modal">&times;</button>
        </div>
 
        <!-- Modal body -->
        <div class="modal-body">
          <form action="<%= contextPath %>/updatePwd.me" method="post">
            <input type="hidden" name="userId" value="<%= loginUser.getUserId() %>">
            <table align="center">
              <tr>
                <th>* 현재 비밀번호</th>
                <td><input type="password" class="form-control" name="userPwd" required></td>
              </tr>
              <tr>
                <th>* 변경할 비밀번호</th>
                <td><input type="password" class="form-control" name="updatePwd" required></td>
              </tr>
              <tr>
                <th>* 변경할 비밀번호 재입력</th>
                <td><input type="password" class="form-control" required></td>
              </tr>
              <tr>
                <td colspan="2" style="text-align:center; padding-top: 10px;">
                  <button type="submit" class="btn btn-warning btn-sm">비밀번호 변경</button>
                </td>
              </tr>
            </table>
          </form>
        </div>
 
      </div>
    </div>
  </div>

  <!-- 회원탈퇴용 Modal -->
  <div class="modal" id="resignModal">
    <div class="modal-dialog">
      <div class="modal-content">
 
        <!-- Modal Header -->
        <div class="modal-header">
          <h4 class="modal-title">회원탈퇴</h4>
          <button type="button" class="close" data-dismiss="modal">&times;</button>
        </div>
 
        <!-- Modal body -->
        <div class="modal-body">
          <form action="<%= contextPath %>/delete.me" method="post">
            <table align="center">
              <tr>
                <th colspan="2">
                  탈퇴 후 복구가 불가능합니다. <br>
                  정말로 탈퇴하시겠습니까?
                </th>
              </tr>
              <tr>
                <th>현재 비밀번호</th>
                <td><input type="password" class="form-control" name="userPwd" required></td>
              </tr>
              <tr>
                <td colspan="2" style="text-align:center; padding-top: 10px;">
                  <button type="submit" class="btn btn-danger btn-sm">회원탈퇴</button>
                </td>
              </tr>
            </table>
          </form>
        </div>
 
      </div>
    </div>
  </div>

</body>
</html>
 

 

 

- header와 footer에 include 지시어를 작성한다.

- 화면구현하며 만들었던 "마이페이지.html"의 body 태그 안 내용들을 복사해서 붙여넣기 한다.

- 아이디, 이름, 전화번호, 이메일, 주소 부분의 value 속성값을 'user01', '홍길동' 이렇게 정적으로 작성했었는데,

 출력식을 사용해서 loginUser 객체에서 getXXX 메소드로 뽑는다.

 

- 전화번호, 이메일, 주소는 필수 입력값이 아니다.

db로부터 조회했을 때 데이터가 없으면 이 필드들에는 null이 있다.

회원가입시 입력을 안했다면 db로부터 조회했을 때 데이터가 없으면 이 필드에 null이 있다.

- 그러면 value="null"이 되어서 null이 불필요하게 노출된다. 그러므로 삼항연산자를 사용한다.

 

 

 

 

 

 

- 관심분야는 텍스트 상자가 아니라 체크박스 형태로 되어있다.

이런 경우엔 script 구문을 사용해야 한다.

- 텍스트 상자의 경우 value 속성값만 주면 되지만,

체크박스나 라디오버튼은 그 요소들에 checked 속성을 부여해줘야 한다.

- script 구문을 이용해서 사용자가 선택했던 각각의 체크박스에 checked된 상태로 보여준다.

- jQuery 방식으로 $(function() { })으로 요소가 다 만들어지고 나서 바로 실행되게끔 한다.

 

- 체크박스들을 순차적으로 탐색하면서 로그인한 회원의 관심분야인지를 비교한다.

맞다면 checked 속성을 부여한다.

- 6개의 타입이 체크박스인 요소들에 일일이 접근하면서 비교한다.

순차 접근하고자 한다면 jQuery 메소드 중에 each() 메소드를 사용한다. 

each() 메소드로 각각의 요소에 순차적으로 접근하면서 그때마다 실행시킬 function()을 작성할 수 있다.

 

 

- : jQuery에서 필터 선택자를 나타내는 문자입니다. 필터 선택자는 특정 조건에 맞는 요소를 선택할 때 사용됩니다.

- :checkbox 는 이 필터 선택자 중 하나로, 현재 문서에서 모든 체크박스 요소를 선택합니다.

 

 

 

- interest.indexOf(el.value) != -1는 interest 문자열에 el.value가 포함되어 있는지 확인하는 조건입니다.

(interest는 문자열이다. String 타입의 배열을 컴마로 하나의 문자열로 만들어서 interest 변수에 대입했었다.)

- interest 문자열에서 el.value 값이 처음 나타나는 위치의 인덱스를 반환합니다.

- 만약 el.value가 interest에 포함되어 있다면, 그 위치의 인덱스를 반환하고, 포함되어 있지 않다면 -1을 반환합니다.

 

 

- interest.indexOf(el.value)는 자바스크립트 방식이고, jQuery 방식으로 선택하고 jQuery 메소드를 사용해서 interest.indexOf($(el).val()) 이렇게 작성해도 된다.

- $(el).prop("checked", true);는 jQuery 방식이고, 자바스크립트 방식으로 하면 el.checked = true; 이다.

 

 

 

ㅁ 메인페이지에서 로그인해보고 마이페이지를 클릭해서 localhost:8888/web/myinfo.me로 url이 잘 뜨는지, 마이페이지에 회원정보가 잘 뜨는지 확인한다.

 

 

 

 

 

======================================================================================

 

 

 

ㅁ 마이페이지에서 '회원정보변경' 버튼 클릭시 "/update.me"라는 url mapping 값을 가지는 서블릿 클래스를 호출한다.

 

 

- 아래는 myInfo.jsp다.

 
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

  <div class="container p-3">

    <!-- Header, Nav start -->
    <%@ include file="/views/common/header.jsp" %>
    <!-- Header, Nav end -->

    <!-- Section start -->
    <section class="row m-3" style="min-height: 500px">

      <div class="container border p-5 m-4 rounded">
        <h2 class="m-4">마이페이지</h2>
       
        <form action="<%= contextPath %>/update.me" method="post" class="m-4">
          <table class="table">
            <tr>
              <th>* 아이디</th>
              <td><input type="text" class="form-control" placeholder="Enter Your ID" name="userId" value="<%= loginUser.getUserId() %>" readonly></td>
              <td></td>
            </tr>
            <tr>
              <th>* 이름</th>
              <td><input type="text" class="form-control" placeholder="Enter Your Name" name="userName" value="<%= loginUser.getUserName() %>" required></td>
              <td></td>
            </tr>
            <tr>
              <th>&nbsp;&nbsp;전화번호</th>
              <td><input type="text" class="form-control" placeholder="Enter Your Phone (- include)" name="phone" value='<%= loginUser.getPhone() == null ? "" : loginUser.getPhone() %>'></td>
              <td></td>
            </tr>
            <tr>
              <th>&nbsp;&nbsp;이메일</th>
              <td><input type="text" class="form-control" placeholder="Enter Your Email (@ include)" name="email" value='<%= loginUser.getEmail() == null ? "" : loginUser.getEmail() %>'></td>
              <td></td>
            </tr>
            <tr>
              <th>&nbsp;&nbsp;주소</th>
              <td><input type="text" class="form-control" placeholder="Enter Your Address" name="address" value='<%= loginUser.getAddress() == null ? "" : loginUser.getAddress() %>'></td>
              <td></td>
            </tr>
            <tr>
              <th>&nbsp;&nbsp;관심분야</th>
              <td>
                <input type="checkbox" name="interest" value="운동" id="sports">
                <label for="sports">운동</label>
                <input type="checkbox" name="interest" value="등산" id="climibing">
                <label for="climibing">등산</label>
                <input type="checkbox" name="interest" value="낚시" id="fishing">
                <label for="fishing">낚시</label>
                <input type="checkbox" name="interest" value="요리" id="cooking">
                <label for="cooking">요리</label>
                <input type="checkbox" name="interest" value="게임" id="game">
                <label for="game">게임</label>
                <input type="checkbox" name="interest" value="영화" id="movie">
                <label for="movie">영화</label>
              </td>
              <script>
                $(function() {
                  let interest = '<%=loginUser.getInterest() == null ? "" : loginUser.getInterest()%>';
                  // "" | "운동,등산"
                 
                  $(":checkbox").each(function(idx, el) { // el : 순차적으로 접근되는 체크박스 요소
                                                          // el.value : 접근되는 체크박스의 value값
                    if(interest.indexOf(el.value) != -1){
                      $(el).prop("checked", true);
                    }                                    
                  })      
                 
                })
              </script>
              <td></td>
            </tr>
          </table>
          <br>
          <div align="center">
            <button type="submit" class="btn btn-outline-primary btn-sm">정보변경</button>
            <button type="button" class="btn btn-outline-warning btn-sm" data-toggle="modal" data-target="#changePwdModal">비밀번호변경</button>
            <button type="button" class="btn btn-outline-danger btn-sm" data-toggle="modal" data-target="#resignModal">회원탈퇴</button>
          </div>
        </form>
      </div>

    </section>
    <!-- Section end -->

    <!-- Footer start -->
    <%@ include file="/views/common/footer.jsp" %>
    <!-- Footer end -->

  </div>

  <!-- 비밀번호 변경용 Modal -->
  <div class="modal" id="changePwdModal">
    <div class="modal-dialog">
      <div class="modal-content">
 
        <!-- Modal Header -->
        <div class="modal-header">
          <h4 class="modal-title">비밀번호 변경</h4>
          <button type="button" class="close" data-dismiss="modal">&times;</button>
        </div>
 
        <!-- Modal body -->
        <div class="modal-body">
          <form action="<%= contextPath %>/updatePwd.me" method="post">
            <input type="hidden" name="userId" value="<%= loginUser.getUserId() %>">
            <table align="center">
              <tr>
                <th>* 현재 비밀번호</th>
                <td><input type="password" class="form-control" name="userPwd" required></td>
              </tr>
              <tr>
                <th>* 변경할 비밀번호</th>
                <td><input type="password" class="form-control" name="updatePwd" required></td>
              </tr>
              <tr>
                <th>* 변경할 비밀번호 재입력</th>
                <td><input type="password" class="form-control" required></td>
              </tr>
              <tr>
                <td colspan="2" style="text-align:center; padding-top: 10px;">
                  <button type="submit" class="btn btn-warning btn-sm">비밀번호 변경</button>
                </td>
              </tr>
            </table>
          </form>
        </div>
 
      </div>
    </div>
  </div>

  <!-- 회원탈퇴용 Modal -->
  <div class="modal" id="resignModal">
    <div class="modal-dialog">
      <div class="modal-content">
 
        <!-- Modal Header -->
        <div class="modal-header">
          <h4 class="modal-title">회원탈퇴</h4>
          <button type="button" class="close" data-dismiss="modal">&times;</button>
        </div>
 
        <!-- Modal body -->
        <div class="modal-body">
          <form action="<%= contextPath %>/delete.me" method="post">
            <table align="center">
              <tr>
                <th colspan="2">
                  탈퇴 후 복구가 불가능합니다. <br>
                  정말로 탈퇴하시겠습니까?
                </th>
              </tr>
              <tr>
                <th>현재 비밀번호</th>
                <td><input type="password" class="form-control" name="userPwd" required></td>
              </tr>
              <tr>
                <td colspan="2" style="text-align:center; padding-top: 10px;">
                  <button type="submit" class="btn btn-danger btn-sm">회원탈퇴</button>
                </td>
              </tr>
            </table>
          </form>
        </div>
 
      </div>
    </div>
  </div>

</body>
</html>
 

 

 

- 마이페이지를 감싸고 있는 form에 action 속성값으로 "<%= contextPath %>/update.me"을, method 속성 값으로 "post"를 준다.

 

 

 

 

ㅁ/webApp/src/main/java/com/br/web/member/controller에 MemberUpdateController.java라는 서블릿 클래스를 만든다.

 

- 아래는 MemberUpdateController.java다.

 
package com.br.web.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 javax.servlet.http.HttpSession;

import com.br.web.member.model.service.MemberService;
import com.br.web.member.model.vo.Member;


@WebServlet("/update.me")
public class MemberUpdateController extends HttpServlet {

    private static final long serialVersionUID = 1L;
       
    public MemberUpdateController() {
        super();
    }


    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
   
        // 1. 요청
        request.setCharacterEncoding("utf-8");
 
        String userId = request.getParameter("userId");
        String userName = request.getParameter("userName");
        String phone = request.getParameter("phone");
        String email = request.getParameter("email");
        String address = request.getParameter("address");
        String[] interestArr = request.getParameterValues("interest");
 
        String interest = interestArr == null ? "" : String.join(",", interestArr);
       
        Member m = new Member(userId, userName, phone, email, address, interest);
       
        Member updateMem = new MemberService().updateMember(m);
 
       
        // 2. 응답
        if(updateMem == null) { // 실패
 
            // 응답페이지 : 에러페이지
            // 응답데이터 : "회원 정보 변경 실패" 메세지
            request.setAttribute("msg", "회원 정보 변경 실패");
            request.getRequestDispatcher("/views/common/errorPage.jsp").forward(request, response);
           
           
        }else { // 성공
           
            // session에 담겨있는 loginUser를 갱신된 회원객체로 변경
            HttpSession session = request.getSession();
            session.setAttribute("loginUser", updateMem);
           
            // 응답페이지 : 다시 마이페이지
            // 응답데이터 : "성공적으로 회원정보를 수정했습니다." alert 메세지
            session.setAttribute("alertMsg", "성공적으로 회원정보를 수정했습니다.");
           
            // /web/myinfo.me   url 재요청 => 마이페이지 포워딩
            response.sendRedirect(request.getContextPath() + "/myinfo.me");
           
        }
       
    }


    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}
 

 

 

- 회원가입하는 MemberInsertController 클래스와 비슷하다. 

차이점은 비밀번호 변경은 따로 빼놔서 비밀번호 부분이 없고, insert가 아닌 update 쿼리를 실행한다.

- SQL에서 UPDATE 쿼리를 실행하면, 데이터베이스는 수정된 행의 수를 반환합니다.

 

- userId는 readonly를 줘서 회원정보 변경이 불가능한 상태였다.

db에 update 쿼리문을 사용할 때 회원정보를 변경할 회원을 찾기 위한 조건으로 userId를 사용하기 위해 필요하다.

- userName은 required를 줘서 필수입력하게끔 했었다. 뭐라도 값이 넘어온다.

- 핸드폰번호와 이메일, 주소는 텍스트상자가 비어있으면 빈문자열이 넘어온다.

- 관심분야는 null일 수도 있고 문자열 배열일 수 있다. null이 아니라면 하나의 문자열로 합쳐준다.

 

- 다수의 데이터를 담기 위해 String 배열도 되지만 Member 객체에 담는다. 

기본 생성자로 Member 객체를 생성하고 setXXX 메소드로 담아도 되고,

내가 담을 데이터의 순서와 개수를 맞춰서 생성자를 또 만들어서 매개변수로 담아도 된다.

- Member.java에 가서 alt shift s + o로 생성자를 만들어준다.

 

 

 

 

 

 

ㅁ MemberService 메소드에 updateMember() 메소드를 만든다.

 

 
package com.br.web.member.model.service;

import static com.br.web.common.template.JDBCTemplate.close;
import static com.br.web.common.template.JDBCTemplate.commit;
import static com.br.web.common.template.JDBCTemplate.getConnection;
import static com.br.web.common.template.JDBCTemplate.rollback;

import java.sql.Connection;
import java.util.Map;

import com.br.web.member.model.dao.MemberDao;
import com.br.web.member.model.vo.Member;

public class MemberService {
   
    private MemberDao mDao = new MemberDao();
   
    public Member loginMember(String userId, String userPwd) {
 
        Connection conn = getConnection();
        Member loginUser = mDao.loginMember(conn, userId, userPwd);
        close(conn);
        return loginUser;
 
    }
 
   
    public int insertMember(Member m) {
 
        Connection conn = getConnection();
        int result = mDao.insertMember(conn, m);
       
        if(result > 0) {
            commit(conn);
        }else {
            rollback(conn);
        }
       
        close(conn);
       
        return result;
       
    }
 
   
    public Member updateMember(Member m) {
       
        Connection conn = getConnection();
       
        // 1. 회원정보 변경 (update)
        int result = mDao.updateMember(conn, m);
       
        Member updateMem = null;
 
 
        if(result > 0) {
 
            commit(conn);
 
            // 2. 갱신된 회원 조회 (select)
            updateMem = mDao.selectMemberById(conn, m.getUserId());
           
        }else {
            rollback(conn);
        }
 
       
        close(conn);
        return updateMem; // null(정보변경실패) | 갱신된회원객체(정보변경성공)
       
    }
   
}
 

 

 

- 정보 변경과 관련된 비즈니스 로직을 서비스 메소드 하나에서 다 진행하면 된다.

- service 클래스에서 각각의 기능별 비즈니스 로직을 처리하는 구문을 작성해야 한다.

- 항상 기능 단위로 service를 묶는다. 지금은 정보 변경이라는 기능을 구현하고 있다.

정보 변경 기능을 서비스의 하나의 메소드로 작업한다.

- 항상 기능당 service 메소드는 하나여야 한다. 그런데 실행쿼리는 여럿일 수 있다.

 

 

- 기능별로 주로 하나의 쿼리만을 실행하지만,

한 기능에 여러 쿼리가 실행될 때는 서비스 메소드 하나에, 각각의 쿼리를 실행하는 dao를 여러번 호출한다.

 

- service 클래스의 updateMember 메소드 하나에서 

dao의 updateMember() 메소드로 update 쿼리(회원정보 변경)를 실행하고,

dao의 selectMemberById() 메소드로 select 쿼리(갱신된 회원 조회)를 실행한다.

 

 

 

- 현재 session의 "loginUser"라는 key값에 담겨있는 Member 객체는 정보 변경이 되기 전의 Member 객체다.

그래서 정보변경이 된 후에 갱신된 회원 객체를 다시 조회해 온다.

그래야 session에 담겨있는 Member 객체를 바꿔치기할 수 있다.

 

- commit 이후에 session의 Member 객체를 바꿔치기 해야 한다.

commit 이후에 db로부터 갱신된 데이터를 조회해 온다.

- 만약 commit() 메소드를 호출하지 않으면, 데이터베이스 삽입, 수정, 삭제가 반영되지 않아서

다른 사용자가나 시스템이 이러한 변경 사항을 볼 수 없습니다.

 

 

 

- 이미 member-mapper.xml에 "loginMember"라는 key값을 가지는 entry는 있지만, 

그 쿼리로 회원데이터를 조회하기 위해서는 id와 비밀번호가 다 필요하다. 

지금은 id로만 조회해야하기 때문에 "selectMemberById"라는 dao 메소드를 만들어야 한다.

 

- id도 UNIQUE 제약조건 이기 때문에 회원번호와 같이 식별자로 쓸 수 있다.

 

 

 

 

ㅁ MemberDao 클래스에 updateMember() 메소드와 selectMemberById() 메소드를 만든다.

 

 
package com.br.web.member.model.dao;

import static com.br.web.common.template.JDBCTemplate.close;

import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.Properties;

import com.br.web.member.model.vo.Member;
 

public class MemberDao {
   
    private Properties prop = new Properties();
 
   
    public MemberDao() {
       
        String filePath = MemberDao.class.getResource("/db/mappers/member-mapper.xml").getPath();
       
        try {
            prop.loadFromXML(new FileInputStream(filePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
       
    }
 
   
    public Member loginMember(Connection conn, String userId, String userPwd) {
 
        // select문 => ResultSet (한 행, 한 회원) => Member객체
        Member m = null;
        PreparedStatement pstmt = null;
        ResultSet rset = null;
 
        String sql = prop.getProperty("loginMember");
       
        try {
            pstmt = conn.prepareStatement(sql); // 미완성된 sql문
            pstmt.setString(1, userId);
            pstmt.setString(2, userPwd);
            rset = pstmt.executeQuery();
           
            if(rset.next()) {
                m = new Member(rset.getInt("USER_NO")
                             , rset.getString("user_id")
                             , rset.getString("user_pwd")
                             , rset.getString("user_name")
                             , rset.getString("phone")
                             , rset.getString("email")
                             , rset.getString("address")
                             , rset.getString("interest")
                             , rset.getDate("enroll_date")
                             , rset.getDate("modify_date")
                             , rset.getString("status"));
            }
           
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            close(rset);
            close(pstmt);
        }
       
        return m;
       
    }
 
   
    public int insertMember(Connection conn, Member m) {
 
        // insert => 처리된 행 수
        int result = 0;
        PreparedStatement pstmt = null;
 
        String sql = prop.getProperty("insertMember");
       
        try {
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, m.getUserId());
            pstmt.setString(2, m.getUserPwd());
            pstmt.setString(3, m.getUserName());
            pstmt.setString(4, m.getPhone());
            pstmt.setString(5, m.getEmail());
            pstmt.setString(6, m.getAddress());
            pstmt.setString(7, m.getInterest());
           
            result = pstmt.executeUpdate();
           
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            close(pstmt);
        }
       
        return result;
    }
 
   
    public int updateMember(Connection conn, Member m) {
 
        // update문 => 처리된 행수가 돌아온다.
        int result = 0;
        PreparedStatement pstmt = null;
 
        String sql = prop.getProperty("updateMember");
 
       
        try {
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, m.getUserName());
            pstmt.setString(2, m.getPhone());
            pstmt.setString(3, m.getEmail());
            pstmt.setString(4, m.getAddress());
            pstmt.setString(5, m.getInterest());
            pstmt.setString(6, m.getUserId());
           
            result = pstmt.executeUpdate();
           
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            close(pstmt);
        }
       
        return result;
       
    }
 
   
    public Member selectMemberById(Connection conn, String userId) {
 
        // select => ResultSet (한행, 한회원) => Member
 
        Member m = null;
        PreparedStatement pstmt = null;
        ResultSet rset = null;
 
        String sql = prop.getProperty("selectMemberById");
 
       
        try {
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, userId);
            rset = pstmt.executeQuery();
           
            if(rset.next()) {
                m = new Member(rset.getInt("USER_NO")
                             , rset.getString("user_id")
                             , rset.getString("user_pwd")
                             , rset.getString("user_name")
                             , rset.getString("phone")
                             , rset.getString("email")
                             , rset.getString("address")
                             , rset.getString("interest")
                             , rset.getDate("enroll_date")
                             , rset.getDate("modify_date")
                             , rset.getString("status"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            close(rset);
            close(pstmt);
        }
       
        return m;
    }
   
}
 

 

 

- update, select 쿼리를 dao의 한 메소드에서 하지 않고, 각각 따로 메소드를 만들어서 한다. 

dao의 한 메소드가 하나의 쿼리만을 담당해야 한다. 그래야 나중에 재사용할 수 있다.

- update문을 실행하면 처리된 행 수가 돌아온다.

- select문을 실행하면 여기서는 한 행(한 회원)만 돌아온다.

 

 

 

 

 

 

ㅁ /webApp/src/main/java/db/mappers/member-mapper.xml에 쿼리문을 2개 작성한다.

 

 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>

    <entry key="loginMember">
        SELECT
                     USER_NO
                 , USER_ID
                 , USER_PWD
                 , USER_NAME
                 , PHONE
                 , EMAIL
                 , ADDRESS
                 , INTEREST
                 , ENROLL_DATE
                 , MODIFY_DATE
                 , STATUS
          FROM
                 MEMBER
         WHERE
                     USER_ID = ?
             AND USER_PWD = ?
             AND STATUS IN ('A', 'U')
    </entry>
   
    <entry key="insertMember">
        INSERT
          INTO MEMBER
          (
            USER_NO
          , USER_ID
          , USER_PWD
          , USER_NAME
          , PHONE
          , EMAIL
          , ADDRESS
          , INTEREST
          )
          VALUES
          (
            SEQ_UNO.NEXTVAL
          , ?
          , ?
          , ?
          , ?
          , ?
          , ?
          , ?
          )
    </entry>
 
   
    <entry key="updateMember">
        UPDATE
                     MEMBER
             SET
                     USER_NAME = ?
                   , PHONE = ?
                   , EMAIL = ?
                   , ADDRESS = ?
                   , INTEREST = ?
                   , MODIFY_DATE = SYSDATE
         WHERE
                     USER_ID = ?
    </entry>
 
   
    <entry key="selectMemberById">
        SELECT
                     USER_NO
                   , USER_ID
                   , USER_PWD
                   , USER_NAME
                   , PHONE
                   , EMAIL
                   , ADDRESS
                   , INTEREST
                   , ENROLL_DATE
                   , MODIFY_DATE
                   , STATUS
          FROM
                   MEMBER
         WHERE
                     USER_ID = ?
    </entry>

   
</properties>
 

 

 

- 메소드명을 따서 entry의 key값을 작성한다.

- MEMBER 테이블에 MODIFY_DATE라는 컬럼이 있다.

언제 마지막으로 정보 변경을 했는지 기록을 위해서 MODIFY_DATE도 SYSDATE로 UPDATE 한다.

 

 

 

 

ㅁ MemberUpdateController.java로 돌아온다.

 

 
package com.br.web.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 javax.servlet.http.HttpSession;

import com.br.web.member.model.service.MemberService;
import com.br.web.member.model.vo.Member;


@WebServlet("/update.me")
public class MemberUpdateController extends HttpServlet {

    private static final long serialVersionUID = 1L;
       
    public MemberUpdateController() {
        super();
    }


    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
   
        // 1. 요청
        request.setCharacterEncoding("utf-8");
        String userId = request.getParameter("userId");
        String userName = request.getParameter("userName");
        String phone = request.getParameter("phone");
        String email = request.getParameter("email");
        String address = request.getParameter("address");
        String[] interestArr = request.getParameterValues("interest");
        String interest = interestArr == null ? "" : String.join(",", interestArr);
       
        Member m = new Member(userId, userName, phone, email, address, interest);
       
        Member updateMem = new MemberService().updateMember(m);
 
       
        // 2. 응답
        if(updateMem == null) { // 실패
 
            // 응답페이지 : 에러페이지
            // 응답데이터 : "회원 정보 변경 실패" 메세지
            request.setAttribute("msg", "회원 정보 변경 실패");
            request.getRequestDispatcher("/views/common/errorPage.jsp").forward(request, response);
           
           
        }else { // 성공
           
            // session에 담겨있는 loginUser를 갱신된 회원객체로 변경
            HttpSession session = request.getSession();
            session.setAttribute("loginUser", updateMem);
           
            // 응답페이지 : 다시 마이페이지
            // 응답데이터 : "성공적으로 회원정보를 수정했습니다." alert 메세지
            session.setAttribute("alertMsg", "성공적으로 회원정보를 수정했습니다.");
           
            // /web/myinfo.me   url 재요청 => 마이페이지 포워딩
            response.sendRedirect(request.getContextPath() + "/myinfo.me");
           
        }
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}
 

 

 

- 에러페이지로 이동은 redirect가 아닌 forward로 한다.

갱신된 데이터를 보여줘야하는 것도 아닌 단순 페이지 요청이다.

redirect를 하면 새로운 요청이다.

- forward 아니면 redirect인데 이미 이 페이지를 응답하는 서블릿이 만들어져 있으면 서블릿을 재호출하면 된다.

 

 

- header.jsp에 String alertMsg = (String)session.getAttribute("alertMsg");가 있다.

alertMsg가 null이 아닐 경우에 <script>구문으로 한번 alert가 뜨고 

session.removeAttribute("alertMsg");로 다시 비워지게끔 작성해놨다.

- alert 메세지를 띄우고 싶으면 session에 "alertMsg"라는 key값으로 문자열을 담으면 된다. 

 

 

 

 

ㅁ 자바코드를 수정했으니 서버를 restart 한다.

- 서버가 재시작되면 session이 만료되므로 다시 로그인부터 시작해야 한다.

- 로그인하고 마이페이지로 이동해서 '회원 정보 변경' 버튼을 클릭해서 정상적으로 반영되었는지 확인한다.