Spring MVC with Spring Boot
Spring MVC (Model-View-Controller) is a framework for building web applications. When combined with Spring Boot, it simplifies configuration, development, and deployment of web and RESTful applications.
Create a Spring MVC Application Using Spring Boot
In this small tutorial you will see how to create a simple Spring MVC application. We will use maven for it. To start the project it is recommended to use the Spring Initializr. We will be packaging as a JAR file later. For Spring MVC we need the starter dependency spring-boot-starter-web. Optionally we can add spring-boot-starter-thymeleaf or similar for templating:
<!-- for deployment later -->
<packaging>jar</packaging>
<dependencies>
<!-- Spring Boot Starter for Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Starter for Thymeleaf (Optional for MVC views, only for HTML pages) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
Your main class can stay the way it has been created by the Spring Initializr. We won't make any changes to it.
Basic Request Processing Lifecycle for REST Requests
The simplified dataflow is as follows:
- HTTP Request:
- A client sends an HTTP request to a URL mapped in the application.
- Request Mapping:
- The request is matched to a controller method using @RequestMapping, @GetMapping, or other annotations.
- Method Execution:
- The controller processes the request and returns a response object (e.g., ResponseEntity, JSON).
- Response Generation:
- The response is serialized (e.g., JSON or XML) and sent back to the client.
RESTful Controller
This controller is annotated with @RestController which is a combination of @Controller and @ResponseBody. This marks all handler methods with @ResponseBody internally. The @RequestMapping annotation prefixes all the handler methods with the set path. so the method getAllProducts is reachable using /api/products directly, without setting it in the @GetMapping annotation.
There are many different method arguments that are available for the differently annotated controller methods.
Different things can be returned using those methods:
- String: Directly returns a string, which is typically used for simple text responses. However, it’s less common with @RestController because it’s more geared towards returning objects that are automatically converted to JSON or XML.
- ModelAndView: Returns a ModelAndView object, which is useful for returning a view along with model attributes. This is more common with @Controller rather than @RestController, as @RestController is designed to return data rather than views.
- ResponseEntity: Provides a more flexible way to return HTTP responses, allowing you to set the status code, headers, and body of the response. This is particularly useful when you need more control over the HTTP response.
- Map: Returns a map object, which is automatically converted to JSON or XML. This is useful for returning dynamic data structures.
- Custom Object: Returns a custom object, which is automatically converted to JSON or XML by Spring’s HttpMessageConverter. This is one of the most common return types for @RestController methods.
- List: Returns a list of objects, which is also automatically converted to JSON or XML. This is useful for returning collections of data.
- Void: Returns void, which is typically used with methods that perform an action and do not return any data.
import org.springframework.web.bind.annotation.*;
import java.util.*;
@RestController
@RequestMapping("/api/products")
public class ProductController {
private final Map<Integer, String> products = new HashMap<>();
@PostMapping
public String createProduct(@RequestBody String product) {
int id = products.size() + 1;
products.put(id, product);
return "Product created with ID: " + id;
}
@GetMapping
public Map<Integer, String> getAllProducts() {
return products;
}
@GetMapping("/{id}")
public String getProductById(@PathVariable int id) {
return products.getOrDefault(id, "Product not found");
}
@PutMapping("/{id}")
public String updateProduct(@PathVariable int id, @RequestBody String updatedProduct) {
if (products.containsKey(id)) {
products.put(id, updatedProduct);
return "Product updated: " + updatedProduct;
}
return "Product not found";
}
@DeleteMapping("/{id}")
public String deleteProduct(@PathVariable int id) {
if (products.remove(id) != null) {
return "Product deleted with ID: " + id;
}
return "Product not found";
}
}
Configure for Deployment
Now we have a very basic application. Calling the defined endpoint while the local development server is running should yield the expected values.
The deployment is straight forward. Since Spring Boot uses an embedded Tomcat server by default, so no external server is required.
To generate a JAR file we simply need to call mvn clean package. This generates a JAR file in the target/ directory, e.g., target/my-app-0.0.1-SNAPSHOT.jar. Afterwards we can easily run the application with its default settings using:
// with default configuration
java -jar my-app-0.0.1-SNAPSHOT.jar
// with configuration file
java -jar my-app-0.0.1-SNAPSHOT.jar --spring.config.location=/path/to/custom-config.properties
