점프 투 스프링부트를 참고하여 학습,작성하였습니다.
1.회원 엔티티 생성
id 필드는@Id로 기본키 역할을 지정받으며, GenerationType.IDENTITY으로 기본키 역할을 하며 자동으로 증가한다.
username,email은 유니크값을 가진다.
password는 비밀번호다.
package com.example.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 SiteUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true)
private String username;
private String password;
@Column(unique = true)
private String email;
}
2.회원 리포지토리 생성
package com.example.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.model.*;
public interface UserRepository extends JpaRepository<SiteUser, Long> {
}
3.회원서비스 생성
create 메소드는 username, email, password를 매개변수로 받아서
password를 암호화하고 user객체에 저장한뒤
설정된 유저 객체를 리포지터리를 통해 데이터베이스에 저장한뒤
유저 객체를 반환한다.
package com.example.service;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import com.example.model.*;
import com.example.repository.*;
@RequiredArgsConstructor
@Service
public class UserService {
private final UserRepository userRepository;
public SiteUser create(String username, String email, String password) {
SiteUser user = new SiteUser();
user.setUsername(username);
user.setEmail(email);
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
user.setPassword(passwordEncoder.encode(password));
this.userRepository.save(user);
return user;
}
}
3-1. BCryptPasswordEncoder @Bean으로 생성
SecurityConfig.java에 다음 bean을 추가한다.
@Bean 어노테이션을 사용하여 직접 정의한 메소드에 대해 스프링 컨테이너에 의해 관리되는 빈을 정의한다.
그렇게 되면
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
회원 서비스에서 비밀번호를 암호화하는것을 위에 선언한 Bean 을 사용할수있다.
@RequiredArgsConstructor
@Service
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));
this.userRepository.save(user);
return user;
}
}
4.회원가입 폼 생성
각각 검증 조건을 설정하여 회원가입 폼을 만든다.
package com.example.form;
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 = "비밀번호는 필수")
private String password1;
@NotEmpty(message = "비밀번호 확인은 필수")
private String password2;
@NotEmpty(message = "이메일은 필수")
@Email
private String email;
}
5.회원 컨트롤러 생성
signup GETMapping 은 회원가입 페이지로 이동할떄
signup PostMapping 은 회원가입을 시도할때다.
package com.example.controller;
import jakarta.validation.Valid;
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 org.springframework.web.bind.annotation.RequestMapping;
import com.example.form.UserCreateForm;
import com.example.service.UserService;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Controller
@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";
}
//성공
userService.create(userCreateForm.getUsername(),
userCreateForm.getEmail(), userCreateForm.getPassword1());
return "redirect:/";
}
}
6.회원가입 템플릿
/user/signup으로 Post한다.
컨트롤러에서 전송된 모델 객체인 userCreateForm을 참조하여 form의 각 입력 필드와 모델 객체의 필드를 자동으로 매핑한다.
<html layout:decorate="~{layout}">
<div layout:fragment="content" class="container my-3">
<h4>회원가입</h4>
<form th:action="@{/user/signup}" th:object="${userCreateForm}" method="post"></form>
<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>
회원가입에 접근가능하도록 네비게이션바에 회원가입링크를 추가해준다.
<li class="nav-item">
<a class="nav-link" href="@{/user/signup}">회원가입</a>
</li>
7.중복 회원막기
DataIntegrityViolationException예외는 이미 등록된 사용자일떄 나온다. 이때 예외를 처리해준다.
//성공
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:/";
}
'BackEnd > SpringBoot' 카테고리의 다른 글
[오류][SpringBoot] sec:authorize 오류 (0) | 2024.07.05 |
---|---|
[Spring Boot] 스프링 시큐리티 (0) | 2024.07.04 |
[Spring Boot]페이징, 답변개수 (0) | 2024.07.04 |