Spring and its features
The Model View Controller pattern
Spring Web MVC and its components
The Java ecosystem is filled with frameworks such as Jersey and RESTEasy, which allow you to develop REST applications. Spring Web MVC is one such popular web framework that simplifies web and REST application development. We begin this chapter with an overview of the Spring Framework and take a deep dive into Spring Web MVC and its components.
This book doesn’t give a comprehensive overview of Spring and Spring Web MVC. Refer to Pro Spring and Pro Spring MVC and WebFlux (both published by Apress) for detailed treatment of these concepts.
Spring Overview
As a developer, you are not forced to use everything that the Spring Framework has to offer. The modularity of the Spring Framework allows you to pick and choose the modules based on your application needs. In this book, we will be focusing on the web module for developing REST services. Additionally, we will be using a few other Spring portfolio projects such as Spring Data, Spring Security, and Spring Boot. These projects are built on top of the infrastructure provided by the Spring Framework modules and are intended to simplify data access, authentication/authorization, and Spring application creation.
Developing Spring-based applications requires a thorough understanding of two core concepts—dependency injection and aspect-oriented programming.
Dependency Injection
At the heart of the Spring Framework lies dependency injection (DI). As the name suggests, dependency injection allows dependencies to be injected into components that need them. This relieves those components from having to create or locate their dependencies, allowing them to be loosely coupled.
To better understand DI, consider the scenario of purchasing a product in an online retail store. Completing a purchase is typically implemented using a component such as an OrderService. The OrderService itself would interact with an OrderRepository that would create order details in a database and a NotificationComponent that would send out the order confirmation to the customer. In a traditional implementation, the OrderService creates (typically in its constructor) instances of OrderRepository and NotificationComponent and uses them. Even though there is nothing wrong with this approach, it can lead to hard-to-maintain, hard-to-test, and highly coupled code.
DI, by contrast, allows us to take a different approach when dealing with dependencies. With DI, you let an external process such as Spring create dependencies, manage dependencies, and inject those dependencies into the objects that need them. So, with DI, Spring would create the OrderRepository and NotificationComponent and then hand over those dependencies to the OrderService. This decouples OrderService from having to deal with OrderRepository/NotificationComponent creation, making it easier to test. It allows each component to evolve independently, making development and maintenance easier. Also, it makes it easier to swap these dependencies with different implementations or use these components in a different context.
Aspect-Oriented Programming
Aspect-oriented programming (AOP) is a programming model that implements crosscutting logic or concerns. Logging, transactions, metrics, and security are some examples of concerns that span (crosscut) different parts of an application. These concerns don't deal with business logic and are often duplicated across the application. AOP provides a standardized mechanism called an aspect for encapsulating such concerns in a single location. The aspects are then weaved into other objects so that the crosscutting logic is automatically applied across the entire application.
Spring provides two-proxy implementations—JDK dynamic proxy and CGLIB proxy. If the target bean implements an interface, Spring will use JDK dynamic proxy to create the AOP proxy. If the class doesn't implement an interface, Spring uses CGLIB to create a proxy.
You can read more about JDK dynamic proxy in the official documentation: https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html
Spring Web MVC Overview
Spring Web MVC, part of the Spring Framework’s web module, is a popular technology for building web-based applications. It is based on the model-view-controller architecture and provides a rich set of annotations and components. Over the years, the framework has evolved; it currently provides a rich set of configuration annotations and features such as flexible view resolution and powerful data binding.
Model View Controller Pattern
Model—The model represents data or state. In a web-based banking application, information representing accounts, transactions, and statements are examples of the model.
View—Provides a visual representation of the model. This is what the user interacts with by providing inputs and viewing the output. In our banking application, web pages showing accounts and transactions are examples of views.
Controller—The controller is responsible for handling user actions such as button clicks. It then interacts with services or repositories to prepare the model and hands the prepared model over to an appropriate view.
Spring Web MVC Architecture
- 1.
The interaction begins with the DispatcherServlet receiving the request from the client.
- 2.
DispatcherServlet queries one or more HandlerMapping to figure out a Handler that can service the request. A Handler is a generic way of addressing a Controller and other HTTP-based endpoints that Spring Web MVC supports.
- 3.
The HandlerMapping component uses the request path to determine the right Handler and passes it to the DispatcherServlet. The HandlerMapping also determines a list of Interceptors that need to get executed before (Pre-) and after (Post-) Handler execution.
- 4.
The DispatcherServlet then executes the Pre-Process Interceptors if any are appropriate and passes the control to the Handler.
- 5.
The Handler interacts with any Service(s) needed and prepares the model.
- 6.
The Handler also determines the name of the view that needs to get rendered in the output and sends it to DispatcherServlet. The Post-Process Interceptors then get executed.
- 7.
This is followed by the DispatcherServlet passing the logical view name to a ViewResolver, which determines and passes the actual View implementation.
- 8.
The DispatcherServlet then passes the control and model to the View, which generates response. This ViewResolver and View abstraction allow the DispatcherServlet to be decoupled from a particular View implementation.
- 9.
The DispatcherServlet returns the generated response over to the client.
Spring Web MVC Components
In the previous section, you were introduced to Spring Web MVC components such as HandlerMapping and ViewResolver. In this section, we will take a deeper look at those as well as additional Spring Web MVC components.
In this book, we will be using Java configuration for creating Spring beans. Contrary to XML-based configuration, Java configuration provides compile-time safety, flexibility, and added power/control.
Controller
HomeController Implementation
The @Controller annotation designates the HomeController class as a MVC controller. The @GetMapping is a composed annotation that acts as a shortcut for @RequestMapping(method = RequestMethod.GET). @GetMapping annotation maps web requests to handler classes and handler methods. In this case, the @GetMapping indicates that when a request for home.html is made, the showHomePage method should get executed. The showHomePage method has a tiny implementation and simply returns the logical view name home. This controller did not prepare any model in this example.
Model
Model Interface
showHomePage with Model Attribute
showHomePage with Map Attribute
View
View Interface API
Spring Web MVC View Implementations
Class name | Description |
---|---|
org.springframework.web.servlet.view.json.MappingJackson2JsonView | View implementation that encodes model attributes and returns JSON |
org.springframework.web.servlet.view.xslt.XsltView | View implementation that performs XSLT transformation and returns the response |
org.springframework.web.servlet.view.InternalResourceView | View implementation that delegates the request to a JSP page inside the web application |
org.springframework.web.servlet.view.tiles2.TilesView | View implementation that uses Apache Tiles configuration for Tile definition and rendering |
org.springframework.web.servlet.view.JstlView | Specialized implementation of InternalResourceView that supports JSP pages using JSTL |
org.springframework.web.servlet.view.RedirectView | View implementation that redirects to a different (absolute or relative) URL |
HomeController View Implementation
Controller implementations typically don't deal with view instances. Instead, they return logical view names, as shown in Listing 2-1, and let view resolvers determine and create view instances. This decouples the controllers from tying to a specific view implementation and makes it easy to swap view implementations. Also, the controllers no longer need to know intricacies such as the location of the views.
@RequestParam
RequestParam Usage
Making a Request Parameter Not Required
@RequestMapping
RequestMapping Elements
Element name | Description |
---|---|
Method | Restricts a mapping to a specific HTTP method such as GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE |
Produces | Narrows mapping to media type that is produced by the method |
Consumes | Narrows mapping to media type that the method consumes |
Headers | Narrows mapping to the headers that should be present |
Name | Allows you to assign a name to the mapping |
Params | Restricts a mapping to the supplied parameter name and value |
Value | Narrowing path for a specific handler method (if don’t have any elements, by default value is the main element) |
Path | Narrowing path for a specific handler method (alias for value) |
POST Method Example
@RequestMapping Shortcut Annotations
You can use “shortcut annotation” for @RequestMapping.
It looks more readable because you can use “shortcut annotation” instead of @RequestMapping.
All shortcut annotations inherit all elements from @RequestMapping, without method, because the method is already in the title of the annotation.
Shortcut Annotations for @RequestMapping
Annotation | Replacement |
---|---|
@GetMapping | @RequestMapping(method = RequestMethod.GET) |
@PostMapping | @RequestMapping(method = RequestMethod.POST) |
@PutMapping | @RequestMapping(method = RequestMethod.PUT) |
@DeleteMapping | @RequestMapping(method = RequestMethod.DELETE) |
@PatchMapping | @RequestMapping(method = RequestMethod.PATCH) |
Produces Element Example
It is possible for the client to perform a GET request on /search.html but send an Accept header with value application/JSON. In that scenario, Spring will not invoke the search method. Instead, it will return a 404 error. The produces element provides a convenient way to restrict mappings to content types that the controller can serve. In the same fashion, the consumes element is used to indicate the media type that the annotated method consumes.
As discussed in Chapter 1, REST resources can have multiple representations. REST clients typically use the Accept and Content-Type headers to work with these representations.
The q parameter, also known as relative quality parameter, indicates the degree of preference and has values ranging from 0 to 1. From the string, we can infer that the HTML and XHTML will have a priority of 1 because they don't have an associated q value. The XML media type has priority 0.9, and the rest of the representations have a priority of 0.8. On receiving this request, the server would try to send an HTML/XHTML representation because it has the highest priority.
In a similar fashion, REST clients use the Content-Type header to indicate the media type of the request being sent to the server. This allows the server to properly interpret the request and parse the contents correctly. If the server is unable to parse the content, it will send a 415 Unsupported Media Type error status code.
Method Arguments and Descriptions
Method argument | Description |
---|---|
HttpServletRequest/HttpServletResponse | HTTP Servlet request and response objects. Allows raw access to client’s data, such as request parameters and headers. |
HttpSession | Instance representing a user’s HTTP session. |
Command object | A POJO or model object that Spring populates/binds with the user-submitted data. The command object can be annotated with @ModelAttribute. |
BindingResult | Instance representing a command object’s validation and binding. This parameter must immediately precede the command object. |
HttpEntity<?> | Instance representing an HTTP request. Each HttpEntity is composed of request body and a set of headers. |
Principal | A java.security.Principal instance that represents the authenticated user. |
Return Types and Descriptions
Return type | Description |
---|---|
String | Represents the logical view name. Registered view resolvers are employed to resolve the physical view, and a response is generated. |
View | Instance representing a view. In this case, no view resolution is performed and the view object is responsible for generating the response. Examples include JstlView, VelocityView, RedirectView, and so on. |
HttpEntity<?> | Instance representing an HTTP response. Each HttpEntity is composed of response body and a set of headers. |
HttpHeaders | Instance capturing the headers to be returned. Response will have an empty body. |
Pojo | Java object that is considered to be a model attribute. A specialized RequestToViewNameTranslator is used to determine the appropriate logical view name. |
Path Variables
PathVariable Example
View Resolver
ViewResolver Interface
Table 2-6 lists some of the ViewResolver implementations provided by Spring Web MVC.
As you might have noticed, the different view resolvers in Table 2-6 mimic the different types of views we looked at earlier. Listing 2-13 shows the code required for creating an InternalViewResolver.
ViewResolver Implementations and Descriptions
Return type | Description |
---|---|
BeanNameViewResolver | ViewResolver implementation that looks for a bean with an id that matches the logical view name in the ApplicationContext. If it doesn't find the bean in the ApplicationContext, a null is returned. |
InternalResourceViewResolver | ViewResolver that looks for an internal resource that has the logical view name. The location of the internal resource is typically computed by prefixing and suffixing the logical name with path and extension information. |
ContentNegotiatingViewResolver | ViewResolver that delegates the view resolution to other view resolvers. The choice of the view resolver is based on the requested media type, which itself is determined using an Accept header or file extension or URL parameter. |
TilesViewResolver | ViewResolver that looks for a template in the Tiles configuration that matches the logical view name. |
InternalViewResolver Example
Exception Handler
HandlerExceptionResolver API
HandlerExceptionResolver Implementations and Descriptions
Resolver implementation | Description |
---|---|
org.springframework.web.servlet.handler.SimpleMappingExceptionResolver | Exception resolver implementation that maps exception class names to view names. |
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver | Exception resolver implementation that translates standard Spring exceptions to HTTP status codes. |
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver | Custom exceptions in Spring applications can be annotated with @ResponseStatus, which takes a HTTP status code as its value. This exception resolver translates the exceptions to its mapped HTTP status codes. |
org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver | Exception resolver implementation that resolves exceptions using annotated @ExceptionHandler methods. |
ExceptionHandler Example
The @ExceptionHandler annotated methods can only handle exceptions that occur in the controller or its subclasses. So, if we need to handle SQL exceptions in other controllers, then we need to copy and paste the handleSQLException method in all of those controllers. This approach can pose severe limitations, as exception handling is truly a crosscutting concern and should be centralized.
GlobalExceptionHandler Example
Interceptors
Before the controller gets executed. This allows the interceptor to decide if it needs to continue the execution chain or return with an exception or custom response.
After the controller gets executed but before the response is sent out. This allows the interceptor to provide any additional model objects to the view.
After the response is sent out allowing any resource cleanup.
Spring Web MVC interceptors are similar to HTTP servlet filters. Both can be used to intercept a request and execute common concerns. However, there are a few differences between them that are worth noting. Filters have the capability to wrap or even swap the HttpServletRequest and HttpServletResponse objects. Interceptors can’t decorate or swap those objects. Interceptors are Spring-managed beans, and we can easily inject other spring beans in them. Filters are container-managed instances; they don't provide a straightforward mechanism for injecting Spring-managed beans.
HandlerInterceptor API
Spring Web MVC Interceptor Example
Example Registering Interceptors
When an interceptor is added to the interceptor registry, the interceptor gets applied to all of the handler mappings. So, the LocaleChangeInterceptor in Listing 2-19 gets applied to all the handler mappings. However, it is also possible to restrict the interceptor to certain URLs. This is demonstrated in Listing 2-19 using the addPathPatterns method . Here we are indicating that the SimpleInterceptor should be applied to only the URLs that are under the auth path.
Summary
In this chapter, we have looked at the basics of the Spring Framework and different components of a Spring Web MVC. In the next chapter, we will bring things together and look at building our first RESTful application using Spring Boot.