1.회원가입-백엔드
엔드포인트는 signup이다.
그러므로 controller를 다음과 같이 설정했다.
(관련 있는 부분만 골랐다. 회원가입과 관련 없는 부분은 불러오지 않았다.)
@GetMapping("/signup") // 회원가입 페이지로 이동하는 컨트롤러.
public String gosignup() {
return "signup";
}
// 회원가입 페이지에서 요청을 받아옴.
// ResponseEntity:Spring Framework에서 제공하는 클래스. http 응답을 나타낸다.
@PostMapping("/signup")
public ResponseEntity<String> signup(@RequestBody memberDTO memberDTO) {
try {
memberService.save(memberDTO);
// 회원가입이 완료되었다는 신호를 보낸다.
return ResponseEntity.ok("회원가입이 완료되었습니다.");
} catch (Exception e) {
// 오류 신호를 보낸다.
return ResponseEntity.status(500).body("회원가입 중 오류가 발생했습니다.");
}
}
// 회원가입 페이지에서, 중복 check에 관한 요청을 받아옴.
@PostMapping("/checkDuplicateId")
public ResponseEntity<Boolean> checkDuplicateId(@RequestBody String memberId) {
try {
// 중복되지 않은 경우에 true.
boolean isDuplicate = memberService.idCheck(memberId) != null;
return ResponseEntity.ok(isDuplicate);
} catch (Exception e) {
return ResponseEntity.status(500).body(false);
}
}
// id중복 체크를 하기 위한 controller 코드.
// service의 idCheck을 통해 중복된 id check을 한다.
// 데이터를 requestparam을 통해 받아온다.
@PostMapping("/member/idcheck")
@ResponseBody
public String idCheck(@RequestParam("memberId") String memberId) {
// 아이디를 디비에서 체크하기 위해 memberservice에서 함수를 만든다.
String checkResult = memberService.idCheck(memberId);
return checkResult;
}
// 이메일 중복 체크를 하기 위한 controller 코드이다.
@PostMapping("member/emailcheck")
@ResponseBody
public String emailCheck(@RequestParam("email") String email) {
// 이메일을 디비에서 체크하기 위해 memberservice에서 함수를 만든다.
String emailResult = memberService.emailCheck(email);
return emailResult;
}
보면 알겠지만, 단순히 페이지에 관한 get,post 이외에도
id/이메일 중복 체크를 위한 코드도 있다.
그런 다음, service를 다음과 같이 설정했다.
package com.example.finalproject.finalproject.service;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.finalproject.finalproject.dto.memberDTO;
import com.example.finalproject.finalproject.entity.MemberEntity;
import com.example.finalproject.finalproject.repository.memberRepository;
@Service
@Component
public class memberservice {
/*
* dto와 entity의 관계
* service의 코드들을 잘 보기 전에, dto,entity의 관계를 잘 볼 필요가 있다.
* 1.entity는 실제 디비와 매핑되는 핵심 클래스이다.
* 테이블이 가지지 않는 컬럼을 필드로 가져서는 안된다
* entity는 데이터베이스 영속성을 목적으로 사용되기 때문에 request,response값을 전달하는 클래스로 쓰지 말것.
*
* 2.dto는 레이어간 데이터 교환이 이뤄질 수 있도록 하는 객체이다.
* 디비에서 데이터를 얻어, service나 controller등으로 보낼 때 사용한다.
*
* 3.entity를 직접 반환할 경우에는 엔터티의 이름이 변경될 경우, 추가 작업이 필요할 수 있다.
* 또한, 보안 문제도 있고, 필요한 데이터만 전송하기 어렵다.
*
*
* 4.컨트롤러에서는 dto의 형태로 데이터를 받아 서비스에 전달한다.
* 5.서비스에서는 컨트롤러에서 받은 DTO를 Entity로 변환하고, 필요한 작업을 수행한 뒤에 Repository에 Entity를
* 전달한다.
*
*/
// service 객체에 쓰일 repository를 정의한다.
// repository에 jpa가 있기 때문에 꼭 정의를 해야 한다.
@Autowired
private final memberRepository memberRepository;
// memberRepository가 null인 상태에서 save 메서드를 호출하려 하면 오류가 난다. 그래서 이 코드를 추가.
@Autowired
public memberservice(memberRepository memberRepository) {
this.memberRepository = memberRepository;
}
// 받아온 데이터들을 저장하는 메소드이다.
public void save(memberDTO memberDTO) {
// repository의 save 메서드 호출.(entity를 넘겨야 한다.)
// 1.dto를 entity로 변환한다.(dto 클래스에 구현)
try {
MemberEntity memberEntity = MemberEntity.toMemberEntity(memberDTO);
memberRepository.save(memberEntity); // 이렇게 레포지토리로 데이터를 save시킨다.
}
// 2.save 메서드를 호출한다.(jpa에서 호출한다.)
// 3.이 쿼리를 통해 데이터베이스 내에서 쿼리를 만들어 주는 것이다.
catch (Exception e) {
e.printStackTrace();
}
}
public memberDTO login(memberDTO memberDTO) {
// 로그인을 수행할 때 수행되는 함수이다.
// 1.회원이 입력한 아이디로 db에서 조회를 한다.
// Optional은 memberentity를 한번 더 감싸는 개념이다.
Optional<MemberEntity> findById = memberRepository.findByMemberId(memberDTO.getMemberId());
// 조회 결과가 있다면
if (findById.isPresent()) {
// 일단 이 구문을 통해 데이터를 벗겨낸다.
MemberEntity memberEntity = findById.get();
// 2.db에서 조회한 비밀번호(entity)가 사용자가 입력한 비밀번호(dto)가 일치하는지 판단한다.
if (memberEntity.getPassword().equals(memberDTO.getPassword())) {
// 비밀번호 일치
// entity를 dto로 변환한 후 리턴해야 한다.(번거롭다.)
// 결국, 로그인을 성공했을 때만 dto에 뭘 담아서 주는 것이다.
memberDTO dto = memberDTO.toMemberDTO(memberEntity);
return dto;
} else {
// 비밀번호 불일치(로그인 실패)
return null;
}
} else {
// 3.없다면
return null;
}
}
// 회원 조회를 위한 함수이다.
public List<memberDTO> findAll() {
List<MemberEntity> memberEntityList = memberRepository.findAll();
// entity list를 dto list로 변환해야 한다.
List<memberDTO> memberDTOList = new ArrayList<>();
// 하나하나 꺼낸다.
for (MemberEntity memberEntity : memberEntityList) {
memberDTOList.add(memberDTO.toMemberDTO(memberEntity));
}
return memberDTOList;
}
public String emailCheck(String memberEmail) {
// repository 함수를 통해 사용자가 입력한 이메일 값으로 조회를 한다. 이렇게 조회하는 것은 JPA의 repository를 통해
// 조회할 수 있다.
Optional<MemberEntity> byMemberEmail = memberRepository.findByEmail(memberEmail);
if (byMemberEmail.isPresent()) {
// 이메일 값이 이미 있으면(회원이 중복되어 있으면)사용할 수 없다.
return null;
}
else {
// 조회 결과가 없으면 사용할 수 있다.
return "ok";
}
}
public String idCheck(String memberId) {
// repository 함수를 통해 사용자가 입력한 아이디 값으로 조회를 한다.
Optional<MemberEntity> byMemberId = memberRepository.findByMemberId(memberId);
if (byMemberId.isPresent()) {
// 아이디 값이 이미 있으면(회원이 중복되어 있으면)사용할 수 없다.
return null;
}
else {
// 조회 결과가 없으면 사용할 수 있다.
return "ok";
}
}
public MemberEntity getPasswordByEmail(String memberEmail) {
Optional<MemberEntity> byMemberEmail = memberRepository.findByEmail(memberEmail);
return byMemberEmail.orElse(null);
}
// Transactional 어노테이션은 여러 줄의 코드를 하나의 작업으로 처리해준다.
// 하나의 작업으로 처리해주면, 부분적으로 오류가 난 것을 같이 처리할 수 있다는 장점이 있다.
@Transactional
public boolean changePassword(String email, String newPassword) {
Optional<MemberEntity> userOptional = memberRepository.findByEmail(email);
if (userOptional.isPresent()) {
MemberEntity user = userOptional.get();
user.setPassword(newPassword);
memberRepository.save(user);
return true;
}
return false;
}
// 이메일로 아이디 찾기
public Optional<MemberEntity> findIdByEmail(String email) {
return memberRepository.findByEmail(email);
}
// 아이디로 비밀번호 찾기
public Optional<MemberEntity> findPasswordById(String memberId) {
return memberRepository.findByMemberId(memberId);
}
}
controller에서, memberService로 정의된 함수들이 여기에 정의되어 있다.
그런 다음, repository를 다음과 같이 설정했다.
package com.example.finalproject.finalproject.repository;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.finalproject.finalproject.entity.MemberEntity;
public interface memberRepository extends JpaRepository<MemberEntity, Long> {
// jparepository를 상속받는다.
// 첫번째 인자는 엔터티이고, 두번째 인자는 primary key의 자료형이다.
// 인터페이스로 repository를 정의하기 때문에, 추상 클래스를 정의할 수 있다.
// 이메일로 찾기
Optional<MemberEntity> findByEmail(String email);
// member_id로 찾기.
Optional<MemberEntity> findByMemberId(String memberId);
}
2.회원가입-html
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8" />
<link rel="icon" th:href="@{/favicon.ico}" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link th:href="@{/static/css/signup.css}" rel="stylesheet"/>
<title>회원가입</title>
<!--이 stylesheet을 통해 텍스트의 스타일을 더 세련되게 한다.-->
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat%3A400%2C600%2C700"/>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro%3A400%2C600%2C700"/>
<script
src="https://code.jquery.com/jquery-3.7.1.min.js"
integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo="
crossorigin="anonymous"></script>
</head>
<body>
<div class="item--M9e">
<div class="frame-3851-uD6">
<div class="frame-3851-Chz">
<div class="roads-v8C">ROADs</div>
<p class="road-obstacle-ai-detection-service-kN8">Road Obstacle Ai Detection service</p>
</div>
<div class="frame-830-Msi">
<!--아이디/비밀번호/이메일/비밀번호확인 등의 input,span -->
<input id="id" type="text" placeholder="영문 및 숫자 8자 이상" class="text-field-oYg" onblur="checkId()"></input>
<span id="idMessage" class="validation-message"></span>
<input id="email" type="text" placeholder="이메일 주소 입력(반드시 주소를 다 입력해주세요.)" class="text-field-oYg"></input>
<span id="emailMessage" class="vaildation-message"></span>
<input id="password" type="password" placeholder="PW 영문+숫자+특수문자 8~15자 이내" class="text-field-oYg" onblur="checkPassword()"></input>
<span id="passwordMessage" class="validation-message"></span>
<input id="passwordconfirm" type="password" placeholder="비밀번호 확인" class="text-field-oYg" onblur="checkPasswordConfirmation()"></input>
<span id="passwordConfirmMessage" class="validation-message"></span>
<button class="button-tvp" onclick="register()">회원가입</button>
</div>
</div>
</div>
<script src="/static/js/signup.js"></script> <!-- js 파일은 가장 나중에 선언되어야 오류가 없다.-->
</body>
</html>
코드에 대한 설명은 다음과 같다.
1.thymeleaf를 써서 더 간편하게 html을 작성할 수 있게 되었다.
2.을 통해 signup.css를 css 파일로 작성할 수 있게 되었다.
3.제이쿼리를 설정해서 javascript에서 제이쿼리를 쓸 수 있게 되었다.
4.회원가입 코드에서, '회원가입'버튼을 누르면 javascript에서 정의한
'register'함수를 실행할 수 있도록 했다.
5.을 통해 signup.js를 javascript 파일로 쓸 수 있게 했다.
6. 이 부분은 구글 api에서 글꼴을 따와서 쓸 수 있게 해주는 코드이다.
3.여기서 잠깐!
사소한 설정이지만, 하지 않으면 오류가 나는 것이 있다.
바로, application.properties에서 이 설정을 하는 것이다.
#자원 재배치(정적 파일들은 어떻게 인식할 것인가)
spring.mvc.static-path-pattern=/static/**
spring.resources.static-locations=classpath:/static/
이 설정을 해주지 않으면, 디버거가 에플리케이션을 읽을 때, static 파일에 대해 잘 읽을 수 없게 되어서
whitepage error
가 나게 된다. 이점을 꼭 유의하자!
4.회원가입-css
자, 다음은 디자인 부분인 css이다.
코드가 많고 복잡하지만, 정작 따로 설명할 것은 없다.
html {
font-size:62.5%;
}
* {
margin: 0;
padding: 0;
}
ul, li {
list-style: none;
}
input {
border: none;
}
body {
width: 144rem;
}.item--M9e {
box-sizing: border-box;
padding: 14.7rem 44.7rem 17.3rem 44.8rem;
width: 100%;
height: 80rem;
overflow: hidden;
position: relative;
background-color: #ffffff;
border-radius: 3rem;
}
.item--M9e .frame-3851-uD6 {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.item--M9e .frame-3851-uD6 .frame-3851-Chz {
margin-bottom: 4rem;
display: flex;
flex-direction: column;
flex-shrink: 0;
}
.item--M9e .frame-3851-uD6 .frame-3851-Chz .roads-v8C {
margin-bottom: 2rem;
font-size: 5.4rem;
font-weight: 700;
line-height: 1.2175;
color: #000000;
font-family: Montserrat, 'Source Sans Pro';
white-space: nowrap;
flex-shrink: 0;
}
.item--M9e .frame-3851-uD6 .frame-3851-Chz .road-obstacle-ai-detection-service-kN8 {
font-size: 1.4rem;
font-weight: 600;
line-height: 1.7142857143;
letter-spacing: 0.014rem;
color: #000000;
font-family: Montserrat, 'Source Sans Pro';
white-space: nowrap;
flex-shrink: 0;
}
.item--M9e .frame-3851-uD6 .frame-830-Msi {
width: 100%;
row-gap: 2rem;
align-items: center;
display: flex;
flex-direction: column;
flex-shrink: 0;
}
.item--M9e .frame-3851-uD6 .frame-830-Msi .text-field-GDz {
box-sizing: border-box;
padding: 1.3rem 2rem;
width: 100%;
font-size: 1.4rem;
font-weight: 400;
line-height: 1.7142857143;
letter-spacing: 0.014rem;
color: #828282;
font-family: Montserrat, 'Source Sans Pro';
white-space: nowrap;
display: flex;
align-items: baseline;
border: solid 0.1rem #e0e0e0;
flex-shrink: 0;
}
.item--M9e .frame-3851-uD6 .frame-830-Msi .text-field-GDz .text-field-GDz-sub-0 {
}
.item--M9e .frame-3851-uD6 .frame-830-Msi .text-field-GDz .text-field-GDz-sub-1 {
font-size: 1.4rem;
font-weight: 400;
line-height: 1.7142857143;
letter-spacing: 0.014rem;
color: #828282;
font-family: Montserrat, 'Source Sans Pro';
}
.item--M9e .frame-3851-uD6 .frame-830-Msi .text-field-GDz .text-field-GDz-sub-2 {
}
.item--M9e .frame-3851-uD6 .frame-830-Msi .text-field-oYg {
box-sizing: border-box;
padding: 1.3rem 2rem;
width: 100%;
font-size: 1.4rem;
font-weight: 400;
line-height: 1.7142857143;
letter-spacing: 0.014rem;
color: #828282;
font-family: Montserrat, 'Source Sans Pro';
white-space: nowrap;
border: solid 0.1rem #e0e0e0;
flex-shrink: 0;
}
.item--M9e .frame-3851-uD6 .frame-830-Msi .text-field-ZAU {
box-sizing: border-box;
padding: 0.9rem 1.2rem 1rem 2rem;
width: 100%;
height: 5rem;
display: flex;
align-items: center;
border: solid 0.1rem #e0e0e0;
flex-shrink: 0;
}
.item--M9e .frame-3851-uD6 .frame-830-Msi .text-field-ZAU .email--DF2 {
margin: 0.1rem 30.4rem 0rem 0rem;
font-size: 1.4rem;
font-weight: 400;
line-height: 1.7142857143;
letter-spacing: 0.014rem;
color: #828282;
font-family: Montserrat, 'Source Sans Pro';
white-space: nowrap;
flex-shrink: 0;
}
.item--M9e .frame-3851-uD6 .frame-830-Msi .text-field-ZAU .auto-group-fcrx-mQx {
width: 9.2rem;
height: 100%;
position: relative;
flex-shrink: 0;
}
.item--M9e .frame-3851-uD6 .frame-830-Msi .text-field-ZAU .auto-group-fcrx-mQx .rectangle-1899-GMi {
width: 9.2rem;
height: 3.1rem;
position: absolute;
left: 0;
top: 0;
background-color: #5491f5;
}
.item--M9e .frame-3851-uD6 .frame-830-Msi .text-field-ZAU .auto-group-fcrx-mQx .item--ZLp {
width: 5.2rem;
height: 2.4rem;
position: absolute;
left: 0.7rem;
top: 0.3rem;
font-size: 1.4rem;
font-weight: 400;
line-height: 1.7142857143;
letter-spacing: 0.014rem;
color: #ffffff;
font-family: Montserrat, 'Source Sans Pro';
white-space: nowrap;
}
.item--M9e .frame-3851-uD6 .frame-830-Msi .text-field-foA {
box-sizing: border-box;
padding: 1.3rem 2rem;
width: 100%;
font-size: 1.4rem;
font-weight: 400;
line-height: 1.7142857143;
letter-spacing: 0.014rem;
color: #828282;
font-family: Montserrat, 'Source Sans Pro';
white-space: nowrap;
border: solid 0.1rem #e0e0e0;
flex-shrink: 0;
}
.item--M9e .frame-3851-uD6 .frame-830-Msi .button-tvp {
width: 100%;
height: 5rem;
font-size: 1.6rem;
font-weight: 700;
line-height: 1.2175;
text-transform: uppercase;
color: #ffffff;
font-family: Montserrat, 'Source Sans Pro';
white-space: nowrap;
display: flex;
align-items: center;
justify-content: center;
background-color: #5491f5;
flex-shrink: 0;
}
.button-tvp:hover{
background-color: #50bcdf;
}
.input-field {
width: 200px; /* 원하는 너비로 조절 */
height: 20px; /* 원하는 높이로 조절 */
}
.roads-v8C:hover{
cursor:pointer;
}
5.회원가입-javascript
//회원가입 관련 javascript코드
//async, await 함수를 사용함으로서, 비동기 작업을 동기적으로 처리한다.
// 입력 필드에 input 이벤트 추가
//addeventlistener에 'input'은 값이 추가가 될 때, 해당 함수를 적용한다는 의미이다.
document.getElementById("id").addEventListener("input", checkId);
document.getElementById("password").addEventListener("input", checkPassword);
document.getElementById("passwordconfirm").addEventListener("input", checkPasswordConfirmation);
document.getElementById("email").addEventListener("input",checkEmailFunction);
//roads 클릭 시 메인 페이지로 이동
document.querySelector('.roads-v8C').addEventListener('click', function() {
window.location.href = '/main';
});
// id를 체크하고 중복 여부를 서버에 요청하는 함수
async function checkId() {
var id = String(document.getElementById("id").value);
console.log("입력값:",id);
var idMessage = document.getElementById("idMessage");
//입력값이 비어 있는 경우에도 빨간색 알림을 띄운다.
if(id.trim()===""){
idMessage.style.color="red";
idMessage.innerHTML="아이디를 입력해주세요.";
return;
}
//id의 길이가 8미만이여도 알림을 띄운다.
if(id.length<8){
idMessage.style.color = "red";
idMessage.innerHTML="아이디는 영문 및 숫자 8자 이상입니다.";
return;
}
//ajax를 통해 디비와 통신한다. 아이디 값이 있는지 없는지 통신하는 것이다.
$.ajax({
type:"post",
url:"http://localhost:8090/member/idcheck",
data:{
"memberId":id
},
success:function(res){
console.log("요청성공",res);
if(res==="ok"){
idMessage.style.color = "green";
idMessage.innerHTML="생성 가능한 id입니다.";
} else {
idMessage.style.color = "red";
idMessage.innerHTML="이미 사용중인 아이디입니다.";
}
},
error:function(err){
console.log("에러발생",err);
}
});
}
// 비밀번호를 체크하는 함수
function checkPassword() {
var password = document.getElementById("password").value;
var passwordMessage = document.getElementById("passwordMessage");
if (password.length < 8 || password.length > 15) {
passwordMessage.innerText = "PW는 8~15자 이내로 입력하세요.";
passwordMessage.style.color = "red";
} else {
passwordMessage.innerText = "비밀번호 체크가 완료되었습니다.";
passwordMessage.style.color = "green";
}
}
// 비밀번호 확인을 체크하는 함수
function checkPasswordConfirmation() {
var password = document.getElementById("password").value;
var passwordConfirm = document.getElementById("passwordconfirm").value;
var passwordConfirmMessage = document.getElementById("passwordConfirmMessage");
if (password !== passwordConfirm) {
passwordConfirmMessage.innerText = "비밀번호가 일치하지 않습니다.";
passwordConfirmMessage.style.color = "red";
} else {
passwordConfirmMessage.innerText = "일치합니다.";
passwordConfirmMessage.style.color = "green";
}
}
//이메일 중복을 확인하는 함수
function checkEmailFunction(){
var email= String(document.getElementById("email").value);
var emailMessage = document.getElementById("emailMessage");
//입력값이 비어 있는 경우에도 빨간색 알림을 띄운다.
//trim은 좌우 공백을 제거한 것이다.
if(email.trim()===""){
emailMessage.style.color="red";
emailMessage.innerHTML="이메일을 입력해주세요.";
return;
}
//ajax를 통해 디비와 통신한다. 이메일 값이 있는지 없는지 통신하는 것이다.
$.ajax({
type:"post",
url:"http://localhost:8090/member/emailcheck",
data:{
"email":email
},
success:function(res){
console.log("요청성공",res);
if(res==="ok"){
emailMessage.style.color = "green";
emailMessage.innerHTML="사용 가능한 이메일입니다.";
} else {
emailMessage.style.color = "red";
emailMessage.innerHTML="이미 사용중인 이메일입니다.";
}
},
error:function(err){
console.log("에러발생",err);
}
});
}
// 회원가입 처리 함수
async function register() {
var id = document.getElementById("id").value;
var password = document.getElementById("password").value;
var email = document.getElementById("email").value;
// 위에서 정의한 함수들을 여기서 실행한다.
checkId();
checkPassword();
checkPasswordConfirmation();
checkEmailFunction();
var idMessage = document.getElementById("idMessage").innerText;
var passwordMessage = document.getElementById("passwordMessage").innerText;
var passwordConfirmMessage = document.getElementById("passwordConfirmMessage").innerText;
var emailMessage = document.getElementById("emailMessage").innerText;
// 조건을 만족하지 않으면, 회원가입 요청이 보내지지 않음.
if (idMessage === "생성 가능한 id입니다." && passwordMessage === "비밀번호 체크가 완료되었습니다." && passwordConfirmMessage === "일치합니다."&& emailMessage === "사용 가능한 이메일입니다.") {
try {
// 데이터를 JSON 형태로 변환
var data = {
memberId: id,
password: password,
email: email
};
// 서버로 데이터 전송
//data들을 json으로 변환해서 서버에 전송해야 한다. 전송 type은 post이다.
$.ajax({
type: "POST",
url: "/signup",
contentType: "application/json", // 데이터 타입 설정
data: JSON.stringify(data), // 데이터 전송 전 JSON 형태로 변환
success: function(res) {
if (res === "회원가입이 완료되었습니다.") {
alert(res);
window.location.href = "/main";
} else {
alert("회원가입에 실패했습니다.");
window.location.href = "/signup";
}
},
error: function(err) {
console.error("에러 발생", err);
}
});
} catch (error) {
alert("회원가입에 실패하였습니다. 다시 시도해주세요.");
}
} else {
alert("아이디 또는 비밀번호 체크를 완료해주세요.");
}
}
위 코드에서 꼭 알아야 할 것들을 설명하고자 한다.
5.1.값이 입력될 때마다 함수를 호출해서 실행
document.getElementById("id").addEventListener("input", checkId);
document.getElementById("password").addEventListener("input", checkPassword);
document.getElementById("passwordconfirm").addEventListener("input", checkPasswordConfirmation);
document.getElementById("email").addEventListener("input",checkEmailFunction);
id/password/passwordconfirm/email의 값을 바꿀 때, addEventListener에서 적은 함수가 실행이 된다.
이를 통해, 값을 바꿀 때 마다 아이디/이메일 중복과 비밀번호 확인 로직이
실행되어 화면에 나타난다.
5.2.ajax를 통해 디비와 통신
//ajax를 통해 디비와 통신한다. 아이디 값이 있는지 없는지 통신하는 것이다.
$.ajax({
type:"post",
url:"http://localhost:8090/member/idcheck",
data:{
"memberId":id
},
success:function(res){
console.log("요청성공",res);
if(res==="ok"){
idMessage.style.color = "green";
idMessage.innerHTML="생성 가능한 id입니다.";
} else {
idMessage.style.color = "red";
idMessage.innerHTML="이미 사용중인 아이디입니다.";
}
},
error:function(err){
console.log("에러발생",err);
}
});
이 때, controller에서 이 요청을 받아서, 아이디가 중복되어있는지 체크
한 뒤, 결과를 res로 받아서 res값을 토대로 로직을 실행한다.
controller와 백엔드 부분에 대해서는 글의 초반부에 코드를 적어놓았다.
5.3.document.getElementById
사소하지만 가장 중요한 것 중 하나이다.
html의 요소들을 받아와서, 그것을 토대로 기능을 구현한다.
var password = document.getElementById("password").value;
var passwordMessage = document.getElementById("passwordMessage");
이런 식으로, 변수를 할당할 수도 있다. 변수를 할당하면 더 쉽게 기능을 구현할 수 있으니 유의하자.
6.화면 스크린샷

회원가입 화면을 구현했다.

아이디/이메일 등을 타이핑하면, 로직에 맞게 안내문이 나오는 것을 볼 수 있다.