diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml new file mode 100644 index 0000000..e3dee18 --- /dev/null +++ b/.github/workflows/cd.yml @@ -0,0 +1,56 @@ +name: Deploy to GCP + +on: + push: + branches: + - main + paths-ignore: + - '.github/workflows/**' + +jobs: + deploy: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + steps: + - uses: actions/checkout@v4 + + # CI에서 생성한 JAR 파일 다운로드 + - name: Download JAR Artifact + uses: actions/download-artifact@v4 + with: + name: application-jar + path: build/libs/ + + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build & Push Docker Image + uses: docker/build-push-action@v6 + with: + push: true + context: . + tags: ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}:latest + + - name: Authenticate to GCP + uses: google-github-actions/auth@v2 + with: + workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }} + service_account: ${{ secrets.SERVICE_ACCOUNT_EMAIL }} + + - name: Deploy to GCP Compute Engine + uses: google-github-actions/ssh-compute@v1 + with: + instance_name: ${{ secrets.GCP_INSTANCE_NAME }} + zone: ${{ secrets.GCP_INSTANCE_ZONE }} + ssh_private_key: ${{ secrets.GCP_SSH_PRIVATE_KEY }} + command: | + cd /app/${{ github.repository }} + sudo curl -o docker-compose.yml https://raw.githubusercontent.com/${{ github.repository }}/main/docker-compose.yml + sudo docker-compose down + sudo docker-compose up -d ${{ secrets.DOCKER_IMAGE_NAME }} + sudo docker image prune -a -f diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..30ae094 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,37 @@ +name: Java CI with Gradle + +on: + push: + branches: + - main + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Build with Gradle + run: ./gradlew build + + # 빌드 결과물을 아티팩트로 업로드 (JAR 파일) + - name: Upload JAR Artifact + uses: actions/upload-artifact@v4 + with: + name: application-jar + path: build/libs/*.jar diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml deleted file mode 100644 index f452af0..0000000 --- a/.github/workflows/gradle.yml +++ /dev/null @@ -1,104 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. -# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle - -name: Java CI with Gradle - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - -jobs: - build: - if: github.event.repository.fork == false - runs-on: ubuntu-latest - permissions: - id-token: write - contents: read - - steps: - - uses: actions/checkout@v4 - - name: Set up JDK 21 - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - - # Configure Gradle for optimal use in GitHub Actions, including caching of downloaded dependencies. - # See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md - - name: Setup Gradle - uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 - - - name: Build with Gradle Wrapper - run: ./gradlew build - - # 3. 도커허브 로그인 - - name: Login to DockerHub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - # 4. 도커 허브에 이미지 푸시 - - name: Push Docker Image - uses: docker/build-push-action@v6 - with: - push: true - context: . - tags: ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}:latest - - # 5. GCP 인증 - - name: Authenticate to GCP - id: 'auth' - uses: 'google-github-actions/auth@v2' - with: - workload_identity_provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }} # 생성한 워크로드 아이덴티티 풀의 ID - service_account: ${{ secrets.SERVICE_ACCOUNT_EMAIL }} # IAM 서비스 계정 - - # 6. GCP Compute Engine SSH로 배포 - - name: Deploy to GCP Compute Engine - id: 'compute-ssh' - uses: 'google-github-actions/ssh-compute@v1' - with: - instance_name: ${{ secrets.GCP_INSTANCE_NAME }} - zone: ${{ secrets.GCP_INSTANCE_ZONE }} - ssh_private_key: ${{ secrets.GCP_SSH_PRIVATE_KEY }} - command: | - mkdir ./${{ github.repository }} - cd ./${{ github.repository }} - ls -al - sudo curl -o docker-compose.yml https://raw.githubusercontent.com/${{ github.repository }}/main/docker-compose.yml - sudo docker-compose down - sudo docker-compose up -d ${{ secrets.DOCKER_IMAGE_NAME }} - sudo docker image prune -a -f - - # Example of using the output - - id: 'debug' - run: |- - echo '${{ steps.compute-ssh.outputs.stdout }}' - echo '${{ steps.compute-ssh.outputs.stderr }}' - - - dependency-submission: - - runs-on: ubuntu-latest - permissions: - contents: write - - steps: - - uses: actions/checkout@v4 - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - - # Generates and submits a dependency graph, enabling Dependabot Alerts for all project dependencies. - # See: https://github.com/gradle/actions/blob/main/dependency-submission/README.md - - name: Generate and submit dependency graph - uses: gradle/actions/dependency-submission@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 diff --git a/src/main/java/com/example/Jinus/controller/v2/CafeteriaControllerV2.java b/src/main/java/com/example/Jinus/controller/v2/CafeteriaControllerV2.java index f2fa87f..0a785c4 100644 --- a/src/main/java/com/example/Jinus/controller/v2/CafeteriaControllerV2.java +++ b/src/main/java/com/example/Jinus/controller/v2/CafeteriaControllerV2.java @@ -10,6 +10,7 @@ import com.example.Jinus.utility.ListCardResponse; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; @@ -18,6 +19,7 @@ import java.util.Map; @RestController +@RequestMapping("/api/v2/spring") public class CafeteriaControllerV2 { private final UserServiceV2 userServiceV2; @@ -33,20 +35,14 @@ public CafeteriaControllerV2( this.cafeteriaServiceV2 = cafeteriaServiceV2; } - // 사용자 존재 여부에 따라 응답 - @PostMapping("/api/spring/cafeteria/v2") + @PostMapping("/cafeteria") public String responseCafeteriaOrCampusListCard(@RequestBody RequestDto requestDto) { // userId로 campusId 찾기 String userId = requestDto.getUserRequest().getUser().getId(); int campusId = userServiceV2.getUserCampusId(userId); int sysCampusId = requestDto.getAction().getClientExtra().getSys_campus_id(); - // 사용자가 존재 & 식당 블록에서 캠퍼스 눌렀을 때 -> 식당 리스트 - if (campusId != -1 && sysCampusId != -1) { - return cafeteriaServiceV2.makeCafeteriaListCard(campusId); - } else { // 사용자가 존재 X & 식당 블록에서 더보기 버튼 눌렀을 때 -> 캠퍼스 리스트 - return campusServiceV2.makeCampusListCard(); - } + return cafeteriaServiceV2.campusOrCafeteria(campusId, sysCampusId); } } diff --git a/src/main/java/com/example/Jinus/controller/v2/DietControllerV2.java b/src/main/java/com/example/Jinus/controller/v2/DietControllerV2.java new file mode 100644 index 0000000..eea29e8 --- /dev/null +++ b/src/main/java/com/example/Jinus/controller/v2/DietControllerV2.java @@ -0,0 +1,21 @@ +package com.example.Jinus.controller.v2; + +import com.example.Jinus.dto.request.RequestDto; +import com.example.Jinus.service.v2.cafeteria.DietServiceV2; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/v2/spring") +@RequiredArgsConstructor +public class DietControllerV2 { + private final DietServiceV2 dietServiceV2; + + @PostMapping("/dish") + public String handleRequest(@RequestBody RequestDto requestDto) { + return dietServiceV2.requestHandler(requestDto); + } +} diff --git a/src/main/java/com/example/Jinus/controller/v2/NoticeControllerV2.java b/src/main/java/com/example/Jinus/controller/v2/NoticeControllerV2.java index 7db8dfb..9964f77 100644 --- a/src/main/java/com/example/Jinus/controller/v2/NoticeControllerV2.java +++ b/src/main/java/com/example/Jinus/controller/v2/NoticeControllerV2.java @@ -3,7 +3,7 @@ import com.example.Jinus.dto.request.RequestDto; import com.example.Jinus.dto.response.*; import com.example.Jinus.entity.notice.NoticeCategoryEntity; -import com.example.Jinus.service.v2.notice.NoticeCategoryServiceV2; +import com.example.Jinus.service.v2.notice.CategoryServiceV2; import com.example.Jinus.service.v2.notice.NoticeServiceV2; import com.example.Jinus.service.v2.userInfo.DepartmentServiceV2; import com.example.Jinus.service.v2.userInfo.UserServiceV2; @@ -11,6 +11,7 @@ import com.example.Jinus.utility.TextCardResponse; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; @@ -19,15 +20,16 @@ import static java.lang.String.valueOf; @RestController +@RequestMapping("/api/v2/spring") public class NoticeControllerV2 { private final NoticeServiceV2 noticeServiceV2; - private final NoticeCategoryServiceV2 noticeCategoryServiceV2; + private final CategoryServiceV2 noticeCategoryServiceV2; private final DepartmentServiceV2 departmentServiceV2; private final UserServiceV2 userServiceV2; public NoticeControllerV2(NoticeServiceV2 noticeServiceV2, - NoticeCategoryServiceV2 noticeCategoryServiceV2, + CategoryServiceV2 noticeCategoryServiceV2, DepartmentServiceV2 departmentServiceV2, UserServiceV2 userServiceV2) { this.noticeServiceV2 = noticeServiceV2; @@ -37,7 +39,7 @@ public NoticeControllerV2(NoticeServiceV2 noticeServiceV2, } // 학교 공지사항 조회 - @PostMapping("/api/spring/main-notice/v2") + @PostMapping("/main-notice") public String getMainNotice() { int departmentId = 117; // 학교 공지사항 id String departmentEng = "main"; // 학과 영문명 @@ -45,7 +47,7 @@ public String getMainNotice() { } // 학과 공지사항 조회 - @PostMapping("/api/spring/department-notice/v2") + @PostMapping("/department-notice") public String responseDepartmentNotice(@RequestBody RequestDto requestDto) { String userId = requestDto.getUserRequest().getUser().getId(); int departmentId = userServiceV2.getUserDepartmentId(userId); diff --git a/src/main/java/com/example/Jinus/dto/request/HandleRequestDto.java b/src/main/java/com/example/Jinus/dto/request/HandleRequestDto.java new file mode 100644 index 0000000..aa4ad92 --- /dev/null +++ b/src/main/java/com/example/Jinus/dto/request/HandleRequestDto.java @@ -0,0 +1,23 @@ +package com.example.Jinus.dto.request; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class HandleRequestDto { + private final String kakaoId; + private final String campusName; + private final String day; + private final String period; + private final String cafeteriaName; + + public HandleRequestDto(String kakaoId, String campusName, String day, String period, String cafeteriaName) { + this.kakaoId = kakaoId; + this.campusName = campusName; + this.day = day; + this.period = period; + this.cafeteriaName = cafeteriaName; + } + +} diff --git a/src/main/java/com/example/Jinus/entity/cafeteria/CafeteriaDietEntity.java b/src/main/java/com/example/Jinus/entity/cafeteria/CafeteriaDietEntity.java index 9809b9a..ae8c42b 100644 --- a/src/main/java/com/example/Jinus/entity/cafeteria/CafeteriaDietEntity.java +++ b/src/main/java/com/example/Jinus/entity/cafeteria/CafeteriaDietEntity.java @@ -6,7 +6,7 @@ import lombok.NoArgsConstructor; import lombok.Setter; -import java.time.LocalDateTime; +import java.sql.Date; @Entity @Getter @@ -20,11 +20,8 @@ public class CafeteriaDietEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private int dietId; - @Column(name = "date", columnDefinition = "TIMESTAMP WITH TIME ZONE") - private LocalDateTime dateTime; // 날짜 + 시간 + 시간대 - -// @Column(name = "date") -// private LocalTime date; + @Column(name = "date") + private Date dietDate; @Column(name = "day") private String day_of_week; diff --git a/src/main/java/com/example/Jinus/repository/v2/cafeteria/CafeteriaRepositoryV2.java b/src/main/java/com/example/Jinus/repository/v2/cafeteria/CafeteriaRepositoryV2.java index 1dd1109..390fbbd 100644 --- a/src/main/java/com/example/Jinus/repository/v2/cafeteria/CafeteriaRepositoryV2.java +++ b/src/main/java/com/example/Jinus/repository/v2/cafeteria/CafeteriaRepositoryV2.java @@ -7,6 +7,7 @@ import java.util.HashMap; import java.util.List; +import java.util.Optional; public interface CafeteriaRepositoryV2 extends JpaRepository { // 사용자 campusId와 동일한 식당이름과 url 찾기 @@ -16,6 +17,10 @@ public interface CafeteriaRepositoryV2 extends JpaRepository findCafeteriaId(@Param("cafeteriaName") String cafeteriaName, + @Param("campusId") int campusId); + + // cafeteriaId로 imgUrl 찾기 + @Query("SELECT c.thumbnailUrl FROM CafeteriaEntity c WHERE c.id = :cafeteriaId") + String findImgUrlByCafeteriaId(@Param("cafeteriaId")int cafeteriaId); } diff --git a/src/main/java/com/example/Jinus/repository/v2/cafeteria/CampusRepositoryV2.java b/src/main/java/com/example/Jinus/repository/v2/cafeteria/CampusRepositoryV2.java index 56917fe..4565376 100644 --- a/src/main/java/com/example/Jinus/repository/v2/cafeteria/CampusRepositoryV2.java +++ b/src/main/java/com/example/Jinus/repository/v2/cafeteria/CampusRepositoryV2.java @@ -12,9 +12,17 @@ public interface CampusRepositoryV2 extends JpaRepository { // 사용자 campusId로 캠퍼스 이름 찾기 @Query("SELECT c.campusNameKo FROM CampusEntity c WHERE c.id = :campusId") - String findCampusNameById(@Param("campusId") int campusId); + String findCampusNameByCampusId(@Param("campusId") int campusId); // campusId가 5보다 작은 캠퍼스들 찾기 @Query("SELECT c FROM CampusEntity c WHERE c.id < 5") List findCampusList(); + + // campusName으로 imgUrl 찾기 + @Query("SELECT c.thumbnailUrl FROM CampusEntity c WHERE c.campusNameKo = :campusName") + String findCampusImgUrlByCampusName(@Param("campusName")String campusName); + + // campusName으로 id 찾기 + @Query("SELECT c.id FROM CampusEntity c WHERE c.campusNameKo = :campusName") + int findCampusIdByName(@Param("campusName")String campusName); } diff --git a/src/main/java/com/example/Jinus/repository/v2/cafeteria/DietRepositoryV2.java b/src/main/java/com/example/Jinus/repository/v2/cafeteria/DietRepositoryV2.java index ed6ef3a..42dd8e9 100644 --- a/src/main/java/com/example/Jinus/repository/v2/cafeteria/DietRepositoryV2.java +++ b/src/main/java/com/example/Jinus/repository/v2/cafeteria/DietRepositoryV2.java @@ -6,16 +6,15 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.time.LocalDateTime; -import java.time.OffsetDateTime; +import java.sql.Date; import java.util.List; @Repository public interface DietRepositoryV2 extends JpaRepository { - @Query("SELECT c.dishName, c.dishCategory, c.dishType FROM CafeteriaDietEntity c " + - "WHERE c.dateTime = :date " + + @Query("SELECT c.dishCategory, c.dishType, c.dishName FROM CafeteriaDietEntity c " + + "WHERE c.dietDate = :dietDate " + "AND c.time = :period AND c.cafeteriaId = :cafeteriaId") - List findDietList(@Param("date") LocalDateTime date, + List findDietList(@Param("dietDate") Date dietDate, @Param("period") String period, @Param("cafeteriaId") int cafeteriaId); } diff --git a/src/main/java/com/example/Jinus/repository/v2/notice/NoticeCategoryRepositoryV2.java b/src/main/java/com/example/Jinus/repository/v2/notice/CategoryRepositoryV2.java similarity index 84% rename from src/main/java/com/example/Jinus/repository/v2/notice/NoticeCategoryRepositoryV2.java rename to src/main/java/com/example/Jinus/repository/v2/notice/CategoryRepositoryV2.java index c7e31ae..23e56ba 100644 --- a/src/main/java/com/example/Jinus/repository/v2/notice/NoticeCategoryRepositoryV2.java +++ b/src/main/java/com/example/Jinus/repository/v2/notice/CategoryRepositoryV2.java @@ -7,7 +7,7 @@ import java.util.List; -public interface NoticeCategoryRepositoryV2 extends JpaRepository { +public interface CategoryRepositoryV2 extends JpaRepository { @Query("SELECT n FROM NoticeCategoryEntity n" + " WHERE n.departmentId = :departmentId AND n.lastNttSn != 0") List findCategoryListByDepartmentId(@Param("departmentId")int departmentId); diff --git a/src/main/java/com/example/Jinus/service/v2/cafeteria/CafeteriaServiceV2.java b/src/main/java/com/example/Jinus/service/v2/cafeteria/CafeteriaServiceV2.java index 640e478..c4b01be 100644 --- a/src/main/java/com/example/Jinus/service/v2/cafeteria/CafeteriaServiceV2.java +++ b/src/main/java/com/example/Jinus/service/v2/cafeteria/CafeteriaServiceV2.java @@ -31,6 +31,34 @@ public List getCafeteriaList(int campusId) { return cafeteriaRepositoryV2.findCafeteriaListByCampusId(campusId); } + // 캠퍼스에 식당이 존재한다면 cafeteriaId 찾기 + public int getCafeteriaId(String cafeteriaName, int campusId) { + return cafeteriaRepositoryV2.findCafeteriaId(cafeteriaName, campusId).orElse(-1); + } + + // 식당 imgUrl 찾기 + public String getImgUrl(int cafeteriaId) { + return cafeteriaRepositoryV2.findImgUrlByCafeteriaId(cafeteriaId); + } + + // 반환 조건 설정 + public String campusOrCafeteria(int campusId, int sysCampusId) { + // 더보기 버튼 누른 경우 + if (sysCampusId == -1) { + return campusServiceV2.makeCampusListCard(); + } + + // 사용자가 원하는 캠퍼스가 있을 때 + if (sysCampusId > 0) { + return makeCafeteriaListCard(sysCampusId); + } + + // 사용자가 원하는 캠퍼스가 없을 때 + return (campusId != -1) + ? makeCafeteriaListCard(campusId) + : campusServiceV2.makeCampusListCard(); + } + // 식당 리스트 반환 메소드 public String makeCafeteriaListCard(int campusId) { String campusName = campusServiceV2.getUserCampusName(campusId); diff --git a/src/main/java/com/example/Jinus/service/v2/cafeteria/CampusServiceV2.java b/src/main/java/com/example/Jinus/service/v2/cafeteria/CampusServiceV2.java index bb58005..a0a3532 100644 --- a/src/main/java/com/example/Jinus/service/v2/cafeteria/CampusServiceV2.java +++ b/src/main/java/com/example/Jinus/service/v2/cafeteria/CampusServiceV2.java @@ -25,7 +25,7 @@ public CampusServiceV2(CampusRepositoryV2 campusRepositoryV2) { // 사용자의 campusId 받아 캠퍼스 이름 찾기 public String getUserCampusName(int campusId) { - return campusRepositoryV2.findCampusNameById(campusId); + return campusRepositoryV2.findCampusNameByCampusId(campusId); } // id < 5인 캠퍼스 찾아 리스트로 반환 @@ -33,6 +33,11 @@ public List getCampusList() { return campusRepositoryV2.findCampusList(); } + // 캠퍼스 이름으로 id 찾기 + public int getCampusId(String campusName) { + return campusRepositoryV2.findCampusIdByName(campusName); + } + // 캠퍼스 리스트 반환 메소드 public String makeCampusListCard() { List campusList = getCampusList(); diff --git a/src/main/java/com/example/Jinus/service/v2/cafeteria/DietServiceV2.java b/src/main/java/com/example/Jinus/service/v2/cafeteria/DietServiceV2.java new file mode 100644 index 0000000..c4d9bae --- /dev/null +++ b/src/main/java/com/example/Jinus/service/v2/cafeteria/DietServiceV2.java @@ -0,0 +1,255 @@ +package com.example.Jinus.service.v2.cafeteria; + +import com.example.Jinus.dto.request.DetailParamsItemFieldDto; +import com.example.Jinus.dto.request.HandleRequestDto; +import com.example.Jinus.dto.request.RequestDto; +import com.example.Jinus.dto.response.*; +import com.example.Jinus.repository.v2.cafeteria.CampusRepositoryV2; +import com.example.Jinus.repository.v2.cafeteria.DietRepositoryV2; +import com.example.Jinus.repository.v2.userInfo.UserRepositoryV2; +import com.example.Jinus.utility.JsonUtils; +import com.example.Jinus.utility.SimpleTextResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.servlet.View; + +import java.sql.Date; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +@Service +@RequiredArgsConstructor +public class DietServiceV2 { + private final DietRepositoryV2 dietRepositoryV2; + private final UserRepositoryV2 userRepositoryV2; + private final CampusRepositoryV2 campusRepositoryV2; + private final CampusServiceV2 campusServiceV2; + private final CafeteriaServiceV2 cafeteriaServiceV2; + private final View error; + + // 식단 데이터 찾기 위해 필요한 파라미터 추출 및 초기화 + public String requestHandler(RequestDto requestDto) { + String kakaoId = requestDto.getUserRequest().getUser().getId(); + + // 현재 시간 파악 + LocalTime time = getCurrentTime(); + + // 요청 일반 파라미터 추출 + DetailParamsItemFieldDto campusName = requestDto.getAction().getDetailParams().getSys_campus_name(); + DetailParamsItemFieldDto day = requestDto.getAction().getDetailParams().getSys_date(); + DetailParamsItemFieldDto period = requestDto.getAction().getDetailParams().getSys_time_period(); + // null이면 값 초기화하기 + String campusNameValue = (campusName != null) ? campusName.getValue() : getCampusName(kakaoId); + String dayValue = (day != null) ? day.getValue() : getDay(time); // 오늘, 내일 + String periodValue = (period != null) ? period.getValue() : getPeriodOfDay(time); // 아침, 점심, 저녁 + // 요청 필수 파라미터 추출 + String cafeteriaName = requestDto.getAction().getParams().getSys_cafeteria_name(); + + // 요청 파라미터 객체 생성 + HandleRequestDto parameters = new HandleRequestDto(kakaoId, campusNameValue, dayValue, periodValue, cafeteriaName); + + return makeResponse(parameters); + } + + // response 생성 로직 + public String makeResponse(HandleRequestDto parameters) { + int campusId = campusServiceV2.getCampusId(parameters.getCampusName()); + int cafeteriaId = cafeteriaServiceV2.getCafeteriaId(parameters.getCafeteriaName(), campusId); + // 캠퍼스에 식당이 존재하는 경우 + if (checkIsThereCafeteria(parameters) != -1) { + // 식당 메뉴가 존재하는 경우 + if (checkThereIsDiet(parameters, cafeteriaId) != -1) { + // 메뉴 찾기 + MultiValueMap dietList = getDiets(parameters, cafeteriaId); + StringBuilder diets = processDietList(dietList); + return makeContents(parameters, cafeteriaId, diets); + } else { // 메뉴 존재하지 않는 경우 + StringBuilder diets = new StringBuilder("\n\n").append("메뉴가 존재하지 않습니다."); + return makeContents(parameters, cafeteriaId, diets); + } + } else { // 식당 존재하지 않는 경우 + return errorMsgThereIsNoCafeteria(); + } + } + + + // 캠퍼스에 식당 존재여부 확인 -> cafeteriaId 찾기 + // cafeteriaId가 -1이면 존재하지 않음 + private int checkIsThereCafeteria(HandleRequestDto parameters) { + int campusId = campusServiceV2.getCampusId(parameters.getCampusName()); + return cafeteriaServiceV2.getCafeteriaId(parameters.getCafeteriaName(), campusId); + } + + + // 캠퍼스에 식당이 존재하지 않는 경우 메시지 출력 + private String errorMsgThereIsNoCafeteria() { + return SimpleTextResponse + .simpleTextResponse("식당을 찾지 못했어!\n어떤 캠퍼스에 있는 식당인지 정확히 알려줘!"); + } + + + // 식당 메뉴 존재여부 확인 + private int checkThereIsDiet(HandleRequestDto parameters, int cafeteriaId) { + // 오늘, 내일 문자열로 날짜 설정하기 + Date dietDate = getCurrentDate(parameters.getDay()); + List dietObject = + dietRepositoryV2.findDietList(dietDate, parameters.getPeriod(), cafeteriaId); + return (!dietObject.isEmpty()) ? 1 : -1; + } + + + // 카테고리별 메뉴 리스트 생성하기 + private MultiValueMap getDiets(HandleRequestDto parameters, int cafeteriaId) { + // 오늘, 내일 문자열로 날짜 설정하기 + Date dietDate = getCurrentDate(parameters.getDay()); + List dietObject = + dietRepositoryV2.findDietList(dietDate, parameters.getPeriod(), cafeteriaId); + MultiValueMap dietList = new LinkedMultiValueMap<>(); // 중복 키 허용(값을 리스트로 반환) + + for (Object[] o : dietObject) { + String key = (o[0] != null) ? (String)o[0] // dishCategory + : (o[1] != null) ? (String) o[1] // dishType + : "메뉴"; + + String dishName = (String) o[2]; + dietList.add(key, dishName); + } + return dietList; + } + + + // 카테고리별 메뉴 문자열로 나열하기 + public StringBuilder processDietList(MultiValueMap dietList) { + // 키 추출 + Set keys = new TreeSet<>(dietList.keySet()); // 순서 보장 - 오름차순 + StringBuilder description = new StringBuilder(); + + for (String key : keys) { + description.append("\n[").append(key).append("]").append("\n"); + dietList.get(key).forEach(diet -> description.append(diet).append("\n")); + } + return description; + } + + + // 응답 내용 초기화 + private String makeContents(HandleRequestDto parameters, int cafeteriaId, StringBuilder diets) { + // 식당 img 찾기 + String imgUrl = cafeteriaServiceV2.getImgUrl(cafeteriaId); + + // title 데이터 연결 + StringBuilder title = new StringBuilder("\uD83C\uDF71 ") + .append(parameters.getCafeteriaName()).append("(") + .append(parameters.getCampusName(), 0, 2).append(") 메뉴"); + + // 식단 날짜 + Date dietDate = getCurrentDate(parameters.getDay()); + // 메뉴 연결 + StringBuilder description = new StringBuilder(String.valueOf(dietDate)).append(" ") + .append(parameters.getPeriod()).append(diets); + + return mappingResponse(parameters, imgUrl, title.toString(), description.toString()); + } + + // 응답 객체 매핑 + public String mappingResponse(HandleRequestDto parameters, String imgUrl, String title, String description) { + // imgUrl 객체 생성 + ThumbnailDto thumbnail = new ThumbnailDto(imgUrl); + + // 버튼 리스트 객체 생성 + List buttonList = List.of(new ButtonDto("공유하기", "share")); + + // 아이템 객체 생성 + BasicCardDto basicCardDto = new BasicCardDto(title, description, thumbnail, buttonList); + List outputs = List.of(new ComponentDto(basicCardDto)); + + List quickReplies = mappingQuickReply(parameters); + + TemplateDto templateDto = new TemplateDto(outputs, quickReplies); + ResponseDto responseDto = new ResponseDto("2.0", templateDto); + + return JsonUtils.toJsonResponse(responseDto); + } + + + // quickReply 객체 생성 + private List mappingQuickReply(HandleRequestDto parameters) { + return switch (parameters.getPeriod()) { + case "아침" -> List.of( + new QuickReplyDto("점심", "message", parameters.getCampusName() + " " + parameters.getCafeteriaName() + " " + parameters.getDay() + " 점심 메뉴"), + new QuickReplyDto("저녁", "message", parameters.getCampusName() + " " + parameters.getCafeteriaName() + " " + parameters.getDay() + " 저녁 메뉴") + ); + case "점심" -> List.of( + new QuickReplyDto("아침", "message", parameters.getCampusName() + " " + parameters.getCafeteriaName() + " " + parameters.getDay() + " 아침 메뉴"), + new QuickReplyDto("저녁", "message", parameters.getCampusName() + " " + parameters.getCafeteriaName() + " " + parameters.getDay() + " 저녁 메뉴") + ); + default -> List.of( + new QuickReplyDto("아침", "message", parameters.getCampusName() + " " + parameters.getCafeteriaName() + " " + parameters.getDay() + " 아침 메뉴"), + new QuickReplyDto("점심", "message", parameters.getCampusName() + " " + parameters.getCafeteriaName() + " " + parameters.getDay() + " 점심 메뉴") + ); + }; + } + + + // 일반 파라미터 값 채우기 + // sys_campus_name 파라미터 초기화 + public String getCampusName(String kakaoId) { + // 학과 등록 여부 확인 + int campusId = userRepositoryV2.findCampusIdById(kakaoId).orElse(-1); + // 학과 등록한 경우 campusId가 존재함 + if (campusId != -1) { + return campusRepositoryV2.findCampusNameByCampusId(campusId); + } else { // 학과 등록 안한 경우 + return "가좌캠퍼스"; + } + } + + // sys_date 파라미터 초기화 - 시간 범위에 따라 오늘, 내일 판별 + public String getDay(LocalTime time) { + if (time.isAfter(LocalTime.parse("00:00:00")) && time.isBefore(LocalTime.parse("19:00:00"))) { + return "오늘"; + } else { + return "내일"; + } + } + + // sys_period 파라미터 초기화 - 시간 범위에 따라 아침, 점심, 저녁을 판별 + public static String getPeriodOfDay(LocalTime time) { + if (time.isAfter(LocalTime.parse("19:00:00")) || time.isBefore(LocalTime.parse("09:30:00"))) { + return "아침"; + } else if (!time.isBefore(LocalTime.parse("09:30:00")) && time.isBefore(LocalTime.parse("13:30:00"))) { + return "점심"; + } else { + return "저녁"; + } + } + + // 현재 시간 출력 함수 + public LocalTime getCurrentTime() { + LocalDateTime currentDateTime = LocalDateTime.now(ZoneId.of("Asia/Seoul")); + String[] dateTimeParts = currentDateTime.toString().split("T"); + String[] timeSplit = dateTimeParts[1].split("\\."); + + return LocalTime.parse(timeSplit[0]); + } + + // sysDay 파라미터 값으로 조회할 날짜 찾는 함수 + public Date getCurrentDate(String sysDate) { + // 현재 날짜 + LocalDate today = LocalDate.now(); + LocalDate tomorrow = today.plusDays(1); // 하루 뒤 날짜 계산 + + if (sysDate.equals("오늘")) { + return Date.valueOf(today); + } else { // 내일 + return Date.valueOf(tomorrow); + } + } +} diff --git a/src/main/java/com/example/Jinus/service/v2/notice/NoticeCategoryServiceV2.java b/src/main/java/com/example/Jinus/service/v2/notice/CategoryServiceV2.java similarity index 64% rename from src/main/java/com/example/Jinus/service/v2/notice/NoticeCategoryServiceV2.java rename to src/main/java/com/example/Jinus/service/v2/notice/CategoryServiceV2.java index 5bbe10a..7d10c2f 100644 --- a/src/main/java/com/example/Jinus/service/v2/notice/NoticeCategoryServiceV2.java +++ b/src/main/java/com/example/Jinus/service/v2/notice/CategoryServiceV2.java @@ -1,17 +1,17 @@ package com.example.Jinus.service.v2.notice; import com.example.Jinus.entity.notice.NoticeCategoryEntity; -import com.example.Jinus.repository.v2.notice.NoticeCategoryRepositoryV2; +import com.example.Jinus.repository.v2.notice.CategoryRepositoryV2; import org.springframework.stereotype.Service; import java.util.List; @Service -public class NoticeCategoryServiceV2 { +public class CategoryServiceV2 { - private final NoticeCategoryRepositoryV2 noticeCategoryRepository; + private final CategoryRepositoryV2 noticeCategoryRepository; - public NoticeCategoryServiceV2(NoticeCategoryRepositoryV2 noticeCategoryRepository) { + public CategoryServiceV2(CategoryRepositoryV2 noticeCategoryRepository) { this.noticeCategoryRepository = noticeCategoryRepository; } diff --git a/src/main/java/com/example/Jinus/service/v2/userInfo/UserServiceV2.java b/src/main/java/com/example/Jinus/service/v2/userInfo/UserServiceV2.java index 520bb26..b11aa39 100644 --- a/src/main/java/com/example/Jinus/service/v2/userInfo/UserServiceV2.java +++ b/src/main/java/com/example/Jinus/service/v2/userInfo/UserServiceV2.java @@ -3,6 +3,7 @@ import com.example.Jinus.repository.v2.userInfo.UserRepositoryV2; import org.springframework.stereotype.Service; +import java.util.Map; import java.util.Optional; @Service @@ -23,8 +24,18 @@ public int getUserCampusId(String userId) { // 사용자 학과id 찾기 public int getUserDepartmentId(String userId) { - Optional departmentId = userRepositoryV2.findDepartmentIdById(userId); - // 존재한다면 departmentId, 존재하지 않는다면 -1 반환 - return departmentId.orElse(-1); + int departmentId = userRepositoryV2.findDepartmentIdById(userId).orElse(-1); + + // 부모 게시판 매핑 (해당 학과 ID가 없으면 기본값 그대로 유지) + Map parentDepartmentMap = Map.of( + 52, 51, + 53, 51, + 103, 102, + 104, 102, + 106, 105, + 107, 105 + ); + return parentDepartmentMap.getOrDefault(departmentId, departmentId); } + } diff --git a/src/test/java/com/example/Jinus/repository/cafeteria/CafeteriaRepositoryV2Test.java b/src/test/java/com/example/Jinus/repository/cafeteria/CafeteriaRepositoryV2Test.java index 657ad13..b2664d5 100644 --- a/src/test/java/com/example/Jinus/repository/cafeteria/CafeteriaRepositoryV2Test.java +++ b/src/test/java/com/example/Jinus/repository/cafeteria/CafeteriaRepositoryV2Test.java @@ -14,6 +14,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; @@ -58,7 +59,7 @@ public void checkCafeteriaId() { int userCampusId = 2; // when - int result = cafeteriaRepositoryV2.findCafeteriaId(cafeteriaName, userCampusId); + Optional result = cafeteriaRepositoryV2.findCafeteriaId(cafeteriaName, userCampusId); // then assertThat(result).isEqualTo(1); diff --git a/src/test/java/com/example/Jinus/repository/cafeteria/CampusRepositoryV2Test.java b/src/test/java/com/example/Jinus/repository/cafeteria/CampusRepositoryV2Test.java index 7de1112..5219920 100644 --- a/src/test/java/com/example/Jinus/repository/cafeteria/CampusRepositoryV2Test.java +++ b/src/test/java/com/example/Jinus/repository/cafeteria/CampusRepositoryV2Test.java @@ -42,7 +42,7 @@ public void checkUserCampusName_usingCampusId() { String campusName = "가좌"; // when - String result = campusRepositoryV2.findCampusNameById(campusId); + String result = campusRepositoryV2.findCampusNameByCampusId(campusId); System.out.println("result: " + result); // then diff --git a/src/test/java/com/example/Jinus/repository/cafeteria/DietRepositoryV2Test.java b/src/test/java/com/example/Jinus/repository/cafeteria/DietRepositoryV2Test.java deleted file mode 100644 index 60ae0ea..0000000 --- a/src/test/java/com/example/Jinus/repository/cafeteria/DietRepositoryV2Test.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.example.Jinus.repository.cafeteria; - -import com.example.Jinus.entity.cafeteria.CafeteriaDietEntity; -import com.example.Jinus.repository.v2.cafeteria.DietRepositoryV2; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - - -@ExtendWith(SpringExtension.class) -@DataJpaTest -@ActiveProfiles("test") // application-test.properties 적용 -@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.ANY) // H2 사용 -public class DietRepositoryV2Test { - @Autowired - private DietRepositoryV2 dietRepositoryV2; - - @BeforeEach - void setUp() { - // 날짜 + 시간 + 시간대 포함 (한국 시간: UTC+9) - LocalDateTime dateTime = LocalDateTime.of(25, 2, 11, 0, 0, 0); - CafeteriaDietEntity cafeteriaDietEntity = - new CafeteriaDietEntity(1, dateTime, "월", "점심", "A코스", "주식", "쌀밥", 7); - CafeteriaDietEntity cafeteriaDietEntity2 = - new CafeteriaDietEntity(1, dateTime, "월", "점심", "B코스", "주식", "달걀", 7); - dietRepositoryV2.save(cafeteriaDietEntity); - dietRepositoryV2.save(cafeteriaDietEntity2); - } - - @Test - @DisplayName("조건에 맞는 식단 찾기") - public void checkDiet_meetConditions() { - //given - LocalDateTime dateTime = LocalDateTime.of(25, 2, 11, 0, 0, 0); - String period = "점심"; - int cafeteriaId = 7; - - // 예상 데이터 - List dietList = new ArrayList<>(); - Object[] diet1 = {"A코스", "주식", "쌀밥"}; - Object[] diet2 = {"B코스", "주식", "달걀"}; - dietList.add(diet1); - dietList.add(diet2); - - // when - List result = dietRepositoryV2.findDietList(dateTime, period, cafeteriaId); - - // then - assertThat(result).usingRecursiveComparison().isEqualTo(dietList); - } -} diff --git a/src/test/java/com/example/Jinus/repository/notice/NoticeCategoryRepositoryV2Test.java b/src/test/java/com/example/Jinus/repository/notice/NoticeCategoryRepositoryV2Test.java index 25cd2e3..0ca8929 100644 --- a/src/test/java/com/example/Jinus/repository/notice/NoticeCategoryRepositoryV2Test.java +++ b/src/test/java/com/example/Jinus/repository/notice/NoticeCategoryRepositoryV2Test.java @@ -1,7 +1,7 @@ package com.example.Jinus.repository.notice; import com.example.Jinus.entity.notice.NoticeCategoryEntity; -import com.example.Jinus.repository.v2.notice.NoticeCategoryRepositoryV2; +import com.example.Jinus.repository.v2.notice.CategoryRepositoryV2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -25,7 +25,7 @@ public class NoticeCategoryRepositoryV2Test { @Autowired - private NoticeCategoryRepositoryV2 noticeCategoryRepository; + private CategoryRepositoryV2 noticeCategoryRepository; @BeforeEach void setUp() { diff --git a/src/test/java/com/example/Jinus/service/cafeteria/CampusServiceV2Test.java b/src/test/java/com/example/Jinus/service/cafeteria/CampusServiceV2Test.java index f74248e..16765f7 100644 --- a/src/test/java/com/example/Jinus/service/cafeteria/CampusServiceV2Test.java +++ b/src/test/java/com/example/Jinus/service/cafeteria/CampusServiceV2Test.java @@ -39,7 +39,7 @@ public void checkUserCampusName() { String campusName = "가좌캠퍼스"; // when - Mockito.when(campusRepositoryV2.findCampusNameById(campusId)).thenReturn(campusName); // Mocking + Mockito.when(campusRepositoryV2.findCampusNameByCampusId(campusId)).thenReturn(campusName); // Mocking String result = campusServiceV2.getUserCampusName(campusId); System.out.println("result:" + result); diff --git a/src/test/java/com/example/Jinus/service/notice/NoticeCategoryServiceV2Test.java b/src/test/java/com/example/Jinus/service/notice/NoticeCategoryServiceV2Test.java index c8774b0..e6b1163 100644 --- a/src/test/java/com/example/Jinus/service/notice/NoticeCategoryServiceV2Test.java +++ b/src/test/java/com/example/Jinus/service/notice/NoticeCategoryServiceV2Test.java @@ -1,21 +1,13 @@ package com.example.Jinus.service.notice; -import com.example.Jinus.entity.notice.NoticeCategoryEntity; -import com.example.Jinus.repository.v2.notice.NoticeCategoryRepositoryV2; -import com.example.Jinus.service.v2.notice.NoticeCategoryServiceV2; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; +import com.example.Jinus.repository.v2.notice.CategoryRepositoryV2; +import com.example.Jinus.service.v2.notice.CategoryServiceV2; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; @@ -25,9 +17,9 @@ public class NoticeCategoryServiceV2Test { @Autowired - NoticeCategoryServiceV2 categoryService; + CategoryServiceV2 categoryService; @MockBean - NoticeCategoryRepositoryV2 noticeCategoryRepository; + CategoryRepositoryV2 noticeCategoryRepository; // @Test // @DisplayName("사용자 학과id와 일치하는 카테고리 찾기")