2021. 12. 27. 21:27ㆍ스프링부트

myPage 에서 내 닉네임을 클릭했을 때 회원정보 수정페이지로 이동합니다
UserController에 내정보 메서드를 추가합니다
@GetMapping("/user/myInfo") public String myInfo() { return "user/myInfo"; }
user패키지에 jsp, css, js를 추가합니다
myInfo.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ include file="/WEB-INF/view/include/link.jsp" %> <link rel="stylesheet" href="/css/layout/nav.css" > <link rel="stylesheet" href="/css/user/myInfo.css" > <%@ include file="/WEB-INF/view/include/header.jsp" %> <div class="wrap"> <section class="title"> <h1>내 정보 수정</h1> </section> <main> <div class="info_box"> <h2>닉네임</h2> <div class="user_nickname">${SPRING_SECURITY_CONTEXT.authentication.principal.user.nickname }</div> <h2>비밀번호</h2> <div> <div class="input_box"> <div> <span>현재 비밀번호</span> <input class="present_password" type="password" placeholder="현재 비밀번호" > </div> <div> <span>신규 비밀번호</span> <input class="new_password" type="password" placeholder="신규 비밀번호" maxlength="20" > </div> <div> <span>신규 비밀번호 확인</span> <input class="new_password_check" type="password" placeholder="신규 비밀번호 확인" maxlength="20" > </div> </div> <div class="btn_box"> <button type="button" class="pwd_modify">변경</button> </div> </div> <h2>닉네임 변경</h2> <div> <div class="input_box"> <input type="text" class="nickname" name="nickname" required placeholder="변경하실 닉네임을 입력해 주세요"> </div> <div class="btn_box"> <button type="button" class="nickname_modify">수정</button> </div> </div> <h2>휴대폰 번호 변경</h2> <div> <div class="input_box"> <div> <input type="number" class="phone" name="phone" required placeholder="전화번호를 입력해 주세요" onkeypress="return lenthCheck(this, 11);" > </div> <div class="auth_num_box"> <input type="text" class="phone_auth_num" name="authNum" required placeholder="인증번호 입력"> <span class="timer_box"> <span>남은시간</span> <span class="timer"></span> </span> </div> </div> <div class="btn_box"> <div> <button type="button" class="auth_num_send">인증번호 전송</button> </div> <div class="auth_num_box"> <button type="button" class="phone_auth_btn">인증</button> </div> </div> </div> </div> </main> </div> <%@ include file="/WEB-INF/view/include/nav.jsp" %> <%@ include file="/WEB-INF/view/include/footer.jsp" %> <script type="text/javascript" src="/js/user/myInfo.js" ></script> </body> </html>
myInfo.css
@charset "utf-8"; .wrap { width: 90%; max-width: 1000px; margin: 0 auto; flex-wrap: wrap; } section.title { width: 100%; } section.title h1 { text-align: center; margin: 20px 0 20px 0; } /* main */ main { width: 80%; margin: 40px auto; border: 1px solid #ddd; border-radius: 15px; padding-bottom: 40px; } .info_box { margin: 0px auto; width: 90%; font-size: 1.5rem; } .info_box>div { display: flex; margin: 10px 0; } .info_box h2 { text-align: center; margin-top: 10px; } .info_box .input_box { width: 80%; text-align: right; margin-right: 5px; } .info_box .input_box > div, .info_box .btn_box > div { margin-top: 10px; } .info_box .user_nickname { justify-content: center; font-size: 1.8rem; } .info_box input { padding: 10px; font-size: 1.5rem; width: 100%; border: 1px solid #ddd; box-sizing: border-box; } .info_box input[type=password] { width: 75%; } .info_box button { padding: 11px; font-size: 1.5rem; background: #2AC1BC; color: #fff; border: none; border-radius: 10px; width: 100%; } .info_box .btn_box { width: 18%; display: flex; flex-direction: column; justify-content: end; } .input_box .auth_num_box { position: relative; } .auth_num_box { display: none; } .input_box .timer_box { position: absolute; left: 0; bottom: 0; transform: translate(10%, 120%); } @media ( max-width :1024px) { main { width: 90%; } .info_box input[type=password] { width: 70%; } } @media ( max-width : 767px) { .wrap { width: 100%; } main { width: 100%; } .info_box { width: 95%; } .info_box input[type=password] { width: 70%; } } @media ( max-width : 600px) { .info_box { width: 100%; margin-left: 10px; } .info_box input[type=password] { width: 60%; } .info_box .btn_box { width: 20%; } .info_box .input_box { width: 75%; } } @media ( max-width : 480px) { .info_box .btn_box { width: 25%; } .info_box .input_box { width: 70%; } }
myInfo.js
$(document).ready(function(){ // 유저 정보 변경하기 function infoModify(data) { $.ajax({ url: "/user/info", type: "PATCH", data: data }) .then(function(result){ swal(result); $("input").val(""); }) .fail(function(){ alert("에러가 발생했습니다"); }) } $(".pwd_modify").click(function() { const prevPassword = $(".present_password").val().replaceAll(" ", ""); const newPassword = $(".new_password").val().replaceAll(" ", ""); const newPasswordCheck = $(".new_password_check").val().replaceAll(" ", ""); if(!prevPassword || !newPassword) { return; } if(newPassword != newPasswordCheck) { swal('변경하실 비밀번호를 확인해 주세요'); return; } swal({ text: '비밀번호를 변경하시겠습니까?', buttons: ['취소', '변경하기'] }) .then(function(value){ if(value) { const data = { value: newPassword, valueType: "password", prevPassword : prevPassword }; infoModify(data); } }) }) $(".nickname_modify").click(function() { const nickname = $(".nickname").val(); if (!nickname) { return; } if (!nicknameCheck(nickname)) { swal('닉네임은 한글, 영어, 숫자만 4 ~10자리로 입력 가능합니다'); return; } const data = { value: nickname, valueType: "nickname" }; $.ajax({ url: "/overlapCheck", type: "get", data: data, }) .then(function(result){ if (result != 0) { swal('이미 사용중인 닉네임입니다'); } else { swal('닉네임을 ' + nickname + '으로 변경하시겠습니까?', { buttons: ['취소', '변경하기'], }) .then(function(value){ if (value) { infoModify(data); $(".user_nickname").text(nickname); } }) } }) .fail(function(){ alert("에러가 발생했습니다"); }) }); // 인증번호 전송 $(".auth_num_send").click(function(){ const phone = $(".phone").val(); if (!phoneCheck(phone)) { swal('휴대폰번호를 정확히 입력해주세요'); return; } if(!timer.status().isStart) { swal(timer.status().restartTime +' 초 후에 전송가능합니다'); return; } $.ajax({ url: "/send/authNum", type: "POST", data: {phone : phone} }) .then(function(result){ swal(result); $(".auth_num_box").fadeIn(100); timer.start(); }) .fail(function(result){ alert("에러") ; }) }) $(".phone_auth_btn").click(function(){ const authNum = $(".phone_auth_num").val().replaceAll(" ", ""); if(!authNum) { return; } const data = { authNum : authNum } $.ajax({ url: "/send/authNumCheck", type: "POST", data: data }) .then(function(){ swal({ text: "전화번호를 변경하시겠습니까?", buttons: ['취소', '변경'] }) .then(function(value){ if(value) { const data = { value: $(".phone").val(), valueType: "phone" }; infoModify(data); $(".auth_num_box").fadeOut(100); } }) }) .fail(function(result){ swal(result.responseText); }) }) })

유저정보 수정을 위한 컨트롤러 UserInfoController를 따로 만들어서 진행하였습니다
UserInfoController에 정보 수정 메서드를 추가합니다
@Autowired private BCryptPasswordEncoder encodePwd;
// 내 비밀번호, 닉네임 수정하기 @PatchMapping("/user/info") public ResponseEntity<String> modifyInfo(String value, String valueType, String prevPassword, @AuthenticationPrincipal LoginService user, HttpSession session) { // value = 변경할 값 // valueType = password, nickname, phone String username = user.getUser().getUsername(); String msg = ""; switch (valueType) { case "password": if(!encodePwd.matches(prevPassword, user.getPassword())) { return new ResponseEntity<String>("현재 비밀번호가 일치하지 않습니다", HttpStatus.OK); } value = encodePwd.encode(value); msg = "비밀번호가 변경되었습니다"; break; case "nickname": msg = "닉네임이 변경되었습니다"; break; case "phone": msg = "전화번호가 변경되었습니다"; session.setMaxInactiveInterval(0); session.setAttribute("authNum", null); break; } userService.modifyInfo(username, valueType, value); UserInfoSessionUpdate.sessionUpdate(value, valueType, user); return new ResponseEntity<String>(msg, HttpStatus.OK); }
한개의 컨트롤러에 넘어온 valueType에 따라 정보를 변경할 수 있게했습니다
정보를 변경 후 세션도 업데이트 해줍니다
Service와 DAO에 추가합니다
UserServiceImp
@Override public void modifyInfo(String username, String valueType, String value) { Map<String, Object> map = new HashMap<>(); map.put("username", username); map.put("valueType", valueType); map.put("value", value); userDAO.modifyInfo(map); }
UserDAO
@Override public void modifyInfo(Map<String, Object> map) { sql.update("user.modifyInfo", map); }
UserMapper
<update id="modifyInfo"> UPDATE BM_USER SET <if test="valueType == 'password'"> PASSWORD = #{value } </if> <if test="valueType == 'nickname'"> NICKNAME = #{value } </if> <if test="valueType == 'phone'"> PHONE = #{value } </if> WHERE USERNAME = #{username } </update>

휴대폰번호 변경은 인증번호를 휴대폰으로 보내야 하지만 문자보내기api가 유료라서 인증번호를 콘솔에서 확인하고 휴대폰번호를 변경 할 수 있게 했습니다
util.js에 타이머 함수를 추가합니다
const timer = (function(){ let time; // 타이머 시간 let timerStart; // setInterval 이름 let timerArr = []; // 실행중인 타이머 let isStart = true; // 재시작 가능여부 let restartTime; // 재시작 가능한 시간 let minute; let second; const start = function(){ if(!isStart) { return false; } // 타이머 초기화하기 const reset = function(){ time = 300; restartTime = 30; minute = Math.floor(time / 60); second = time % 60; } // 배열이 사이즈가 0이면 처음 실행 if(timerArr.length == 0) { reset(); } // 배열이 사이즈가 1이면 재실행 if(timerArr.length == 1) { // 재실행시 실행중인 타이머를 종료하고 다시 실행 clearInterval(timerArr.pop()); reset(); } isStart = false; $(".timer").text(minute + ' : ' + String(second).padStart(2,'0')); timerStart = setInterval(function(){ if(0 < restartTime) { restartTime--; } if(restartTime == 0) { isStart = true; } if(second == 0) { minute--; if(minute == -1) { for(i=0;i<timerArr.length;i++) { clearInterval(timerArr[i]); } timerArr = []; return; } second = 60; } second--; $(".timer").text(minute + ' : ' + String(second).padStart(2,'0')); }, 1000) timerArr.push(timerStart); } const status = function(){ return { isStart : isStart, restartTime : restartTime, } } return { start : start, status : status, } })();
UserInfoController에 인증번호 보내기 메서드를 추가합니다
// 인증번호 보내기 @PostMapping("/send/authNum") private ResponseEntity<String> authNum(String phone, String email, HttpSession session){ String authNum = ""; for(int i=0;i<6;i++) { authNum += (int)(Math.random() * 10); } System.out.println("인증번호 : " + authNum); // 전화번호로 인증번호 보내기 추가 if(phone != null) { System.out.println("전화번호로 인증번호 보내기"); // 이메일로 인증번호 보내기 } else if(email != null) { System.out.println("이메일로 인증번호 보내기"); } Map<String, Object> authNumMap = new HashMap<>(); long createTime = System.currentTimeMillis(); // 인증번호 생성시간 long endTime = createTime + (300 *1000); // 인증번호 만료시간 authNumMap.put("createTime", createTime); authNumMap.put("endTime", endTime); authNumMap.put("authNum", authNum); session.setMaxInactiveInterval(300); session.setAttribute("authNum", authNumMap); return new ResponseEntity<String>("인증번호가 전송되었습니다", HttpStatus.OK); }
인증번호 6자리를 생성하고 생성시간, 만료시간을 map에 담아 세션에 저장합니다

전화번호 입력 후 인증번호 전송 버튼을 클릭하면 인증번호 입력박스와 타이머가 나타납니다
컨트롤러에 인증번호 확인 메서드를 추가합니다
// 인증번호가 맞는지 확인 @PostMapping("/send/authNumCheck") private ResponseEntity<String> authNumCheck(String authNum, HttpSession session){ Map<String, Object> sessionAuthNumMap = (Map<String, Object>) session.getAttribute("authNum"); String msg = ""; if(sessionAuthNumMap == null) { msg = "인증번호를 전송해주세요"; return new ResponseEntity<String>(msg, HttpStatus.BAD_REQUEST); } // 인증번호 만료시간 long endTime = (long) sessionAuthNumMap.get("endTime"); // 현재시간이 만료시간이 지났다면 if(System.currentTimeMillis() > endTime) { msg = "인증시간이 만료되었습니다"; session.setAttribute(authNum, null); session.setMaxInactiveInterval(0); return new ResponseEntity<String>(msg, HttpStatus.BAD_REQUEST); } // 인증번호 String sessionAuthNum = (String) sessionAuthNumMap.get("authNum"); if(!authNum.equals(sessionAuthNum)) { msg = "인증번호가 일치하지 않습니다"; return new ResponseEntity<String>(msg, HttpStatus.BAD_REQUEST); } else { // 인증번호가 일치하면 return new ResponseEntity<String>(HttpStatus.OK); } }
세션에 저장된 인증번호Map을 꺼내 확인후 알맞는 메세지를 출력합니다

알맞는 인증번호 입력시 전화번호를 변경 할 수 있습니다
변경 후 세션에 전화번호도 업데이트 할 수 있게 if문을 하나 더 추가합니다
if문 아래에 세션에 저장하는 부분은 필요없기 때문에 주석처리 하였습니다
public class UserInfoSessionUpdate { public static void sessionUpdate(String value, String valueType, LoginService user) { ServletRequestAttributes attr = (ServletRequestAttributes)RequestContextHolder.currentRequestAttributes(); // HttpSession session = attr.getRequest().getSession(); LoginService loginService = (LoginService) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); if(valueType.equals("nickname")) { loginService.getUser().setNickname(value); } else if(valueType.equals("password")) { loginService.getUser().setPassword(value); } else if(valueType.equals("point")) { int point = loginService.getUser().getPoint() + Integer.parseInt(value); loginService.getUser().setPoint(point); } else if(valueType.equals("phone")) { loginService.getUser().setPhone(value); } // SecurityContext sc = SecurityContextHolder.getContext(); // // sc.setAuthentication(new UsernamePasswordAuthenticationToken(loginService, null, user.getAuthorities())); // // session.setAttribute("SPRING_SECURITY_CONTEXT", sc); } }
'스프링부트' 카테고리의 다른 글
스프링부트+jsp로 배달사이트 만들기-39 비밀번호 찾기, 비밀번호 변경 (0) | 2022.01.04 |
---|---|
스프링부트+jsp로 배달사이트 만들기-38 이메일보내기(아이디 찾기,비번찾기) (0) | 2021.12.29 |
스프링부트+jsp로 배달사이트 만들기-36 카카오아이디로 로그인 (0) | 2021.12.23 |
스프링부트+jsp로 배달사이트 만들기-35 네이버아이디로 로그인 (0) | 2021.12.23 |
스프링부트+jsp로 배달사이트 만들기-34 구글아이디로 로그인 (1) | 2021.12.22 |