Anatomy of a Java Web App

    Atul Kabra4 min readUpdated

    A modern Java web application is organised into clear layers and a conventional directory layout so that each piece of code has an obvious home. At a high level, a typical Spring Boot project separates controllers (handle web requests), services (business logic), repositories (database access), and models/entities (the data), all wired together by the Spring container. Understanding this anatomy means you can open any Java project and immediately know where to look — and where your own code belongs.

    The standard directory layout

    Java projects built with Maven or Gradle follow a near-universal structure:

    my-app/
    ├── pom.xml                       # build file: dependencies, plugins, build config
    ├── src/
    │   ├── main/
    │   │   ├── java/                 # all application source code
    │   │   │   └── in/infoplanet/app/
    │   │   │       ├── Application.java        # the main entry point
    │   │   │       ├── controller/             # web layer (REST/MVC controllers)
    │   │   │       ├── service/                # business logic
    │   │   │       ├── repository/             # data access
    │   │   │       └── model/                  # entities / domain objects
    │   │   └── resources/
    │   │       ├── application.properties      # configuration
    │   │       ├── static/                     # CSS, JS, images
    │   │       └── templates/                  # server-rendered views (if used)
    │   └── test/
    │       └── java/                 # tests mirror the main package layout
    

    The split between main and test, and between java and resources, is a convention every Java tool understands. Configuration and assets live in resources; code lives in java.

    The layered architecture

    Inside the code, responsibilities are layered. A request flows downward and a response flows back up:

    1. Controller layer — receives the HTTP request, validates input, and delegates. It does not contain business logic.
    2. Service layer — the brain: business rules, calculations, coordinating multiple repositories, managing transactions.
    3. Repository layer — talks to the database (often via Spring Data JPA), returning entities.
    4. Model layer — the entities and value objects that represent your data.

    Each layer depends only on the one below it. Controllers call services; services call repositories. Skipping a layer (a controller hitting the database directly) is what creates tangled, untestable code.

    How a request flows

    Here is a thin controller showing how the layers connect — notice it does almost nothing except delegate:

    import org.springframework.web.bind.annotation.*;
    
    @RestController
    @RequestMapping("/api/students")
    public class StudentController {
    
        private final StudentService service; // depends on the service layer only
    
        public StudentController(StudentService service) {
            this.service = service;
        }
    
        // 1. Controller receives the request
        @GetMapping("/{id}")
        public Student getStudent(@PathVariable long id) {
            // 2. Delegates to the service (which calls the repository, which hits the DB)
            return service.findById(id);
            // 3. The returned object is serialized to JSON and sent back
        }
    }
    

    The controller never touches SQL or the database — it asks the service, which orchestrates everything below. This is the layered architecture in action.

    Want to learn this properly?

    Join the waitlist for our courses — beginner-friendly, project-first classes in Jalgaon.

    Browse courses

    Package by layer vs package by feature

    Two common ways to organise packages:

    • By layercontroller, service, repository packages (shown above). Simple and familiar for smaller apps.
    • By feature — packages like students, courses, fees, each containing its own controller, service, and repository. This scales better in large apps because related code stays together.

    Either is valid; consistency within a project matters more than the choice.

    Where configuration lives

    Application settings (port, database URL, feature flags) live in application.properties or application.yml under resources. Build configuration (dependencies, plugins) lives in pom.xml (Maven) or build.gradle (Gradle). Keeping these separate from code means you can change behaviour per environment without recompiling.

    Common mistakes

    • Letting controllers contain business logic. Keep them thin; the service layer is where logic belongs, so it stays testable and reusable.
    • Calling repositories directly from controllers. This skips the service layer and couples web concerns to data access.
    • Scattering classes outside the scanned package. Spring scans from the main class's package downward; misplaced classes will not be picked up.
    • Putting config values in code. Hard-coding the database URL or port makes the app un-deployable across environments. Use application.properties.
    • Inconsistent package strategy. Mixing package-by-layer and package-by-feature randomly makes the project hard to navigate.

    FAQ

    Is this layout the same for non-Spring apps? The Maven/Gradle directory structure is universal across Java. The layered packages are a best practice that most frameworks encourage.

    Where do tests go? Under src/test/java, mirroring the main package structure so each class's tests are easy to find.

    Keep learning

    This structure organises the MVC pattern and is generated for you by Spring Boot. When you are ready, learn how to deploy a Java web app. More in the Advanced Java hub.


    Want to build well-structured Java projects from scratch? Join the waitlist for the Advanced Java course at Infoplanet, Jalgaon.

    Want to learn this properly?

    Join the waitlist for our courses — beginner-friendly, project-first classes in Jalgaon.

    Browse courses
    Atul Kabra

    Founder, Infoplanet

    Atul Kabra founded Infoplanet in 2001 and has spent over two decades teaching programming — C, C++, Java, databases and more — to students across Maharashtra.

    Related guides