앞에서 스프링 시큐리티 설정을 끝냈으므로 이번에는 회원가입 기능을 추가하겠습니다.
User 엔티티
먼저 User 엔티티를 작성하고 데이터베이스에 등록을 합니다.
package com.crud.model;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true)
private String username;
private String password;
@Column(unique = true)
private String email;
}
User 테이블에는 id, username, password, email 4개의 칼럼으로 구성되어 있으며,
username 과 email 은 동일한 값을 저장할 수 없도록 @Column(unique = true ) 애너테이션을 적용했습니다.
MariaDB [springboot_crud]> show tables;
+---------------------------+
| Tables_in_springboot_crud |
+---------------------------+
| answer |
| question |
| user |
+---------------------------+
3 rows in set (0.001 sec)
MariaDB [springboot_crud]> desc user;
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| email | varchar(255) | YES | UNI | NULL | |
| password | varchar(255) | YES | | NULL | |
| username | varchar(255) | YES | UNI | NULL | |
+----------+--------------+------+-----+---------+----------------+
4 rows in set (0.012 sec)
데이터베이스에 접속해서 확인을 해보면 User 엔티티가 반영된것을 볼 수 있습니다.
UserRepository
다음으로 UserRepository 를 작성하겠습니다.
package com.crud.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.crud.model.User;
public interface UserRepository extends JpaRepository<User, Long>{
}
UserRepository 는 접근할 대상이 User 엔티티며, User 엔티티 기본키의 속성 타입은 Long 이므로
JpaRepository <User, Long> 을 사용합니다.
UserService
다음으로 위에서 만든 UserRepository 를 사용해서 user 를 저장하는 UserService 를 생성합니다.
package com.crud.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.crud.model.User;
import com.crud.repository.UserRepository;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public User create(String username, String email, String password) {
User user = new User();
user.setUsername(username);
user.setEmail(email);
user.setPassword(password);
userRepository.save(user);
return user;
}
}
UserService 의 create 메서드는 username, email, password 를 입력받아
새로운 user 객체를 하나 생성해서 3개의 값을 저장하고
UserRepository 를 사용해서 해당 객체를 저장합니다.
이때, password 는 보안을 위해 암호화하여 저장할 수 있도록 BCryptPasswordEncoder 클래스를 사용해 암호화합니다.
BCryptPasswordEncoder 는 해싱 함수를 사용해서 비밀번호를 암호화
package com.crud.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import com.crud.model.User;
import com.crud.repository.UserRepository;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public User create(String username, String email, String password) {
User user = new User();
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
user.setUsername(username);
user.setEmail(email);
user.setPassword(bCryptPasswordEncoder.encode(password));
userRepository.save(user);
return user;
}
}
UserForm
다음으로 UserForm 을 사용해서 회원가입에 필요한 항목들이 제대로 입력되었는지 확인합니다.
- 필수 입력사항 : username, email, password, passwordAgain
- 중복된 값 : 아이디와 이메일이 중복된 값이 있는지
- 아이디 : 25글자 미만으로 설정
- 비밀번호 확인 : password 와 passwordAgain 이 동일한 값인지
- 이메일 : 이메일 형식에 맞게 입력이 되어있는지
package com.crud.model;
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 UserForm {
@Size(max = 25)
@NotEmpty(message = "사용자 아이디를 입력해주세요.")
private String username;
@NotEmpty(message = "비밀번호를 입력해주세요.")
private String password;
@NotEmpty(message = "비밀번호를 한번 더 입력해주세요.")
private String passwordAgain;
@NotEmpty(message = "이메일을 입력해주세요.")
@Email
private String email;
}
필수입력사항과 아이디, 이메일의 검증은 각각의 애너테이션을 통해 확인하고 있으며,
password 와 passwordAgain 의 값이 동일한지는 UserController 에서 값을 넘겨받아 확인하겠습니다.
UserController
다음으로 UserController 를 작성하겠습니다.
localhost:8080/user/signup 에 get 방식으로 접속을 하면 회원가입 폼이 화면에 나오게 되고,
post 방식으로 폼을 제출하면 컨트롤러에서 에러메세지를 보내거나 혹은 UserService 를 통해 저장합니다.
package com.crud.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import com.crud.model.UserForm;
import com.crud.service.UserService;
import jakarta.validation.Valid;
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/user/signup")
public String signup(UserForm userForm) {
return "signup_form";
}
@PostMapping("/user/signup")
public String signup(@Valid UserForm userForm, BindingResult bingBindingResult) {
if(bingBindingResult.hasErrors()) {
return "signup_form";
}
if(!userForm.getPassword().equals(userForm.getPasswordAgain())) {
bingBindingResult.rejectValue("passwordAgain", "passwordInCorrect", "비밀번호가 일치하지 않습니다.");
return "signup_form";
}
try {
userService.create(userForm.getUsername(), userForm.getEmail(), userForm.getPassword());
} catch (DataIntegrityViolationException e) {
// TODO: handle exception
bingBindingResult.reject("signupFailed", "이미 등록된 아이디입니다.");
return "signup_form";
} catch(Exception e) {
bingBindingResult.reject("signupFailed", e.getMessage());
return "signup_form";
}
return "redirect:/";
}
}
username 혹은 email 이 동일한 경우 DataIntegrityViolationException 를 통해 예외처리를 하였습니다.
회원가입 페이지
다음으로 회원가입 페이지인 signup_form 을 작성합니다.
<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="${userForm}" method="post">
<div class="alert alert-danger" role="alert" th:if="${#fields.hasAnyErrors()}">
<div th:each="err : ${#fields.allErrors()}" th:text="${err}" />
</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="password" class="form-label">비밀번호</label>
<input type="password" th:field="*{password}" class="form-control">
</div>
<div class="mb-3">
<label for="passwordAgain" class="form-label">비밀번호 확인</label>
<input type="password" th:field="*{passwordAgain}" 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 방식으로 userForm 에 값을 저장해서 localhost:8080/user/signup 으로 보내게됩니다.
네비게이션바에서도 회원가입 페이지로 이동할 수 있도록 회원가입 메뉴를 추가합니다.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
...
</head>
<body>
...
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="#">로그인</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/user/signup">회원가입</a>
</li>
</ul>
...
</body>
</html>
결과
다음과 같이 회원가입 폼에 맞춰 가입을 합니다.
mysql 을 통해 확인해보면 비밀번호가 암호화되어 회원 데이터가 저장이 잘 된것을 알 수 있습니다.
MariaDB [springboot_crud]> select * from user;
+----+-------------------+--------------------------------------------------------------+----------+
| id | email | password | username |
+----+-------------------+--------------------------------------------------------------+----------+
| 1 | tjtojan@naver.com | $2a$10$Y73FGw/XodKjfeOsFNyyTuoyV9HyvkIIQ6760YK5T/Q0OxW.0wFA6 | jeehwan |
+----+-------------------+--------------------------------------------------------------+----------+
1 row in set (0.001 sec)
'Spring > Springboot 실습' 카테고리의 다른 글
게시판 만들기 - 로그아웃 (0) | 2023.01.25 |
---|---|
게시판 만들기 - 로그인 (0) | 2023.01.25 |
게시판 만들기 - 회원가입(1) (0) | 2023.01.24 |
게시판 만들기 - 페이징 처리(2) (0) | 2023.01.22 |
게시판 만들기 - 페이징 처리(1) (0) | 2023.01.22 |