Skip to content

Commit

Permalink
[FEATURE] BaseResponse 및 기본 설정 (#16)
Browse files Browse the repository at this point in the history
* application.yml 추가

* Create deploy.yml

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* 자동 배포 설정

* [FEATURE] 엔티티를 생성한다. (#9) (#10)

* feat: Avatar 엔티티 생성

* feat: Category enum 생성

* feat: Member 엔티티 생성

* feat: Post 엔티티 생성

* feat: Comment 엔티티 생성

* feat: PostLike 엔티티 생성

* feat: PostPhoto 엔티티 생성

* feat: Record 엔티티 생성

* feat: RecordPhoto 엔티티 생성

* feat: Report 엔티티 생성

* feat: Tag 엔티티 생성

* feat: BaseTimeEntity 추상 클래스 생성

* feat: ReportType enum 생성

* chore: category id 추가

* chore: submodule 변경사항

* Readme.md 추가

* deploy.sh 주석 추가 (자동 배포 마무리)

* chore: controller, service, repository 생성

* feature: BaseResponse 생성

* feature: ExceptionResponse 생성

* feature: ErrorCode interface 생성

* feature: BaseException 생성

* feature: ControllerAdvice 생성

* feature: GlobalErrorCode 생성

* feature: 도메인별 errorCode 생성

* feature: 도메인별 Repository 생성

* fix: ErrorCode 구현하도록 수정

* feature: UtilService 생성

* fix: 필요 없는 에러 코드 제거

---------

Co-authored-by: Sewoong <[email protected]>
  • Loading branch information
EUNJEONGMUN and SeWooooong authored Mar 20, 2023
1 parent 173e450 commit d684f5e
Show file tree
Hide file tree
Showing 34 changed files with 682 additions and 4 deletions.
111 changes: 111 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# This workflow will build and push a new container image to Amazon ECR,
# and then will deploy a new task definition to Amazon ECS, when there is a push to the "main" branch.
#
# To use this workflow, you will need to complete the following set-up steps:
#
# 1. Create an ECR repository to store your images.
# For example: `aws ecr create-repository --repository-name my-ecr-repo --region us-east-2`.
# Replace the value of the `ECR_REPOSITORY` environment variable in the workflow below with your repository's name.
# Replace the value of the `AWS_REGION` environment variable in the workflow below with your repository's region.
#
# 2. Create an ECS task definition, an ECS cluster, and an ECS service.
# For example, follow the Getting Started guide on the ECS console:
# https://us-east-2.console.aws.amazon.com/ecs/home?region=us-east-2#/firstRun
# Replace the value of the `ECS_SERVICE` environment variable in the workflow below with the name you set for the Amazon ECS service.
# Replace the value of the `ECS_CLUSTER` environment variable in the workflow below with the name you set for the cluster.
#
# 3. Store your ECS task definition as a JSON file in your repository.
# The format should follow the output of `aws ecs register-task-definition --generate-cli-skeleton`.
# Replace the value of the `ECS_TASK_DEFINITION` environment variable in the workflow below with the path to the JSON file.
# Replace the value of the `CONTAINER_NAME` environment variable in the workflow below with the name of the container
# in the `containerDefinitions` section of the task definition.
#
# 4. Store an IAM user access key in GitHub Actions secrets named `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
# See the documentation for each action used below for the recommended IAM policies for this IAM user,
# and best practices on handling the access key credentials.

name: Deploy to Amazon EC2

on:
push:
branches: [ "main" ]

env:
AWS_REGION: ap-northeast-2
S3_BUCKET_NAME: todaysgym-github-actios-s3-bucket
CODE_DEPLOY_APPLICATION_NAME: todaysgym-codedeploy-app
CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: todaysgym-codedeploy-deployment-group

permissions:
contents: read

jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
environment: production

steps:
# (1) 기본 체크아웃
- name: Checkout
uses: actions/checkout@v3

# (2) JDK 11 세팅
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '11'

# (3) 서브 모듈 접근하기
- name: Checkout repo
uses: actions/checkout@v3
with:
token: ${{ secrets.TOKEN }}
submodules: true

# (4) 서브 모듈 변경 점 있으면 update
- name: Git Sumbodule Update
run: |
git pull --recurse-submodules
git submodule update --remote --recursive
# (5) gradle 권한 변경
- name: Run chmod to make gradlew executable
run: chmod +x ./gradlew

# (6) Gradle build (Test 제외)
- name: Build with Gradle
uses: gradle/gradle-build-action@0d13054264b0bb894ded474f08ebb30921341cee
with:
arguments: clean build -x test

# (7) 원하는 파일 Zip 하기
- name: Zip build file and deploy sh
run: |
mv ./build/libs/*.jar ./
zip buildFile.zip ./appspec.yml ./*.jar ./scripts/start.sh ./scripts/stop.sh
# (8) AWS 인증 (IAM 사용자 Access Key, Secret Key 활용)
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}

# (9) 빌드 결과물을 S3 버킷에 업로드
- name: Upload to AWS S3
run: |
aws s3 cp \
--region ap-northeast-2 \
buildFile.zip s3://$S3_BUCKET_NAME/community-build/
# (10) S3 버킷에 있는 파일을 대상으로 CodeDeploy 실행
- name: Deploy to AWS EC2 from S3
run: |
aws deploy create-deployment \
--application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
--deployment-config-name CodeDeployDefault.AllAtOnce \
--deployment-group-name ${{ env.CODE_DEPLOY_DEPLOYMENT_GROUP_NAME }} \
--s3-location bucket=$S3_BUCKET_NAME,key=community-build/buildFile.zip,bundleType=zip
1 change: 1 addition & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[submodule "config"]
path = config
url = https://github.com/Today-s-Gym/application.git
branch = "main"
52 changes: 51 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,51 @@
# TodaysGym Backend
<h1 align="middle">오늘의 짐(Gym)</h1>

<p align="middle"> 아바타와 함께 성장하는 운동기록 & SNS </p>

## 💪 오늘의 짐(Gym) 소개

운동을 기록하면 당신의 아바타가 성장합니다!

하루에 한 번 운동을 기록할 수 있으며 태그 기능으로 손쉽게 관리할 수 있습니다.

다양한 운동 게시판이 준비되어 있습니다. 여러 사람들과 함께 운동 경험을 공유하세요!

## 🥋 팀원
| Backend | Backend | Backend | Backend |
|:--------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------:|:------------------------------------:|:--------------------------------------------------------------------------------------:|
| <img src="https://avatars.githubusercontent.com/u/71329329?v=4" width=400px alt="보라"/> | <img src="https://avatars.githubusercontent.com/u/76484542?v=4" width=400px alt="풀솦"/> | <img src="https://avatars.githubusercontent.com/u/67584244?v=4" width=400px alt="해나"/> | <img src="https://avatars.githubusercontent.com/u/49395754?v=4" width=400px alt="헤론"/> |
| [보라](https://github.com/YooJisu826) | [풀솦](https://github.com/injoon149) | [해나](https://github.com/EUNJEONGMUN) | [헤론](https://github.com/Heron-Woong) |

## ⚒ 프로젝트 기술 스택
- Java 11
- Spring Boot 2.7.7
- Spring Data JPA
- MySQL

## 🎯 ERD
<img alt="erd" src = "https://user-images.githubusercontent.com/67584244/217715413-38fcaf96-b562-478f-bcec-85ed83b5ab9c.png">


## 👨‍💻 협업 규칙
### 1. 브랜치 규칙
feature/{기능} 형식

예시 : feature/Login, feature/Chart

### 2. Commit Message
* feat : 새로운 기능 추가
* fix : 버그 수정, 기능 수정
* docs : 문서 수정
* refactor : 코드 리팩토링 (변수명 수정 등)
* test : 테스트 코드, 리팩토링 테스트 코드 추가
* style : 코드 스타일 변경, 코드 자체 변경이 없는 경우
* remove : 파일 또는 코드, 리소스 제거
* resource : 이미지 리소스, prefab 등의 코드와 상관없는 리소스 추가

예시 :
* resource : 이미지 리소스, prefab 등의 코드와 상관없는 리소스 추가
* feat : Add translation to missing strings
* feat : Disable publishing
* feat : Sort list context menu
* feat : Resize minimize/delete handle icons so they take up the entire topbar
* fix : Fix typo in cleanup.sh file
23 changes: 23 additions & 0 deletions appspec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
version: 0.0
os: linux

files:
- source: /
destination: /home/ubuntu/app
overwrite: yes

permissions:
- object: /
pattern: "**"
owner: ubuntu
group: ubuntu

hooks:
AfterInstall:
- location: scripts/stop.sh
timeout: 60
runas: ubuntu
ApplicationStart:
- location: scripts/start.sh
timeout: 60
runas: ubuntu
9 changes: 7 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ dependencies {
//implementation group: 'org.springframework.cloud', name: 'spring-cloud-aws', version: '2.2.1.RELEASE', ext: 'pom'
implementation 'com.amazonaws:aws-java-sdk-s3:1.11.901'
implementation 'io.awspring.cloud:spring-cloud-aws:2.4.2'

// jwt
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
implementation 'io.jsonwebtoken:jjwt-impl:0.11.5'
Expand All @@ -47,8 +46,14 @@ tasks.named('test') {
useJUnitPlatform()
}


processResources.dependsOn('copyGitSubmodule')
task copyGitSubmodule(type: Copy) {
from './config'
include '*.yml'
into './src/main/resources'
into 'src/main/resources'
}

jar {
enabled = false
}
2 changes: 1 addition & 1 deletion config
19 changes: 19 additions & 0 deletions scripts/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env bash

PROJECT_ROOT="/home/ubuntu/app"
JAR_FILE="$PROJECT_ROOT/todaysgym-0.0.1-SNAPSHOT.jar"

APP_LOG="$PROJECT_ROOT/application.log"
ERROR_LOG="$PROJECT_ROOT/error.log"
DEPLOY_LOG="$PROJECT_ROOT/deploy.log"

TIME_NOW=$(date +%c)

# jar 파일 실행
echo "$TIME_NOW > $JAR_FILE 파일 실행" >> $DEPLOY_LOG
nohup java -jar \
-Dspring.profiles.active=main \
$JAR_FILE > $APP_LOG 2> $ERROR_LOG &

CURRENT_PID=$(pgrep -f $JAR_FILE)
echo "$TIME_NOW > 실행된 프로세스 아이디 $CURRENT_PID 입니다." >> $DEPLOY_LOG
19 changes: 19 additions & 0 deletions scripts/stop.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env bash

PROJECT_ROOT="/home/ubuntu/app"
JAR_FILE="$PROJECT_ROOT/todaysgym-0.0.1-SNAPSHOT.jar"

DEPLOY_LOG="$PROJECT_ROOT/deploy.log"

TIME_NOW=$(date +%c)

# 현재 구동 중인 애플리케이션 pid 확인
CURRENT_PID=$(pgrep -f $JAR_FILE)

# 프로세스가 켜져 있으면 종료
if [ -z $CURRENT_PID ]; then
echo "$TIME_NOW > 현재 실행중인 애플리케이션이 없습니다" >> $DEPLOY_LOG
else
echo "$TIME_NOW > 실행중인 $CURRENT_PID 애플리케이션 종료 " >> $DEPLOY_LOG
kill -15 $CURRENT_PID
fi
75 changes: 75 additions & 0 deletions src/main/java/com/todaysgym/todaysgym/config/ControllerAdvice.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.todaysgym.todaysgym.config;

import com.todaysgym.todaysgym.config.exception.BaseException;
import com.todaysgym.todaysgym.config.exception.ErrorCode;
import com.todaysgym.todaysgym.config.exception.errorCode.GlobalErrorCode;
import com.todaysgym.todaysgym.config.response.ExceptionResponse;
import java.util.List;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

@RestControllerAdvice
public class ControllerAdvice {

@ExceptionHandler(BaseException.class)
public ExceptionResponse handleBaseException(BaseException e) {
ExceptionResponse exceptionResponse = new ExceptionResponse(e.getErrorCode(),
e.getMessage());
return exceptionResponse;
}

@ExceptionHandler(MethodArgumentNotValidException.class)
public ExceptionResponse handleException(MethodArgumentNotValidException e) {
String detailMessage = extractMessage(e.getBindingResult().getFieldErrors());
return convert(GlobalErrorCode.NOT_VALID_ARGUMENT_ERROR, detailMessage);
}

private String extractMessage(List<FieldError> fieldErrors) {
StringBuilder builder = new StringBuilder();
fieldErrors.forEach((error) -> {
builder.append("[");
builder.append(error.getField());
builder.append(": ");
builder.append(error.getDefaultMessage());
builder.append(" || input value: ");
builder.append("]");
builder.append(System.lineSeparator());
});
return builder.toString();
}

@ExceptionHandler(NoHandlerFoundException.class)
public ExceptionResponse handleNoHandlerFoundException() {
return convert(GlobalErrorCode.NOT_SUPPORTED_URI_ERROR);
}

@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public ExceptionResponse handleMethodNotSupportedException() {
return convert(GlobalErrorCode.NOT_SUPPORTED_METHOD_ERROR);
}

@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
public ExceptionResponse handleMediaTypeNotSupportedException() {
return convert(GlobalErrorCode.NOT_SUPPORTED_MEDIA_TYPE_ERROR);
}

@ExceptionHandler(RuntimeException.class)
public ExceptionResponse handleRuntimeException() {
return convert(GlobalErrorCode.SERVER_ERROR);
}

private ExceptionResponse convert(ErrorCode e) {
ExceptionResponse exceptionRes = new ExceptionResponse(e.getErrorCode(), e.getMessage());
return exceptionRes;
}

private ExceptionResponse convert(ErrorCode e, String detailMessage) {
ExceptionResponse exceptionRes = new ExceptionResponse(e.getErrorCode(), detailMessage);
return exceptionRes;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.todaysgym.todaysgym.config.exception;

import lombok.Getter;

@Getter
public class BaseException extends RuntimeException {

private final String errorCode;
private final String message;

public BaseException(ErrorCode code) {
errorCode = code.getErrorCode();
message = code.getMessage();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.todaysgym.todaysgym.config.exception;

public interface ErrorCode {

String getErrorCode();

String getMessage();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.todaysgym.todaysgym.config.exception.errorCode;

import com.todaysgym.todaysgym.config.exception.ErrorCode;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum AuthErrorCode implements ErrorCode {
EMPTY_JWT("AUTH_001", "JWT를 입력해주세요."),
INVALID_JWT("AUTH_002", "유효하지 않은 JWT입니다."),
EXPIRED_MEMBER_JWT("AUTH_003", "만료된 JWT입니다."),
;
private final String errorCode;
private final String message;
}
Loading

0 comments on commit d684f5e

Please sign in to comment.