From e09983953ac70b47393c997c86b0888ebbb1f39b Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 25 Mar 2025 10:54:54 +0100 Subject: [PATCH] Refactor MaterialController to use MaterialService Replaced direct MaterialRepository usage in MaterialController with MaterialService to encapsulate business logic. Introduced MaterialService, centralizing operations like create, update, and delete while adding normalization for part numbers. Updated MaterialRepository with a new `create` method and adjusted `getById` for clarity. --- .../lcc/controller/MaterialController.java | 26 +++++------ .../lcc/repositories/MaterialRepository.java | 29 +++++++++++- .../avatic/lcc/service/MaterialService.java | 46 +++++++++++++++++++ 3 files changed, 87 insertions(+), 14 deletions(-) create mode 100644 src/main/java/de/avatic/lcc/service/MaterialService.java diff --git a/src/main/java/de/avatic/lcc/controller/MaterialController.java b/src/main/java/de/avatic/lcc/controller/MaterialController.java index 0128d21..becf544 100644 --- a/src/main/java/de/avatic/lcc/controller/MaterialController.java +++ b/src/main/java/de/avatic/lcc/controller/MaterialController.java @@ -2,9 +2,8 @@ package de.avatic.lcc.controller; import de.avatic.lcc.model.materials.Material; import de.avatic.lcc.model.materials.MaterialListEntry; -import de.avatic.lcc.repositories.MaterialRepository; -import de.avatic.lcc.repositories.utils.SearchQueryPagination; import de.avatic.lcc.repositories.utils.SearchQueryResult; +import de.avatic.lcc.service.MaterialService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -16,11 +15,11 @@ import java.util.List; public class MaterialController { - private final MaterialRepository materialRepository; + private final MaterialService materialService; @Autowired - public MaterialController(MaterialRepository materialRepository) { - this.materialRepository = materialRepository; + public MaterialController(MaterialService materialService) { + this.materialService = materialService; } /** @@ -38,7 +37,7 @@ public class MaterialController { @RequestParam(defaultValue = "0") int page, @RequestParam(required = false, defaultValue = "") String filter) { - SearchQueryResult materials = materialRepository.listMaterials(filter, new SearchQueryPagination(page, limit)); + SearchQueryResult materials = materialService.listMaterials(filter, page, limit); return ResponseEntity.ok() .header("X-Total-Count", String.valueOf(materials.getTotalElements())) @@ -56,7 +55,7 @@ public class MaterialController { */ @GetMapping("/{id}") public ResponseEntity getMaterialDetails(@PathVariable Integer id) { - return ResponseEntity.ok(materialRepository.getMaterialDetails(id).orElseThrow(() -> new RuntimeException("Material not found with id " + id))); + return ResponseEntity.ok(materialService.getMaterial(id)); } /** @@ -66,15 +65,11 @@ public class MaterialController { * @param material The updated material details * @return The updated material */ - @PutMapping("/{id}") public ResponseEntity updateMaterial( @PathVariable Integer id, @RequestBody Material material) { - - material.setId(id); - Material updatedMaterial = materialRepository.update(material); - return ResponseEntity.ok(updatedMaterial); + return ResponseEntity.ok(materialService.updateMaterial(id, material)); } /** @@ -86,7 +81,12 @@ public class MaterialController { */ @DeleteMapping("/{id}") public ResponseEntity deleteMaterial(@PathVariable Integer id) { - materialRepository.deleteById(id); + materialService.deleteMaterial(id); return ResponseEntity.noContent().build(); } + + @PostMapping("/") + public ResponseEntity createMaterial(@RequestBody Material material) { + return ResponseEntity.ok(materialService.createMaterial(material)); + } } \ No newline at end of file diff --git a/src/main/java/de/avatic/lcc/repositories/MaterialRepository.java b/src/main/java/de/avatic/lcc/repositories/MaterialRepository.java index 63f2991..33add49 100644 --- a/src/main/java/de/avatic/lcc/repositories/MaterialRepository.java +++ b/src/main/java/de/avatic/lcc/repositories/MaterialRepository.java @@ -10,9 +10,14 @@ import de.avatic.lcc.repositories.utils.SearchQueryResult; import de.avatic.lcc.repositories.utils.UnitConverter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; +import java.sql.PreparedStatement; +import java.sql.Statement; +import java.util.Objects; import java.util.Optional; @Repository @@ -46,7 +51,7 @@ public class MaterialRepository { } @Transactional - public Optional getMaterialDetails(Integer id) { + public Optional getById(Integer id) { String query = "SELECT * FROM material WHERE id = ? AND is_deprecated = FALSE"; Material material = jdbcTemplate.queryForObject(query, (rs, rowNum) -> { @@ -134,4 +139,26 @@ public class MaterialRepository { jdbcTemplate.update(updateQuery, material.getName(), material.getPartNumber(), material.getNormalizedPartNumber(), material.getHsCode(), material.getId()); return material; } + + @Transactional + public Optional create(Material material) { + + KeyHolder keyHolder = new GeneratedKeyHolder(); + + jdbcTemplate.update(connection -> { + PreparedStatement ps = connection + .prepareStatement("INSERT INTO material (name, part_number, normalized_part_number, hs_code) VALUES (?, ?, ?, ?)", + Statement.RETURN_GENERATED_KEYS); + ps.setString(1, material.getName()); // + ps.setString(2, material.getPartNumber()); + ps.setString(3, material.getNormalizedPartNumber()); + ps.setString(4, material.getHsCode()); + return ps; + }, keyHolder); + + + return Optional.ofNullable(!Objects.requireNonNull(keyHolder.getKeys()).isEmpty() ? ((Integer) keyHolder.getKeys().values().iterator().next()) + : null); + + } } diff --git a/src/main/java/de/avatic/lcc/service/MaterialService.java b/src/main/java/de/avatic/lcc/service/MaterialService.java new file mode 100644 index 0000000..d09e37e --- /dev/null +++ b/src/main/java/de/avatic/lcc/service/MaterialService.java @@ -0,0 +1,46 @@ +package de.avatic.lcc.service; + +import de.avatic.lcc.model.materials.Material; +import de.avatic.lcc.model.materials.MaterialListEntry; +import de.avatic.lcc.repositories.MaterialRepository; +import de.avatic.lcc.repositories.utils.SearchQueryPagination; +import de.avatic.lcc.repositories.utils.SearchQueryResult; +import org.springframework.stereotype.Service; + +@Service +public class MaterialService { + + MaterialRepository materialRepository; + + public MaterialService(MaterialRepository materialRepository) { + this.materialRepository = materialRepository; + } + + public Material updateMaterial(Integer id, Material material) { + material.setId(id); + material.setNormalizedPartNumber(normalizePartNumber(material.getPartNumber())); + return materialRepository.update(material); + } + + private String normalizePartNumber(String partNumber) { + if(partNumber.length() > 12) throw new IllegalArgumentException("Part number must be less than 12 characters"); + return "000000000000".concat(partNumber).substring(partNumber.length()); + } + + public Material getMaterial(Integer id) { + return materialRepository.getById(id).orElseThrow(() -> new RuntimeException("Material not found with id " + id)); + } + + public Integer createMaterial(Material material) { + material.setNormalizedPartNumber(normalizePartNumber(material.getPartNumber())); + return materialRepository.create(material).orElseThrow(() -> new RuntimeException("Unable to create Material " + material)); + } + + public SearchQueryResult listMaterials(String filter, int page, int limit) { + return materialRepository.listMaterials(filter, new SearchQueryPagination(page, limit)); + } + + public void deleteMaterial(Integer id) { + materialRepository.deleteById(id); + } +}