[231020] 회원가입 - 동의, 가입, 인증

MJ·2023년 10월 26일

수업 TIL🐣💚

목록 보기
67/68

1교시

1. 로그인 후 돌아갈 페이지 바꾸기

  • 로그인 후 돌아갈 페이지를 메인이 아닌 로그인 하기 전 페이지로 바꾸기

UserController.java

  • 로그인 화면으로 이동시켜주는 컨트롤러다. (login.form은 header.jsp에서 받았다)
  @GetMapping("/login.form")
  public String loginForm(HttpServletRequest request, Model model) throws Exception {
    // referer : 이전 주소가 저장되는 요청 Header 값
    String referer = request.getHeader("referer");
    model.addAttribute("referer", referer == null ? request.getContextPath() + "/main.do" : referer);
  }
  • 모델이 하는 일 = 전달, login.form 이전 주소값을 login.jsp로 전달할거임 (전달할 값 저장을 model로 했으니 login.jsp에서 el ${referer}로 확인 가능)
  • 이전 주소값 = referer (request에 있는 헤더 중 하나)
  • referer가 동작하지 않으면 (=null이면) main으로 돌아갈 수 있도록 한다.

login.jsp

<input type="hidden" name="referer" value="${referer}">
  • referer 값(컨트롤러에서 전달되어 왓다)을 login.do로 보내서 최종적으로 UserServiceImpl에 닿을 수 있도록 한다.
  • 화면에 referer 값 보여줄 필요 없으니 hidden, 파라미터는 보내줘야하니까 name 필요, 값에는 ${referer} 저장

UserServiceImpl.java

response.sendRedirect(request.getParameter("referer"));
  • referer에 전체주소가 다 들어있으므로 contextPath 붙이면 안됨

2. 회원가입 - 동의

  • 동의화면(agree.form) -> 회원가입(join.form)

agree.jsp

<script src="${contextPath}/resources/js/user_agree.js"></script>
  • fnChkAll( ), fnChkEach( ), fnJoinForm( ) 정의해준 user_agree.js를 불러옴. (fnChkAll(), fnChkEach()은 14장에서 했었다)
    • 함수는 변수에 저장할 수 있으므로 function fnChkAll()를 const fnChkAll()의 형태로 전부 고쳤다.

user_agree.js

.prop()

  • 지정한 선택자를 가진 첫번째 요소의 속성값을 가져오거나 속성값을 추가한다. 주의할 점은 HTML 입장에서의 속성(attribute)이 아닌 JavaScript 입장에서의 속성(property)이라는 것이다.
  • .attr()는 HTML의 속성을 취급, .prop()는 JavaScript property를 취급
  • attr() - HTML attribute 값이 모두 String 으로 넘어옴
  • prop() - 자바스크립트의 프로퍼티 값이 넘어오기 때문에 boolean, date, function 등도 가져올 수 있음

// 1. 전체 선택을 클릭하면 개별 선택에 영향을 미친다.
const fnChkAll = () => {
  $('#chk_all').click((ev) => {
    $('.chk_each').prop('checked', $(ev.target).prop('checked'));
  })
}

// 2. 개별 선택을 클릭하면 전체 선택에 영향을 미친다.
const fnChkEach = () => {
  $(document).on('click', '.chk_each', () => {
    var total = 0;
    $.each($('.chk_each'), (i, elem) => {
      total += $(elem).prop('checked');
    })
    $('#chk_all').prop('checked', total === $('.chk_each').length);
  })
}

// 3. 필수 동의를 해야만 가입 페이지로 이동할 수 있다.
const fnJoinForm = () => {
  $('#frm_agree').submit((ev) => {
    if(!$('#service').is(':checked')){
      alert('필수 약관에 동의하세요.');
      ev.preventDefault();
      return;
    }
  })
}

1

  • ev : 이벤트 객체
  • ev.target: 이벤트 리스너는 $(this) 못 써서 $(ev.target)로 썻음. this랑 같은 역할. (js 객체니까 $( ) 필요)

3

  • is(':checked') : checked를 선택자 형태로 콜론 붙여서 적어줘야한다.

2교시

2. 회원가입 - 동의 (back)

agree.jsp

  • form에서 submit 하기 위해 입력 요소들의 name 속성이 필요 -> 모두 동의(id="chk_all")는 체크 편하게 해주기 위한 프론트 기술이니까 보낼 필요 없어서 제외하고 나머지 두 개만 name 속성 추가해준다
<form id="frm_agree" action="${contextPath}/user/join.form">
    
    <h1>약관 동의하기</h1>
    
    <div>
      <input type="checkbox" id="chk_all">
      <label for="chk_all">모두 동의합니다</label>
    </div>
    
    <hr>
    
    <div>
      <input type="checkbox" name="service" id="service" class="chk_each">
      <label for="service">서비스 이용약관 동의(필수)</label>
    </div>
    <div>
      <textarea>본 약관은 ...</textarea>
    </div>
    
    <div>
      <input type="checkbox" name="event" id="event" class="chk_each">
      <label for="event">이벤트 알림 동의(선택)</label>
    </div>
    <div>
      <textarea>본 약관은 ...</textarea>
    </div>

    <div>
      <button type="submit">다음</button>
    </div>
    
  </form>
  • id="service"와 id="event" 모두 value를 만들지 않았다. 이러면 넘어가는 값이 없을 것 같지만 on이 넘어간다.

    service와 event에 둘 다 체크했을 때 모습

    event에 체크안했을 때 모습. 체크 안하면 on 안넘어가고 null

  • 이제 백단에서 on이 있는지 확인하고 판단하면 된다. (그런데 아까 필수 약관 동의 안한 경우는 ev.preventDefault로 막았으니까 추가 작업 안해도잘 판별돼서 전송되긴 한다. 그래도 할거다.)

UserController.java

  @GetMapping("/join.form")
  public String joinForm(@RequestParam(value="service", required=false, defaultValue="off") String service
                       , @RequestParam(value="event", required=false, defaultValue="off") String event
                       , Model model) {
    String rtn = null;
    if(service.equals("off")) {
      rtn = "redirect:/main.do";
    } else {
      model.addAttribute("event", event);  // user 폴더 join.jsp로 전달하는 event는 "on" 또는 "off" 값을 가진다.
      rtn = "user/join";
    }
    return rtn;
  }
  • 위에서 봤듯이 파라미터 주소로 값 전달하니까 GetMapping
  • service랑 event를 각각 String으로 직접 받는거니까 @RequestParam을 썼다 (@RequestParam은 생략이 가능하지만 헷갈리니까 그냥 써줫음)
    • @RequestParam String event 라고 기본 RequestParam만 적으면 null 값일 때 전달을 못해서 오류난다. (값 필수라서) -> required=false 로 필수 요소가 아니라고 명시해줘야 한다.
    • required=false일 때 defaultValue로 off를 적어준다 (on의 반대라서 off로)
    • 서비스는 프론트할 때 체크 안하면 못 넘어가게 해놨지만, GetMapping이다보니 주소 조작(직접 join.form 주소에 입력해서 service 없이 들어가면 service에도 event랑 동일한 오류 발생)이 가능하니까 required=false, defaultValue="off" 적어준다.
  • 데이터를 join.form(join.jsp)로 옮기는 작업이므로 데이터를 옮겨주는 model이 필요하다.
  • if(service.equals("off")) : 서비스가 off인 경우는 주소조작해서 join.jsp로 억지로 넘어온 경우밖에 없기 때문에 다시 main으로 돌아가도록 리다이렉트 시켜줌, service가 off가 아니라면 동의했다는 뜻이니까 모델에 event데이터 실어서 join.jsp로 이동 (서비스는 이미 판별 끝나서 안보낸다)

2,3,4,5 교시

2. 회원가입 - 가입

  • 이메일 정규식 검사, 이메일 중복 검사(mapper), 비밀번호 정규식 검사, 이메일 인증

join.jsp

  <form id="frm_join" method="post" action="${contextPath}/user/join.do">
  • 아이디랑 비밀번호 주소에 실리면 안되니까 post
  • jsp로 이동 -> .form / 서비스 구현할 거 -> .do (맞나?)
<input type="hidden" name="event" value="${event}">
  • 바로 직전 동의 작업할 때 넘어오게 했던 event 객체

2. 회원가입 - 가입 (이메일 인증) -1

pom.xml

  • Random String 생성(이메일 인증 코드) : Apache Commons Lang 3.12
  • 이메일 전송 API (javax.mail) : `JavaMail API JAR 1.6.2
  • 이메일 전송 API : Spring Context Support 5.3.3
  • 기타 원래 있던 애들은 코드에 설명 적어둠

MySecurityUtils.java

  // 인증코드 반환
  public String getRandomString(int count, boolean letters, boolean numbers) {
    return RandomStringUtils.random(count, letters, numbers);
  }
  • count: 몇 글자 쓸지, letters: 문자 사용 여부, numbers: 숫자 사용 여부
  // 크로스 사이트 스크립팅(Cross Site Scripting) 방지
  public String preventXSS(String source) {
    return source.replace("<", "&lt;").replace(">", "&gt;");
  }
  • 태그 삽입하려면 < > 필수로 써야하니까 악성 스크립팅 방지하기 위해 < 는 작다라는 뜻인 &lt;로 바꾸고 >는 크다라는 뜻인 &gt;로 바꾼다.

email.properties

  • email.properties 파일 만들기 전에 .gitignore에 아래꺼 추가해서 깃헙에 email.properties 안 올라가도록 처리
# mail
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.username=
spring.mail.password=
  • application.properties 복붙해서 email.properties 만들면 된다.
  • smtp.gmail.com : 구글의 이메일 보내는 프로토콜 (이메일 보내는 사이트 비슷한 거)
  • port : 포트번호
  • username과 password는 각자 정해서, password는 구글 비번아니다.
 * 1. 구글에 로그인한다.
 * 2. [계정] - [보안]
 * 3. [2단계 인증] - [앱 비밀번호] - [App name] : myhome 입력
 * 4. 생성된 비밀번호를 복사해서 email.properties 파일에 붙여넣기한다. (띄어쓰기 지우고)

MyJavaMailUtils.java

  • email.properties를 읽어서 Properties 객체를 만들고 Properties 객체를 메일 보내는 놈한테 전달

🔻 프로퍼티 객체 생성 (@PropertySource)

  • email 프로퍼티 읽어서 해당 값 사용할거라 달아줬음
    • 참고. AppConfig에서도 있었다
@PropertySource(value="classpath:email.properties") 

읽어들일 프로퍼티 파일 적어주고

  @Autowired
  private Environment env;
  • Environment를 autowired 시켜주고
  • (Environment는 ibatis 아니라 springframework 임포트해서 사용 (propertySource와 함께 동작하는 코드))
// Properties 객체 생성 (이메일 보내는 호스트 정보)
Properties properties = new Properties();
properties.put("mail.smtp.host", env.getProperty("spring.mail.host"));
properties.put("mail.smtp.port", env.getProperty("spring.mail.host"));
properties.put("mail.smtp.auth", env.getProperty("spring.mail.properties.mail.smtp.auth"));
properties.put("mail.smtp.starttls.enable", env.getProperty("spring.mail.properties.mail.smtp.starttls.enable"));

// javax.mail.Session 객체 생성 (이메일 보내는 사용자 정보)
Session session = Session.getInstance(properties, new Authenticator() {
  @Override
  protected PasswordAuthentication getPasswordAuthentication() {
    return new PasswordAuthentication(env.getProperty("spring.mail.username"), env.getProperty("spring.mail.password"));
  }
});
  • env.getProperty로 email.properties에서 만든 프로퍼티 이름들(spring.mail 어쩌구들) 적어주면 해당 프로퍼티 값을 불러올 수 있다.
  • javax.mail.Session : 우리가 알고 있던 Session이 아닌 javax.mail의 세션
  • javax.mail의 getInstance 통해서 위에서 생성한 프로퍼티와 인증관리자(authenticator) 전달
    • 인증관리자 : getPasswordAuthentication()의 리턴값으로 유저이름( env.getProperty("spring.mail.username"))과 패스워드(env.getProperty("spring.mail.password"))를 전달한다.

🔻 메일 만들기

  • MimeMessage라고 하는 객체를 임포트해서 사용한다.
      // 메일 만들기 (보내는 사람 + 받는 사람 + 제목 + 내용)
      MimeMessage mimeMessage = new MimeMessage(session);
      mimeMessage.setFrom(new InternetAddress(env.getProperty("spring.mail.username"), "사이트관리자"));
      mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
      mimeMessage.setSubject(subject);
      mimeMessage.setContent(content, "text/html; charset=UTF-8");
  • internetAddress :자바 네트워크에서 배우는 부분, 이걸로 인터넷 어드레스의 주소값을 스트링 어드레스로 전달하면 되는거고 (지금은 그것만 알고 넘어가고 또 한다는 것 같은데 확실치는 않음)
  • 메일 만들기에 사용할 받는 사람 + 제목 + 내용은 sendJavaMail 메소드를 만들 때 파라미터로 이미 불러온 상태(String to, String subject, String content) 이 파라미터들 대해선 뒤에 설명할듯
  • setFrom = 보내는 사람
    • env.getProperty("spring.mail.username") : user
    • "사이트 관리자" : 화면에 표시될 보내는 사람 이름 (사진에서는 Google)
  • setRecipient = 받는 사람
    • setRecipient(반환타입, 주소)
    • Message.RecipientType에는 TO(받는 사람), CC(참조) BCC(숨은참조)가 있다. 여기선 TO를 선택한다.
    • 받는 사람 주소 = sendJavaMail() 파라미터 String to로 join.jsp에서 받아온 상태, join.jsp의 이부분에서 받을거다.
      <input type="text" name="email" id="email">
      가입한 사람이 입력한 이메일이 곧 받는 사람 이메일.
    • internetAddress로 감싸서 주소값을 전달해준다.
  • setSubject (제목) : sendJavaMail() 파라미터 String subject 그대로
  • setContent (내용) : sendJavaMail() 파라미터 String subject 그대로, 두번째 자리는 타입 적는 곳이다. 타입 html로 설정한다.

user_join.js (이메일 검사, 전송)

  • 정규식 검사(js) 통과 -> 중복체크(dao 필요) 통과 -> 이메일 전송 3단 구성
    • 1) 스크립트에서 db 가려면 ajax 사용해야함. 이 둘은 같이 이뤄져야하는거라 페이지가 바뀌지 않는다.
    • 2) 중복체크 끝나면 전송해야 하는데 이때도 (자바로 요청해야하니까?) ajax 사용해야함.
      			$.ajax({
         success: () => {
         	$ajax({
           })
         }
       })  
      ajax를 연속으로 써야할 때는 이렇게 중복해서 적어준다. 만약 따로 두개를 쓰면 하나 끝나고 그 결과를 바탕으로 다음 ajax가 도는게 아니라 비동기처리로 동시에 돌 수도 있다. (그런데 우리는 이 방법 대신 이걸 씀. 이걸 해결하는 방법이 promise 객체였음.)
    • Promise 함수의 기본 베이스
const fnCheckEmail = () => {
  $('#btn_get_code').click(() => {
    let email = $('#email').val();
    // 연속된 ajax() 함수 호출의 실행 순서를 보장하는 JavaScript 객체 Promise
    new Promise((resolve, reject) => {
      // 성공했다면 resolve() 함수 호출 -> then() 메소드에 정의된 화살표 함수 호출
      // 실패했다면 reject() 함수 호출 -> catch() 메소드에 정의된 화살표 함수 호출
      // 1. 정규식 검사
      let regEmail = /^[A-Za-z0-9-_]+@[A-Za-z0-9]{2,}([.][A-Za-z]{2,6}){1,2}$/;
      if(!regEmail.test(email)){
        reject(1);
        return;
      }
      // 2. 이메일 중복 체크
      $.ajax({
        // 요청
        type: 'get',
        url: getContextPath() + '/user/checkEmail.do',
        data: 'email=' + email,
        // 응답
        dataType: 'json',
        success: (resData) => {  // resData === {"enableEmail": true}
          if(resData.enableEmail){
            resolve();
          } else {
            reject(2);
          }
        }
      })
    }).then(() => {
      // 3. 인증코드 전송
      $.ajax({
        // 요청
        type: 'get',
        url: getContextPath() + '/user/sendCode.do',
        data: 'email=' + email,
        // 응답
        dataType: 'json',
        success: (resData) => {  // resData === {"code": "6자리코드"}
          alert(email + "로 인증코드를 전송했습니다.");
          $('#code').prop('disabled', false);
          $('#btn_verify_code').prop('disabled', false);
          $('#btn_verify_code').click(() => {
            emailPassed = $('#code').val() === resData.code;
            if(emailPassed){
              alert('이메일이 인증되었습니다.');
            } else {
              alert('이메일 인증이 실패했습니다.');
            }
          })
        }
      })
    }).catch((state) => {
      emailPassed = false;
      switch(state){
      case 1: $('#msg_email').text('이메일 형식이 올바르지 않습니다.'); break;
      case 2: $('#msg_email').text('이미 가입한 이메일입니다. 다른 이메일을 입력해 주세요.'); break;
      }
    })
  })
}
  • catch문에 emailPassed = false; 를 넣어서 catch문에 왔다면 이메일 통과 실패햇다는 것을 확실하게 명시해준다. (fnJoin에서도 emailPassed 값이 쓰인다)

🔻 정규식 검사

if(!regEmail.test(email)){
        reject(1);
        return; // return으로 꼭 종료해줘야 한다
      }

email이 정규식(regEmail) 테스트를 통과하지 못했다면 reject(1) 호출 (catch문의 state 매개변수로 1이 들어가서 case 1과 연결)

🔻 이메일 중복 체크

🔺userMapper.xml(DB작업)

  • USER_T, LEAVE_USER_T, INACTIVE_USER_T에 해당 이메일이 있는지 검사
  • 동적쿼리 써서 getUser에 추가할거임.
    • 정적쿼리는 쿼리의 형태가 동일한 반면, 동적쿼리는 파라미터에 따라 달라질 수 있는 (동적으로 바뀌는) 쿼리

      비슷한 기능으로 코드 길어지면 복잡하니까 이거 재활용할거이. 원래 모습. 원래부터 EMAIL 조건이 있기 때문에 재활용할 수 있다.
  <select id="getUser" parameterType="Map" resultType="UserDto">
    SELECT USER_NO, EMAIL, PW, NAME, GENDER, MOBILE, POSTCODE, ROAD_ADDRESS, JIBUN_ADDRESS, DETAIL_ADDRESS, AGREE, STATE, PW_MODIFIED_AT, JOINED_AT
      FROM USER_T
    <where>
      <if test="email != null">EMAIL = #{email}</if>
      <if test="pw != null">AND PW = #{pw}</if>
      <if test="userNo != null">AND USER_NO = #{userNo}</if>
    </where>
  </select>
다음과 같이 수정했다. email이 있으면 EMAIL = #{email} 조건을 체크 
  • 재활용했으니 유저매퍼 인터페이스에 뭐 추가할건 없지만 service는 기능대로 추가해줘야 한다.
  • LEAVE_USER_T랑 INACTIVE_USER_T는 재활용할거 없으니까 따로 만들어준다. (getLeaveUser, getInactiveUser)
    • resultType 맞춰서 dto도 작성, mybatis-config에서 별명도 지정
    • 팁. select 적을 때 그 테이블이 갖고 있는 필드(dto에 선언해준 필드)들 다 적어주기. 안 필요해보여도 나중에 필요해지면 일일이 추가하기 힘드니까 일단 적어주고 가져갈꺼만 쓰는게 편하다.
  <select id="getLeaveUser" parameterType="Map" resultType="LeaveUserDto">
    SELECT EMAIL, JOINED_AT, LEAVED_AT
      FROM LEAVE_USER_T
     WHERE EMAIL = #{email}
  </select>
  <select id="getInactiveUser" parameterType="Map" resultType="InactiveUserDto">
    SELECT USER_NO, EMAIL, PW, NAME, GENDER, MOBILE, POSTCODE, ROAD_ADDRESS, JIBUN_ADDRESS, DETAIL_ADDRESS, AGREE, STATE, PW_MODIFIED_AT, JOINED_AT, INACTIVED_AT
      FROM INACTIVE_USER_T
    <where>
      <if test="email != null">EMAIL = #{email}</if>
      <if test="pw != null">AND PW = #{pw}</if>
    </where>
  </select>

🔺UserService.java (서비스 작업)

  public ResponseEntity<Map<String, Object>> checkEmail(String email);
  • ajax 처리할꺼니까 map 반환하거나 ResponseEntity에 반환값 담아서 반환. ResponseEntity에 담으면 @ResponseBody를 생략할 수 있다

🔺UserServiceImpl.java (서비스 작업)

  @Transactional(readOnly=true)
  @Override
  public ResponseEntity<Map<String, Object>> checkEmail(String email) {
    
    Map<String, Object> map = Map.of("email", email);
    
    boolean enableEmail = userMapper.getUser(map) == null
                       && userMapper.getLeaveUser(map) == null
                       && userMapper.getInactiveUser(map) == null;
    
    return new ResponseEntity<>(Map.of("enableEmail", enableEmail), HttpStatus.OK);
    
  }
  • Map.of
  • 이메일 중복 체크를 통과하려면 getUser, getLeaveUser, getInactiveUser 셋 다 null이 나와야 한다.
  • 생성자 new 호출할 때는 제네릭 문법 <>안의 타입 생략 가능해서 원래는 ResponseEntity<Map<String,Object>>인데 생략해준것
return new ResponseEntity<>(Map.of("enableEmail", enableEmail), HttpStatus.OK);

🔺user_join.js 요청

  • ajax 요청 -> 컨트롤러 -> 서비스 -> ajax 응답
  • DB 갔다와야되기 때문에 ajax 동작시켜야 함
  • type: select 요구하는거니까 get (항상 SELECT는 get이고 CREATE,UPDATE,DELETE는 post다)
  • url: JS니까 ${contextPath}로 쓰면 안된다. el 형태는 jsp에서 쓰는거고 js에서는 getContextPath()로 가져오기
    • 상단부에 정의해준 getContextPath()
      const getContextPath = () => {
      let begin = location.href.indexOf(location.host) + location.host.length;
      let end = location.href.indexOf('/', begin + 1);
      return location.href.substring(begin, end);
      }
    • 찾아야 할 contextpath값은 http://localhost:8080/myhome/~~에서 myhome
    • location.href = 전체 주소, location.host = localhost:8080
    • begin(myhome 시작위치) : host 시작 위치에 host 길이를 더하면 http://localhost:8080/까지 통과할 수 있다. -> myhome 시작위치(begin)
    • end(myhome 종료위치): begin 다음 슬래시 오는 부분이 myhome 종료 위치
    • begin과 end 기준으로 substring 하면 myhome만 추출된다
  • data: 보내줄 데이터는 'email='+email(파라미터) 이다. email 파라미터는 함수 상단에서 let email = $('#email').val();로 선언했었다.
  • success: 응답(resData)가 오면 if문 실행

🔺UserController.java

  • produces=MediaType.APPLICATION_JSON_VALUEproduces="application/json"과 같다. (후자로 쓰면 오타날 수 있으니 전자로 쓰는 것도 괜춘)

🔺user_join.js 응답

  • resData = 서비스임플에서 반환된 데이터
  • resData.enableEmail (getUser, getLeaveUser, getInactiveUser가 모두 null일 때 true라고 UserServiceImpl에서 해준 상태)이 true면 resolve();로 아니면 reject(2)로
  • resolve는 then메소드를 호출.

6교시

2. 회원가입 - 가입 (이메일 인증) -2 전송

🔻 인증코드 전송

  • 첫 ajax 응답 결과 resolve인 경우이므로 then 메소드 내부에 작업
  • ajax로 작업
  • 응답부에서 resData 얻으려면 서비스임플 먼저 구현하고 컨트롤러 연결도 해주자

UserServiceImpl.java (sendCode)

  • 매퍼는 위에서 한거랑 겹쳐서 더 안만들어도 되고 UserService.java에는 sendCode 이름으로 하나 만들어준 상태
  • code값 리턴하는 이유 : 무슨 코드 만들었는지 보내줘야 사용자가 입력한 코드하고 비교할 수 있다.

UserController.java (sendCode)

  • userService.sendCode(email): 반환해주는 건 6자리 랜덤 스트링 (code)

6교시

2. 회원가입 - 가입 (이메일 인증) -3 확인

join.jsp

<div>
  <label for="email">이메일</label>
  <input type="text" name="email" id="email">
  <button type="button" id="btn_get_code">인증코드받기</button>
  <span id="msg_email"></span>
</div>
<div>
  <input type="text" id="code" placeholder="인증코드입력" disabled>
  <button type="button" id="btn_verify_code" disabled>인증하기</button>
</div>
  • disabled: 인증코드 받을 때까지는 인증코드입력과 인증하기 버튼이 활성화되면 안되므로 disabled 처리

user_join.js (then)

$.ajax({
        // 요청
        type: 'get',
        url: getContextPath() + '/user/sendCode.do',
        data: 'email=' + email,
        // 응답
        dataType: 'json',
        success: (resData) => {  // resData === {"code": "6자리코드"}
          alert(email + "로 인증코드를 전송했습니다.");
          $('#code').prop('disabled', false);
          $('#btn_verify_code').prop('disabled', false);
          $('#btn_verify_code').click(() => {
            emailPassed = $('#code').val() === resData.code;
            if(emailPassed){
              alert('이메일이 인증되었습니다.');
            } else {
              alert('이메일 인증이 실패했습니다.');
            }
          })
  • .prop('disabled', false) : join.jsp에서 disabled 처리해뒀던 걸 없애준다.
  • emailPassed : 사용자가 입력한 코드 $('#code').val()와 이메일 인증 코드resData.code가 같다면 T
const fnJoin = () => {
  $('#frm_join').submit((ev) => {
    if(!emailPassed){
      alert('이메일을 인증 받아야 합니다.');
      ev.preventDefault();
      return;
    } else if(!pwPassed || !pw2Passed){
      alert('비밀번호를 확인하세요.');
      ev.preventDefault();
      return;
    } else if(!namePassed){
      alert('이름을 확인하세요.');
      ev.preventDefault();
      return;
    } else if(!mobilePassed){
      alert('휴대전화번호를 확인하세요.');
      ev.preventDefault();
      return;
    }
  })
}

0개의 댓글