1. 아이디 찾기
컨트롤러
@PostMapping("/FindUsernameByEmail")
public ModelAndView FindUsernameByEmail(String email) {
String username = memberService.FindUsernameByEmail(email);
ModelAndView view = new ModelAndView();
view.addObject("username", username);
view.setViewName("Member/ViewUsername");
return view;
}
서비스
//유저 아이디 찾기
public String FindUsernameByEmail(String email) {
MemberVO memberVO = memberRepository.findByEmail(email);
if (memberVO != null) {
return memberVO.getUsername();
}
return null;
}
jsp
<%@ page import="org.core.vo.MemberVO" %>
<%@ page import="org.member.MemberDTO" %>
<%@ page import="org.member.clothController.ClothDTO" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>
<body>
<h1>View Username Page</h1>
<p>
<c:set var="username" value="${username}"></c:set>
<c:choose>
<c:when test="${not empty username}">
고객님의 아이디는 [ <c:out value="${username}"/> ] 입니다.
</c:when>
<c:otherwise>
유저 아이디를 찾을 수 없습니다. 입력하신 이메일을 확인해주세요.
</c:otherwise>
</c:choose>
</p>
<p>
<a href="<c:url value='/LoginPage'/>">로그인</a>
</p>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
crossorigin="anonymous"></script>
</body>
</html>
2. 임시 비밀번호 생성
// 임시 비밀번호 생성기
public String makeTemporaryPassword(int passwordLength){
//비밀번호를 형성할 배열
char[] passwordChars = new char[]{
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
};
//글자 길이 지정
StringBuilder newPassword = new StringBuilder(passwordLength);
//입력한 숫자만큼의 길이의 비밀번호 생성
Random random = new Random();
for (int i = 0; i < passwordLength; i++) {
int randomIndex = random.nextInt(passwordChars.length);
newPassword.append(passwordChars[randomIndex]);
}
return newPassword.toString();
}
char 배열과 Random 클래스를 사용한 간단한 임시 비밀번호 생성기이다.
3. 임시 비밀번호로 변경
컨트롤러
@PostMapping("/UpdatePasswordByEmail")
public String FindUsernameByEmail(String username, String email) {
String foundedUsername = memberService.UpdatePasswordByEmail(username, email);
return "redirect:/prgForUpdatePasswordByEmail?username=" + foundedUsername;
} //prg Pattern
@GetMapping("/prgForUpdatePasswordByEmail")
public ModelAndView PrgForUpdatePasswordByEmail(String username) {
ModelAndView view = new ModelAndView();
view.addObject("username", username);
view.setViewName("Member/ChangeToTemporaryPassword");
return view;
}
서비스
//유저 비밀번호 변경하기
public String UpdatePasswordByEmail(String username, String email) {
MemberVO memberVO = memberRepository.findByUsernameAndEmail(username, email);
if (memberVO != null) {
String newPassword = makeTemporaryPassword(15);
log.info("New password: {}", newPassword);
memberVO.setPassword(passwordEncoder.encode(newPassword));
memberRepository.save(memberVO);
/**
* 유저 이메일로 비밀번호 전송하기
*/
return memberVO.getUsername();
}
return null;
}
jsp
<%@ page import="org.core.vo.MemberVO" %>
<%@ page import="org.member.MemberDTO" %>
<%@ page import="org.member.clothController.ClothDTO" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>
<body>
<h1>Change To Temporary Page</h1>
<p>
<c:choose>
<c:when test="${username ne 'null'}">
고객님의 비밀번호가 임시 비밀번호로 변경되었습니다.<br>
회원가입 시 입력하신 이메일로 임시 비밀번호가 전송되었으니 확인해주세요.
</c:when>
<c:otherwise>
유저 정보를 찾을 수 없습니다. 입력하신 아이디와 이메일을 확인해주세요.
</c:otherwise>
</c:choose>
</p>
<p>
<a href="<c:url value='/LoginPage'/>">로그인</a>
</p>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
crossorigin="anonymous"></script>
</body>
</html>
컨트롤러 부분
@PostMapping("/UpdatePasswordByEmail")
public String FindUsernameByEmail(String username, String email) {
String foundedUsername = memberService.UpdatePasswordByEmail(username, email);
return "redirect:/prgForUpdatePasswordByEmail?username=" + foundedUsername;
} //prg Pattern
@GetMapping("/prgForUpdatePasswordByEmail")
public ModelAndView PrgForUpdatePasswordByEmail(String username) {
ModelAndView view = new ModelAndView();
view.addObject("username", username);
view.setViewName("Member/ChangeToTemporaryPassword");
return view;
}
컨트롤러부분은 prg 패턴을 사용하여, 결과 창에서 새로고침을 눌러도 같은 작업이 반복되지 않도록 막았다.
4. 회원 이메일 정보 변경
컨트롤러
//회원 이메일 변경
@PostMapping("/UpdateEmailByUsername")
public String UpdateEmailByUsername(Principal principal, String newEmail) {
Boolean changeSuccess = principalService.UpdateEmailByUsername(principal.getName(), newEmail);
return "redirect:/logout";
}
서비스
public Boolean UpdateEmailByUsername(String username, String newEmail) {
MemberVO memberVO = principalRepository.findByUsername(username);
if (memberVO != null) {
memberVO.setEmail(newEmail);
principalRepository.save(memberVO);
return true;
}
return false;
}
js
$(function(){
$("#newEmail").on("focusout", function () {
checkEmail()
})
$("#ChangeEmailForm").on("submit", function(event){
event.preventDefault();
const duplicatedEmailField = $("#duplicatedEmailField")
if(duplicatedEmailField.html().trim() !== ""){
event.preventDefault();
} else {
$("#ChangeEmailForm")[0].submit();
}
})
$("#newEmail").on("input", function(){
$("#duplicatedEmailField").html("");
})
})
function checkEmail(){
const duplicatedEmailField = $("#duplicatedEmailField")
const email = $("#newEmail").val()
$.ajax({
type: "post",
url: "/AjaxExistByEmail",
data: {email: email},
dataType: "text",
success: function (response) {
if(response === "true"){
duplicatedEmailField.html("중복된 이메일입니다.").css("color", "red")
} else {
duplicatedEmailField.html("");
}
},
error: function (error) {
console.error("이메일 중복 검사 에러")
}
})
}
jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script type="text/javascript" src="/resources/js/ChangeEmailPage.js"></script>
</head>
<body>
<h1>Change Email Page</h1>
<form id="ChangeEmailForm" method="post" action="<c:url value='/UpdateEmailByUsername'/>">
New Email: <input type="email" id="newEmail" name="newEmail"><br>
<input type="submit" value="이메일 변경">
</form>
<span id="duplicatedEmailField"></span>
<a href="<c:url value="/MemberPage"/>">돌아가기</a>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
crossorigin="anonymous"></script>
</body>
</html>
5. 비밀번호 변경
컨트롤러
// 비밀번호 변경
@PostMapping("/UpdatePasswordByUsername")
public String UpdatePasswordByUsername(Principal principal, String newPassword) {
Boolean changeSuccess = principalService.UpdatePasswordByUsername(principal.getName(), newPassword);
return "redirect:/logout";
}
서비스
public Boolean UpdatePasswordByUsername(String username, String newPassword) {
MemberVO memberVO = principalRepository.findByUsername(username);
if (memberVO != null) {
memberVO.setPassword(passwordEncoder.encode(newPassword));
principalRepository.save(memberVO);
return true;
}
return false;
}
jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>
<body>
<h1>Change Password Page</h1>
<form method="post" action="<c:url value='/UpdatePasswordByUsername'/>">
New Password: <input type="text" name="newPassword"><br>
<input type="submit" value="비밀번호 변경">
</form>
<a href="<c:url value="/MemberPage"/>">돌아가기</a>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
crossorigin="anonymous"></script>
</body>
</html>
6. 회원 탈퇴
컨트롤러
@PostMapping("/withdrawByUsername")
public String withdrawByUsername(Principal principal) {
principalService.deleteByUsername(principal.getName());
return "redirect:/logout";
}
서비스
public void deleteByUsername(String username) {
principalRepository.deleteByUsername(username);
}
리포지토리
@Transactional
void deleteByUsername(String username);
jpa에서 crud 중 c, u, d를 직접 만들 때는 @Transactional을 붙여주어야 한다.
이유 - 데이터베이스 연산의 일관성과 무결성을 보장하기 위함
1. 원자성
- 처리 | not 처리 상태만 존재
2. 일관성
- 데이터를 삭제하면 관련된 모든 데이터 삭제
3. 격리성
- 동시에 실행되는 다른 트랜잭션으로부터 독립적
4. 내구성
- 완료되면 결과가 DB에 영구적으로 저장
## 반드시 리포지토리에 붙이는 것이 아니라, 여러 작업이 순차적으로 발생하는 서비스 메서드에도 붙임으로서 트랜잭션을 사용할 수도 있다.
7. 회원가입 시 중복 확인 ajax 개선
이전 코드
//유저 아이디 중복 검사
var username = $("#username").val();
if(username){
var existUsername = $("#existUsername")
$.ajax({
type: "post",
url: "<c:url value='/AjaxExistByUsername'/>",
data: {username: username},
dataType: "text",
success: function(response){
if(response){
existUsername.text('중복된 아이디입니다.')
}
else {
existUsername.text('')
}
},
error: function (error){
console.error("아이디 중복 체크 에러")
}
}
)
}//유저 아이디 중복 검사 끝
//유저 이메일 중복 검사
var email = $("#email").val();
if(email){
var existEmail = $("#existEmail")
$.ajax({
type: "post",
url: "<c:url value='/AjaxExistByEmail'/>",
data: {email: email},
dataType: "text",
success: function(response){
if(response){
existEmail.text("중복된 이메일입니다.")
}
else{
existEmail.text("");
}
},
error: function (error) {
console.error("이메일 중복 검사 에러")
}
})
}//이메일 중복 검사 끝
})
개선된 코드
//유저 아이디 중복 검사
$("#username").on("focusout", function (){
checkUsername()
})//유저 아이디 중복 검사 끝
//유저 이메일 중복 검사
$("#email").on("focusout", function () {
checkEmail()
})//이메일 중복 검사 끝
//아이디 칸 입력 시 경고창 삭제
$("#username").on("input", function(){
$("#existUsername").html('')
})
//이메일 칸 입력 시 경고창 삭제
$("#email").on("input", function(){
$("#existEmail").html('')
})
//제출 시 재확인 및 경고창 확인
$("#registerForm").on("submit", function(event){
checkUsername()
checkEmail()
if($("#existUsername").html().trim() !== "" || $("#existEmail").html().trim() !== ""){
event.preventDefault();
} else {
$("#registerForm")[0].submit();
}
})
function checkEmail(){
var email = $("#email").val();
var existEmail = $("#existEmail")
$.ajax({
type: "post",
url: "/AjaxExistByEmail",
data: {email: email},
dataType: "text",
success: function (response) {
if(response === "true"){
existEmail.html("중복된 이메일입니다.").css("color", "red")
} else {
existEmail.html("");
}
},
error: function (error) {
console.error("이메일 중복 검사 에러")
}
})
}
function checkUsername(){
var username = $("#username").val();
var existUsername = $("#existUsername")
console.log(username)
$.ajax({
type: "post",
url: "/AjaxExistByUsername",
data: {username: username},
dataType: "text",
success: function(response){
if(response === "true"){
existUsername.html('중복된 아이디입니다.').css("color", "red")
}
else {
existUsername.html('')
}
},
error: function (error){
console.error("아이디 중복 체크 에러")
}
}
)
}
기존 코드는 ajax만 있었지, 실제로 기능을 하진 못하고 있었다.
왜 이렇게 만들었지?
또한 변수 var로 하고 블록 밖에 선언을 해서 안에서 블록 단위인 var를 ajax 내에서 못 읽는 문제가 발생하고 있었다.
1. ajax 내로 변수 이동
2. ajax 경고 출력
3. 입력 시 경고 문구 삭제
4. 경고 문구 출력 시 subtmit 제한
이라는 기본적인 기능을 추가했다.
'개인프로젝트 > 기능프로그램_오늘뭐입지' 카테고리의 다른 글
20240523_메일 시스템(임시비밀번호 전송, 이메일 인증) (0) | 2024.05.23 |
---|---|
20240519_퍼센트 인코딩 (0) | 2024.05.19 |
20240518_에러페이지 (0) | 2024.05.19 |
20240518_로그인 실패 ajax + 위치 자동 출력&위치에 따른 지역 자동 출력 (0) | 2024.05.18 |
20240518_GPT 답변 구현하기(MSA(3)) (0) | 2024.05.18 |