Careeroza
Real World Example
ShopEase Product Catalogue
The catalogue service behind a Myntra- or Flipkart-style product listing: search, category pages, new arrivals, and a low-stock report for the operations team.
public interface ProductRepository extends JpaRepository<Product, Long> {
Optional<Product> findBySku(String sku);
boolean existsBySku(String sku);
List<Product> findByCategoryAndStatusOrderByPriceAsc(String category, ProductStatus status);
List<Product> findByNameContainingIgnoreCaseAndStatus(String text, ProductStatus status);
List<Product> findTop8ByStatusOrderByCreatedAtDesc(ProductStatus status);
List<Product> findByStockLessThanEqualAndStatus(int threshold, ProductStatus status);
}
public record ProductResponse(Long id, String name, BigDecimal price, boolean inStock) {
static ProductResponse from(Product p) {
return new ProductResponse(p.getId(), p.getName(), p.getPrice(), p.isInStock());
}
}
@Service
@Transactional(readOnly = true)
public class CatalogService {
private final ProductRepository repo;
public CatalogService(ProductRepository repo) { this.repo = repo; }
public List<ProductResponse> category(String category) {
return repo.findByCategoryAndStatusOrderByPriceAsc(category, ProductStatus.ACTIVE)
.stream().map(ProductResponse::from).toList();
}
public List<ProductResponse> search(String q) {
return repo.findByNameContainingIgnoreCaseAndStatus(q.trim(), ProductStatus.ACTIVE)
.stream().map(ProductResponse::from).toList();
}
public List<ProductResponse> newArrivals() {
return repo.findTop8ByStatusOrderByCreatedAtDesc(ProductStatus.ACTIVE)
.stream().map(ProductResponse::from).toList();
}
@Transactional
public ProductResponse create(CreateProductRequest req) {
if (repo.existsBySku(req.sku())) throw new DuplicateSkuException(req.sku());
Product saved = repo.save(new Product(req.sku(), req.name(), req.price(), req.stock(), req.category()));
return ProductResponse.from(saved);
}
}Request and SQL
Category page
Opening the Electronics category page:
curl localhost:8080/api/catalog/categories/ElectronicsExample output
Hibernate: select p1_0.id,p1_0.category,p1_0.created_at,p1_0.description,p1_0.name,p1_0.price,p1_0.sku,p1_0.status,p1_0.stock from products p1_0 where p1_0.category=? and p1_0.status=? order by p1_0.price
HTTP/1.1 200 OK
[{"id":7,"name":"USB-C Cable","price":199.00,"inStock":true},
{"id":57,"name":"Boat Airdopes 141","price":1099.00,"inStock":true},
{"id":42,"name":"Boat Rockerz 450","price":1499.00,"inStock":false}]- DTOs in the response: entities stay inside the service; the API returns records.
readOnly = trueon the class: Hibernate skips dirty checking for reads. Onlycreateis a read-write transaction.- No SQL written by hand: every query is derived from a method name and logged for review.
Tip: Next steps (medium level): turn category into a @ManyToOne Category, add pagination with Pageable for long category pages, and write complex filters with @Query and Specifications.