로그인한 후 NickName 부분을 클릭하게 되면
회원정보를 수정하는 페이지로 이동하게 한다
그 부분을 구현하는 동안 알게 된 부분을 정리한 게시글
//절대경로로 내정보 페이지로 이동한다
//contextPath가 없으면 상대경로이지만 최상위를 명시해서 절대경로로 위치를 지정한다.
<a href="${contextPath}/member/myPage/info" id="nickname">${loginMember.memberNickName}</a>
<a href="/community/member/logout" id="logout-btn">로그아웃</a>
웹상 주소 : {contextPath}(최상위) /member /myPage /info
폴더상 주소 : webapp /WEB_INF /views / myPage-info.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%-- 문자열 관련 함수 (메서드 ) 제공 JSTL (el 형식으로 작성) --%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<!DOCTYPE html>
<html lang="en">
<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>
//header , footer는 main-style.css에서 적용하고 실직적인 content의 스타일 부분은 myPage-style.css에서 적용한다.
<link rel="stylesheet" href="${contextPath}/resources/css/main-style.css">
<link rel="stylesheet" href="${contextPath}/resources/css/myPage-style.css">
</head>
<body>
<main class="container">
//header 부분을 js로 호출해와 포함시키는 방식.
<jsp:include page="/WEB-INF/views/common/header.jsp"/>
<!-- 마이페지이지 - 내정보-->
<section class="myPage-content">
<!-- 왼쪽 사이드 메뉴 -->
<section class="left-side">
사이드 메뉴
<ul class="list-group">
<li><a href="#">프로필</a></li>
<li><a href="#">내 정보</a></li>
<li><a href="#">비밀번호 변경</a></li>
<li><a href="#">회원 탈퇴</a></li>
</ul>
</section>
<!-- 오른쪽 myPage 주요 내용 부분 -->
<section class="myPage-main">
<h1 class="myPage-title">내 정보</h1>
<span class="myPage-explanation">원하는 회원 정보를 수정 할 수 있습니다.</span>
//수정사항을 입력한 후에 전달이 필요해 만들어 두었다 .
//전달되는 값의 길이가 길어 get방식으로 보내면 주소창이 너무 길어 post보내는게 심미적 깔끔해 좋다
<form action="info" method="POST" name="myPage-form">
<div class="myPage-row">
<label for="">닉네임</label>
<input type="text" name="memberNickname" value="${loginMember.memberNickName}" maxlength="10">
</div>
<div class="myPage-row">
<label for="">전화번호</label>
<input type="text" name="memberTel" value="${loginMember.memberTell}" minlength="11" maxlength="11">
</div>
<%--주소 --%> <%--fn:split(문자열,'구분자)'--%>
<c:set var="addr" value="${fn:split(loginMember.memberAddress,',,')}"/>
<%--${loginMember.memberAddress} --%>
<div class="myPage-row info-title"><span>주소</span></div>
<div class="myPage-row info-address" >
<input type="text" name="memberAddress" value="${addr[0]}" maxlength="6">
<button type="button" id="info-address-btn">검색</button>
</div>
<div class="myPage-row info-address" >
<input type="text" name="memberAddress" value="${addr[1]}">
</div>
<div class="myPage-row info-address" >
<input type="text" name="memberAddress" value="${addr[2]}" >
</div>
<button id="info-update-btn">수정하기</button>
</form>
</section>
</section>
</main>
//footer부분을 호출해오는 js문법
<jsp:include page="/WEB-INF/views/common/footer.jsp"/>
</body>
</html>
데이터를 수정할 경우 POST방식으로 전달에 DB 업데이트 구문을 수정한다.
이 때 비밀번호등 암호화가 필요한 부분이 없어 암호화를 하는 필터인 EncryptFilter에 chain를 걸지 않아도 괜찮다.
@WebServlet("/member/myPage/info")
public class MyPageInfoServlet extends HttpServlet {
// 메인 페이지에서 닉네임 클릭시 요청되는 방식(GET)
// 언제 doGet을 하지 ? >> index.jsp에서 닉네임을 클릭해 내정보 페이지로 들어올 때
// 이 때 Session Scope로 loginMember 객체가 유지되고 있음으로 별다른 동작이 필요없다.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//path에 내 정보의 폴더 위치를 저장한다.
//Why? : 주소가 길어서 코드의 깔끔함을 위해
String path = "/WEB-INF/views/member/myPage-info.jsp";
//path(목표하는 위치)로 위임한다(forward)
//이때 community/index에서 community/member/info 으로 이동하는 거니깐
//resp.resend방식 Redirect 으로 전달하지 않아도 된다 (Redirect로 하면 uri가 그대로)
req.getRequestDispatcher(path).forward(req, resp);
}
// 회원 정보 수정 요청.(POST)
// 정보를 입력받아 DB와 연결해 수정하고 다시 전달
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//필요한 값(수정할 값)들을 가져온다
String memberNickname = req.getParameter("memberNickname");
String memberTell = req.getParameter("memberTel");
//주소 값이 여러칸으로 구성되어 있어서 배열로 저장받아야한다.
String[] address = req.getParameterValues("memberAddress");
String memberAddress = null;
// 배열에서 받아온 첫번째 배열이 값이 없으면 을 의미하지만
// ' ! '논리부정을 사용해 비어있지 않는 경우에는 진행한다
if (!address[0].equals("")) {
memberAddress = String.join(",,", address);
}
// 세션에서 로그인한 회원 정보 얻어오기
HttpSession session = req.getSession();
// 얕은 복사 (세션에 있는 회원 정보의 객체 주소!)
// -> loginMember를 수정하면 session의 로그인정보도 수정된다,.
//object로 반환하기 때문에 강제 형변환 필요.
Member loginMember = (Member) (session.getAttribute("loginMember"));
int memberNo = loginMember.getMemberNo(); // 회원 번호
// 업데이트 필요한 정보를 모아둔 Member 객체 생성
Member mem = new Member();
mem.setMemberNo(memberNo);
mem.setMemberNickName(memberNickname);
mem.setMemberTell(memberTell);
mem.setMemberAddress(memberAddress);
try {
MemberService service = new MemberService();
int result = service.updateMember(mem);
// 수정 성공 / 실패에 따른 메세지
if (result > 0) { // 수정 성공
session.setAttribute("message", "회원 정보가 수정되었습니다.");
// DB는 수정 되었지만!
// 로그인한 회원 정보가 담겨있는 Session 의 정보는 그대로다.
// ->동기화 작업 필요
//얕은 복사임으로 현재 loginMember객체에 입력받은 값을 그대로 대입하면 그게 바로 동기화다
loginMember.setMemberNickName(memberNickname);
loginMember.setMemberTell(memberTell);
loginMember.setMemberAddress(memberAddress);
} else { // 실패
session.setAttribute("message", "회원 정보 수정 실패");
}
// 성공 실패 여부 관계 없이 "내 정보" 화면 재요청
// 절대 경로
// resp.sendRedirect(req.getContextPath()+"/member/myPage/info");
// 상대 경로
//이 때는 이미 member/info에 있는 상태에서 화면을 수정하는 것이기 때문에
//send를 이용해야 한다.
resp.sendRedirect("info");
} catch (Exception e) {
e.printStackTrace();
}
}
}
전체적으로 다시 복기 하면서 적는 점
1. header , footer js로 include 한다
2. 주소같이 여러 칸으로 분리되어 작성되지만 하나의 name 속성을 가져 동일하게 저장된다 (배열저장)
3. 배열값으로 저장된 주소를 문자열 변수로 가공하는 과정이 필요 ( Split 활용이 편함 )
4. 입력받은 값을 수정할 때 PK(회원번호)를 사용한다( 유일성 체크조건 확인이 가장 좋기 때문에. )
5. 회원정보 수정 후 정상 수행 시 동기화작업이 필요하다.(입력받은 값을 loginMember에 대입해 기존의정보를 덮어 씌움)
6. Session Scope로 Message값으로 결과를 팝업해준다. (footer에서 message를 출현시킴)