본문 바로가기

Server Programming/Spring Boot Backend Programming

8장 -4. 회원 가입 처리

반응형

요구사항

  • 직접 회원가입
  • 소셜 로그인
    • 기존 가입된 회원이면 해당 이메일을 이용해 로그인
    • 기존 가입된 회원이 아니면, 소셜 로그인의 정보를 이용한 간편 회원가입

 

회원 가입 기능 구현

  • GET 방식 : 회원가입 페이지
  • POST 방식 : 회원가입 <form>데이터를 전달해 DB에 추가
  • GET 방식 화면 출력 -> POST 방식으로 데이터 전달 -> 목록 페이지로 이동

 

회원 가입 구현 순서

  • DTO
  • 컨트롤러
  • 화면
  • 서비스

 

시큐리티의 DTO와 회원가입 전용 DTO

  • 시큐리티가 사용하는 DTO :  User UserDetails를 구현한 User클래스를 상속하는 DTO
  • 회원가입 전용 DTO : MemberJoinDTO 작성

1. 회원가입 전용 DTO인 MemberJoinDTO 작성

package org.zerock.b01.dto;

import lombok.Data;

@Data
public class MemberJoinDTO {
    private String mid;
    private String mpw;
    private String email;
    private boolean del;
    private boolean social;
}

 

2. 회원가입 컨트롤러 작성

//GET 방식으로 회원가입 페이지
@GetMapping("/join")
public void joinGET(){
    log.info("join get...");
}
//POST 방식으로 회원가입 form 전송
@PostMapping("/join")
public String joinPOST(MemberJoinDTO memberJoinDTO){
    log.info("join post...");
    log.info(memberJoinDTO);
    
    return "redirect:/board/list";
}

 

3. 회원가입 화면 작성

-컨트롤러와 서비스의 파라미터 수집 확인과 이동

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layout/basic.html}">

<head>
    <title>Member Join Page</title>
</head>

<div layout:fragment="content">
    <div class="row mt-3">
        <div class="col">
            <div class="card">
                <div class="card-header">
                    JOIN
                </div>
                <div class="card-body">
                    <form id="registerForm" action="/member/join" method="post">
                        <div class="input-group mb-3">
                            <span class="input-group-text">MID</span>
                            <input type="text" name="mid" class="form-control">
                        </div>

                        <div class="input-group mb-3">
                            <span class="input-group-text">MPW</span>
                            <input type="password" name="mpw" class="form-control">
                        </div>

                        <div class="input-group mb-3">
                            <span class="input-group-text">EMAIL</span>
                            <input type="email" name="email" class="form-control">
                        </div>

                        <div class="my-4">
                            <div class="float-end">
                                <button type="submit" class="btn btn-primary submitBtn">Submit</button>
                                <button type="reset" class="btn btn-secondary">Reset</button>
                            </div>
                        </div>
                    </form>
                </div><!--end card body-->

            </div><!--end card-->
        </div><!-- end col-->
    </div><!-- end row-->


</div>

<script layout:fragment="script" th:inline="javascript">




</script>

- '/member/join'을 호출해 화면 출력

-화면 출력-> 입력한 폼을 POST 방식으로 전달 -> '/board/list'로 이동

 

4. 회원 가입 서비스 계층 처리

 

-멤버 서비스에서 MidExistException 예외를 static 클래스로 선언해서 사용

package org.zerock.b01.service;

import org.zerock.b01.dto.MemberJoinDTO;

public interface MemberService {
    static class MidExistException extends Exception{
        
    }
    void join(MemberJoinDTO memberJoinDTO)throws MidExistException;
        
}

 

-MemberServiceImpl에서는 mid가 존재할 경우 MidExistException 발생하도록 작성

-정상적으로 회원가입 될 경우, PasswordEncoder를 이용해 입력된 패스워드를 인코딩

 

서비스 계층 설정

  1. MemberjoinDTO -> Member
  2. Password 인코딩
  3. 권한 설정 (유저, 관리자)
  4. 아이디 중복체크
    : Repository에서 제공하는 existsById()를 이용해 mid 값이 유일한지 체크
package org.zerock.b01.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.modelmapper.ModelMapper;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.ui.ModelMap;
import org.zerock.b01.domain.Member;
import org.zerock.b01.domain.MemberRole;
import org.zerock.b01.dto.MemberJoinDTO;
import org.zerock.b01.repository.MemberRepository;

@Log4j2
@Service
@RequiredArgsConstructor
public class MemberServiceImpl implements MemberService{

    //의존성 주입
    private final ModelMapper modelMapper;
    private final MemberRepository memberRepository;

    private final PasswordEncoder passwordEncoder;


    @Override
    public void join(MemberJoinDTO memberJoinDTO) throws MidExistException{
        String mid = memberJoinDTO.getMid();

        //리포지토리에서 아이디 중복체크를 위해, ID 존재여부 체크
        boolean exist = memberRepository.existsById(mid);
        
        //중복된 아이디 존재시 예외처리
        if(exist){
            throw new MidExistException();
        }

        //회원 전용 DTO -> Memer 도메인으로 변환
        Member member=modelMapper.map(memberJoinDTO, Member.class);
        //pw는 인코딩 필요
        member.changePassword(passwordEncoder.encode(memberJoinDTO.getMpw()));
        //회원 권한 설정
        member.addRole(MemberRole.USER);

        log.info("---");
        log.info(member);
        log.info(member.getRoleSet());

        memberRepository.save(member);

    }
}

 

 

5. 멤버 컨트롤러 변경

-컨트롤러에서 아이디 중복 예외 발생시 다시 회원가입 페이지로 이동

 

변경 전, 컨트롤러

package org.zerock.b01.controller;

import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.zerock.b01.dto.MemberJoinDTO;

@Controller
@RequestMapping("/member")
@Log4j2
@RequiredArgsConstructor
public class MemberController {

    @GetMapping("/login")
    //로그인 과정에서 문제 발생 시, 로그아웃 시 사용하기 위한 파라미터
    public void loginGET(String error, String logout){
        log.info("login get...");
        log.info("logout : "+logout);

        if(logout!=null){
            log.info("user logout...");
        }
    }

    //GET 방식으로 회원가입 페이지
    @GetMapping("/join")
    public void joinGET(){
        log.info("join get...");
    }
    //POST 방식으로 회원가입 form 전송
    @PostMapping("/join")
    public String joinPOST(MemberJoinDTO memberJoinDTO){
        log.info("join post...");
        log.info(memberJoinDTO);

        return "redirect:/board/list";
    }

}

 

변경 후, 중복발생시 회원가입 페이지로 이동 처리

package org.zerock.b01.controller;

import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.zerock.b01.dto.MemberJoinDTO;
import org.zerock.b01.service.MemberService;
import org.zerock.b01.service.MemberServiceImpl;

@Controller
@RequestMapping("/member")
@Log4j2
@RequiredArgsConstructor
public class MemberController {

    //의존성 주입
    private final MemberService memberService;

    @GetMapping("/login")
    //로그인 과정에서 문제 발생 시, 로그아웃 시 사용하기 위한 파라미터
    public void loginGET(String error, String logout){
        log.info("login get...");
        log.info("logout : "+logout);

        if(logout!=null){
            log.info("user logout...");
        }
    }

    //GET 방식으로 회원가입 페이지
    @GetMapping("/join")
    public void joinGET(){
        log.info("join get...");
    }

    //POST 방식으로 회원가입 form 전송
    @PostMapping("/join")
    public String joinPOST(MemberJoinDTO memberJoinDTO, RedirectAttributes redirectAttributes){
        log.info("join post...");
        log.info(memberJoinDTO);

        try{
            //예외처리를 설정한 메서드의 경우, try{}catch(){}
            memberService.join(memberJoinDTO);
        }catch (MemberService.MidExistException e){
            redirectAttributes.addFlashAttribute("error", "mid");
            
            return "redirect:/member/join";
        }

        //결과라는 이름으로 성공 메시지 전송
        redirectAttributes.addFlashAttribute("result", "success");

        //return "redirect:/board/list";
        return "redirect:/board/login"; //회원 가입 후 로그인
    }

}

 

6. join.html에서 'error'로 전달된 데이터를 받으면 이를 출력하도록 처리

<script layout:fragment="script" th:inline="javascript">

    const error = [[${error}]]

    if(error && error === 'mid'){
        alert("동일한 MID를 가진 계정이 존재합니다.")
    }


</script>

 

반응형