일단, 다듬는 이유부터 말하자면, 실제 웹사이트에서 회원 정보 수정을 할 때를 생각해보았을 때, 이게 이상하다고 느꼈기 때문이다.
보통 회원정보를 수정하면, 한 페이지에서 이메일, 닉네임, 비밀번호 수정등을 모두 하는데,
지금 만든 프로젝트에서는 각 정보마다 수정을 따로 해주어야 하기 때문이다.
이걸 동적으로 하면 되겠다는 생각이 들었다.
기존의 코드를 조금 인용해서,
@Transactional
public void editMember(EditMemberRequestDto editMemberRequestDto, Member member){
if(editMemberRequestDto.getNickname() == null && editMemberRequestDto.getEmail() == null
&& editMemberRequestDto.getPassword() == null && editMemberRequestDto.getPasswordCheck() == null)
throw new NeedToAddEditConditionException();
if((editMemberRequestDto.getPassword() != null && editMemberRequestDto.getPasswordCheck() == null) ||
(editMemberRequestDto.getPassword() == null && editMemberRequestDto.getPasswordCheck() != null))
throw new NeedToPutPasswordTwiceToEditException();
if(editMemberRequestDto.getNickname() != null)
changeMemberNickname(editMemberRequestDto.getNickname(), member);
if(editMemberRequestDto.getEmail() != null)
changeMemberEmail(editMemberRequestDto.getEmail(), member);
if(editMemberRequestDto.getPassword() != null && editMemberRequestDto.getPasswordCheck() != null)
changeMemberPassword(editMemberRequestDto.getPassword()
, editMemberRequestDto.getPasswordCheck(), member);
}
이런 식으로 기능을 만들었다.
전부 null이면 예외처리하고,
비밀번호 2회 입력중에 하나만 있을 때 예외처리하고,
null이 아닌 값들만 수정을 해주는 방식으로 만들었다.
기존의 change~~의 메서드를 그대로 이용했다. 물론, 입력 파라미터를 dto에서 문자열과 Member로 변경했다.
테스트도 만들어서 검증까지는 끝마쳤다. 만약 궁금하면 깃허브로 가보면 된다
이걸 컨트롤러로 끌고와서 테스트를 했다.
- 400에러
- 이미 사용중인 닉네임
- 이미 사용중인 이메일
- 비밀번호가 서로 다를 때
- 비밀번호가 둘중 하나 null일 때
- 비밀번호가 기존과 같을 때
- 이메일 형식이 올바르지 않을 때
- 401에러
- 로그인해서 받는 토큰이 존재하지 않을 때
- 200 성공
400과 200은 기존의 서비스 로직에서 발생하는 예외이며, 401에러는 Spring Security에서 처리된다.
일단 테스트를 성공하는 경우만 만들어서 보여보자면,
@Test
@DisplayName("닉네임 변경을 요청할 떄, 성공하면 200코드와 수정에 성공했음을 반환해준다. ")
public void editNickname_Success() throws Exception{
//given
authService.registerNewMember(RegisterRequestDto.builder()
.username("test")
.nickname("test")
.email("test@test.com")
.password("test")
.passwordCheck("test").build());
TokenResponseDto tokenResponseDto = authService.signIn(SignInRequestDto.builder()
.username("test")
.password("test").build());
EditMemberRequestDto editMemberRequestDto = EditMemberRequestDto.builder()
.nickname("newNick")
.build();
//expected
mvc.perform(MockMvcRequestBuilders.patch("/api/members/edit")
.header("Authorization", "Bearer ".concat(tokenResponseDto.getAccessToken()))
.header("RefreshToken", "Bearer ".concat(tokenResponseDto.getRefreshToken()))
.contentType(MediaType.APPLICATION_JSON)
.content(makeJson(editMemberRequestDto)))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.jsonPath("$.success").value(true))
.andExpect(MockMvcResultMatchers.jsonPath("$.code").value(200))
.andExpect(MockMvcResultMatchers.jsonPath("$.result.data").value("수정을 성공했습니다."))
.andDo(MockMvcResultHandlers.print());
Assertions.assertThat(memberRepository.findByUsername("test").get().getNickname()).isEqualTo("newNick");
}
이런식으로 로그인로직을 이용해 토큰을 넣어서 만들었다.
그렇다면, 컨트롤러에서 서비스로직에 파라미터로 Member를 넣어야 한다는 뜻이다.
이것도 구현을 컨트롤러에서 만들까 했는데, 그러진 않았다.
Member -> MemberRepository -> MemberService -> MemberController로 레이어를 구분했는데, 컨트롤러에서 MemberRepository.findByUsername으로 해서 다시 찾아오게 하는 것을 진행하고싶진 않았다.
그래서, MemberService에 로직을 하나 추가했다.
public Member findMemberByUsername(String username){
return memberRepository.findByUsername(username).orElseThrow(MemberNotFoundException::new);
}
이걸 이용해 컨트롤러에서 Member를 불러올 것이다.
SecurityContextHolder.getContext().getAuthentication().getName()을 이용해 현재 이용하는 멤버의 username을 가져오고,
이걸 위의 메서드에 넣었다.
private Member getUsingMember(){
String username = SecurityContextHolder.getContext().getAuthentication().getName();
return memberService.findMemberByUsername(username);
}
그렇게 만들어진 컨트롤러 로직을 이용해
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/members")
public class MemberController {
private final MemberService memberService;
@PatchMapping("/edit")
public Response edit(@RequestBody EditMemberRequestDto editMemberRequestDto){
memberService.editMember(editMemberRequestDto, getUsingMember());
return Response.success("수정을 성공했습니다.");
}
이런식으로 기능을 만들었다.
이제 테스트를 해보았다.
나이쑤~
'스프링 공부 > 게시판 프로젝트 만들기' 카테고리의 다른 글
[스프링] 37. MemberController 조회, 삭제 기능 만들기 (0) | 2023.02.20 |
---|---|
[스프링] 35. AuthController.reissue 테스트부터 프로젝트 코드까지 (0) | 2023.02.20 |
[스프링] 34. AuthController.signIn을 테스트해보자. (0) | 2023.02.20 |
[스프링] 33. 잠깐 쉬면서 만들었던 것들을 리펙토링 한 과정을 요약해보자. (0) | 2023.02.16 |
[스프링] 32. MemberController.register 중복과 기타사유의 예외 테스트 (0) | 2023.02.12 |