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 |