diff --git a/src/main/java/com/back/global/init/DevInitData.java b/src/main/java/com/back/global/init/DevInitData.java index dd4729a0..6101f7e7 100644 --- a/src/main/java/com/back/global/init/DevInitData.java +++ b/src/main/java/com/back/global/init/DevInitData.java @@ -1,13 +1,10 @@ package com.back.global.init; +import com.back.domain.cocktail.entity.Cocktail; +import com.back.domain.cocktail.repository.CocktailRepository; import com.back.domain.notification.entity.Notification; import com.back.domain.notification.enums.NotificationType; import com.back.domain.notification.repository.NotificationRepository; -import com.back.domain.cocktail.entity.Cocktail; -import com.back.domain.cocktail.enums.AlcoholBaseType; -import com.back.domain.cocktail.enums.AlcoholStrength; -import com.back.domain.cocktail.enums.CocktailType; -import com.back.domain.cocktail.repository.CocktailRepository; import com.back.domain.post.category.entity.Category; import com.back.domain.post.category.repository.CategoryRepository; import com.back.domain.post.comment.entity.Comment; @@ -19,7 +16,6 @@ import com.back.domain.post.post.repository.PostRepository; import com.back.domain.user.entity.User; import com.back.domain.user.repository.UserRepository; -import org.springframework.transaction.annotation.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationRunner; @@ -27,6 +23,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Profile; +import org.springframework.transaction.annotation.Transactional; @Configuration @Profile("dev") @@ -50,67 +47,14 @@ public class DevInitData { @Bean ApplicationRunner devInitDataApplicationRunner() { return args -> { - self.cocktailInit(); self.userInit(); - self.boardInit(); + // myBar는 사용자 활성 상태 기준으로 초기화가 필요하므로 boardInit(soft delete)보다 먼저 실행 self.myBarInit(); + self.boardInit(); self.notificationInit(); }; } - @Transactional - public void cocktailInit() { - if (cocktailRepository.count() > 0) return; - - // 1) 하이볼 - cocktailRepository.save(Cocktail.builder() - .cocktailName("Highball") - .cocktailNameKo("하이볼") - .alcoholStrength(AlcoholStrength.LIGHT) - .cocktailType(CocktailType.LONG) - .alcoholBaseType(AlcoholBaseType.WHISKY) - .ingredient("위스키, 탄산수, 얼음, 레몬피") - .recipe("잔에 얼음 → 위스키 → 탄산수 → 가볍게 스터") - .cocktailImgUrl("/img/cocktail/1.jpg") - .build()); - - // 2) 진토닉 - cocktailRepository.save(Cocktail.builder() - .cocktailName("Gin and Tonic") - .cocktailNameKo("진토닉") - .alcoholStrength(AlcoholStrength.WEAK) - .cocktailType(CocktailType.LONG) - .alcoholBaseType(AlcoholBaseType.GIN) - .ingredient("진, 토닉워터, 얼음, 라임") - .recipe("잔에 얼음 → 진 → 토닉워터 → 라임") - .cocktailImgUrl("/img/cocktail/2.jpg") - .build()); - - // 3) 올드패션드 - cocktailRepository.save(Cocktail.builder() - .cocktailName("Old Fashioned") - .cocktailNameKo("올드패션드") - .alcoholStrength(AlcoholStrength.STRONG) - .cocktailType(CocktailType.SHORT) - .alcoholBaseType(AlcoholBaseType.WHISKY) - .ingredient("버번 위스키, 설탕/시럽, 앙고스투라 비터스, 오렌지 필") - .recipe("시럽+비터스 → 위스키 → 얼음 → 스터 → 오렌지 필") - .cocktailImgUrl("/img/cocktail/3.jpg") - .build()); - - // 4) 모히또 - cocktailRepository.save(Cocktail.builder() - .cocktailName("Mojito") - .cocktailNameKo("모히또") - .alcoholStrength(AlcoholStrength.LIGHT) - .cocktailType(CocktailType.LONG) - .alcoholBaseType(AlcoholBaseType.RUM) - .ingredient("라임, 민트, 설탕/시럽, 화이트 럼, 탄산수, 얼음") - .recipe("라임+민트+시럽 머들 → 럼 → 얼음 → 탄산수") - .cocktailImgUrl("/img/cocktail/4.jpg") - .build()); - } - @Transactional public void userInit() { userRepository.findByNickname("사용자A").orElseGet(() -> @@ -270,39 +214,72 @@ public void notificationInit() { public void myBarInit() { if (myBarRepository.count() > 0) return; - User userA = userRepository.findByNickname("사용자A").orElse(null); - User userB = userRepository.findByNickname("사용자B").orElse(null); - User userC = userRepository.findByNickname("사용자C").orElse(null); - - if (userA == null || userC == null) return; + User userA = userRepository.findByNickname("사용자A").orElseThrow(); + User userB = userRepository.findByNickname("사용자B").orElseThrow(); + User userC = userRepository.findByNickname("사용자C").orElseThrow(); - // 칵테일 참조 준비 - var cocktails = cocktailRepository.findAll(); - Cocktail c1 = cocktails.stream().filter(c -> "하이볼".equals(c.getCocktailNameKo())).findFirst().orElse(null); - Cocktail c2 = cocktails.stream().filter(c -> "진토닉".equals(c.getCocktailNameKo())).findFirst().orElse(null); - Cocktail c3 = cocktails.stream().filter(c -> "올드패션드".equals(c.getCocktailNameKo())).findFirst().orElse(null); - Cocktail c4 = cocktails.stream().filter(c -> "모히또".equals(c.getCocktailNameKo())).findFirst().orElse(null); + // 칵테일 참조 준비: 이름 우선 매칭, 부족하면 ID 오름차순으로 보충 + var all = cocktailRepository.findAll(); + if (all.isEmpty()) return; // 칵테일 데이터 없으면 스킵 + + java.util.List prefer = java.util.List.of("하이볼", "진토닉", "올드패션드", "모히또"); + java.util.List selected = new java.util.ArrayList<>(); + + // 선호 이름 매칭 + for (String nameKo : prefer) { + all.stream() + .filter(c -> nameKo.equals(c.getCocktailNameKo())) + .findFirst() + .ifPresent(c -> { + if (selected.stream().noneMatch(s -> java.util.Objects.equals(s.getId(), c.getId()))) { + selected.add(c); + } + }); + } - // 방어: 칵테일 누락 시 스킵 - if (c1 == null || c2 == null || c3 == null || c4 == null) return; + // 부족분 보충: ID 오름차순으로 정렬 후 채우기 + all.stream() + .sorted(java.util.Comparator.comparingLong(c -> c.getId() == null ? Long.MAX_VALUE : c.getId())) + .forEach(c -> { + if (selected.size() < 4 && selected.stream().noneMatch(s -> java.util.Objects.equals(s.getId(), c.getId()))) { + selected.add(c); + } + }); + + // 실제 사용에 필요한 인덱스가 없으면 해당 동작을 스킵 + Cocktail c1 = selected.size() > 0 ? selected.get(0) : null; + Cocktail c2 = selected.size() > 1 ? selected.get(1) : null; + Cocktail c3 = selected.size() > 2 ? selected.get(2) : null; + Cocktail c4 = selected.size() > 3 ? selected.get(3) : null; // A: c1(now-2d), c2(now-1d) - myBarService.keep(userA.getId(), c1.getId()); - myBarService.keep(userA.getId(), c2.getId()); - myBarRepository.findByUser_IdAndCocktail_Id(userA.getId(), c1.getId()).ifPresent(m -> m.setKeptAt(java.time.LocalDateTime.now().minusDays(2))); - myBarRepository.findByUser_IdAndCocktail_Id(userA.getId(), c2.getId()).ifPresent(m -> m.setKeptAt(java.time.LocalDateTime.now().minusDays(1))); + if (c1 != null) { + myBarService.keep(userA.getId(), c1.getId()); + myBarRepository.findByUser_IdAndCocktail_Id(userA.getId(), c1.getId()).ifPresent(m -> m.setKeptAt(java.time.LocalDateTime.now().minusDays(2))); + } + if (c2 != null) { + myBarService.keep(userA.getId(), c2.getId()); + myBarRepository.findByUser_IdAndCocktail_Id(userA.getId(), c2.getId()).ifPresent(m -> m.setKeptAt(java.time.LocalDateTime.now().minusDays(1))); + } - if (userB != null && !userB.isDeleted()) { + // B: c3 keep 후 unkeep -> DELETED + if (c3 != null) { myBarService.keep(userB.getId(), c3.getId()); myBarService.unkeep(userB.getId(), c3.getId()); } // C: c2(now-3d), c3(now-2d), c4(now-1h) - myBarService.keep(userC.getId(), c2.getId()); - myBarService.keep(userC.getId(), c3.getId()); - myBarService.keep(userC.getId(), c4.getId()); - myBarRepository.findByUser_IdAndCocktail_Id(userC.getId(), c2.getId()).ifPresent(m -> m.setKeptAt(java.time.LocalDateTime.now().minusDays(3))); - myBarRepository.findByUser_IdAndCocktail_Id(userC.getId(), c3.getId()).ifPresent(m -> m.setKeptAt(java.time.LocalDateTime.now().minusDays(2))); - myBarRepository.findByUser_IdAndCocktail_Id(userC.getId(), c4.getId()).ifPresent(m -> m.setKeptAt(java.time.LocalDateTime.now().minusHours(1))); + if (c2 != null) { + myBarService.keep(userC.getId(), c2.getId()); + myBarRepository.findByUser_IdAndCocktail_Id(userC.getId(), c2.getId()).ifPresent(m -> m.setKeptAt(java.time.LocalDateTime.now().minusDays(3))); + } + if (c3 != null) { + myBarService.keep(userC.getId(), c3.getId()); + myBarRepository.findByUser_IdAndCocktail_Id(userC.getId(), c3.getId()).ifPresent(m -> m.setKeptAt(java.time.LocalDateTime.now().minusDays(2))); + } + if (c4 != null) { + myBarService.keep(userC.getId(), c4.getId()); + myBarRepository.findByUser_IdAndCocktail_Id(userC.getId(), c4.getId()).ifPresent(m -> m.setKeptAt(java.time.LocalDateTime.now().minusHours(1))); + } } } diff --git a/src/main/java/com/back/global/security/SecurityConfig.java b/src/main/java/com/back/global/security/SecurityConfig.java index 8144e8df..b5356587 100644 --- a/src/main/java/com/back/global/security/SecurityConfig.java +++ b/src/main/java/com/back/global/security/SecurityConfig.java @@ -14,7 +14,6 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import java.util.Arrays; -import static org.springframework.http.HttpMethod.DELETE; @Configuration @EnableWebSecurity @@ -52,7 +51,6 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { ) // OAuth 인증시 필요할때만 세션 사용 .authorizeHttpRequests(auth -> auth - .requestMatchers(DELETE, "/me/account").authenticated() // 개발 편의성을 위해 모든 요청 허용 .anyRequest().permitAll() @@ -125,4 +123,4 @@ public CorsConfigurationSource corsConfigurationSource() { source.registerCorsConfiguration("/**", configuration); return source; } -} +} \ No newline at end of file diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 14ffcbf4..d29d56b7 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -20,7 +20,7 @@ spring: jpa: database-platform: org.hibernate.dialect.H2Dialect hibernate: - ddl-auto: create-drop # 개발용: 시작할 때 테이블 생성, 종료할 때 삭제 / db_dev 에러 방지용으로 upsdate->create-drop 변경 + ddl-auto: update # 실행전 db_dev 파일 삭제 필요 properties: hibernate: format_sql: true