팀 최종 프로젝트(23.12~24.02)(9)-프론트2-회원가입 구현

이장한·2024년 2월 22일

팀프로젝트

목록 보기
10/15

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.화면 스크린샷

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

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

profile
기술을 통해 세상을 이롭게 하리라

0개의 댓글