Skip to content

Commit

Permalink
Merge branch 'develop' into feat/#60
Browse files Browse the repository at this point in the history
  • Loading branch information
khw7385 authored Feb 10, 2025
2 parents b07f9c9 + 37de6e5 commit 87a6f85
Show file tree
Hide file tree
Showing 129 changed files with 3,150 additions and 240 deletions.
80 changes: 80 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: Java CI with Gradle

on:
push:
branches: [ "develop" ]
pull_request:
branches: [ "develop" ]

permissions:
contents: write # Docker 이미지 푸시 및 배포 시 사용

jobs:
CI-CD:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./backend
steps:
- uses: actions/checkout@v3

- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'corretto'

- name: Gradle Caching
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('backend/**/*.gradle*', 'backend/**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Build with Gradle
run: ./gradlew build -x test -DPROD_SERVER_URL=${{ secrets.PROD_SERVER_URL }} -Pspring.profiles.active=prod

- name: Docker build & push to prod
if: contains(github.ref, 'develop')
run: |
docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
docker build -t ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPOSITORY }} .
docker push ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPOSITORY }}
- name: Deploy to prod
uses: appleboy/[email protected] # 최신 릴리스 버전을 명시하는 것
id: deploy-prod
if: contains(github.ref, 'develop')
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USERNAME }}
key: ${{ secrets.EC2_PRIVATE_KEY }}
envs: GITHUB_SHA
script: |
sudo docker stop ${{ secrets.DOCKER_REPOSITORY }} || true
sudo docker rm ${{ secrets.DOCKER_REPOSITORY }} || true
sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPOSITORY }}
sudo docker run -d -p 8080:8080 \
--network ${{ secrets.DOCKER_NERWORK }} \
-e DB_HOST=${{ secrets.DB_HOST }} \
-e DB_NAME=${{ secrets.DB_NAME }} \
-e DB_PORT=${{ secrets.DB_PORT }} \
-e DB_USERNAME=${{ secrets.DB_USERNAME }} \
-e DB_PASSWORD=${{ secrets.DB_PASSWORD }} \
-e REDIS_HOST=${{ secrets.REDIS_HOST }} \
-e REDIS_PORT=${{ secrets.REDIS_PORT }} \
-e JWT_SECRET=${{ secrets.JWT_SECRET }} \
-e JWT_ACCESS_TOKEN_TIME=${{ secrets.JWT_ACCESS_TOKEN_TIME }} \
-e JWT_REFRESH_TOKEN_TIME=${{ secrets.JWT_REFRESH_TOKEN_TIME }} \
-e KAKAO_CLIENT_ID=${{ secrets.KAKAO_CLIENT_ID }} \
-e KAKAO_CLIENT_SECRET=${{ secrets.KAKAO_CLIENT_SECRET }} \
-e NAVER_CLIENT_ID=${{ secrets.NAVER_CLIENT_ID }} \
-e NAVER_CLIENT_SECRET=${{ secrets.NAVER_CLIENT_SECRET }} \
-e ODSAY_CLIENT_API_KEY=${{ secrets.ODSAY_CLIENT_API_KEY }} \
-e PROD_SERVER_URL=${{ secrets.PROD_SERVER_URL }} \
--name ${{ secrets.DOCKER_REPOSITORY }} \
${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPOSITORY }}
sudo docker image prune -f
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
/.idea/workspace.xml
.idea
12 changes: 12 additions & 0 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# open jdk 17 버전의 환경을 구성
FROM openjdk:17

# build가 되는 시점에 JAR_FILE이라는 변수 명에 build/libs/*.jar 선언
# build/libs - gradle로 빌드했을 때 jar 파일이 생성되는 경로
ARG JAR_FILE=build/libs/*.jar

# JAR_FILE을 app.jar로 복사
COPY ${JAR_FILE} app.jar

# 운영 및 개발에서 사용되는 환경 설정을 분리
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=prod", "/app.jar"]
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,30 @@
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

import java.util.List;

@Configuration
@RequiredArgsConstructor
public class OpenApiConfig {
private final Environment environment;

@Bean
public OpenAPI customOpenAPI() {
final String securitySchemeName = "AccessToken";

String activeProfile = environment.getProperty("spring.profiles.active", "local");

String serverUrl = System.getenv("PROD_SERVER_URL");
if (serverUrl == null || serverUrl.isBlank()) {
serverUrl = "http://localhost:8080";
}

return new OpenAPI()
.components(new Components()
.addSecuritySchemes(securitySchemeName,
Expand All @@ -22,8 +37,9 @@ public OpenAPI customOpenAPI() {
.scheme("bearer")
.bearerFormat("JWT")))
.addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
.info(new Info().title("API Documentation")
.description("API 문서")
.servers(List.of(new Server().url(serverUrl).description(activeProfile + " server")))
.info(new Info().title("두리번 API Documentation")
.description("팀 두부의 두리번 서비스 API 문서입니다.")
.version("1.0"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ public void addFormatters(FormatterRegistry registry) {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenInterceptor)
.addPathPatterns("/members/**")
.addPathPatterns("/routes/**");
.addPathPatterns("/members/**", "/plans/**", "/routes/**");
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.dubu.backend.global.domain;

public record PageResponse<T>(boolean hasNext, Long nextCursor, T data) {
public record PageResponse<C, T>(boolean hasNext, C nextCursor, T data) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public enum ErrorCode {
UNSUPPORTED_SOCIAL_LOGIN(BAD_REQUEST, "지원하지 않는 소셜 로그인 타입입니다."),

// Member
INVALID_MEMBER_STATUS(BAD_REQUEST, "회원의 상태가 %s인 경우 해당 API를 이용할 수 없습니다."),
MEMBER_NOT_FOUND(NOT_FOUND, "회원을 찾을 수 없습니다. memberId : %d"),

// Address
Expand All @@ -40,22 +41,26 @@ public enum ErrorCode {
// Category
CATEGORY_NOT_FOUND(NOT_FOUND, "카테고리를 찾을 수 없습니다. categoryName : %s"),

// Plan
NOT_FOUND_PLAN(NOT_FOUND, "계획을 찾을 수 없습니다. planId : %d"),
UNAUTHORIZED_PLAN_DELETION(UNAUTHORIZED, "회원이 해당 계획에 접근 권한이 없어 삭제할 수 없습니다. memberId : %d, planId : %d"),

// Path
INVALID_TRAFFIC_TYPE(BAD_REQUEST, "지원하지 않는 대중교통 형식입니다. trafficType : %s"),

// Member_Category
MEMBER_CATEGORY_NOT_FOUND(NOT_FOUND, "회원의 카테고리 정보를 찾을 수 없습니다. memberId : %d"),

// Todo
TODO_NOT_FOUND(NOT_FOUND, "해당 할 일이 존재하지 않습니다."),

ALREADY_ADDED_TODO(BAD_REQUEST, "이미 추가된 할 일 입니다."),

TODO_LIMIT_EXCEEDED(BAD_REQUEST, "할 일은 최대 3개까지 추가할 수 있습니다."),

// Schedule
SCHEDULE_NOT_FOUND(NOT_FOUND, "스케줄을 찾을 수 없습니다."),

// External API
NAVER_SERVICE_UNAVAILABLE(SERVICE_UNAVAILABLE, "네이버 API 서버가 장애 상태입니다."),

;

public final HttpStatus httpStatus;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons
Long memberId = tokenService.validateToken(token);

request.setAttribute("memberId", memberId);

}
return true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.List;

import static org.springframework.http.HttpStatus.NO_CONTENT;

@RestController
Expand Down Expand Up @@ -42,4 +44,11 @@ public SuccessResponse<MemberSavedAddressResponse> getMemberSavedAddress(

return new SuccessResponse<>(response);
}

@GetMapping("/category")
public SuccessResponse<List<String>> getMemberCategory(
@RequestAttribute("memberId") Long memberId
){
return new SuccessResponse<>(memberService.getMemberCategory(memberId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,13 @@ public MemberSavedAddressResponse getMemberSavedAddress(Long memberId) {

return MemberSavedAddressResponse.from(addresses);
}

public List<String> getMemberCategory(Long memberId){
Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new MemberNotFoundException(memberId));

return memberCategoryRepository.findMemberCategoriesWithCategoryByMember(member)
.stream().map(memberCategory -> memberCategory.getCategory().getName())
.toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@

public interface MemberCategoryRepository extends JpaRepository<MemberCategory, Long> {
@Query("SELECT mc.category.id FROM MemberCategory mc WHERE mc.member = :member")
List<Long> findByMember(@Param("member") Member member);
List<Long> findCategoryIdsByMember(@Param("member") Member member);

@Query("SELECT mc FROM MemberCategory mc JOIN FETCH mc.category WHERE mc.member = :member")
List<MemberCategory> findMemberCategoriesWithCategoryByMember(Member member);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.dubu.backend.plan.api;

import com.dubu.backend.global.domain.SuccessResponse;
import com.dubu.backend.plan.application.PlanService;
import com.dubu.backend.plan.dto.request.PlanSaveRequest;
import com.dubu.backend.plan.dto.response.PlanRecentResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
@RequestMapping("/plans")
public class PlanController {
private final PlanService planService;

@ResponseStatus(HttpStatus.CREATED)
@PostMapping
public void savePlan(
@RequestAttribute("memberId") Long memberId,
@RequestBody PlanSaveRequest planSaveRequest
) {
planService.savePlan(memberId, planSaveRequest);
}

@GetMapping("/recent")
public SuccessResponse<PlanRecentResponse> getRecentPlan(
@RequestAttribute("memberId") Long memberId
) {
PlanRecentResponse response = planService.findRecentPlan(memberId);

return new SuccessResponse<>(response);
}

@ResponseStatus(HttpStatus.NO_CONTENT)
@DeleteMapping
public void deletePlan(
@RequestAttribute("memberId") Long memberId,
@RequestParam("planId") Long planId
){
planService.removePlan(memberId, planId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import com.dubu.backend.global.domain.SuccessResponse;
import com.dubu.backend.plan.application.RouteService;
import com.dubu.backend.plan.dto.RouteSearchResponseDto;
import com.dubu.backend.plan.dto.response.RouteSearchResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

Expand All @@ -16,14 +16,14 @@ public class RouteController {
private final RouteService routeService;

@GetMapping("/search")
public SuccessResponse<List<RouteSearchResponseDto>> routeSearch(
public SuccessResponse<List<RouteSearchResponse>> routeSearch(
@RequestAttribute("memberId") Long memberId,
@RequestParam("startX") Double startX,
@RequestParam("startY") Double startY,
@RequestParam("endX") Double endX,
@RequestParam("endY") Double endY
) {
List<RouteSearchResponseDto> response = routeService.getRoutesByStartAndDestination(memberId, startX, startY, endX, endY);
List<RouteSearchResponse> response = routeService.getRoutesByStartAndDestination(memberId, startX, startY, endX, endY);

return new SuccessResponse<>(response);
}
Expand Down
Loading

0 comments on commit 87a6f85

Please sign in to comment.