2022.11.22 - [Java/spring 게시판] - spring boot 게시판 - 6
이전 시간에 머리 식히려고 프론트 관련된 내용을 진행했었는데 이번에는 회원 정보 수정 및 탈퇴를 구현했다.
✅ 회원 정보 수정 <이름 변경>
현재 member entity에 email은 pk로 지정되어 있고 나머지 컬럼은 username과 password 밖에 없어서
둘 다 한번에 수정을 할까 하다가 그냥 하나씩 수정할 수 있도록 구현했다.
⏹️ MemberController.java
/**
* 회원 이름 변경
* @param model
* @param authentication 인증 정보
* @return 회원 이름 변경 페이지
*/
@GetMapping("/update/username")
public String updateUsernameForm(Model model, Authentication authentication) {
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
MemberResponseDTO member = memberService.findMember(userDetails.getUsername());
model.addAttribute("member", member);
return "/members/updateUsername";
}
우선 회원 정보 수정 페이지에 접근할 때 Authentication을 통해 유저 정보를 확인하고
최대한 view 영역에서 Entity를 알 수 없도록 지정된 DTO를 반환하였다.
⏹️ 회원 정보 수정 화면
DTO를 반환 받아서 Email과 User name을 보여주고 email은 pk라 변경할 수 없으니 readonly를 걸어주고
username만 변경할 수 있도록 해뒀다.
⏹️ MemberController.java
/**
* 회원 이름 변경 post
* @param memberUsernameUpdateDTO
* @param errors
* @param model
* @return 회원 정보 페이지
*/
@PostMapping("/update/username")
public String updateUsername(@Valid MemberUsernameUpdateDTO memberUsernameUpdateDTO, Errors errors, Model model, Authentication authentication) {
if (errors.hasErrors()) {
model.addAttribute("member", memberUsernameUpdateDTO);
globalService.messageHandling(errors, model);
return "/members/updateUsername";
}
memberService.updateMemberUsername(memberUsernameUpdateDTO);
return "redirect:/member/info";
}
다시 컨트롤러로 넘어와서 이번에는 username을 변경한 뒤 update를 클릭하면 작동할 로직을 구현했다.
username의 유효성 검사를 진행해야 하니 검증 코드를 거쳐 유효성 검사를 진행하고
검증이 완료 됐다면 service에 정보를 넘겨준다.
그전에 먼저 Member Entity에서 메서드를 작성해준다.
⏹️ Member.java
public void updateUsername(String username) {
this.username = username;
}
public void updatePassword(String password) {
this.password = password;
}
repository를 제외한 다른 영역에서 Entity를 수정할 수 있게 만들고 싶지 않아서 최대한 이런 메서드는
쓰지 않으려고 했지만 별다른 방안을 찾지 못해서 결국 메서드를 만들었다.
(혹시 다른 방법을 알고 계신분은 알려주시면 감사하겠습니다. 꾸벅)
⏹️ MemberServiceImpl.java
@Override
public Long updateMemberUsername(MemberUsernameUpdateDTO memberUsernameUpdateDTO) {
Member member = memberRepository.findByEmail(memberUsernameUpdateDTO.getEmail()).orElseThrow(() -> new UsernameNotFoundException("이메일이 존재하지 않습니다."));
member.updateUsername(memberUsernameUpdateDTO.getUsername());
memberRepository.save(member);
return member.getId();
}
Member Entity에 메서드를 만들었다면 Service 영역에서 넘겨받은 데이터를 통해 유저를 찾고
해당 유저의 username을 변경한 뒤 다시 save 해주고 id를 리턴한다.
저 리턴 값은 지금은 무의미 하지만 프로젝트가 커지면 사용할 수 있으니 저렇게 만들어 놓았다.
⏹️ 회원 정보 수정 테스트
변경 전을 보면 User name이 minki로 나타난다.
User name을 magic으로 변경해 보았다.
성공적으로 User name이 변경되었다.
✅ 회원 정보 수정 <비밀번호 변경>
비밀번호 변경은 현재 비밀번호를 입력하고 변경할 비밀번호를 두 번 입력하는 형식으로 작성하였다.
하지만 현재 비밀번호가 맞지 않았을 경우 Exception이 터지는 것을 좀 더 간결하고 멋지게
작성하고 싶었는데 구닥다리(?) 식으로 구현한 것 같아서 마음에 들지 않는다..
⏹️ 비밀번호 변경 화면
비밀번호 변경 url로 접속하면 별다른 내용 없이 해당 화면이 표시되게 만들었다.
⏹️ MemberController.java
/**
* 회원 비밀번호 변경 post
* @param memberPasswordUpdateDTO
* @param model
* @param authentication
* @return 회원 정보 페이지
*/
@PostMapping("/update/password")
public String updatePassword(@Valid MemberPasswordUpdateDTO memberPasswordUpdateDTO, Model model, Authentication authentication) {
// new password 비교
if (!Objects.equals(memberPasswordUpdateDTO.getNewPassword(), memberPasswordUpdateDTO.getConfirmPassword())) {
model.addAttribute("dto", memberPasswordUpdateDTO);
model.addAttribute("differentPassword", "비밀번호가 같지 않습니다.");
return "/members/updatePassword";
}
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
Long result = memberService.updateMemberPassword(memberPasswordUpdateDTO, userDetails.getUsername());
// 현재 비밀번호가 틀렸을 경우
if (result == null) {
model.addAttribute("dto", memberPasswordUpdateDTO);
model.addAttribute("wrongPassword", "비밀번호가 맞지 않습니다.");
return "/members/updatePassword";
}
return "redirect:/member/info";
}
코드가 굉장히 난잡하다...
우선 첫번째 분기문을 보면 DTO을 통해 현재 비밀번호, 새 비밀번호, 확인 비밀번호 이렇게 3가지를 전달받는데
새 비밀번호와 확인 비밀번호가 같은지를 확인하고 다르다면 입력했던 정보들과 함께 메세지를 보낸다.
비밀번호 2개가 다르면 위와 같은 메세지가 나온다.
그리고 Authentication을 통해 User 정보를 받아온 뒤 Service 영역으로 해당 정보와 비밀번호 정보를 함께 넘겨준다.
그런 뒤 결괏값이 있다면 변경이 완료되어 유저 프로필 페이지로 넘어가고
결과값이 없다면 입력했던 비밀번호 정보와 함께 기존 비밀번호가 틀렸다는 메세지를 넘겨준다.
위와 같이 기존 비밀번호가 맞지 않다는 오류를 출력한다.
⏹️ MemberServiceImpl.java
@Override
public Long updateMemberPassword(MemberPasswordUpdateDTO memberPasswordUpdateDTO, String email) {
Member member = memberRepository.findByEmail(email).orElseThrow(() -> new UsernameNotFoundException("이메일이 존재하지 않습니다."));
if (!passwordEncoder.matches(memberPasswordUpdateDTO.getCurrentPassword(), member.getPassword())) {
return null;
} else {
memberPasswordUpdateDTO.setNewPassword(passwordEncoder.encode(memberPasswordUpdateDTO.getNewPassword()));
member.updatePassword(memberPasswordUpdateDTO.getNewPassword());
memberRepository.save(member);
}
return member.getId();
}
Service 영역에서는 전달받은 데이터를 가지고 member 객체를 가져오고
해당 member의 비밀번호와 전달 받은 기존 비밀번호가 같은지를 체크한다.
같지 않다면 null을 리턴하고 같다면
새로운 비밀번호를 암호화해서 비밀번호를 update하고 save를 진행한다.
⏹️ 비밀번호 변경 테스트
비밀번호가 제대로 변경되었다.
✅ 회원 탈퇴
회원 탈퇴는 그냥 버튼만 누르면 할 수 있도록 만들까 하다가 그래도 비밀번호로 한 번쯤은 체크하자 싶어서
아래처럼 구성하였다.
⏹️ 회원 탈퇴 화면
위처럼 회원 탈퇴 페이지로 들어가면 비밀번호를 입력한 뒤 탈퇴를 할 수 있도록 만들었다.
⏹️ MemberController.java
/**
* 회원 탈퇴 post
* @param password
* @param model
* @param authentication
* @return 홈 페이지
*/
@PostMapping("/withdrawal")
public String memberWithdrawal(@RequestParam String password, Model model, Authentication authentication) {
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
boolean result = memberService.withdrawal(userDetails.getUsername(), password);
if (result) {
return "redirect:/logout";
} else {
model.addAttribute("wrongPassword", "비밀번호가 맞지 않습니다.");
return "/members/withdrawal";
}
}
여기서는 비밀번호를 하나만 입력받기 때문에 DTO를 통해 받지 않고 @RequestParam을 통해 직접 받았다.
Service영역으로 데이터를 전달하면 boolean값을 리턴하는데 회원 탈퇴가 완료되면 true를 리턴한다.
회원 탈퇴가 이루어진 뒤 로그아웃이 진행되지 않아 리턴 값을 logout으로 리다이렉트 시켰다.
그리고 여기서도 비밀번호가 맞는지를 확인하는데 이 부분은 위에서 설명했으니 패스
⏹️ MemberServiceImpl.java
@Override
public boolean withdrawal(String email, String password) {
Member member = memberRepository.findByEmail(email).orElseThrow(() -> new UsernameNotFoundException("이메일이 존재하지 않습니다."));
if (passwordEncoder.matches(password, member.getPassword())) {
memberRepository.delete(member);
return true;
} else {
return false;
}
}
전달받은 데이터로 member 객체를 가져온 뒤 비밀번호를 검사하고 맞다면 회원을 삭제한 뒤 true값을 리턴하고
아니면 false를 리턴한다.
✅ 끝
아무리 봐도 코드에 분기문이 너무 많아 마음에 들지 않지만 일단 어떻게든 작동되게 만들었다..
엄청 쉬운 작업인데도 혼자 하려니 만만치 않은 것 같다.
이래서 개발은 이것저것 만들어 봐야 한다고 하는 것 같다. 다음에는 본격적으로 게시글에 관련된
로직을 구현해보겠다.
'Java > Spring Boot 게시판' 카테고리의 다른 글
spring boot 게시판 - 9 <게시물 수정, 삭제> (2) | 2022.11.30 |
---|---|
spring boot 게시판 - 8 <게시물 작성, 조회> (0) | 2022.11.30 |
spring boot 게시판 - 6 <bootstrap 적용하기> (0) | 2022.11.22 |
spring boot 게시판 - 5 <thymeleaf layout 적용> (0) | 2022.11.21 |
spring boot 게시판 - 4 <spring security form login 구현> (0) | 2022.11.18 |