jav spring boot mastery

🎯 Objective

Separate internal models from external API contracts using DTOs (Data Transfer Objects) and simplify object mapping using ModelMapper.

πŸ“¦ Step 1: Create a ProductDTO Class

public class ProductDTO {
    private Long id;

    @NotBlank(message = "Product name is required")
    private String name;

    @NotNull(message = "Price is required")
    @Min(value = 0, message = "Price must be positive")
    private Double price;

    // Getters and Setters
}

πŸ” Explanation

  • This class mirrors the Product entity, but is designed for API interaction.
  • Keeps entity class decoupled from client-facing code.

πŸ”§ Step 2: Add ModelMapper Bean

@Configuration
public class AppConfig {
    @Bean
    public ModelMapper modelMapper() {
        return new ModelMapper();
    }
}

πŸ” Explanation

  • Configures ModelMapper as a Spring bean so it can be autowired anywhere.

πŸ” Step 3: Update Service to Use DTOs

@Service
public class ProductService {

    @Autowired
    private ProductRepository productRepository;

    @Autowired
    private ModelMapper modelMapper;

    public List<ProductDTO> getAll() {
        return productRepository.findAll().stream()
                .map(product -> modelMapper.map(product, ProductDTO.class))
                .collect(Collectors.toList());
    }

    public ProductDTO getById(Long id) {
        Product product = productRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("Product not found: " + id));
        return modelMapper.map(product, ProductDTO.class);
    }

    public ProductDTO save(ProductDTO dto) {
        Product product = modelMapper.map(dto, Product.class);
        Product saved = productRepository.save(product);
        return modelMapper.map(saved, ProductDTO.class);
    }

    public void delete(Long id) {
        productRepository.deleteById(id);
    }
}

πŸ” Explanation

  • Converts between entity and DTO using ModelMapper.map().
  • Maintains a clear separation between internal model and external contract.

🌐 Step 4: Update Controller

@RestController
@RequestMapping("/api/products")
public class ProductController {

    private final ProductService productService;

    public ProductController(ProductService productService) {
        this.productService = productService;
    }

    @GetMapping
    public List<ProductDTO> getAllProducts() {
        return productService.getAll();
    }

    @GetMapping("/{id}")
    public ResponseEntity<ProductDTO> getProductById(@PathVariable Long id) {
        return ResponseEntity.ok(productService.getById(id));
    }

    @PostMapping
    public ResponseEntity<ProductDTO> createProduct(@Valid @RequestBody ProductDTO productDTO) {
        return new ResponseEntity<>(productService.save(productDTO), HttpStatus.CREATED);
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteProduct(@PathVariable Long id) {
        productService.delete(id);
        return ResponseEntity.noContent().build();
    }
}

πŸ” Explanation

  • Uses ProductDTO instead of entity in controller layer.
  • Keeps HTTP interface separate from database logic.

πŸ› οΈ Benefits of Using DTOs

  • πŸ”’ Hides sensitive fields (like passwords or internal IDs).
  • πŸ’‘ Allows custom formats for clients.
  • 🧱 Clean separation of concerns.
  • πŸ” Prevents accidental data overwrites from external input.

➑️ Next Up: Part 6 – Entity Relationships and JPA Associations

Similar Posts