Skip to content

Commit

Permalink
Release (#154)
Browse files Browse the repository at this point in the history
* docs: change README.md

* style: fix name

* docs: update readme

* Update README.md

* Update README.md

* Update README.md

* docs: 모카콩 README 소개 부분 수정 작업 (#152)

* feat: S3 오브젝트 벌크 삭제 시 1000건 단위로 삭제되도록 변경 (#153)

* feat: List 파티셔닝을 위한 Guava 라이브러리 추가

mvn: https://mvnrepository.com/artifact/com.google.guava/guava/32.1.3-jre

* feat: S3 오브젝트 삭제 시, 1000건 단위로 삭제하도록 기능 구현

---------

Co-authored-by: 김태현 <[email protected]>

---------

Co-authored-by: Jisu Lim <[email protected]>
Co-authored-by: Lea <[email protected]>
Co-authored-by: TaeHyeon Kim <[email protected]>
Co-authored-by: 김태현 <[email protected]>
  • Loading branch information
5 people authored Feb 29, 2024
1 parent c0446b0 commit 1b0b846
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 31 deletions.
70 changes: 42 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,58 @@
## 모각코하기 좋은 카페 지도 애플리케이션, 모카콩(MOCACONG)
# 모각코하기 좋은 카페 지도 애플리케이션, 모카콩 <img alt="image" width="100" src="https://github.com/mocacong/Mocacong-Backend/assets/69844138/2058a9f5-447e-4a9b-8664-048f6792c955" align="left">

코딩하기 좋은 카페만 모아놓은 지도는 없을까? 고민했다면 모카콩!
[![App Store](https://img.shields.io/badge/App_Store-0D96F6?style=flat-square&logo=app-store&logoColor=white)](https://apps.apple.com/kr/app/mocacong/id6446925939)
[![Google Play](https://img.shields.io/badge/Google_Play-414141?style=flat-square&logo=google-play&logoColor=white)](https://play.google.com/store/apps/details?id=com.konkuk.mocacong&hl=en-KR)
[![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Fmocacong%2FMocacong-Backend&count_bg=%2379C83D&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false)](https://hits.seeyoufarm.com)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=mocacong_Mocacong-Backend&metric=coverage)](https://sonarcloud.io/summary/new_code?id=mocacong_Mocacong-Backend)
<br><br><br>

<p align="center">
<img width="20%" height="400" alt="image" src="https://github.com/mocacong/Mocacong-Backend/assets/57135043/b8510091-a49a-439d-b067-eb92afe282ab">
<img width="20%" height="400" alt="image" src="https://github.com/mocacong/Mocacong-Backend/assets/57135043/ed9d723f-8161-4de4-9dae-3cfc2eea43b1">
<img width="20%" height="400" alt="image" src="https://github.com/mocacong/Mocacong-Backend/assets/57135043/614c6e44-9199-4042-9f29-b90f659dc613">
<img width="20%" height="400" alt="image" src="https://github.com/mocacong/Mocacong-Backend/assets/57135043/a81d4fbd-a4a4-4ebb-bc63-c8e0e815e2cb">
![Artboard](https://github.com/mocacong/Mocacong-Backend/assets/69844138/3c0c2962-a4e0-4136-8120-516c123c51c4)
<br><br>

## 🔎 Introduction

<p align="center" width="100%">
<img src="https://github.com/mocacong/Mocacong-Backend/assets/69844138/3ce38fb5-1a5a-4789-9a5a-bcc30ba78879" width="31%">
<img src="https://github.com/mocacong/Mocacong-Backend/assets/69844138/bd6506f6-17a4-45a3-9fd5-20a59764ac44" width="31%">
<img src="https://github.com/mocacong/Mocacong-Backend/assets/69844138/b07a2c9f-f00e-416c-9cac-7f3bc5511a2b" width="31%">
</p>
<br><br>

## 💻 Server Architecture
### 📦 Dependency
- Java 11, Junit 5
- Spring Boot 2.7.9
- MySQL

- - -
<br>

### MVP 기능
### 🤲 AWS Architechture Diagram
<p align="center">
<img width="90%" alt="image" src="https://github.com/mocacong/Mocacong-Backend/assets/57135043/328495c2-4332-45b5-b052-359c1ed4cbd2">
<img width="90%" alt="image" src="https://github.com/mocacong/Mocacong-Backend/assets/57135043/27e4efcd-1d2e-4aca-a7c2-d655dede951a">
</p>

- - -
<br>

### 사용 기술스택
- `Language`: Java 11, JUnit 5
- `Framework`: Spring Boot 2.7.9
- `Database`: H2, Amazon RDS for MySQL, Amazon Elasticache for Redis
- `ORM`: JPA (Spring Data JPA)
- `Deploy`: Github Actions, Docker CI/CD
- `Logging`: Logback, AWS Cloudwatch, AWS Lambda, Slack API
- `API Docs`: SpringDoc Swagger 3
- `Performance Test`: nGrinder
### 🛠️ Tech Stack
#### Framework - <img src="https://img.shields.io/badge/Spring Boot-6DB33F?style=for-the-social&logo=Spring Boot&logoColor=white"> <img src="https://img.shields.io/badge/Gradle-02303A?style=for-the-social&logo=Gradle&logoColor=white">
#### Database - <img src ="https://img.shields.io/badge/H2 Database-blue"> <img src="https://img.shields.io/badge/Amazon RDS for MySQL-527FFF?style=for-the-sociak&logo=Amazon RDS&logoColor=white"> <img src="https://img.shields.io/badge/Amazon Elasticache for Redis-DC382D?style=for-the-sociak&logo=redis&logoColor=white">
#### ORM - <img src="https://img.shields.io/badge/Spring Data JPA-6DB33F?style=for-the-social&logo=Databricks&logoColor=white">
#### Deploy - <img src="https://img.shields.io/badge/Github Actions-2088FF?style=for-the-sociak&logo=githubactions&logoColor=white"> <img src="https://img.shields.io/badge/Docker-2496ED?style=for-the-sociak&logo=docker&logoColor=white">
#### Logging - <img src="https://img.shields.io/badge/Logback-25A162"> <img src="https://img.shields.io/badge/AWS Cloudwatch-FF4F8B?style=for-the-sociak&logo=amazoncloudwatch&logoColor=white"> <img src="https://img.shields.io/badge/AWS Lambda-FF9900?style=for-the-sociak&logo=awslambda&logoColor=white"> <img src="https://img.shields.io/badge/Slack API-4A154B?style=for-the-social&logo=slack&logoColor=white">
#### API Docs - <img src="https://img.shields.io/badge/SpringDoc Swagger 3-85EA2D?style=for-the-sociak&logo=swagger&logoColor=white">
#### Performance Test - <img src="https://img.shields.io/badge/nGrinder-orange">
#### Test - <img src="https://img.shields.io/badge/JUnit5-25A162?style=for-the-sociak&logo=junit5&logoColor=white"> <img src="https://img.shields.io/badge/RestAssured-25A162"> <img src="https://img.shields.io/badge/CodeCov-F01F7A?style=for-the-sociak&logo=codecov&logoColor=white">

- - -
<br><br>

### ERD
## 🖇️ DataBase Schema
<p align="center">
<img width="90%" alt="image" src="https://github.com/mocacong/Mocacong-Backend/assets/57135043/1def43a1-9271-4b1f-947a-0ff8ad07f77d">
<img width="90%" alt="image" src="https://github.com/mocacong/Mocacong-Backend/assets/69844138/969731a8-8852-46ba-9bdd-bbf515215b6d">
</p>

- - -
<br><br>

### 서비스 아키텍처
<p align="center">
<img width="90%" alt="image" src="https://github.com/mocacong/Mocacong-Backend/assets/57135043/27e4efcd-1d2e-4aca-a7c2-d655dede951a">
</p>
## 🙋🏻‍♂️ Server Engineers
| Taehyeon | Jisoo | Jungwoo |
|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|
| <img src="https://avatars.githubusercontent.com/u/57135043?v=4" width="100" height="100" style="border-radius: 50%;"><br/><a href="https://github.com/kth990303" target="_blank"><img src="https://img.shields.io/badge/kth990303-181717?style=for-the-social&logo=github&logoColor=white"/></a> | <img src="https://avatars.githubusercontent.com/u/69844138?v=4" width="100" height="100" style="border-radius: 50%;"><br/><a href="https://github.com/Ji-soo708" target="_blank"><img src="https://img.shields.io/badge/Jisoo708-181717?style=for-the-social&logo=github&logoColor=white"/></a> |<img src="https://avatars.githubusercontent.com/u/76640167?s=400&u=a046b207b40b564a97db82bd2264b81727b50b77&v=4" width="100" height="100" style="border-radius: 50%;"><br/><a href="https://github.com/jung-woo-kim" target="_blank"><img src="https://img.shields.io/badge/jungwookim-181717?style=for-the-social&logo=github&logoColor=white"/></a>|
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ dependencies {
implementation 'com.slack.api:slack-api-client:1.29.0'
implementation platform("org.springframework.cloud:spring-cloud-dependencies:2021.0.5")
implementation "org.springframework.cloud:spring-cloud-starter-openfeign"
implementation 'com.google.guava:guava:32.1.3-jre'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'com.mysql:mysql-connector-j'
Expand Down
20 changes: 17 additions & 3 deletions src/main/java/mocacong/server/support/AwsS3Uploader.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package mocacong.server.support;

import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.*;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.DeleteObjectsRequest;
import com.amazonaws.services.s3.model.DeleteObjectsRequest.KeyVersion;
import com.amazonaws.services.s3.model.DeleteObjectsResult;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.google.common.collect.Lists;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
Expand All @@ -23,6 +29,8 @@
public class AwsS3Uploader {

private static final String S3_BUCKET_DIRECTORY_NAME = "static";
private static final int IMAGE_CHUNK_SIZE = 1000;


private final AmazonS3Client amazonS3Client;

Expand All @@ -36,7 +44,8 @@ public String uploadImage(MultipartFile multipartFile) {
objectMetadata.setContentType(multipartFile.getContentType());
objectMetadata.setContentLength(multipartFile.getSize());

String fileName = S3_BUCKET_DIRECTORY_NAME + "/" + UUID.randomUUID() + "." + multipartFile.getOriginalFilename();
String fileName =
S3_BUCKET_DIRECTORY_NAME + "/" + UUID.randomUUID() + "." + multipartFile.getOriginalFilename();

try (InputStream inputStream = multipartFile.getInputStream()) {
amazonS3Client.putObject(new PutObjectRequest(bucket, fileName, inputStream, objectMetadata)
Expand All @@ -58,10 +67,15 @@ private void checkInvalidUploadFile(MultipartFile multipartFile) {
@EventListener
public void deleteImages(DeleteNotUsedImagesEvent event) {
List<String> imgUrls = event.getImgUrls();
Lists.partition(imgUrls, IMAGE_CHUNK_SIZE)
.forEach(this::deleteImagesByChunk);
}

private void deleteImagesByChunk(List<String> imgUrls) {
List<DeleteObjectsRequest.KeyVersion> keys = new ArrayList<>();
for (String imgUrl : imgUrls) {
String fileName = S3_BUCKET_DIRECTORY_NAME + imgUrl.substring(imgUrl.lastIndexOf("/"));
keys.add(new DeleteObjectsRequest.KeyVersion(fileName));
keys.add(new KeyVersion(fileName));
}
DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucket).withKeys(keys);
DeleteObjectsResult result = amazonS3Client.deleteObjects(deleteObjectsRequest);
Expand Down

0 comments on commit 1b0b846

Please sign in to comment.