스프링부트 회원가입 구현
새로운 프로젝트를 시작하여 회원가입을 구현해보았다.
깔아놓은 라이브러리들은 다음과 같다.
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.session:spring-session-core'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
//@NotNull등 사용
implementation 'org.springframework.boot:spring-boot-starter-validation'
//mail authorization
implementation 'org.springframework.boot:spring-boot-starter-mail'
}
회원가입을 할 때 필요한 아주 간단한 기능들을 생각해 보았다.
아이디가 중복되면 안된다.
이메일 인증을 통해 유저의 이메일을 검증한다.
회원가입 창에서 유저가 입력해야 할 것들은 다음과 같다.
유저아이디,비밀번호,이메일,이름,생년월일 등...
@Setter
@Entity
public class User {
@NotBlank //implementation 'org.springframework.boot:spring-boot-starter-validation'임포트해야됨
@Id
@Column(name= "User_id")
private String id;
@NotBlank
private String password;
private String email;
private String name;
private LocalDate birth;
private String sex;
private String mbti;
}
Bean Validation을 사용하기 위해 spring-boot-starter-validation을 build.gradle에 추가해 주었다.
public String register_post(@Validated @ModelAttribute User user, BindingResult bindingResult) {
log.info("{}", user.getName());
log.info("{}", user.getBirth());
if (bindingResult.hasErrors()) {
return "/register";
}
userService.join(user);
return "login";
}
회원가입 버튼을 누르면 실행되는 메서드이다. 검증을 위해 @Validated 어노테이션을 넣고 User user 다음에 BindingResult를 넣어줌으로서 user의 필드에 잘못된 값이 들어가게 되면 Field Error를 bindingResult에 추가하게 된다. 에러가 추가되면 userService.join(user)가 실행되지 않고(회원가입이 되지 않고) 다시 회원가입창으로 가게된다.
user객체에 모든 필드가 정상적으로 입력되면 userService.join(user)가 실행되는데, 이 메서드를 통해 userRepository.save(user)가 실행된다. userRepository.save(User user)메서드는 결국 em.persist(user)로 영속성 컨텍스트에 user를 추가해주고 트랜잭션이 끝나면 커밋이 되어 데이터베이스에 저장된다.
초간단하게 만든 뷰템플릿이다.
<label for="id">회원ID</label>
<input type="text" id="id" th:field="*{id}">
<button type="button" onclick="sameCheck()">아이디 중복체크</button>
</div>
아이디 중복체크 버튼이다. 클릭하게 되면 sameCheck()라는 함수가 실행되는데
let userId = document.getElementById('id').value.trim(); // input에서 사용자가 입력한 ID가져오기
console.log("USERID: "+userId);
if (!userId) {
return;//입력값이 공백인 경우 아무 작업도 수행하지 않음.
}
$.ajax({
type: "get",
url: "/register/idDuplicateCheck?id=" + userId
}).done((res) => {
userIdCheck = true; //중복체크완료. 아이디가 중복되지 않음.
alert("사용가능한 아이디입니다.");
}).fail(()=>{
alert("메시지 중복입니다.");
userIdCheck = false;
});
}
이렇게 생겼다. document.getElementById를 통해 id 인풋폼에 담긴 값을 가져와서 /register/idDuplicateCheck에 매핑되는 메서드를 호출한다.
@ResponseBody
public ResponseEntity<String> register_idDuplicateCheck(@RequestParam String id) {
log.info("id중복확인 실행됨.");
boolean duplicated = userService.validateDuplicateMember(id);
log.info("duplicated:{}", duplicated);
if (duplicated) {
return new ResponseEntity<>("duplicated", HttpStatus.BAD_REQUEST);
} else return new ResponseEntity<>("ok", HttpStatus.OK);
}
log.info를 통해 이 메서드가 실행되는지 확인을 해보았다.
userService.validateDuplicateMember(id)는 데이터베이스의 유저테이블에 회원가입창에 입력한 아이디가 이미 있는지를 체크해 있다면 true를 반환하는 메서드이다. 중복이 된다면 상태코드를 BAD_REQUEST로, 중복이 아니라면 OK로 리턴해준다. 그러면 sameCheck함수에서 userIdCheck를 true로 만들어주고 alert("사용가능한 아이디입니다.")를 통해 사용가능한 아이디라고 알려준다.
public boolean validateDuplicateMember(String id) {
log.info("중복체크함수실행 id={}",id);
Optional<User> existinguser = Optional.ofNullable(userRepository.findById(id));
return existinguser.isPresent();
}
userService.validateDuplicateMember(id)메서드는 이렇게 생겼다. userRepository.findById(id)는
userId(pk)를 이용하여 개체를 리턴한다.
<label for="email">이메일</label>
<input type="email" id="email" th:field="*{email}">
<button type="button" onclick="sendingAuthenticationMail()">이메일 인증번호 발송</button>
</div>
<div id="verificationCodeContainer" style="display: none;">
<label for="verificationCode">인증번호</label>
<input type="text" id="verificationCode">
<button type="button" onclick="checkingAuthenticationMail()">인증번호 확인</button>
</div>
let email = document.getElementById('email').value;
$.ajax({
type: "get",
url: "/register/sendingAuthenticationMail?email=" + email
}).done((res)=>{
alert("이메일이 보내졌습니다. 확인해주세요");
verificationNumber = res;
document.getElementById('verificationCodeContainer').style.display = 'block'; // 'none' 대신 'block'으로 설정하여 보이게 함
}).fail();
}
이메일 인증번호 발송 버튼을 누르면 sendingAuthenticationMail메서드가 실행되는데, 이 메서드의 내부에서 ajax통신을 통해 아래 메서드가 호출된다.
@ResponseBody
public ResponseEntity<String> register_sendingAuthenticationMail
(@RequestParam String email, Model model) {
log.info("이메일 인증 실행...{}", email);
mailService.sendingAuthenticationMail(email, model);
return new ResponseEntity<String>((String) model.getAttribute("randomNumber"),HttpStatus.OK);
}
mailService.sendingAuthenticationMail(email,model)메서드를 통해 메일을 보내는데, 눈여겨 봐야할 점은 model이 같이 넘어간다는 것이다. 이 메서드내부에서 만들어진 인증번호가 model.addAttribute("randomNumber",randomNumber)를 통해 모델에 저장되고 return new ResponseEntity<String>((String) model.getAttribute("randomNumber"),HttpStatus.OK);
를 통해 랜덤값이 스트링형식으로 리턴되는데, 이 값은 인증번호 확인시 사용자가 입력한 값과 대조할 때에 쓰인다.
String randomNumber = String.valueOf(createRandomNumber());
model.addAttribute("randomNumber",randomNumber);
//이메일중복 확인기능 넣어야한다.
String text="홈페이지를 방문해주셔서 감사합니다."+
"\n"+ "인증번호는 "+randomNumber+"입니다." +
"\n" +
"해당 인증번호를 인증번호 확인란에 기입해주세요.";
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(userMail);
message.setFrom(senderEmail);
message.setSubject("요청하신 인증메일입니다.");
message.setText(text);
mailSender.send(message);
}
private int createRandomNumber() {
int value = (int) (Math.random()*888888) + 111111;
return value;
}
https://github.com/LimJaeEun0930/CapstoneDesign_Backend-server