2020
2121import java .time .*;
2222import java .util .*;
23- import java .util .concurrent .ConcurrentHashMap ;
2423import java .util .stream .Collectors ;
2524
2625@ Service
@@ -32,9 +31,7 @@ public class RewardService {
3231 private final FeedbackRepository feedbackRepository ;
3332 private final UserEquippedItemRepository userEquippedItemRepository ;
3433
35- private final static int MAX_REWARD = 19 ; // default item 5개는 카운트에 불포함
36-
37- private final ConcurrentHashMap <String , Object > locks = new ConcurrentHashMap <>();
34+ private final static int MAX_REWARD = 12 ;
3835
3936 /**
4037 * 기록과 동시에 선물 획득
@@ -57,17 +54,20 @@ public void acquireRandomItems(String userKey, LocalDate reqDate) {
5754 LocalDateTime end = start .plusMonths (1 ).minusNanos (1 ); // 23:59:59.999999999
5855
5956 List <UserItem > acquiredItems = userItemRepository .findByUserAndAcquiredAtBetweenOrderByAcquiredAtDesc (user , start , end );
57+ Set <Long > acquiredItemIds = acquiredItems .stream ()
58+ .map (userItem -> userItem .getItem ().getId ())
59+ .collect (Collectors .toSet ());
6060
6161 if (acquiredItems .size () == MAX_REWARD ) {
62- // 인당 월 최대 14개의 선물 생성 가능
63- // throw new IllegalStateException("이번 달 받을 수 있는 선물 개수를 초과하였습니다.");
62+ // 인당 월 최대 12개의 선물 생성 가능
6463 return ;
6564 }
6665
67- // user가 가지고 있지 않은 아이템 중 랜덤으로 획득 (히든 제외)
68- List <RewardItem > allItems = rewardItemRepository .findAllVisibleItems ();
66+ // user가 가지고 있지 않은 아이템 중 랜덤으로 획득 (히든, 디폴트 제외)
67+ List <RewardItem > allItems = rewardItemRepository .findAllVisibleItemsExcludingDefaults ();
68+
6969 List <RewardItem > availableRewards = allItems .stream ()
70- .filter (item -> !acquiredItems .contains (item ))
70+ .filter (item -> !acquiredItemIds .contains (item . getId () ))
7171 .collect (Collectors .toList ());
7272
7373 if (!availableRewards .isEmpty ()) {
@@ -158,26 +158,41 @@ private void acquireHiddenItems(User user, LocalDateTime start, LocalDateTime en
158158 */
159159 @ Transactional (readOnly = true )
160160 public Map <RewardCategory , List <RewardItemResponseDTO >> getAcquiredItem (String userKey ) {
161- User user = userRepository .findByUserKey (userKey ).orElseThrow (() -> new RuntimeException ("USER NOT FOUND" ));
161+ User user = userRepository .findByUserKey (userKey )
162+ .orElseThrow (() -> new RuntimeException ("USER NOT FOUND" ));
162163
163- LocalDateTime start = YearMonth .now (ZoneId .of ("Asia/Seoul" )).atDay (1 ).atStartOfDay ();
164- LocalDateTime end = start .plusMonths (1 ).minusNanos (1 ); // 23:59:59.999999999
164+ ZoneId zoneId = ZoneId .of ("Asia/Seoul" );
165+ LocalDateTime startOfMonth = YearMonth .now (zoneId ).atDay (1 ).atStartOfDay ();
166+ LocalDateTime endOfMonth = startOfMonth .plusMonths (1 ).minusNanos (1 );
167+ LocalDateTime threeDaysAgo = LocalDateTime .now (zoneId ).minusDays (3 );
165168
166- // 유저가 획득한 아이템
167- List <UserItem > acquiredItems = userItemRepository .findByUserAndAcquiredAtBetweenOrderByAcquiredAtDesc (user , start , end );
168- LocalDateTime threeDaysAgo = LocalDateTime .now (ZoneId .of ("Asia/Seoul" )).minusDays (3 );
169+ // 유저가 해당 월 획득한 아이템
170+ List <UserItem > acquiredItems = userItemRepository
171+ .findByUserAndAcquiredAtBetweenOrderByAcquiredAtDesc (user , startOfMonth , endOfMonth );
172+
173+ // 기본 아이템 ID 목록
174+ List <Long > defaultItemIds = List .of (1L , 2L , 3L , 4L );
175+
176+ // 기본 아이템들을 DTO로 변환
177+ List <RewardItemResponseDTO > response = defaultItemIds .stream ()
178+ .map (id -> rewardItemRepository .findById (id )
179+ .map (item -> RewardItemResponseDTO .of (item , false ))
180+ .orElseThrow (() -> new RuntimeException ("Default item ID " + id + " not found" )))
181+ .collect (Collectors .toList ());
169182
170- List <RewardItemResponseDTO > response = acquiredItems .stream ()
183+ response .addAll (
184+ acquiredItems .stream ()
171185 .map (item -> {
172186 // 3일 이내 획득한 Item
173- boolean newAcquired = item .getAcquiredAt ().isAfter (threeDaysAgo ) ? true : false ;
187+ boolean newAcquired = item .getAcquiredAt ().isAfter (threeDaysAgo );
174188 // Hidden 아이템 처음 받았는지 여부
175189 if (item .getItem ().isHidden () && !item .isOpened ()) {
176190 newAcquired = true ;
177191 }
178192
179193 return RewardItemResponseDTO .of (item .getItem (), newAcquired );
180- }).collect (Collectors .toList ());
194+ }).collect (Collectors .toList ())
195+ );
181196
182197 return response .stream ()
183198 .collect (Collectors .groupingBy (RewardItemResponseDTO ::getCategory ));
@@ -214,34 +229,16 @@ public void saveItem(RewardItemSaveRequestDTO request) {
214229 throw new IllegalArgumentException ("유효하지 않은 요청입니다." );
215230 }
216231
217- Optional <UserEquippedItem > equippedItem = userEquippedItemRepository .findTopByUserAndSavedAtInCurrentMonth (user .getId (), year , month );
218-
219232 RewardItem updateBackground = rewardItemRepository .findById (request .getBackgroundId ()).orElseThrow ();
220233 RewardItem updateEffect = rewardItemRepository .findById (request .getEffectId ()).orElseThrow ();
221234 RewardItem updateDecoration = rewardItemRepository .findById (request .getDecorationId ()).orElseThrow ();
222235 RewardItem updateByeoltongCase = rewardItemRepository .findById (request .getByeoltongCaseId ()).orElseThrow ();
223- RewardItem updateBgm = rewardItemRepository .findById (request .getBgmId ()).orElseThrow ();
224-
225- if (equippedItem .isPresent ()) {
226- UserEquippedItem presentEquippedItem = equippedItem .get ();
227- presentEquippedItem .updateEquippedStatus (updateBackground , updateEffect , updateDecoration , updateByeoltongCase , updateBgm , now );
236+ // RewardItem updateBgm = rewardItemRepository.findById(request.getBgmId()).orElseThrow();
228237
229- userEquippedItemRepository .save (presentEquippedItem );
230- }
231- else {
232- UserEquippedItem newEquippedItem = UserEquippedItem .builder ()
233- .user (user )
234- .background (updateBackground )
235- .effect (updateEffect )
236- .decoration (updateDecoration )
237- .byeoltongCase (updateByeoltongCase )
238- .bgm (updateBgm )
239- .savedAt (now )
240- .build ();
241-
242- userEquippedItemRepository .save (newEquippedItem );
243- }
238+ UserEquippedItem presentEquippedItem = userEquippedItemRepository .findTopByUserAndSavedAtInCurrentMonth (user .getId (), year , month ).orElseThrow ();
239+ presentEquippedItem .updateEquippedStatus (updateBackground , updateEffect , updateDecoration , updateByeoltongCase , now );
244240
241+ userEquippedItemRepository .save (presentEquippedItem );
245242 }
246243
247244 /**
@@ -250,68 +247,36 @@ public void saveItem(RewardItemSaveRequestDTO request) {
250247 @ Transactional
251248 public List <RewardItemResponseDTO > getSavedItem (String userKey , int year , int month ) {
252249 List <RewardItemResponseDTO > savedItems = new ArrayList <>();
253- RewardItem background = null , effect = null , decoration = null , byeoltongCase = null , bgm = null ;
254-
255- Object userLock = locks .computeIfAbsent (userKey , k -> new Object ());
256-
257- synchronized (userLock ) {
258- User user = userRepository .findByUserKey (userKey ).orElseThrow (() -> new RuntimeException ("USER NOT FOUND" ));
259-
260- Optional <UserEquippedItem > savedItem = userEquippedItemRepository .findTopByUserAndSavedAtInCurrentMonth (user .getId (), year , month );
261-
262- if (savedItem .isPresent ()) {
263- UserEquippedItem presentSavedItem = savedItem .get ();
264-
265- background = presentSavedItem .getBackground ();
266- effect = presentSavedItem .getEffect ();
267- decoration = presentSavedItem .getDecoration ();
268- byeoltongCase = presentSavedItem .getByeoltongCase ();
269- bgm = presentSavedItem .getBgm ();
270- } else {
271- // 꾸미기 저장 데이터 없으면 default 세팅
272- background = rewardItemRepository .findById (1L ).orElseThrow ();
273- effect = rewardItemRepository .findById (2L ).orElseThrow ();
274- decoration = rewardItemRepository .findById (3L ).orElseThrow ();
275- byeoltongCase = rewardItemRepository .findById (4L ).orElseThrow ();
276- bgm = rewardItemRepository .findById (5L ).orElseThrow ();
277-
278- // default 세팅으로 저장
279- UserEquippedItem newEquippedItem = UserEquippedItem .builder ()
280- .user (user )
281- .background (background )
282- .effect (effect )
283- .decoration (decoration )
284- .byeoltongCase (byeoltongCase )
285- .bgm (bgm )
286- .savedAt (LocalDateTime .now (ZoneId .of ("Asia/Seoul" )))
287- .build ();
288-
289- userEquippedItemRepository .save (newEquippedItem );
290-
291- // default 아이템도 userItem에 추가
292- userItemRepository .save (makeUserItem (user , background ));
293- userItemRepository .save (makeUserItem (user , effect ));
294- userItemRepository .save (makeUserItem (user , decoration ));
295- userItemRepository .save (makeUserItem (user , byeoltongCase ));
296- userItemRepository .save (makeUserItem (user , bgm ));
297- }
298-
299- savedItems .add (RewardItemResponseDTO .of (background ));
300- savedItems .add (RewardItemResponseDTO .of (effect ));
301- savedItems .add (RewardItemResponseDTO .of (decoration ));
302- savedItems .add (RewardItemResponseDTO .of (byeoltongCase ));
303- savedItems .add (RewardItemResponseDTO .of (bgm ));
304-
305- return savedItems ;
250+ RewardItem background = null , effect = null , decoration = null , byeoltongCase = null ;
251+
252+ User user = userRepository .findByUserKey (userKey ).orElseThrow (() -> new RuntimeException ("USER NOT FOUND" ));
253+
254+ Optional <UserEquippedItem > savedItem = userEquippedItemRepository .findTopByUserAndSavedAtInCurrentMonth (user .getId (), year , month );
255+
256+ if (savedItem .isPresent ()) {
257+ UserEquippedItem presentSavedItem = savedItem .get ();
258+
259+ background = presentSavedItem .getBackground ();
260+ effect = presentSavedItem .getEffect ();
261+ decoration = presentSavedItem .getDecoration ();
262+ byeoltongCase = presentSavedItem .getByeoltongCase ();
263+ // bgm = presentSavedItem.getBgm();
264+ } else {
265+ // 꾸미기 저장 데이터 없으면 default
266+ background = rewardItemRepository .findById (1L ).orElseThrow ();
267+ effect = rewardItemRepository .findById (2L ).orElseThrow ();
268+ decoration = rewardItemRepository .findById (3L ).orElseThrow ();
269+ byeoltongCase = rewardItemRepository .findById (4L ).orElseThrow ();
270+ // bgm = rewardItemRepository.findById(5L).orElseThrow();
306271 }
307- }
308272
309- private UserItem makeUserItem (User user , RewardItem item ) {
310- return UserItem .builder ()
311- .user (user )
312- .item (item )
313- .acquiredAt (LocalDateTime .now (ZoneId .of ("Asia/Seoul" )))
314- .isOpened (true ).build ();
273+ savedItems .add (RewardItemResponseDTO .of (background ));
274+ savedItems .add (RewardItemResponseDTO .of (effect ));
275+ savedItems .add (RewardItemResponseDTO .of (decoration ));
276+ savedItems .add (RewardItemResponseDTO .of (byeoltongCase ));
277+ // savedItems.add(RewardItemResponseDTO.of(bgm));
278+
279+ return savedItems ;
315280 }
316281
317282 /**
0 commit comments