슬기의 TIL - 2023.04.18
오늘은 어제 들은 강의를 바탕으로 숙련주차 과제를 시작했고, 하루만에 완성해냈다!
과제 내용은 지난 과제에 회원가입, 로그인 기능을 추가하는 것이다.
완성본은 깃허브에 올라가 있다.
https://github.com/limseulki/hanghaeblog
페어로 진행되어 회원가입, 로그인 기능은 함께 추가하고 나머지 부분은 나눠서 수정해보기로 계획했다.
먼저 API 명세서와 ERD를 설계했다.
ERD(Entity Relationship Diagram)는 객체와 관계를 중심적으로 표시하는 데이터베이스 구조를 한 눈에 알아보기 위해 그려놓는 다이어그램이다.
API 명세서는 몇 번 작성해봐서 알고 있어 수월하게 작성했는데, ERD는 처음 들었다.
데이터베이스 설계처럼 1:다 관계를 설정할 수도 있고, 테이블 구성도 할 수 있었다.
미리 전체적인 흐름과 로직을 생각하고 설계를 하니까 코드 구현하면서 이해 충돌이 발생할 경우가 줄어들었다.
구현하면서도 명세서를 참고해 request와 response가 어떻게 나와야하는지 잊지 않을 수 있었다.
먼저 회원가입, 로그인 부분을 구현하는데 조건을 추가해야 했다.
회원 아이디는 알파벳 소문자, 숫자로 작성되어야 하고 글자수 제한이 있었다.
Service가 구현이 되는 클래스라 조건을 달아주려고 했는데, 코드가 길어져 지저분하다는 생각이 들었다.
다른 좋은 방법이 없을까 찾아보니 @Valid 어노테이션이 있었다.
@Valid는 객체의 제약 조건을 검증하도록 지시하는 어노테이션이다. 사용하기 위해서는 의존성을 추가해주어야 한다.
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-validation'
@Size 어노테이션을 사용해 문자열의 크기를 제한해 글자수 제한을 걸었다.
그리고 Controller의 메소드에는 @Valid를 붙여 유효성 검증을 하도록 했다.
알파벳 소문자와 숫자로 구성되어야 하는 부분은 Service에서 if문으로 조건을 걸어주었다.
// username은 알파벳 소문자, 숫자
if(!Pattern.matches("^[a-z0-9]*$", username)) {
return "사용자 이름은 알파벳 소문자, 숫자로 작성해주세요.";
}
// password는 알파벳 대소문자, 숫자
if(!Pattern.matches("^[a-zA-Z0-9]*$", password)) {
return "비밀번호는 알파벳 대소문자, 숫자로 작성해주세요.";
}
회원가입, 로그인을 하면 데이터베이스에 저장도 잘 되고 동작은 다 하는데 state가 500으로 나오는 이슈가 있었다.
UserController 코드를 천천히 보다가 @Controller가 달려있는 것을 @RestController로 바꾸어줘서 해결했다!
@Controller와 @RestController 차이점
@Controller는 클래스를 Spring MVP Controller로 표시하는 데 사용되고 뷰를 반환하고, @RestController는 모든 메소드가 객체로 작성된다.
오늘 우리를 아주아주 힘들게 괴롭혔던 것은 토큰이 안넘어오는 것이었다.
로그인시 토큰을 생성해 header에 보내주는 건 확인이 되는데, 다른 작업을 할 때 토큰을 헤더에서 읽어오는 부분이 작동하지 않았다. 아무리 코드를 뜯어봐도 틀린 부분이 없는데, 이상한 일이었다.
세시간 정도 진짜 왜이러지 고민하면서 토큰값을 한줄한줄 찍어보는데 NULL이 찍히는게 진짜 이상해서 어쩌면 HTML이 아니라 POSTMAN을 써서 그럴 수도 있겠다는 생각이 들었다.
네트워크를 사용하는 게 아니라 토큰 값이 저장되어 있는 곳이 HTML이 아니니까, 어쩌면 헤더의 토큰값도 다른 메소드를 실행할 때 직접 전달해줘야 하는 걸 수도 있겠다는 생각에 도달하였고, 바로 POSTMAN 헤더값 전달을 찾아봤다.
Auth에 Type을 Bearer Token으로 두고 로그인시 생성된 토큰값을 헤더에서 복사해 Token에 붙여주고, Body에 데이터를 넣어 보내니... 정상적으로 작동했다!
결국 Postman 사용법을 몰라 다른 곳에서 문제를 해결하려고 시간을 보냈던 것이다 ㅠㅠ
이렇게 큰 산을 넘었다.
마지막으로 만났던 또 다른 산이 있다.
createPost를 할 때 username이 null로 들어오는 이슈가 발생했다.
Post 클래스에서 Setter를 사용하고, Service에서 setUsername을 해서 값을 넣어주었더니 해결되었다.
이 부분은 페어님께서 해결!
// 토큰 체크
User user = checkJwtToken(request);
Post post = new Post(requestDto);
post.setUsername(user.getUsername());
postRepository.saveAndFlush(post);
return new PostResponseDto(post);
꼬박 하루가 걸려서 과제를 수행했고, 포기하기 직전에 해결 방법을 찾아 완성해내 더 뿌듯하다.
다음 과제로 넘어가기 전에 입문, 숙련 주차를 조금 더 깊이 파보아야겠다.