Nellie's Blog

[항해99][과제] Spring 숙련주차 - 스프링 부트로 회원가입, 로그인, 댓글 작성/조회/수정/삭제 기능이 추가된 블로그 백엔드 서버 만들기(JWT사용) 본문

회고록/항해99

[항해99][과제] Spring 숙련주차 - 스프링 부트로 회원가입, 로그인, 댓글 작성/조회/수정/삭제 기능이 추가된 블로그 백엔드 서버 만들기(JWT사용)

Nellie Kim 2022. 12. 5. 12:52
728x90

학습 과제의 목표

  • 회원가입, 로그인을 구현할 수 있어요.
  • 인증/인가를 이해하고 JWT를 활용하여 게시글 및 댓글을 처리할 수 있어요.
  • JPA 연관관계를 이해하고 회원, 게시글 및 댓글을 구현할 수 있어요.

 

서비스 완성 요구사항

  1. 회원 가입 API
    • username, password를 Client에서 전달받기
    • username은 최소 4자 이상, 10자 이하이며 알파벳 소문자(a~z), 숫자(0~9)로 구성되어야 한다.
    • password는 최소 8자 이상, 15자 이하이며 알파벳 대소문자(a~z, A~Z), 숫자(0~9), 특수문자로 구성되어야 한다.
    • DB에 중복된 username이 없다면 회원을 저장하고 Client 로 성공했다는 메시지, 상태코드 반환하기
    • 회원 권한 부여하기 (ADMIN, USER) - ADMIN 회원은 모든 게시글, 댓글 수정 / 삭제 가능
    • 참고자료
      1. https://mangkyu.tistory.com/174
      2. https://ko.wikipedia.org/wiki/정규_표현식
      3. https://bamdule.tistory.com/35
  2. 로그인 API
    • username, password를 Client에서 전달받기
    • DB에서 username을 사용하여 저장된 회원의 유무를 확인하고 있다면 password 비교하기
    • 로그인 성공 시, 로그인에 성공한 유저의 정보와 JWT를 활용하여 토큰을 발급하고, 발급한 토큰을 Header에 추가하고 성공했다는 메시지, 상태코드 와 함께 Client에 반환하기
  3. 댓글 작성 API
    • 토큰을 검사하여, 유효한 토큰일 경우에만 댓글 작성 가능
    • 선택한 게시글의 DB 저장 유무를 확인하기
    • 선택한 게시글이 있다면 댓글을 등록하고 등록된 댓글 반환하기
  4. 댓글 수정 API
    • 토큰을 검사한 후, 유효한 토큰이면서 해당 사용자가 작성한 댓글만 수정 가능
    • 선택한 댓글의 DB 저장 유무를 확인하기
    • 선택한 댓글이 있다면 댓글 수정하고 수정된 댓글 반환하기
  5. 댓글 삭제 API
    • 토큰을 검사한 후, 유효한 토큰이면서 해당 사용자가 작성한 댓글만 삭제 가능
    • 선택한 댓글의 DB 저장 유무를 확인하기
    • 선택한 댓글이 있다면 댓글 삭제하고 Client 로 성공했다는 메시지, 상태코드 반환하기
  6. 예외 처리
    • 토큰이 필요한 API 요청에서 토큰을 전달하지 않았거나 정상 토큰이 아닐 때는 "토큰이 유효하지 않습니다." 라는 에러메시지와 statusCode: 400을 Client에 반환하기
    • 토큰이 있고, 유효한 토큰이지만 해당 사용자가 작성한 게시글/댓글이 아닌 경우에는 “작성자만 삭제/수정할 수 있습니다.”라는 에러메시지와 statusCode: 400을 Client에 반환하기
    • DB에 이미 존재하는 username으로 회원가입을 요청한 경우 "중복된 username 입니다." 라는 에러메시지와 statusCode: 400을 Client에 반환하기
    • 로그인 시, 전달된 username과 password 중 맞지 않는 정보가 있다면 "회원을 찾을 수 없습니다."라는 에러메시지와 statusCode: 400을 Client에 반환하기

 

API 명세서 예시

Method(기능) URL Request Header Request Response Response header
POST
(회원가입)
/api/auth/signup   {
"username": "bin1234",
"password": "Bin@12345"
}
{
"msg": "회원가입 성공",
"statusCode": 200
}
 
POST
(로그인)
/api/auth/login   {
"username": "bin1234",
"password": "Bin@12345"
}
{
"msg": "로그인 성공",
"statusCode": 200
}
Authorization: Bearer
eyJhbGciOiJIUzI1NiJ9......
POST
(글 작성)
/api/post Authorization: Bearer
eyJhbGciOiJIUzI1NiJ9......
{
"title": "게시글5",
"content": "내용5"
}
{
"id": 5,
"title": "게시글5",
"content": "내용5",
"username": "bin1234",
"createdAt": "2022-12-01T12:56",
"modifiedAt": "2022-12-01T12:56",
"commentList": []
}
 
GET
(글 목록조회)
/api/post     {
"postList": [
{
"id": 1,
"title": "게시글1",
"content": "내용1",
"username": "bin1234",
"createdAt": "2022-12-01T12:56",
"modifiedAt": "2022-12-01T12:56",
"commentList": [
{
"id": 1,
"content": "댓글1",
"createdAt": "2022-12-01T12:56",
"modifiedAt": "2022-12-01T12:56",
"username": "bin1234"
},
{
"id": 2,
"content": "댓글2",
"createdAt": "2022-12-01T12:56",
"modifiedAt": "2022-12-01T12:56",
"username": "bin1234"
}
]
},
{
"id": 2,
"title": "게시글2",
"content": "내용2",
"username": "bin1234",
"createdAt": "2022-12-01T12:56",
"modifiedAt": "2022-12-01T12:56",
"commentList": [
{
"id": 3,
"content": "댓글1",
"createdAt": "2022-12-01T12:56",
"modifiedAt": "2022-12-01T12:56",
"username": "bin1234"
},
{
"id": 4,
"content": "댓글5 수정",
"createdAt": "2022-12-01T12:56",
"modifiedAt": "2022-12-01T12:56",
"username": "bin1234"
}
]
}
]
}
 
GET
(글 상세조회)
/api/post/{id}     {
"id": 1,
"title": "게시글1",
"content": "내용1",
"username": "bin1234",
"createdAt": "2022-12-01T12:56",
"modifiedAt": "2022-12-01T12:56",
"commentList": [
{ "id": 1,
"content": "댓글1",
"createdAt": "2022-12-01T12:56",
"modifiedAt": "2022-12-01T12:56",
"username": "bin1234"
},
{ "id": 2,
"content": "댓글2",
"createdAt": "2022-12-01T12:56",
"modifiedAt": "2022-12-01T12:56",
"username": "bin1234"
}
]
}
 
PUT
(글 수정)
/api/post/{id} Authorization: Bearer
eyJhbGciOiJIUzI1NiJ9......
{
"title": "게시글4 삭제 내용5 수정",
"content": "내용4 삭제 내용5 수정"
}
{
"id": 5,
"title": "게시글4 삭제 내용5 수정",
"content": "내용4 삭제 내용5 수정",
"username": "bin1234",
"createdAt": "2022-12-01T12:56",
"modifiedAt": "2022-12-01T12:56",
"commentList": []
}
 
DELETE
(글 삭제)
/api/post/{id} Authorization: Bearer
eyJhbGciOiJIUzI1NiJ9......
  {
"msg": "게시글 삭제 성공",
"statusCode": 200
}
 
POST
(댓글 작성)
/api/comment/{id} Authorization: Bearer
eyJhbGciOiJIUzI1NiJ9......
{
"content": "댓글2"
}
{
"
id": 10,

"content": "댓글2",
"createdAt": "2022-12-01T12:56",
"modifiedAt": "2022-12-01T12:56",
"username": "bin1234"
}
 
PUT
(댓글 수정)
/api/comment/{id} Authorization: Bearer
eyJhbGciOiJIUzI1NiJ9......
{
"content": "댓글5 수정"
}
{
"
id": 5,

"content": "댓글5 수정",
"createdAt": "2022-12-01T12:56",
"modifiedAt": "2022-12-01T12:56",
"username": "bin1234"
}
 
DELETE
(댓글 삭제)
/api/comment/{id} Authorization: Bearer
eyJhbGciOiJIUzI1NiJ9......
  {
"msg": "댓글 삭제 성공",
"statusCode": 200
}
 

 

ERD(Entity Relationship Diagram) 설계

 


서버에서 반환받은 JWT 확인하는 방법

로그인 Post 요청 후, 아래 Header 부분의 Authorization에서 확인가능

 

 

HTTP Header에 JWT를 추가하여 요청하는 방법 

글 작성 Post 요청 전, Headers에서 Authorization을 넣고, Body에도 넣고 요청

 


아이디 비밀번호 유효성검사(@NotBlank, @Pattern)


연관관계 매핑

User - Post ( 일대다 )

위와 같이 매핑을 해주니, DB에 USERS_ID 컬럼이 생성되었다.


파일 구조 파악

- controller

 

 

- service

  •  UserService

 

  • PostService

 

  • CommentService

 

- repository

 

 

- dto

 

- entity

 

- jwt

 

- application.properties

 

 

 


https://github.com/hyeonju-kim/hanghae_blog_3w-4w

 

GitHub - hyeonju-kim/hanghae_blog_3w-4w: Spring 입문주차 과제 - 스프링 부트로 로그인 기능이 없는 블로그

Spring 입문주차 과제 - 스프링 부트로 로그인 기능이 없는 블로그 백엔드 서버 만들기 - GitHub - hyeonju-kim/hanghae_blog_3w-4w: Spring 입문주차 과제 - 스프링 부트로 로그인 기능이 없는 블로그 백엔드 서

github.com