Building Web Applications with Spring MVC: Core Annotations and JSON Handling
The Spring MVC framework processes HTTP requests through a defined workflow. A request is first received by the DispatcherServlet, which consults handler mappings to find the appropriate controller method. The selected controller processes the request, potentially interacting with services and repositories, and returns a logical view name or data object. The DispatcherServlet then resolves the view or processes the return value through configured HttpMessageConverter instances (e.g., for JSON) before sending the final response to the client.
To initiate a Spring Boot web project, include the spring-boot-starter-web dependency in your pom.xml. This starter configures an embedded servlet container (like Tomcat) and essential MVC components.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Spring MVC provides several core annotations for request mapping and parameter handling:
@RequestMapping: A general-purpose annotation for mapping web requesst to controller methods. When used without specifying an HTTP method, it handles all request types (GET, POST, PUT, DELETE, etc.). It can be applied at both the class and method levels.- HTTP Method-specific Annotations:
@GetMapping,@PostMapping,@PutMapping,@DeleteMapping, and@PatchMappingare composed annotations that act as shortcuts for@RequestMapping(method = RequestMethod.XXX). They are typically applied only at the method level. @RestController: A convenience annotation that combines@Controllerand@ResponseBody. It indicates that the return value of all handler methods in the class should be written directly to the HTTP response body, typically for RESTful web services returning JSON or XML.@ResponseBody: Binds a method's return value to the web response body. When used with@Controller, it enables returning data objects instead of view names.@RequestBody: Maps the body of the HTTP request to a method parameter. Its commonly used to deserialize JSON request payloads into Java objects.@PathVariable: Extracts values from the URI template. For example, a path like/users/{userId}can have the{userId}segment bound to a method parameter.@RequestParam: Binds request parameters (from query strings or form data) to method parameters. It supports adefaultValueattribute for optional parameters.
@RestController
@RequestMapping("/api/users")
public class UserApiController {
@GetMapping("/{id}")
public UserProfile fetchUser(@PathVariable("id") Long userId) {
// Retrieve user by ID
return userService.getProfile(userId);
}
@PostMapping
public ApiResponse createUser(@RequestBody UserRegistrationRequest request) {
// Process registration
User newUser = userService.register(request);
return ApiResponse.success(newUser);
}
@GetMapping("/search")
public List<User> searchUsers(@RequestParam(defaultValue = "") String keyword) {
// Search based on keyword
return userService.findUsers(keyword);
}
}
To receive JSON data in a POST request, define a plain Java class (a Data Transfer Object or DTO) whose field names correspond to the JSON properties. Spring will automatically deserialize the request body into an instance of this class when the method parameter is annotated with @RequestBody.
public class OrderRequest {
private String productId;
private Integer quantity;
private String customerNotes;
// Standard getters and setters required
}
@PostMapping("/orders")
public OrderConfirmation placeOrder(@RequestBody OrderRequest orderReq) {
return orderService.process(orderReq);
}
For sending structured JSON responses, it's good practice to wrap the payload in a consistent response envelope. This allows including metadata like status codes and messages alongside the actual data.
public class StandardResponse<T> {
private int status;
private String message;
private T payload;
private StandardResponse(int statusCode, String msg, T data) {
this.status = statusCode;
this.message = msg;
this.payload = data;
}
public static <T> StandardResponse<T> ok(T data) {
return new StandardResponse<>(200, "Operation successful", data);
}
public static StandardResponse<Void> error(int statusCode, String errorMsg) {
return new StandardResponse<>(statusCode, errorMsg, null);
}
// Getters
}
@GetMapping("/items/{itemId}")
public StandardResponse<ItemDetails> getItem(@PathVariable String itemId) {
ItemDetails item = inventoryService.lookup(itemId);
return StandardResponse.ok(item);
}
Tools like Postman or cURL are essential for testing HTTP endpoints during development. They allow you to construct requests with specific methods, headers, and body content (like JSON) and inspect the raw responses.
To add logging to your Spring Boot application, include the Lombok dependency and annotation. Lombok's @Slf4j annotation automatically injects a logger instance.
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RestController
public class AuditController {
@PostMapping("/log-event")
public void recordEvent(@RequestBody EventData event) {
log.info("Received event: {}", event.getType());
// Processing logic
}
}