Spring Boot Team Project - λ§μ§ μΆμ² λ° λν μ°ΎκΈ° μ¬μ΄νΈ
μΈν루μΈμ λ§μ§, μ¬μ©μ κ²μ λ§μ§ λ±μ μ 보λ₯Ό μ 곡νλ©°, λν μ°ΎκΈ° κΈμ ν΅ν΄ λ§μ§ λ©μ΄νΈλ₯Ό ꡬν μ μλ κΈ°λ₯μ ꡬν
2023-08-09 ~ 2023-09-15
java version 17
Spring Boot 3.1.1
MySQL
Redis
IntelliJ IDEA Ultimate
Spring Security
JWT token
Spring Data JPA
HTML
Java Script
CSS
Docker
κΈ°λ₯ | HTTP METHOD | URL |
---|---|---|
νμκ°μ | POST | /api/join |
λ‘κ·ΈμΈ | POST | /api/login |
νμ μ 보 μ‘°ν | GET | /api/profile |
νμ μ 보 μμ | PUT | /api/profile |
νλ‘ν μ΄λ―Έμ§ μ λ‘λ | PUT | /api/profile/image |
νμ νν΄ | DELETE | /api/profile |
μ¬μ©μ 리뷰 μ 체 μ‘°ν | GET | /api/profile/reviews |
μ¬μ©μ λν κΈ μ 체 μ‘°ν | GET | /api/profile/post |
μ¬μ©μ μ¦κ²¨μ°ΎκΈ° μ‘°ν | GET | /api/profile/wishlist |
μ¦κ²¨μ°ΎκΈ° μμ | DELETE | /wishlist |
ν ν° μ¬λ°κΈ | POST | /api/reissue |
λ‘κ·Έμμ | POST | /api/logout |
μ¬μ©μμ μ 보λ₯Ό κΈ°λ°μΌλ‘ νμκ°μ μ§ν. μ΅μ΄ μ¬μ©μμ νλ‘ν μ΄λ―Έμ§λ S3 μ μ μ₯λ κΈ°λ³Έ μ΄λ―Έμ§λ‘ μ ν
μ¬μ©μμ ID, PW λ₯Ό κ²μ¦ ν ACCESS TOKEN κ³Ό μ¬λ°κΈμ© REFRESH TOKEN μ λ°κΈ
TOKEN λ°κΈ ν Redis μ username, access token, refresh token μ μ μ₯
- μ€λ³΅ λ‘κ·ΈμΈ μ²λ¦¬μ λ‘κ·Έμμ μ²λ¦¬λ₯Ό μν¨
- μ¬μ©μκ° λ€λ₯Έ κΈ°κΈ° νΉμ λΈλΌμ°μ , μλ‘μ΄ ν λ± κΈ°μ‘΄ λ‘κ·ΈμΈν νκ²½μ΄ μλ λ€λ₯Έ νκ²½μμ λ‘κ·ΈμΈμ ν΄μ token μ λ°κΈλ°κ² λλ©΄ μ΅μ΄ λ°κΈ λ°μ token μ Redis μμ μμ λμ΄ μ¬μ©μ΄ λΆκ°λ₯ ν¨
- μμ²μ ν¬ν¨λμ΄μ μ€λ access token μ νν°μμ redis μ‘΄μ¬ μ¬λΆλ₯Ό κ²μ¦ ν λ‘κ·ΈμΈ μνκ° κΈ°λ‘λμ§ μμ access token μ κ²½μ° μμ²μ reject
μ¬μ©μκ° μλ λ‘κ·ΈμΈμ μ νν κ²½μ°μλ REFRESH TOKEN μ 2μ£Ό κΈ°κ°μ Cookie μ μ μ₯, ACCESS TOKEN μ λΈλΌμ°μ local storage μ μ μ₯
μλ λ‘κ·ΈμΈμ μ ννμ§ μμ κ²½μ°μλ REFRESH TOKEN μ Session Cookie μ μ μ₯, ACCESS TOKEN μ λΈλΌμ°μ session storage μ μ μ₯
- λΈλΌμ°μ μ’ λ£ μ μ¬μ©μ λ‘κ·Έμμ μ²λ¦¬λ₯Ό μν¨
- μ΅μ΄ μμ΄λμ΄λ λΈλΌμ°μ μ’ λ£ μ΄λ²€νΈ κ°μ§ μ μλ² μΈ‘μΌλ‘ λ‘κ·Έμμ μμ²μ 보λ΄λ κ² νμ§λ§ λΈλΌμ°μ μ’ λ£ μ΄λ²€νΈ κ°μ§μ λ²μκ° νμ΄μ§ μ΄λμ΄λ μλ‘κ³ μΉ¨κΉμ§ κ°μ§κ° λκΈ°μ λ§€λ² λ‘κ·Έμμμ΄ λλ μν©μ΄ λ°μ
- νμ¬λ νμ΄μ§ λΈλΌμ°μ μ’ λ£ μ λ‘κ·Έμμ μμ²μ΄ κ°λ κ²μ΄ μλκΈ° λλ¬Έμ Redis μλ λ‘κ·ΈμΈ κΈ°λ‘μ΄ λ¨μ μμ΄μ access token κ³Ό refresh token μ΄ μ μΆλλ€λ©΄ λ¬Έμ κ° λ°μν μ¬μ§κ° μμ (access token μ μκ°μ΄ 짧기 λλ¬Έμ λΉκ΅μ λ¬Έμ κ° μ¬κ°νμ§ μμ)
- νμ¬λ μ ν©ν ν΄κ²°λ°©μμ μ°Ύμ§ λͺ»ν¨
- μ μμ μΌλ‘ μλΉμ€μ λ‘κ·Έμμ κΈ°λ₯μ μ¬μ©ν΄μ λ‘κ·Έμμ νλ κ²½μ°μλ λ¬Έμ κ° μμ
μ€λ³΅ λ‘κ·ΈμΈμ΄λ λ‘κ·Έμμ μ²λ¦¬λ₯Ό μν΄ λ‘κ·ΈμΈ μμ Redis μ λ‘κ·ΈμΈ κΈ°λ‘μ μ μ₯νλ λ°©μμ μΆν λ‘κ·Έμμ μ access token, refresh token μ blacklist λ‘ μ§μ ν΄ μλ² μΈ‘μμ μ¬μ©μμ μν μ 보λ₯Ό μ΅λν μ μ₯νμ§ μλ λ°©μμΌλ‘ λ³κ²½ν μ μμ
νμ μ 보 μ‘°ν / μμ / νν΄ / 리뷰, λν κΈ, μ¦κ²¨μ°ΎκΈ° μ 체 μ‘°ν / νλ‘ν μ΄λ―Έμ§ μ λ‘λ
- νμ μ 보 μ‘°ν
- access token μ μ¬μ©μ μ 보λ₯Ό λ°νμΌλ‘ μ¬μ©μ μ 보λ₯Ό μ‘°ν
- νμ μ 보 μμ
- νμ μ 보 μ€ ID, PW λ₯Ό μ μΈν μ 보 μμ
- νλ‘ν μ΄λ―Έμ§ μ
λ‘λ
- μ¬μ©μ νλ‘ν μ λ‘λ
- μ¬μ©μκ° μ λ‘λν μ΄λ―Έμ§λ S3 μ μ μ₯
- νμ νν΄
- νμ νν΄ κΈ°λ₯
- νμ νν΄ μ ν΄λΉ μ¬μ©μκ° μμ±ν 리뷰, λν κΈ, λ±λ‘ν μ¦κ²¨ μ°ΎκΈ°, μ λ‘λ ν μ΄λ―Έμ§ μ 체λ₯Ό μμ
- 리뷰 μ 체 μ‘°ν
- ν΄λΉ μ¬μ©μκ° μμ±ν 리뷰 μ 체 μ‘°ν
- μ¬μ©μ λν κΈ μ 체 μ‘°ν
- ν΄λΉ μ¬μ©μκ° μμ±ν λν κΈ μ 체 μ‘°ν
- μ¦κ²¨ μ°ΎκΈ° μ‘°ν
- ν΄λΉ μ¬μ©μκ° λ±λ‘ν μ¦κ²¨ μ°ΎκΈ° μ 체 μ‘°ν
μ¬μ©μ λ‘κ·Έμμ κΈ°λ₯ Redis μ κΈ°λ‘λ μ¬μ©μ λ‘κ·ΈμΈ μ΄λ ₯μ μμ
access token λ§λ£ μ refresh token μΌλ‘ ν ν° μ¬λ°κΈ μ¬λ°κΈ μ§ν ν κΈ°μ‘΄μ λ‘κ·ΈμΈ μ΄λ ₯μ μ μ₯λ access token κ³Ό refresh token κ° update
κΈ°λ₯ | HTTP METHOD | URL |
---|---|---|
κ²μ λ§μ§ νμ΄μ§ μ΄λ | GET | /search |
λ§μ§ μ‘°ν | GET | /search?target={target} |
νλ‘ νΈμμ κ°λ¨ν 보μ¬μ€ μ λ³΄κ° λ΄κΈ΄ DTO
μμμ μμΈ νμ΄μ§μμ 보μ¬μ€ μ λ³΄κ° λ΄κΈ΄ DTO
- κ²μ
- μ¬μ©μκ° searchBoxμ targetμ μ λ ₯νλ©΄ "target + μμμ " ννλ‘ μ§μλ¬Έμ λ§λ¦
- λ€μ΄λ² μ§μ κ²μ νμ΄μ§μ μ§μμ΄(ex. κ°λ¨μ μμμ )λ‘ κ²μλ κ²°κ³Ό(μλΉ μ΄λ¦, λ©λ΄, μμ μκ°, μ’ν λ±)λ₯Ό ν¬λ‘€λ§νμ¬ λ°μ΄ν°λ₯Ό λ°μμ΄
- μμλ§ κ°μ μμμ 곡곡 λ°μ΄ν°λ₯Ό μ¬μ©νκΈ°λ³΄λ€ μ΄λ¬ν λ°©μμ μ¬μ©νμ¬ μ체μ μΈ DBλ₯Ό κ΅¬μΆ νμμ
- λ€μ΄λ² μ§λ apiλ₯Ό νμ©νμ¬ λ§μ»€λ₯Ό μ°μ΄μ£Όκ³ , κ²μνμ λ μ§λμ 첫 νλ©΄μ κ²°κ³Ό 리μ€νΈλ€μ νκ· μ’νλ₯Ό ꡬν΄μ£Όμ΄ νλμ 보μ΄κ² νμμ
κΈ°λ₯ | HTTP METHOD | URL |
---|---|---|
μμΈνμ΄μ§ λΆλ¬μ€κΈ° | GET | matprint/detail?name={name}&address={address} |
μμ리μ€νΈ νλ¨ | GET | /api/wishlist/{restaurantId} |
μμ리μ€νΈ λ²νΌ | POST | /api/wishlist/{restaurantId} |
λ§μ΄νμ΄μ§μμ μμ리μ€νΈλ₯Ό μ‘°νλ₯Ό ν λ νμν DTO
- μμΈ νμ΄μ§
- κ²μ λ§μ§ νμ΄μ§λ μΈν루μΈμ λ§μ§ νμ΄μ§μμ λμ€λ μμμ μ΄λ¦μ ν΄λ¦νλ©΄ μμΈ νμ΄μ§λ‘ λμ΄κ°
- μλΉ μ¬μ§, μ£Όμ, μμ μκ°, μ νλ²νΈ, λ©λ΄ λ±μ μ λ³΄κ° μκ³ , 리뷰 μ‘°ν, μμ리μ€νΈ λ±λ‘ κΈ°λ₯, λ‘κ·ΈμΈ ν μ¬μ©μμ νν΄ λ¦¬λ·° μμ± κΈ°λ₯ μ 곡
- μμ리μ€νΈ
- isMyWish ν¨μλ₯Ό ν΅ν΄ μμμ μμΈ νμ΄μ§μ μ§μ ν μ¬μ©μκ° νμ¬ μλΉμ μμ리μ€νΈμ λ±λ‘νλμ§ νλ¨ ν, νλ‘ νΈ νμ΄μ§μμ λ²νΌμ μ΄λ»κ² 보μ¬μ€μ§ μ ν¨
- μμ리μ€νΈ λ±λ‘ λ²νΌμ μ΄λ―Έ μμ리μ€νΈμ λ΄κ²¨μ Έ μλλ° λ²νΌμ λλ₯΄λ©΄ μμ리μ€νΈμμ ν΄μ λκ³ , μ λ΄κ²¨μ Έ μμ λ λλ₯΄λ©΄ μμ리μ€νΈμ λ±λ‘λ¨
κΈ°λ₯ | HTTP METHOD | URL |
---|---|---|
리뷰 μμ± | POST | /api/{restaurantId}/review/ |
리뷰 μμ | PUT | /api/{restaurantId}/review/edit |
리뷰 μ‘°ν | GET | /api/{restaurantId}/review/{reviewId} |
리뷰 μμ | DELETE | /api/{restaurantId}/review/{reviewId} |
μ¬μ©μκ° λ¦¬λ·° μμ±ν λ΄μ©μ λ°μμ€λ DTO. 리뷰 λ΄μ©κ³Ό νμ μ νμλ‘ λ€μ΄κ°μΌ ν¨
μ¬μ©μμ λ°λΌ ui λ³νλ₯Ό μ£ΌκΈ° μν΄ νμ¬ ν΄λΉ μμ²μ λ³΄λΈ μ¬μ©μμ μ 보λ₯Ό ν¬ν¨ν΄ ν¨κ» λ°ν
μ΄μ 리뷰μ λμΌνμ§λ₯Ό νλ¨νλ λ‘μ§ λ€μ΄μμ
-
μμ±
- λ‘κ·ΈμΈν μ¬μ©μλ§ μμ±ν μ μμ
- 리뷰μ μ΄λ―Έμ§λ₯Ό 첨λΆν μ μμΌλ©°, μ΄λ―Έμ§λ bucketμμ κ΄λ¦¬ ν¨
-
μμ
- 리뷰μ μμ μ¬νμ΄ μμ λλ§ μμ ν μ μμΌλ©°, 리뷰λ₯Ό μμ±νλ μ μ λ§μ΄ μμ ν μ μμ
-
μ‘°ν
- μμμ μμΈνμ΄μ§μμ κ·Έ νμ΄μ§μ ν΄λΉνλ μλΉμ λν 리뷰 μ‘°ν κ°λ₯
-
μμ
- 리뷰λ₯Ό μμ±νλ μ μ λ§μ΄ μμ κ°λ₯
κΈ°λ₯ | HTTP METHOD | URL |
---|---|---|
μΈν루μΈμ λ§μ§ μ°ΎκΈ° νμ΄μ§ μ΄λ | GET | matprint/named |
μΉ΄ν κ³ λ¦¬ μ ν μ‘°ν | GET | api/named |
μΉ΄ν κ³ λ¦¬ μ ν μ λ ¬ μ‘°ν | GET | api/named&category={categry}&sortBy={sortBy} |
μΈν루μΈμ λ§μ§ μ°ΎκΈ° νμ΄μ§μμ 보μ¬μ€ κ°λ¨ν μ 보λ€λ§ μλ DTO
-
λ°μ΄ν° μμ§
- μΈν루μΈμλ€μ΄ λ€λ κ° λ§μ§μΌλ‘ μ λͺ ν κ³³μ λ§μ§λ§, κ°λ³΄κ³ μΆμ΄ μ°Ύμλ³΄λ €λ©΄ μΌμΌμ΄ κ²μν΄μΌν λ²κ±°λ‘μμ΄ μμ
- μ±μκ²½ λ§μ§ κ°μ κ²½μ° λ€λ κ° λ§μ§λ€μ μλΉ μ 보μ ν¨κ» μ νλΈμ μ λ‘λ ν¨
- μ νλΈμμ ν¬λ‘€λ§ν λΉμ ν λ°μ΄ν°λ₯Ό Tokenization, Normalizationλ₯Ό ν΅ν΄ λ€μ΄λ² APIμ κ²μμ΄ μ λλλ‘ μ§μμ΄λ₯Ό λ§λ¦
- μ΄ μ§μμ΄λ₯Ό ν΅ν΄ λ€μ΄λ² κ²μμ κ²μν¨μΌλ‘μ¨ λΉμ ν λ°μ΄ν°λ₯Ό μ ν λ°μ΄ν°λ‘ λ°κΏμ€.
-
λ°μ΄ν° μ‘°ν
- μΌλ ¨μ λ°μ΄ν° μμ§κ³Όμ μΌλ‘ μ»μ΄μ¨ μΈν루μΈμ λ§μ§ λ°μ΄ν°λ€μ μ‘°ννλ ν¨μλ₯Ό λ§λ¦
- RequestParamμΌλ‘ μΉ΄ν κ³ λ¦¬λ νμμ μΌλ‘ λ°μμ, μ΄λ€ μΈν루μΈμμ λ§μ§μΈμ§ 보μ¬μ€
- μ νμ μΈ νλΌλ―Έν°λ‘ μ΄λ¦ μ, 리뷰 λ§μ μ, νμ λμ μ λ±μ μ λ ¬ κΈ°μ€μ μ λ ₯λ°μ μ‘°νν μ μμ
- μΉ νμ΄μ§μμλ λ€μ΄λ² μ§λ apiλ₯Ό νμ©νμ¬ λ§μ»€λ₯Ό μΈν루μΈμμ μΌκ΅΄λ‘ μ€μ νμ¬ μ°¨λ³μ μΈ μμλ₯Ό λ£μκ³ , λ§μ»€λ₯Ό λλ₯΄λ©΄ μλΉμ κ°λ¨ν μ€λͺ μ΄ λμ΄
- λ§μ§ κ²μκ³Ό λμΌνκ² μμμ μ΄λ¦μ λλ₯΄λ©΄ μμΈ νμ΄μ§λ‘ μ΄λν¨
- μ±μκ²½, λκ°μ§ λ§μ§μ μ κ΅μ μΌλ‘ λΆν¬λμ΄ μμ΄ μ²μ μ€μ¬ μ’νλ₯Ό μ κ΅μ΄ λ€ λ³΄μ΄κ² μ€μ ν¨
- μ΄μμ λ§μ§μ μμΈμ λΆν¬λμ΄ μμ΄, λ§μ§ κ°μ₯ λ°μ§λμ΄ μλ μ’νλ₯Ό κΈ°μ€μΌλ‘ ν λμ 보μ΄κ² μ€μ ν¨
κΈ°λ₯ | HTTP METHOD | URL |
---|---|---|
λν μ°ΎκΈ° νμ΄μ§ μ΄λ | GET | /mate |
μ¬μ©μ λν κΈ μ 체쑰ν | GET | api/user/posts |
λν κΈ μμ± | POST | api/mate |
λν κΈ μμ | PUT | api/mate |
λν κΈ μμ | DELETE | api/mate/post/ |
λν κΈ λ¨μΌ μ‘°ν | GET | api/mate/{postId} |
λν κΈ μ 체 μ‘°ν | GET | api/mate |
λν κΈ κ²μ | GET | api/mate/search? |
λκΈ μμ± | POST | api/mate/{postId}/comment |
λκΈ μ‘°ν | GET | api/{postId}/comment |
λκΈ μμ | PUT | api/mate/{postId}/comment/{commentId} |
λκΈ μμ | DELETE | api/mate/{postId}/comment/{commentId} |
νΉμ μ μ κ° μμ±ν λνκΈ μ‘°νλ₯Ό μν DTO
λνκΈ μμ±μ μν DTO
κ²μμ΄λ₯Ό ν΅ν΄ λν κΈμ μ°ΎκΈ° μν΄ μμ±ν DTO
λνκΈ μμ μ μν DTO. μ΄μ μ κ²κ³Ό λΉκ΅ν΄μ μμ λ κ²μ΄ μμΌλ©΄ μ λ°μ΄νΈ νμ§ μλλ€.
νΉμ λνκΈμ λκΈ μ‘°νλ₯Ό μν DTO
λκΈ μμ±μ μν DTO
λκΈ μμ μ μν DTO
-
λνκΈ λ±λ‘, μ‘°ν, μμ , μμ
- λν κΈ λ±λ‘μ title, content, λ°©λ¬Έ μμ λ μ§, λν μ€νμΌ λ±μ λ΄μ©μ΄ λ€μ΄μμ
- λν κΈ μ‘°νλ κ²μνμμλ λͺ¨λ λν κΈμ 보μ¬μ£Όλ©°, μ΄μ©μλ μ λͺ©, κ²μμ΄, μ±λ³, λμ΄, λͺ¨μ§ μν λ±μ νν°λ‘ κ²μ κ°λ₯ν¨. λν λ§μ΄νμ΄μ§μμ λ΄κ° μ΄ λνκΈμ μ‘°ν κ°λ₯ν¨
- λν κΈ μμ , μμ λ ν΄λΉ κΈ μμ±μλ§ κ°λ₯νκ³ μμ μ λ³κ²½μ¬νμ΄ μμ΄μΌλ§ κ°λ₯ν¨
-
λκΈ λ±λ‘, μ‘°ν, μμ , μμ
- λκΈ λ±λ‘μ λκΈ λ΄μ©λ§ μ μ΄μ£Όλ©΄ λκ³ , λ‘κ·ΈμΈ ν μ¬μ©μλ§ μ΄μ© κ°λ₯
- λκΈ μ‘°νλ ν΄λΉ λνκΈμμ μ‘°ν κ°λ₯
- λκΈ μμ , μμ λ λκΈ μμ±μλ§ κ°λ₯ν¨
μ¬μ© κΈ°μ : AWS EC2 (Ubuntu), S3, RDS, Route53, Load Balancing, Https, SSL, Docker, Gradle
- AWS EC2 : Docker container κ° μ¬λΌκ° EC2 μΈμ€ν΄μ€
- S3 : μλΉμ€μμ μ λ‘λ λλ μ΄λ―Έμ§ μ μ₯μ
- RDS : Mysql Server
- Route53 : λλ©μΈ μ μ© λ° λ‘λ λ°Έλ°μλ‘ λΌμ°ν
- Https, SSL, Load Balancing : Https μ μ©μ μν SSL μΈμ¦μ λ° Load Balancing μ νμ©ν΄ 80 ν¬νΈλ‘ λ€μ΄μ€λ μμ²μ 443 ν¬νΈλ‘ 리λ€μ΄λ νΈ, 443 ν¬νΈλ‘ λ€μ΄μ¨ μμ²μ λ€μ EC2 80 ν¬νΈλ‘ μ λ¬
- Gradle : νλ‘μ νΈ λΉλ (make jar file)
- Docker : νλ‘μ νΈ λΉλ ν jar file λ‘ docker image μμ±, docker hub μ μ λ‘λ ν ec2 μμ λ€μ΄λ‘λ λ°μ container ν μν΄
EC2 μΈμ€ν΄μ€μμ spring image, redis image, redis-insight image λ₯Ό λμμ λμ°κΈ° μν΄ docker-compose νμ©
spring μ application.yaml νμΌ λ΄λΆμ λ―Όκ° μ 보λ νκ²½ λ³μλ‘ μ€μ (EC2 μΈμ€ν΄μ€μμ μ§μ .env νμΌ μμ±)
services:
redis:
image: redis
ports:
- 6379:6379
container_name: redis
restart: always
redis-insight:
image: redislabs/redisinsight:latest
ports:
- 8001:8001
container_name: redis-insight
restart: always
matprint:
image: syber911911/matprint:0.1
ports:
- 80:8080
container_name: matprint
restart: always
environment:
- DB_URL=${DB_URL}
- DB_USER=${DB_USER}
- DB_PASSWORD=${DB_PASSWORD}
- JWT_SECRET=${JWT_SECRET}
- ACCESS_KEY=${ACCESS_KEY}
- BUCKET=${BUCKET}
- SECRET_KEY=${SECRET_KEY}
depends_on:
- redis
- redis-insight