[Spring] 회원가입

이다혜·2023년 11월 16일
0

Spring

목록 보기
11/27
post-thumbnail

출처 : 점프 투 스프링부트

1. 회원 정보 엔티티


속성설명
username사용자 이름
password비밀번호
email이메일

SiteUser 엔티티

스프링 시큐리티에 이미 User 클래스가 있기 때문에 SiteUser로 회원 엔티티를 만든다.

SiteUser.java

package com.mysite.sbb.user;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Entity
public class SiteUser {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true)
    private String username;

    private String password;

    @Column(unique = true)
    private String email;
}
  • @Column(unique = true)
    : 유일한 값만 저장할 수 있다. 중복되게 저장할 수 없다.

    SiteUser 테이블

2. User 리포지토리와 서비스


User 리포지토리

UserRepository.java

@Repository
public interface UserRepository extends JpaRepository<SiteUser, Long> {}

SiteUser의 pk 타입이 Long이므로 <SiteUser,Long>을 사용한다.

User 서비스

UserService.java

public class UserService {

    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    public SiteUser create(String username, String email, String password) {
        SiteUser user = new SiteUser();

        user.setUsername(username);
        user.setEmail(email);
        user.setPassword(passwordEncoder.encode(password));

        userRepository.save(user);

        return user;
    }
}

User 데이터를 생성하는 create 메서드를 추가한다.

이 때 사용자의 비밀번호는 보안을 위해 암호화하여 저장해야 한다.

암호화를 위해 시큐리티의 BCryptPasswordEncoder 클래스를 사용한다.

BCryptPasswordEncoder?


BCrypt 해싱 함수를 사용해서 비밀번호를 암호화한다.

SecurityConfig 수정

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

PasswordEncoder를 직접 new로 생성하지 않고 bean으로 등록해서 사용하기 위해 @Configuration이 적용된 SecurityConfig에 @Bean 메서드를 생성한다.

3. 회원가입 폼


UserCreateForm 작성

package com.mysite.sbb.user;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class UserCreateForm {

    @Size(min = 3, max = 25)
    @NotEmpty(message = "사용자 이름(ID)는 필수항목입니다.")
    private String username;

    @NotEmpty(message = "이메일은 필수항목입니다.")
    @Email
    private String email;

    @NotEmpty(message = "비밀번호는 필수항목입니다.")
    private String password1;

    @NotEmpty(message = "비밀번호 확인 필수항목입니다.")
    private String password2;
}
  • 이름의 크기를 3~25로 제한
  • 비밀번호 확인을 위해 password 필드를 2개 만든다.
  • @Email : 해당 속성의 값이 이메일 형식과 일치하는지 검증

4. 회원가입 컨트롤러


UserController.java


@Controller
@RequiredArgsConstructor
@RequestMapping("/user")
public class UserController {

    private final UserService userService;

    @GetMapping("/signup")
    public String signup(UserCreateForm userCreateForm) {
        return "signup_form";
    }

    @PostMapping("/signup")
    public String signup(@Valid UserCreateForm userCreateForm, BindingResult bindingResult) {
        if(bindingResult.hasErrors()) {
            return "signup_form";
        }

        if(!userCreateForm.getPassword1().equals(userCreateForm.getPassword2())) {
            bindingResult.rejectValue("password2", "passwordInCorrect", "2개의 패스워드가 일치하지 않습니다.");
            return "signup_form";
        }

        try {
            userService.create(userCreateForm.getUsername(), userCreateForm.getEmail(), userCreateForm.getPassword1());
        } catch(DataIntegrityViolationException e) {
            e.printStackTrace();
            bindingResult.reject("signupFailed", "이미 등록된 사용자입니다.");
            return "signup_form";
        } catch(Exception e) {
            e.printStackTrace();
            bindingResult.reject("signupFailed", e.getMessage());
            return "signup_form";
        }

        return "redirect:/";
    }
}
  • 비밀번호와 비밀번호 확인이 동일한지 검증한다.

  • 만약 일치하지 않으면 bindingResult.rejectValue로 오류가 발생하게 한다.

  • 사용자ID 또는 이메일이 동일한 사용자가 회원가입을 시도할 경우 DataIntegrityViolationException이 발생하므로 "이미 등록된 사용자입니다."라는 오류를 화면에 표시한다.

회원가입 템플릿


signup_form.html

<html layout:decorate="~{layout}">
<div layout:fragment="content" class="container my-3">
    <div class="my-3 border-bottom">
        <div>
            <h4>회원가입</h4>
        </div>
    </div>
    <form th:action="@{/user/signup}" th:object="${userCreateForm}" method="post">
        <div th:replace="~{form_errors :: formErrorsFragment}"></div>
        <div class="mb-3">
            <label for="username" class="form-label">사용자ID</label>
            <input type="text" th:field="*{username}" class="form-control">
        </div>
        <div class="mb-3">
            <label for="password1" class="form-label">비밀번호</label>
            <input type="password" th:field="*{password1}" class="form-control">
        </div>
        <div class="mb-3">
            <label for="password2" class="form-label">비밀번호 확인</label>
            <input type="password" th:field="*{password2}" class="form-control">
        </div>
        <div class="mb-3">
            <label for="email" class="form-label">이메일</label>
            <input type="email" th:field="*{email}" class="form-control">
        </div>
        <button type="submit" class="btn btn-primary">회원가입</button>
    </form>
</div>
</html>

회원 가입 버튼을 누르면 폼 데이터가 POST 방식으로 /user/signup URL로 전송된다.


데이터베이스에 회원 정보가 저장된 것을 확인할 수 있다.

0개의 댓글