From 7fafa0d90356045a4b27fb477290f384d790df6b Mon Sep 17 00:00:00 2001 From: siujamo Date: Mon, 1 Jun 2026 15:30:14 +0800 Subject: [PATCH] refactor: extract ModificationManager for modification creation Move create/batchCreate transactional logic from ModificationService into a dedicated ModificationManager. Both ModificationService and WebhookService delegate to the manager, respecting the Controller -> Service -> Manager layering rule. --- .../manager/ModificationManager.java | 115 ++++++++++++++++++ .../service/ModificationService.java | 47 +------ 2 files changed, 121 insertions(+), 41 deletions(-) create mode 100644 src/main/java/com/onixbyte/deltaforceguide/manager/ModificationManager.java diff --git a/src/main/java/com/onixbyte/deltaforceguide/manager/ModificationManager.java b/src/main/java/com/onixbyte/deltaforceguide/manager/ModificationManager.java new file mode 100644 index 0000000..eb0007a --- /dev/null +++ b/src/main/java/com/onixbyte/deltaforceguide/manager/ModificationManager.java @@ -0,0 +1,115 @@ +package com.onixbyte.deltaforceguide.manager; + +import com.onixbyte.deltaforceguide.domain.entity.Accessory; +import com.onixbyte.deltaforceguide.domain.entity.Firearm; +import com.onixbyte.deltaforceguide.domain.entity.Modification; +import com.onixbyte.deltaforceguide.domain.entity.Tuning; +import com.onixbyte.deltaforceguide.domain.dto.AccessoryRequest; +import com.onixbyte.deltaforceguide.domain.dto.ModificationRequest; +import com.onixbyte.deltaforceguide.domain.dto.ModificationResponse; +import com.onixbyte.deltaforceguide.domain.dto.TuningRequest; +import com.onixbyte.deltaforceguide.repository.FirearmRepository; +import com.onixbyte.deltaforceguide.repository.ModificationRepository; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.server.ResponseStatusException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; + +@Component +public class ModificationManager { + + private final ModificationRepository modificationRepository; + private final FirearmRepository firearmRepository; + + public ModificationManager( + ModificationRepository modificationRepository, + FirearmRepository firearmRepository + ) { + this.modificationRepository = modificationRepository; + this.firearmRepository = firearmRepository; + } + + @Transactional + public ModificationResponse create(ModificationRequest request) { + var firearm = firearmRepository.findById(request.firearmId()) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, + "Firearm not found: " + request.firearmId())); + var modification = toEntity(request, firearm); + return ModificationResponse.from(modificationRepository.save(modification)); + } + + @Transactional + public List batchCreate(List requests) { + var firearmIds = requests.stream() + .map(ModificationRequest::firearmId) + .collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new)); + + Map firearmMap = new HashMap<>(); + firearmRepository.findAllById(firearmIds) + .forEach(firearm -> firearmMap.put(firearm.getId(), firearm)); + + if (firearmMap.size() != firearmIds.size()) { + var missing = firearmIds.stream() + .filter((id) -> !firearmMap.containsKey(id)) + .toList(); + throw new ResponseStatusException(HttpStatus.NOT_FOUND, + "Firearm not found: " + missing); + } + + var modifications = requests.stream() + .map(req -> toEntity(req, firearmMap.get(req.firearmId()))) + .toList(); + return modificationRepository.saveAll(modifications) + .stream() + .map(ModificationResponse::from) + .toList(); + } + + private Modification toEntity(ModificationRequest request, Firearm firearm) { + return Modification.builder() + .firearm(firearm) + .name(request.name()) + .code(request.code()) + .tags(request.tags()) + .accessories(toAccessories(request.accessories())) + .note(request.note()) + .author(request.author()) + .videoUrl(request.videoUrl()) + .build(); + } + + private List toAccessories(List requests) { + if (requests == null) { + return new ArrayList<>(); + } + return requests.stream().map(this::toAccessory).toList(); + } + + private Accessory toAccessory(AccessoryRequest request) { + var accessory = new Accessory(); + accessory.setSlotName(request.slotName()); + accessory.setAccessoryName(request.accessoryName()); + accessory.setTunings(toTunings(request.tunings())); + return accessory; + } + + private List toTunings(List requests) { + if (requests == null) { + return new ArrayList<>(); + } + return requests.stream().map(this::toTuning).toList(); + } + + private Tuning toTuning(TuningRequest request) { + var tuning = new Tuning(); + tuning.setTuningName(request.tuningName()); + tuning.setTuningValue(request.tuningValue()); + return tuning; + } +} diff --git a/src/main/java/com/onixbyte/deltaforceguide/service/ModificationService.java b/src/main/java/com/onixbyte/deltaforceguide/service/ModificationService.java index 39e5ec0..a5129af 100644 --- a/src/main/java/com/onixbyte/deltaforceguide/service/ModificationService.java +++ b/src/main/java/com/onixbyte/deltaforceguide/service/ModificationService.java @@ -9,6 +9,7 @@ import com.onixbyte.deltaforceguide.domain.entity.Accessory; import com.onixbyte.deltaforceguide.domain.entity.Firearm; import com.onixbyte.deltaforceguide.domain.entity.Modification; import com.onixbyte.deltaforceguide.domain.entity.Tuning; +import com.onixbyte.deltaforceguide.manager.ModificationManager; import com.onixbyte.deltaforceguide.repository.FirearmRepository; import com.onixbyte.deltaforceguide.repository.ModificationRepository; import com.fasterxml.jackson.core.JsonProcessingException; @@ -21,10 +22,8 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.server.ResponseStatusException; import java.util.ArrayList; -import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; -import java.util.Map; import java.util.Set; @Service @@ -32,15 +31,18 @@ public class ModificationService { private final ModificationRepository modificationRepository; private final FirearmRepository firearmRepository; + private final ModificationManager modificationManager; private final ObjectMapper objectMapper; public ModificationService( ModificationRepository modificationRepository, FirearmRepository firearmRepository, + ModificationManager modificationManager, ObjectMapper objectMapper ) { this.modificationRepository = modificationRepository; this.firearmRepository = firearmRepository; + this.modificationManager = modificationManager; this.objectMapper = objectMapper; } @@ -79,36 +81,12 @@ public class ModificationService { @Transactional public ModificationResponse create(ModificationRequest request) { - Firearm firearm = firearmRepository.findById(request.firearmId()) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Firearm not found: " + request.firearmId())); - - Modification modification = toEntity(request, firearm); - return ModificationResponse.from(modificationRepository.save(modification)); + return modificationManager.create(request); } @Transactional public List batchCreate(List requests) { - Set firearmIds = requests.stream() - .map(ModificationRequest::firearmId) - .collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new)); - - Map firearmMap = new HashMap<>(); - firearmRepository.findAllById(firearmIds).forEach(firearm -> firearmMap.put(firearm.getId(), firearm)); - - if (firearmMap.size() != firearmIds.size()) { - List missingFirearmIds = firearmIds.stream() - .filter(id -> !firearmMap.containsKey(id)) - .toList(); - throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Firearm not found: " + missingFirearmIds); - } - - List modifications = requests.stream() - .map(request -> toEntity(request, firearmMap.get(request.firearmId()))) - .toList(); - return modificationRepository.saveAll(modifications) - .stream() - .map(ModificationResponse::from) - .toList(); + return modificationManager.batchCreate(requests); } @Transactional @@ -155,19 +133,6 @@ public class ModificationService { modificationRepository.deleteAllInBatch(modifications); } - private Modification toEntity(ModificationRequest request, Firearm firearm) { - return Modification.builder() - .firearm(firearm) - .name(request.name()) - .code(request.code()) - .tags(safeTags(request.tags())) - .accessories(toAccessories(request.accessories())) - .note(request.note()) - .author(request.author()) - .videoUrl(request.videoUrl()) - .build(); - } - private List safeTags(List tags) { return tags == null ? new ArrayList<>() : tags; }