Spring Boot Best Practices

Chapter 2 · Practice 3 of 4

Keep controllers thin and business logic in services

From Structure and dependency injection

Why it matters

A controller's job is HTTP: read the request, validate it, call a service and map the result to a response. When business rules live in controllers, they cannot be reused by a scheduled job or a message listener, and tests need a web layer to reach them.

  • Controllers: map requests and responses, run validation, set status codes.
  • Services: business rules and transaction boundaries.
  • Repositories: data access only.

A quick test: could you call this logic from a command-line runner without faking an HTTP request? If not, it belongs in a service.

Do

  • Put @Transactional on service methods, not controllers
  • Map entities to response DTOs in one place
  • Keep controller methods to a few lines