How do I handle HTTP requests with Spring controllers?

In Spring MVC or Spring Boot, you handle HTTP requests by creating controller classes. A controller receives a request, runs application logic, and returns either:

  • a view name for server-rendered pages, or
  • data such as JSON for REST APIs.

1. Basic Spring MVC Controller

Use @Controller when you want to return views such as JSP, Thymeleaf, or other templates.

package com.example.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {

    @GetMapping("/")
    public String home(Model model) {
        model.addAttribute("message", "Welcome to Spring MVC!");
        return "home";
    }
}

In this example:

  • @Controller marks the class as a Spring MVC controller.
  • @GetMapping("/") handles HTTP GET /.
  • Model passes data to the view.
  • "home" is the logical view name.

If you use Thymeleaf, Spring would typically look for:

src/main/resources/templates/home.html

2. REST Controller Returning JSON

Use @RestController when you want to build REST APIs.

package com.example.web;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingRestController {

    @GetMapping("/api/greeting")
    public Greeting greeting() {
        return new Greeting("Hello from Spring!");
    }

    public record Greeting(String message) {
    }
}

Calling:

GET /api/greeting

returns JSON like:

{
  "message": "Hello from Spring!"
}

@RestController is a shortcut for:

@Controller
@ResponseBody

So every method returns the response body directly instead of a view name.


3. Handling Different HTTP Methods

Spring provides convenient annotations for common HTTP methods.

package com.example.web;

import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @GetMapping("/users")
    public String getUsers() {
        return "Get all users";
    }

    @PostMapping("/users")
    public String createUser() {
        return "Create a new user";
    }

    @PutMapping("/users/1")
    public String replaceUser() {
        return "Replace user";
    }

    @PatchMapping("/users/1")
    public String updateUser() {
        return "Update part of user";
    }

    @DeleteMapping("/users/1")
    public String deleteUser() {
        return "Delete user";
    }
}

Common mappings include:

Annotation HTTP Method
@GetMapping GET
@PostMapping POST
@PutMapping PUT
@PatchMapping PATCH
@DeleteMapping DELETE

4. Reading Path Variables

Use @PathVariable to read values from the URL path.

package com.example.web;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProductController {

    @GetMapping("/products/{id}")
    public String getProduct(@PathVariable Long id) {
        return "Product ID: " + id;
    }
}

Request:

GET /products/10

Response:

Product ID: 10

5. Reading Query Parameters

Use @RequestParam to read query string parameters.

package com.example.web;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SearchController {

    @GetMapping("/search")
    public String search(
            @RequestParam String keyword,
            @RequestParam(defaultValue = "1") int page
    ) {
        return "Searching for: " + keyword + ", page: " + page;
    }
}

Request:

GET /search?keyword=spring&page=2

Response:

Searching for: spring, page: 2

6. Reading Request Body JSON

Use @RequestBody to bind JSON request data to a Java object.

package com.example.web;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

public record CreateUserRequest(String name, String email) {
}

@RestController
public class UserApiController {

    @PostMapping("/api/users")
    public String createUser(@RequestBody CreateUserRequest request) {
        return "Created user: " + request.name() + " with email: " + request.email();
    }
}

Request:

POST /api/users
Content-Type: application/json
{
  "name": "Alice",
  "email": "[email protected]"
}

7. Returning Proper HTTP Status Codes

Use ResponseEntity when you need control over the response status, headers, or body.

package com.example.web;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OrderController {

    @PostMapping("/orders")
    public ResponseEntity<String> createOrder() {
        return ResponseEntity
                .status(HttpStatus.CREATED)
                .body("Order created");
    }
}

This returns:

HTTP/1.1 201 Created

8. Handling Form Submissions

For traditional web applications, a controller can handle form submissions with @PostMapping.

package com.example.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class ContactController {

    @PostMapping("/contact")
    public String submitContactForm(
            @RequestParam String name,
            @RequestParam String message
    ) {
        System.out.println("Name: " + name);
        System.out.println("Message: " + message);

        return "redirect:/contact-success";
    }
}

The redirect prevents duplicate form submissions if the user refreshes the page.


9. Using a Service from a Controller

Controllers should usually be thin. Put business logic in a service class.

package com.example.web;

import com.example.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/api/users/count")
    public int countUsers() {
        return userService.countUsers();
    }
}
package com.example.service;

import org.springframework.stereotype.Service;

@Service
public class UserService {

    public int countUsers() {
        return 5;
    }
}

This keeps the controller focused on HTTP request/response handling.


10. Simple Exception Handling

You can handle exceptions globally using @ControllerAdvice.

package com.example.web;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ErrorResponse handleIllegalArgumentException(IllegalArgumentException ex) {
        return new ErrorResponse(ex.getMessage());
    }

    public record ErrorResponse(String message) {
    }
}

Now if a controller throws:

throw new IllegalArgumentException("Invalid request");

Spring returns a 400 Bad Request response.


Quick Summary

Use these annotations to handle HTTP requests in Spring:

Annotation Purpose
@Controller Web controller returning views
@RestController REST controller returning response bodies
@GetMapping Handle GET requests
@PostMapping Handle POST requests
@PutMapping Handle PUT requests
@PatchMapping Handle PATCH requests
@DeleteMapping Handle DELETE requests
@PathVariable Read values from the URL path
@RequestParam Read query parameters or form fields
@RequestBody Read JSON/XML request body
ResponseEntity Customize status, headers, and body
@ControllerAdvice Centralized exception handling

In short:

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello, Spring!";
    }
}

That is the simplest form of handling an HTTP request with a Spring controller.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.