Notice
Recent Posts
Recent Comments
Link
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
Archives
Today
Total
관리 메뉴

Blog

블로그 만들기 with React, SpringBoot, Oracle 본문

카테고리 없음

블로그 만들기 with React, SpringBoot, Oracle

ggi88 2024. 4. 12. 10:36

Blog Project with React, SpringBoot, Oracle

후기

Visual Studio Code에서는 React를 사용하여 프론트엔드를 개발하였고, IntelliJ에서는 Spring을 사용하여 백엔드를 구현하였다. 또한, DBeaver에서는 Cloude Oracle을 활용하여 데이터베이스 관리를 진행하였다.

일반적으로 샘플 프로젝트를 개발할 때는 다양한 라이브러리를 활용하여 복잡한 부분을 해결하곤 하는데, 이번 프로젝트는 다르게 접근하였다. 이 프로젝트는 가능한 한 최소한의 라이브러리만을 사용하여 개발을 진행하였다. 이는 프로젝트의 기본적인 요소들을 명확하게 이해하고 구현하는 데 중점을 두었다.

인증, CRUD(Create, Read, Update, Delete) 연산, REST API 설계, 기능 설계, 화면 및 프로젝트 구성 및 관리 등의 기본적인 요소들에 대한 이해를 깊게 하기 위해 이런 방식을 선택한 걸로 보인다. 결과적으로 프로젝트의 전반적인 구성과 진행 과정을 살펴볼 수 있었다.

프로젝트 설명 및 환경구성

(1) [Spring boot + Reactjs (ts) + MySQL] 게시판형 블로그 만들기 Reboot - YouTube

구성

  • React, Spring Boot, Oracle

시나리오

  • 회원가입
  • 로그인
  • 프로필 수정
  • 게시물 작성
  • 게시물 리스트 보기
  • 게시물 상세 보기
  • 게시물 수정
  • 게시물 삭제
  • 댓글 작성
  • 좋아요
  1. 사용자가 회원가입을 진행한다.
    1. 이메일 주소, 비밀번호, 비밀번호 확인, 닉네님, 핸드폰 번호, 주소, 상세 주소 입력 후 회원가입 진행한다.
  2. 회원가입이 성공하면 로그인 진행한다.
    1. 로그인 이메일과 패스워드로 로그인 진행한다.
  3. 로그인에 성공하면 메인화면으로 이동한다.
    1. 메인화면에는 주간 Top3 게시글이 보인다.
      1. 주간 top3 은 좋아요 순서
    2. 최신 게시물이 리스트 형식으로 보인다.
    3. 한 페이지에 5개씩 게시물이 보인다.
    4. 페이징 처리가 되며 최대 10 페이지까지 보이고 이전, 이후로 이동하는 방향버튼이 존재
    5. 인기 검색어가 우측에 존재
    6. 상단에 네비게이션 바가 존재
    7. 네이게이션 바에서 검색을 할 수 있음
    8. 네이게이션 바에서 마이페이지로 이동할 수 있다.
    9. 마이페이지로 이동해서 프로필 및 닉네임 수정이 가능하다
    10. 마이페이지에서 게시물을 등록할 수 있다.
    11. 게시물 등록 시에는 제목, 내용, 사진, 동영상, 파일을 올릴 수 있다.
  4. 게시물 목록에서 작성자의 프로필 사진, 닉네임, 게시물의 제목, 내용, 좋아요 수, 댓글 수, 조회 수 가 보인다.
  5. 게시물 리스트에서 게시물을 선택하면 제목, 작성자, 작성자 프로필 사진, 작성일, 내용, 첨부파일(사진, 동영상, 파일) 을 볼 수 있다.
    1. 본인 게시물이라면 게시물을 수정할 수 있다.
    2. 게시물 수정은 제목, 내용, 사진, 동영상, 파일을 수정할 수 있다.
    3. 본인 게시물이라면 삭제할 수 있다.
    4. 본인 게시물이 아니면 좋아요 를 할 수 있다
      1. 게시물에 좋아요를 누른 유저의 프로필사진과 닉네임이 모두 출력된다.
    5. 모든 게시물에 댓글을 작성할 수 있다.
    6. 댓글은 내용만 작성한다
      1. 댓글은 작성자, 프로필 사진, 작성일, 내용이 보인다.
      2. 댓글은 한번에 3개만 출력되고 페이징이 최대 10페이지 까지 가능하다.
      3. 댓글은 이전, 다음 버튼이 존재한다.
      4. 댓글 수와 좋아요 수가 보일 수 있게 한다.

API

  1. 로그인 signIn
    • url
      • post /api/v1/auth/sign-in
    • requrest
      • email: string
      • password: string
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
          • token: "jwt token"
          • expiredDate: Integer
      • 실패
        • 로그인 실패
          • 401 unauthorized
            • code: "sf"
            • message: "sign in failed"
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  2. 회원가입 signUp
    • url
      • post /api/v1/auth/sign-up
    • requrest
      • email: string
      • password: string
      • nickname: stirng
      • telNumber: string
      • address: string
      • addresDetail: string
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
      • 실패
        • 이메일 포맷 불일치 / 비밀번호 8자리 미만 / 전화번호 포맷 불일치 / 필수 정보 미입력
        • 이메일 중복
          • 400 bad request
            • code: "ee"
            • message: "existed email"
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  3. 주간 상위 top3 게시물 리스트 weeklyTop3List
    • url
      • get /api/v1/board/top-3
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
          • top3List: BoardListItem[]
        • BoardListItem
          • boardNumber: Int
          • boardTitle: string
          • boardContent: string
          • boardImage: string
          • boardWritorProfileImage: string
          • boardWirtorNickname: string
          • boardWriteDate: string
          • boardviewCount: int
          • boardfavoriteCount: int
          • boardcommentCount: int
      • 실패
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  4. 최신 게시물 리스트 currentList
    • url
      • get /api/v1/board/current-list/[pageNumber]
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
          • currentList: BoardListItem[]
        • BoardListItem
          • boardNumber: Int
          • title: string
          • content: string
          • boardTitleImage: string
          • favoriteCount: int
          • commentCount: int
          • viewCount: int
          • writeDateTime: string
          • wirtorNickname: string
          • writorProfileImage: string
      • 실패
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  5. 인기 검색어 리스트 popularList
    • url
      • get /api/v1/search/popular-list
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
          • popularWordList: BoardListItem[]
        • BoardListItem
          • boardNumber: Int
          • title: string
          • content: string
          • boardTitleImage: string
          • favoriteCount: int
          • commentCount: int
          • viewCount: int
          • writeDateTime: string
          • wirtorNickname: string
          • writorProfileImage: string
      • 실패
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  6. 관련 검색어 리스트 relativeWordList
    • url
      • get /api/v1/search/[searchWord]/relation-list
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
          • relativeWordList: BoardListItem[]
        • BoardListItem
          • boardNumber: Int
          • title: string
          • content: string
          • boardTitleImage: string
          • favoriteCount: int
          • commentCount: int
          • viewCount: int
          • writeDateTime: string
          • wirtorNickname: string
          • writorProfileImage: string
      • 실패
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  7. 검색 게시물 리스트 searchList
    • url
      • get /api/v1/board/search-list/[searchWord]
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
          • searchList: BoardListItem[]
        • BoardListItem
          • boardNumber: Int
          • title: string
          • content: string
          • boardTitleImage: string
          • favoriteCount: int
          • commentCount: int
          • viewCount: int
          • writeDateTime: string
          • wirtorNickname: string
          • writorProfileImage: string
      • 실패
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  8. 게시물 상세 boardDetail
    • url
      • get /api/v1/board/[boardNumber]
    • header
      • Authorization=Bearer Token
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
          • boardNumber: Int
          • title: string
          • content: string
          • boardImage: string[]
          • writeDateTime: string
          • writerEmail: string
          • wirtorNickname: string
          • writorProfileImage: string
      • 실패
        • 존재하지 않는 게시물
          • 400 internal server error
            • code: "nb"
            • message: "no existed board number"
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  9. 좋아요 리스트 favoriteList
    • url
      • get /api/v1/board/[boardNumber]/favorite-list
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
          • favoritList: FavoriteListItem[]
        • FavoriteListItem
          • userEmail: string
          • userNickname: string
          • userProfileImage: string
      • 실패
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  10. 좋아요 기능 putFavorite
    • url
      • put /api/v1/board/[boardNumber]/favorite
    • header
      • Authorization=Bearer Token
    • request
      • boardNumber: int
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
      • 실패
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  11. 댓글 리스트 commentList
    • url
      • get /api/v1/[boardNumber]/comment-list
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
          • commentList: commentListItem[]
        • commentListItem
          • userEmail: string
          • commentUserNickname: string
          • commentWriteDatetime: string
          • commentContent: string
      • 실패
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  12. 댓글 쓰기 postComment
    • url
      • post /api/v1/[boardNumber]/comment
    • request
      • content: string
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
      • 실패
        • 존재하지 않는 게시물
          • 400 internal server error
            • code: "nb"
            • message: "no existed board"
        • 존재하지 않는 유저
          • 400 internal server error
            • code: "nu"
            • message: "no existed user"
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  13. 게시물 삭제 boardDelete
    • url
      • delete /api/v1/board/[boardNumber]
    • header
      • Authorization=Bearer Token
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
      • 실패
        • 존재하지 않는 게시물
          • 400 bad request
            • code: "nb"
            • message: "no existed board"
        • 존재하지 않는 유저
          • 400 bad request
            • code: "nu"
            • message: "no existed user"
        • 권한 없음
          • 403 forbidden
            • code: "np"
            • message: "no permission"
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  14. 게시물 쓰기 boardwrite
    • url
      • post /api/v1/board
    • header
      • Authorization=Bearer Token
    • request
      • title: string
      • content: string
      • boardImageList string[]
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
      • 실패
        • 존재하지 않는 유저
          • 400 bad request
            • code: "nu"
            • message: "no existed user"
        • 권한 없음
          • 403 forbidden
            • code: "np"
            • message: "no permission"
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  15. 게시물 수정 boardUpdate
    • url
      • patch /api/v1/board/[boardNumber]
    • header
      • Authorization=Bearer Token
    • request
      • title: string
      • content: string
      • boardImageList string[]
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
      • 실패
        • 존재하지 않는 유저
          • 400 bad request
            • code: "nu"
            • message: "no existed user"
        • 권한 없음
          • 403 forbidden
            • code: "np"
            • message: "no permission"
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  16. 유저정보 getUser
    • url
      • get /api/v1/user/[email]
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
          • userDetail
      • 실패
        • 존재하지 않는 유저
          • 400 bad request
            • code: "nu"
            • message: "no existed user"
        • 권한 없음
          • 403 forbidden
            • code: "np"
            • message: "no permission"
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  17. 로그인 유저 정보 getLoginUser
    • url
      • get /api/v1/user
    • header
      • Authorization=Bearer Token
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
          • userDetail
            • code
            • message
            • email
            • nickname
            • profileimage
      • 실패
        • 존재하지 않는 유저
          • 401 unauthorized
            • code: "nu"
            • message: "no existed user"
        • 권한 없음
          • 403 forbidden
            • code: "np"
            • message: "no permission"
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  18. 특정 유저 게시물 리스트 userBoardList
    • url
      • get /api/v1/board/user-board/[email]
    • request
      • title: string
      • content: string
      • boardList string[]
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
      • 실패
        • 존재하지 않는 유저
          • 400 bad request
            • code: "nu"
            • message: "no existed user"
        • 권한 없음
          • 403 forbidden
            • code: "np"
            • message: "no permission"
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  19. 닉네임 수정 patchNickname
    • url
      • patch /api/v1/user/nickname
    • request
      • nickname string
    • header
      • Authorization=Bearer Token
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
      • 실패
        • 존재하지 않는 유저
          • 400 bad request
            • code: "nu"
            • message: "no existed user"
        • 권한 없음
          • 403 forbidden
            • code: "np"
            • message: "no permission"
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  20. 프로필 이미지 수정 patchProfileImage
    • url
      • patch /api/v1/user/profile-image
    • header
      • Authorization=Bearer Token
    • request
      • profileImage string
    • response
      • 성공
        • ok 200
          • code: "su"
          • message: "success"
      • 실패
        • 존재하지 않는 유저
          • 400 bad request
            • code: "nu"
            • message: "no existed user"
        • 권한 없음
          • 403 forbidden
            • code: "np"
            • message: "no permission"
        • 데이터베이스 에러
          • 500 internal server error
            • code: "de"
            • message: "database error"
  21. 파일 업로드 fileUpload
  22. 파일 불러오기 getFile

Response Code

  • 200
    • 성공
      • SU Success
  • 400
    • 유효성 검증 실패
      • VF Validation failed
    • 중복된 이메일
      • DE Duplication email
    • 중복된 전화번호
      • DT Duplication tel number
    • 중복된 닉네임
      • DN Duplication nickname
    • 존재하지 않는 유저
      • NU This user does not exist
    • 존재하지 않는 게시물
      • NB this board does not exist
  • 401
    • 로그인 실패
      • LF Login Information mismatch
    • 인증실패
      • AF Authorization Failed
  • 403
    • 권한없음
      • NP Do not have permission
  • 500
    • 데이터페이스 에러
      • DBE Database error

spring initializr

  • dependencies
    • spring web
    • spring data jpa
    • oracle driver
    • lombok

application.properties

# DB Oracle  
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver  
spring.datasource.url=jdbc:oracle:thin:@v1s1adecjlzt7rps_high?TNS_ADMIN=./src/main/resources/OracleCloude/Wallet_V1S1ADECJLZT7RPS/  
spring.datasource.username=admin  
spring.datasource.password=[password]

build.gradle

// oracle cloud
implementation 'com.oracle.database.security:osdt_cert'  
implementation 'com.oracle.database.security:oraclepki'  
implementation 'com.oracle.database.security:osdt_core'

front init

npx create-react-app blog-frontend --template typescript

db 설계

  • User
    • user_email(PK)
    • user_password
    • user_nickname
    • user_phone_number
    • user_address_detail
    • user_profile_image
  • Board
    • board_number(PK)
    • board_title
    • board_content
    • board_image
    • board_video
    • board_file
    • board_view_count
    • board_writer_email(FK: User.user_email)
    • board_writer_profile_image
    • board_writer_nickname
    • board_write_date
    • board_favorite_count
    • board_comment_count
  • PopularSearch
    • popular_term(PK)
    • popular_search_count
  • Favorite
    • favorite_id
    • board_number(FK: Board.board_number)
    • user_email(FK: User.user_email)
    • favorite_user_profile_image
    • favorite_user_nickname
  • Comment
    • board_number(FK: Board.board_number)
    • user_email(FK: User.user_email)
    • comment_content
    • comment_user_profile_image
    • comment_user_nickname
    • comment_write_date
  • User - Board 관계
    1. User 가 Board 를 작성한다 1:N
    2. User 가 Board 에 좋아요 를 한다 N:N
    3. User 가 Board 에 댓글을 단다 N:N
CREATE TABLE "user" (
    email VARCHAR2(50) PRIMARY KEY,
    password VARCHAR2(20) NOT NULL,
    nickname VARCHAR2(30) NOT NULL,
    tel_number VARCHAR2(15) NOT NULL,
    address VARCHAR2(4000) NOT NULL,
    address_detail VARCHAR2(4000) NOT NULL,
    profile_image VARCHAR2(4000),
    agreed_personal char(5)
);
CREATE TABLE "board" (
    board_number NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    title VARCHAR2(200) NOT NULL,
    content VARCHAR2(4000) NOT NULL,
    image VARCHAR2(4000),
    video VARCHAR2(4000),
    file VARCHAR2(4000),
    writer_email VARCHAR2(50) NOT NULL,
    writer_profile_image VARCHAR2(4000),
    writer_nickname VARCHAR2(30) NOT NULL,
    write_datetime DATE NOT NULL,
    view_count INT DEFAULT 0,
    favorite_count INT DEFAULT 0,
    comment_count INT DEFAULT 0
);
CREATE TABLE "search_log" (
    SEQUENCE NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    SEARCH_WORD VARCHAR2(200),
    RELATION_WORD VARCHAR2(200),
    RELATION CHAR(5)    
)
CREATE TABLE "FAVORITE" (
    favorite_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    board_number NUMBER NOT NULL,
    user_email VARCHAR2(50) NOT NULL,
    user_profile_image VARCHAR2(4000),
    user_nickname VARCHAR2(30) NOT NULL
)
CREATE TABLE "comment" (
    comment_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    board_number INT NOT NULL,
    user_email VARCHAR2(50) NOT NULL,
    content VARCHAR2(4000) NOT NULL,
    user_profile_image VARCHAR2(4000),
    user_nickname VARCHAR2(30) NOT NULL,
    write_datetime DATE NOT NULL
);
CREATE TABLE "IMAGE" (
    SEQUENCE INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    BOARD_NUMBER INT NOT NULL,
    IMAGE VARCHAR2(4000)
);

DB Browser

Entity 및 Repository 생성

어노테이션

  • @Data: 게터, 세터 프로퍼티 지원
  • @Builder: 생성자 지원
  • @AllArgsConstructor: 모든 필드를 인자로 생성자 만듬
  • @NoArgsConstructor: 인자 없는 생성자 만듬
  • @Entity: 해당 클래스를 Entity 클래스로 사용, name = 사용할 Entity 명
  • @Table: db에 있는 테이블와 현재 클래스를 매핑, name = 테이블명
  • @ID: PK
  • @GeneratedValue: 기본키를 자동으로 생성해 주는 어노테이션,
    • IDENTITY: AUTO_INCREMENT like mysql
    • SEQUENCE: like oracle, postgresql
    • TABLE: 키 생성 전용 테이블 만들고 이름, 값을 만들어서 시퀀스 흉내
  • @Repository: 해당 인터페이스를 레포지토리로 사용, 의존성 주입 가능
    • interface 로 생성
    • ORM 을 사용할 것이기에 JPA 상속
    • @Componenet 어노테이션이 포함
  • @RestController: 해당 클래스를 rest한 형태의 컨트롤러 레이어로 인식, Constrolloer + ResponseBody
  • @Controller: 해당 클래스를 컨트롤러 레이어로 인식
  • @ResponseBody: 해당 클래스를 응답 바디를 만들어 리턴해줘야함
  • @RequestMapping(URL 패턴): reqeust의 url 의 패턴을 보고 해당 하는 패턴을 찾아서 해당 클래스 실행
  • @CrossOrigin 도메인 허용
  • @AuthenticationPrincipal 현재 인증된 세션유저 정보를 가져옴
  • @RequiredArgsConstructor 클래스에 선언된 final 변수들, 필드들을 매개변수로 하는 생성자를 자동으로 생성
  • React 구조 및 Axios 통신
  • src
    • apis : backend 와 연결할 axios 함수
    • assets: 이미지, 비디오, 폰트
    • components: 작은 단위 기본 컴포넌트
    • constants: 상수
    • interface: 타입스크립트, 타입으로 사용할 인스턴스
    • stores: 스토어 함수
    • utils: 각종 메서드
    • views: 큰 단위 컴포넌트, 레이아웃
npm install axios

회원가입 Controller 작성 및 HTTP Post Request

회원가입

  • POST /api/auth/signUp
  • Request Body
    • userEmail
    • userPassword
    • userPasswordCheck
    • userNickname
    • userPhoneNumber
    • userAddress
    • userAddressDetail
  • Response Body
    • result
    • message
    • data

DTO

  • Data Transper Object 데이터 전송 오브젝트
  • 프로세스 간 데이터 전달하는 객체
  • 비즈니스 로직을 포함할 필요가 없는 단순한 객체

Cors 정책 변경

기존의 @CrossOrigin 어노테이션을 지우고 메인에서 WebMvcConfiurer 로 @Bean 선언, 전역으로 변경

@Bean  
public WebMvcConfigurer corsConfigurer() {  
    return new WebMvcConfigurer() {  
       @Override  
       public void addCorsMappings(CorsRegistry registry) {  
          registry.addMapping("/**").allowedOriginPatterns();  
          WebMvcConfigurer.super.addCorsMappings(registry);  
       };  
    };  
}

회원가입 기능

로그인 기능 JWT

인증방식

Basic Authentication

  • 사용자 이름 / 비밀번호 를 base64로 인코딩하여 authorization 헤더에 포함하여 전송
  • 안전하지 않음
  • ssl/tls 와 함께 사용됨
  • header
    • Authorization=Basic ~Bearer Token Authentication
  • 헤더에 토큰을 포함하여 전송 authorization 헤더에 포함하여 전송
  • JWT 을 사용하여 인증
  • 간단한 방식, 상태를 유지하지 않음, 확장성이 높음
  • 토큰 노출 위험, 토큰 관리
  • header
    • Authroization=Bearer ~OAuth
  • 토큰 기반 인증방식
  • 사용자가 직접 자격을 증명하지 않음
  • 미리 인증 받아서 토큰을 발급 받고 이 토큰을 이용하여 API를 요청하는 방식
  • 일반적으로 OAuth 2.0 을 사용

API key

session based authentication

JWT

  • 클레임이라고 불리는 정보는 json 형태로 안전하게 전송하기 위한 토큰
  • 인증과 정보 교환에 사용, 서명이 되어 있어 신뢰성 확보가 가능
  • 구성
    • header : 토큰의 타입과 사용된 알고리즘 정보를 담고있음, base64 인코딩
    • payload: 클레임 정보, 대상, 발행자, 만료 시간 등 다양한 정보가 포함됨, base64 로 인코딩
    • signature: header 와 payload, secret key를 사용하여 생성된 서명
  • 인증, 정보교환
  • 장점
    • 상태 유지하지 않는다
    • 간단하고 자기 포함적
    • 확장성
  • 단점
    • 크기: 클레임이 많을 수록 사이즈가 큼
    • 보안: 서명은 되어 있지만 암호화는 되어있지 않음, 중요한 정보를 JWT에 포함하면 안됨
    • 토큰 관리: 만료 시간, 갱신

Frontend 쿠키 및 스토어

npm i @mui/icons-material

Backand Spring Security 인증처리

  • jwt : 전자서명된 토큰
    • json 형태로 구성된 토근
    • [header].[payload].[signature] 형태
    • header
      • typ: 해당 토근의 타입
      • alg: 토큰을 서명하기 위해 사용된 해시 알고리즘
    • payload
      • sub: 해당 토큰의 주인
      • iat: 토큰이 발행된 시간
      • exp: 토큰이 만료되는 시간
  • build.gradle
  1. add spring security
  2. implementation 'org.springframework.boot:spring-boot-starter-security'
  3. setting main application
    • security 설정 후 빌드 하면 아래와 같은 메시지 발생
    • Using generated security password: 554407d7-992c-4ca9-8adf-e6c3736edb7e

This generated password is for development use only. Your security configuration must be updated before running your application in production.


3. filter 패키지 추가
    - 클라이언트가 서버에 요청을 하면 DispatherServlet 을 통해 비즈니스 로직이 실행되기 전 요청을 거르는 역활을 함
    - 즉, 요청 시 필터를 거쳐 비즈니스 로직 실행 및 응답함
    - 패키지 내 JwtAuthencitationFilter 를 생성해, OncePerRequestFilter 를 상속해준다
    - 이는 Request가 들어왔을 때 Request Header의 Authorization 필드의 Bearer Token을 가져와 이를 검증하고 검증 결과를 SecurityContext에 추가한다.

4. setting main application
    - 임시로 main application 에 @SpringBootApplication(exclude = {UserDetailsServiceAutoConfiguration.class})  어노테이션 설정

@SpringBootApplication(exclude = {UserDetailsServiceAutoConfiguration.class})
public class BlogBackendApplication {


## Backend 비밀번호 암호화 및 frontend 인증


## Backend 기능

### 주간 top3 게시글

- GET /api/board/top3
- Response Body
    - result 
    - message
    - data{ BoardEntity[ ] }
### 최신 게시글
- GET /api/board/list
- Response Body
    - result
    - message
    - data{ BoardEntity[ ] }
### 인기검색어
- GET /api/board/popularSearchList
- Response Body
    - result
    - message
    - data { PopularSearchEntity[ ] }

### 네비바 검색
- GET /api/board/search/(title)
- Response Body
    - result
    - message
    - data { PopularSearchEntity[ ] }

### 사용자 수정
- PATCH /api/user
- Request Header 
    - Authorization Bearer token
- Request Body
    - user_nickname: string
    - user_profile_image: string
- Response Body
    - result
    - message
    - data
        - accessToken
        - expireTime
        - user


## Header Layout3
## 회원가입 기능 구현 및 DTO
## Entitiy, Respositoy
## 회원가입 기능 구현 BE

- entity 에서 @table 이름 설정 시 대소문자 구분 확인

## 로그인 기능 구현 BE

## Auth 페이지 공통 스타일

- 피그마

## Auth 페이지 로그인 카드 a

## Auth 페이지 로그인 카드 b

## Auth 페이지 로그인 api 연동

## Validation Failed 처리 BE

## Auth 회원가입 카드 a

``` js
    const emailPattern = /^[a-zA-z0-9]*@([-.]?[a-zA-Z0-9])*\.[a-zA-Z]{2,4}$/;
    const isEmailPattern = emailPattern.test(email);

Auth 회원가입 카드 b

Auth 회원가입 카드 c

Auth 회원가입 API

로그인 유저 정보 불러오기 API

Header 로그인 조건부 렌더링

파일 업로드, 불러오기 API구현

게시물 작성 API 구현

- file 및 image 컬럼 활용 시 엔티니 및 테이블에 백틱으로 감싸기

게시물 작성 페이지 구조 작성

게시물 작성페이지 스타일

게시물 작성 페이지 이벤트 처리

게시물 작성 페이지 api 연동

특정 게시물 불러오기 API 연동

좋아요 API 구현

  • 유저 좋아요 토글게시물 좋아요 리스트 불러오기 API 구현

게시물 댓글 작성 API 구현

게시물 댓글 리스트 불러오기 API 구현

게시물 상세보기 상단 컴포넌트 구조 작성

게시물 상세보기 하단 컴포넌트 구조 작성

게시물 상세 보기 상단 스타일 작성

게시물 상세보기 하단 스타일 작성

게시물 상세 페이지 이벤트 처리

  • textarea 자동 높이 조절
    const onCommentChangeHandler = (

      event: ChangeEvent<HTMLTextAreaElement>

    ) => {

      const { value } = event.target;

      setComment(value);



      if (!commentRef.current) return;

      commentRef.current.style.height = `auto`;

      commentRef.current.style.height = `${commentRef.current.scrollHeight}px`;

    };

게시물 상세 페이지 특정 게시물 불러오기 API 연동

게시물 상세 페이지 좋아요, 댓글 리스트 불러오기 API 연동

npm install dayjs

게시물 상세 페이지 좋아요, 댓글 작성, 게시물 삭제 불러오기 API 연동

  • put 메서드 사용 시 cors error
    SpringBoot CORS에러 해결하기 (tistory.com)
  • cors 설정을 메인 application 쪽에 Bean 으로 설정한 corsConfigurer 와 HttpSecurity 필터 구성 시 cors(CorsConfig ) 를 중복으로 사용해서 동작이 이상한 경우가 생김

게시물 삭제 API 구현

페이지네이션 hook

페이징 처리 컴포넌트 작성, 적용

게시물 수정 API 작성, 연동

최신 게시물 리스트 불러오기 API 작성

주간 Top3 게시물 리스트 불러오기 API 작성

인기 검색어 리스트 불러오기 API 작성

메인 페이지 구조 작성

검색 게시물 리스트 불러오기 API 작성

검색 페이지 구조 및 스타일 작성

검색 페이지 api 연동

유저 및 유저 게시물 불러오기 API 작성

닉네임 및 프로필 이미지 수정 API 작성

유저 페이지 컴포넌트 구조 작성

유저 페이지 상단 컴포넌트 구조, 스타일 작성 및 이벤트 처리

유저 페이지 하단 컴포넌트 구조, 스타일 작성 및 이벤트 처리

유저 페이지 API 연동