Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
a338035
#29 Feat: deploy.yml 생성
Jan 29, 2025
3e8189d
#29 Feat: DockerFile 생성
Jan 29, 2025
be183bf
#29 Fix: MY_APP 환경변수 수정
Jan 29, 2025
e26c5b9
#29 Fix: MY_APP 환경변수 수정2
Jan 29, 2025
df2b354
#29 Fix: deploy.yml 코드 수정
Jan 29, 2025
6d6e640
#29 test: deploy 테스트
Jan 29, 2025
eb0661d
#29 Fix: application.yml 볼륨 마운트
Jan 29, 2025
f426639
#29 Fix: deploy test
Jan 31, 2025
ffae742
#29 Fix: deploy test 2
Jan 31, 2025
bc0a543
#29 Fix: deploy test 3
Jan 31, 2025
a114458
#29 Fix: deploy test 4
Jan 31, 2025
cbc62be
#29 Fix: deploy test 5
Jan 31, 2025
90b1685
#29 Fix: deploy test 6
Jan 31, 2025
be20e79
#29 Fix: deploy test 7
Jan 31, 2025
b9752ea
#29 Fix: deploy test 8
Jan 31, 2025
a2186cd
#29 Fix: deploy test 9
Jan 31, 2025
a7a44fa
#29 Fix: deploy test 10
Jan 31, 2025
95e79d4
#29 Fix: deploy test 11
Jan 31, 2025
738b184
#29 Fix: deploy test 12
Jan 31, 2025
7e49a6e
#29 Fix: deploy test 13
Jan 31, 2025
e261a01
#29 Fix: deploy test 14
Jan 31, 2025
5381758
#29 Fix: deploy test 15
Jan 31, 2025
c779a09
#29 Fix: deploy test 16
Jan 31, 2025
1ec813d
#29 Fix: deploy test 17
Jan 31, 2025
39d0cab
#29 Fix: deploy test 18
Jan 31, 2025
2d29e98
#29 Fix: deploy test 19
Jan 31, 2025
0fdb4fb
Merge branch 'main' of https://github.com/TeamMemeSphere/Backend-Meme…
Jan 31, 2025
235e859
#29 Feat: main 브랜치 병합
Jan 31, 2025
a704b5b
#29 Fix: memecoin.json 파일 추가
Jan 31, 2025
6bde112
#29 Fix: memecoin.json 파일 제거
Jan 31, 2025
078d09a
#29 Fix: File -> InputStream 변경
Jan 31, 2025
70aeaa1
#38 Feat: 구글 로그인 구현
noeyeyh Jan 31, 2025
53c02bc
Merge pull request #46 from TeamMemeSphere/main
kjiyun Feb 2, 2025
ee5347f
#38 Refactor: setter 삭제
noeyeyh Feb 4, 2025
f2d5502
#38 Feat: 닉네임 중복 확인 API 추가
noeyeyh Feb 4, 2025
216560b
Merge pull request #44 from noeyeyh/feat/login-google
noeyeyh Feb 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: CI/CD Pipeline with Docker

on:
push:
branches: [ develop ] # develop 브랜치에 push 발생 시 실행

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
cache: 'gradle'

- name: Create application.yml
run: |
mkdir -p src/main/resources
cat <<EOF > src/main/resources/application.yml
${{ secrets.APPLICATION_YML }}
EOF
shell: bash

- name: Build with Gradle
run: |
chmod +x gradlew
./gradlew bootJar

- name: Login to DockerHub
run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin

- name: Build and push Docker image
run: |
docker build -t ${{ secrets.DOCKER_USERNAME }}/${{ vars.MY_APP }}:latest .
docker push ${{ secrets.DOCKER_USERNAME }}/${{ vars.MY_APP }}:latest

deploy:
needs: build
runs-on: ubuntu-latest

steps:
- name: Deploy to EC2
env:
EC2_SSH_KEY: ${{ secrets.EC2_SSH_KEY }}
EC2_USERNAME: ${{ secrets.EC2_USERNAME }}
EC2_HOST: ${{ secrets.EC2_HOST }}
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
MY_APP: ${{ vars.MY_APP }}
run: |
echo "$EC2_SSH_KEY" > private_key.pem
chmod 600 private_key.pem

ssh -i private_key.pem -o StrictHostKeyChecking=no $EC2_USERNAME@$EC2_HOST "
docker pull $DOCKER_USERNAME/$MY_APP:latest
docker stop $MY_APP || true
docker rm $MY_APP || true
docker run -d -p 8080:8080 --name $MY_APP \
$DOCKER_USERNAME/$MY_APP:latest
"

rm -f private_key.pem
29 changes: 29 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Build stage
FROM bellsoft/liberica-openjdk-alpine:17 AS builder

WORKDIR /app

COPY gradlew build.gradle settings.gradle /app/
COPY gradle /app/gradle
RUN chmod +x gradlew
RUN ./gradlew dependencies --no-daemon

COPY . .
RUN ./gradlew clean build -x test --no-daemon

# Run stage
FROM bellsoft/liberica-openjdk-alpine:17

WORKDIR /app

# JAR 파일 복사
COPY --from=builder /app/build/libs/*.jar app.jar

# 필요한 리소스 파일 복사
COPY src/main/resources/application.yml /app/config/application.yml

EXPOSE 8080

# Spring Boot가 설정 파일을 읽도록 환경 변수 설정
ENTRYPOINT ["java", "-jar", "app.jar"]
CMD ["--spring.config.location=file:/app/config/application.yml"]

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.memesphere.binance.dto.response;
package com.memesphere.domain.binance.dto.response;

import lombok.Data;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.memesphere.domain.binance.service;

import com.memesphere.domain.binance.dto.response.BinanceTickerResponse;

public interface BinanceQueryService {
BinanceTickerResponse getTickerData(String symbol);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.memesphere.binance.service;
package com.memesphere.domain.binance.service;

import com.memesphere.binance.dto.response.BinanceTickerResponse;
import com.memesphere.domain.binance.dto.response.BinanceTickerResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.memesphere.domain.chartdata.converter;

import com.memesphere.binance.dto.response.BinanceTickerResponse;
import com.memesphere.domain.binance.dto.response.BinanceTickerResponse;
import com.memesphere.domain.chartdata.entity.ChartData;
import com.memesphere.domain.memecoin.entity.MemeCoin;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.memesphere.domain.chartdata.scheduler;

import com.memesphere.binance.dto.response.BinanceTickerResponse;
import com.memesphere.binance.service.BinanceQueryService;
import com.memesphere.domain.binance.dto.response.BinanceTickerResponse;
import com.memesphere.domain.binance.service.BinanceQueryService;
import com.memesphere.domain.chartdata.entity.ChartData;
import com.memesphere.global.apipayload.code.status.ErrorStatus;
import com.memesphere.global.apipayload.exception.GeneralException;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.memesphere.domain.memecoin.entity;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.memesphere.domain.memecoin.repository.MemeCoinRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

@Component
@RequiredArgsConstructor
public class MemeCoinInitializer implements CommandLineRunner {
private final MemeCoinRepository memeCoinRepository;
private final ObjectMapper objectMapper;

@Override
public void run(String... args) throws Exception {
if (memeCoinRepository.count() == 0) {
// JAR 내부 classpath에서 JSON 파일 로드
try (InputStream inputStream = getClass().getClassLoader()
.getResourceAsStream("memecoin-storage/memecoin.json")) {

if (inputStream == null) {
throw new IOException("'memecoin-storage/memecoin.json' 파일을 찾을 수 없습니다.");
}

// JSON 파일을 Java 객체(List<MemeCoin>)로 변환
List<MemeCoin> memeCoins = objectMapper.readValue(
inputStream,
new TypeReference<List<MemeCoin>>() {}
);

// DB에 저장
memeCoinRepository.saveAll(memeCoins);

} catch (IOException e) {
throw new RuntimeException("JSON 파일 로드 중 오류 발생: " + e.getMessage(), e);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@
@org.springframework.stereotype.Controller
public class TestLoginController {

@Value("${testLoginUrl}")
private String testLoginUrl;
@Value("${testKakaoLoginUrl}")
private String testKakaoLoginUrl;

@Value("${testGoogleLoginUrl}")
private String testGoogleLoginUrl;

@GetMapping("/login")
public String login(Model model) {

model.addAttribute("testLoginUrl", testLoginUrl);
model.addAttribute("testKakaoLoginUrl", testKakaoLoginUrl);
model.addAttribute("testGoogleLoginUrl", testGoogleLoginUrl);
return "login";
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package com.memesphere.domain.user.controller;

import com.memesphere.domain.user.dto.request.NicknameRequest;
import com.memesphere.domain.user.dto.request.SignInRequest;
import com.memesphere.domain.user.dto.request.SignUpRequest;
import com.memesphere.domain.user.dto.response.GoogleUserInfoResponse;
import com.memesphere.domain.user.dto.response.TokenResponse;
import com.memesphere.domain.user.dto.response.KakaoUserInfoResponse;
import com.memesphere.domain.user.service.AuthServiceImpl;
import com.memesphere.domain.user.service.GoogleServiceImpl;
import com.memesphere.domain.user.service.KakaoServiceImpl;
import com.memesphere.global.apipayload.ApiResponse;
import com.memesphere.domain.user.dto.response.LoginResponse;
import com.memesphere.global.apipayload.code.status.ErrorStatus;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
Expand All @@ -23,18 +27,29 @@
public class UserController {

private final KakaoServiceImpl kakaoServiceImpl;
private final GoogleServiceImpl googleServiceImpl;
private final AuthServiceImpl authServiceImpl;

@PostMapping("/login/oauth2/kakao")
@Operation(summary = "카카오 로그인/회원가입 API")
public ApiResponse<LoginResponse> callback(@RequestParam("code") String code) throws IOException {
public ApiResponse<LoginResponse> kakaoLogin(@RequestParam("code") String code) throws IOException {
TokenResponse kakaoTokenResponse = kakaoServiceImpl.getAccessTokenFromKakao(code);
KakaoUserInfoResponse kakaoUserInfoResponse = kakaoServiceImpl.getUserInfo(kakaoTokenResponse.getAccessToken());
LoginResponse loginResponse = kakaoServiceImpl.handleUserLogin(kakaoUserInfoResponse);

return ApiResponse.onSuccess(loginResponse);
}

@PostMapping("/login/oauth2/google")
@Operation(summary = "구글 로그인/회원가입 API")
public ApiResponse<LoginResponse> googleLogin(@RequestParam("code") String code) throws IOException {
TokenResponse googleTokenResponse = googleServiceImpl.getAccessTokenFromGoogle(code);
GoogleUserInfoResponse googleUserInfoResponse = googleServiceImpl.getUserInfo(googleTokenResponse.getAccessToken());
LoginResponse loginResponse = googleServiceImpl.handleUserLogin(googleUserInfoResponse);

return ApiResponse.onSuccess(loginResponse);
}

@PostMapping("/signup")
@Operation(summary = "일반 회원가입 API")
public ApiResponse<?> signUp(@Valid @RequestBody SignUpRequest signUpRequest) {
Expand All @@ -48,4 +63,16 @@ public ApiResponse<LoginResponse> login(@Valid @RequestBody SignInRequest signIn
LoginResponse loginResponse = authServiceImpl.handleUserLogin(signInRequest);
return ApiResponse.onSuccess(loginResponse);
}

@PostMapping("/signup/nickname/validate")
@Operation(summary = "닉네임 중복 확인 API")
public ApiResponse<?> isNicknameValidate(@RequestBody NicknameRequest nicknameRequest) {
boolean isDuplicate = authServiceImpl.checkNicknameDuplicate(nicknameRequest.getNickname());

if (isDuplicate) {
return ApiResponse.onSuccess("이미 사용 중인 닉네임입니다.");
} else {
return ApiResponse.onSuccess("사용 가능한 닉네임입니다.");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.memesphere.domain.user.converter;

import com.memesphere.domain.user.dto.request.SignUpRequest;
import com.memesphere.domain.user.dto.response.GoogleUserInfoResponse;
import com.memesphere.domain.user.entity.SocialType;
import com.memesphere.domain.user.entity.User;
import com.memesphere.domain.user.dto.response.TokenResponse;
Expand Down Expand Up @@ -35,6 +36,31 @@ public static User toUpdatedKakaoUser(KakaoUserInfoResponse kakaoUserInfoRespons
.build();
}

// 구글 로그인 유저
public static User toGoogleUser(GoogleUserInfoResponse googleUserInfoResponse) {
return User.builder()
.loginId(UUID.randomUUID().getMostSignificantBits() & Long.MAX_VALUE)
.nickname(googleUserInfoResponse.getName())
.email(googleUserInfoResponse.getEmail())
.profileImage(googleUserInfoResponse.getPicture())
.socialType(SocialType.GOOGLE)
.userRole(UserRole.USER)
.build();
}

public static User toUpdatedGoogleUser(GoogleUserInfoResponse googleUserInfoResponse, TokenResponse tokenResponse) {
return User.builder()
.loginId(UUID.randomUUID().getMostSignificantBits() & Long.MAX_VALUE)
.nickname(googleUserInfoResponse.getName())
.email(googleUserInfoResponse.getEmail())
.profileImage(googleUserInfoResponse.getPicture())
.accessToken(tokenResponse.getAccessToken())
.refreshToken(tokenResponse.getRefreshToken())
.socialType(SocialType.GOOGLE)
.userRole(UserRole.USER)
.build();
}

// 일반 로그인 유저
public static User toAuthUser(SignUpRequest signUpRequest, PasswordEncoder passwordEncoder) {
return User.builder()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.memesphere.domain.user.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class NicknameRequest {

@NotEmpty
@Schema(description = "닉네임", example = "홍길동")
private String nickname;
}
Loading