This appendix covers
As mentioned in chapter 7, you can choose to use any server-side technology you want for the end-of-the-chapter project. If you’re interested in setting up Spring MVC for that project, this appendix provides details. It also covers the annotations used. The complete code is available for download.
In case you decide to use a completely different tech stack, this appendix also summarizes the task(s) each call is performing so it’s easier to make the translation. Keep in mind that the project uses RESTful services, so the back-end technology you use must support REST either directly or indirectly via a third-party library/plugin.
Only two data objects are used in the project: a ShoppingCart object and a Game object. Each shopping cart holds a collection of games (see figure C.1). The Game object is standalone and can be used independently of the ShoppingCart object.
You also use an object on the server to hold information about any errors that occur (see figure C.2). The message field is for any error that’s OK to display to the user. In addition to any server-side exception handling, exceptions are sent back to the UI in the exceptionText field.
Now let’s summarize the calls that are made to the server. We’ll do this before talking about Spring MVC. This will make it easier to digest what the back end is doing, regardless of the back-end technology you use.
This section generalizes the tasks the server is performing for a service call. I’ll state the URL format, any object(s) used in the request and response, and a brief summary of what the server code does in each case.
This call is invoked whenever the user clicks the View Cart link. The braces {} indicate a path variable that contains the cart ID requested. Table C.1 contains its properties.
URL |
HTTP method |
Request |
Response |
---|---|---|---|
/shopping/carts/{cartId} | GET | Empty | Cart |
Task list:
When a product item is added, you use the POST HTTP request, passing your cart ID and the ID of the product item. Table C.2 contains the call properties.
URL |
HTTP method |
Request |
Response |
---|---|---|---|
/shopping/carts/{cartId}/products/{productId} | POST | Empty | Cart |
Task list:
This call is used to update an existing product. Any update will submit the entire cart to the back end. Table C.3 contains the call properties.
URL |
HTTP method |
Request |
Response |
---|---|---|---|
/shopping/carts/{cartId} | PUT | Cart | Cart |
Task list:
When an item is deleted, you identify both the cart and the item in the URL. You don’t need to send any objects in the request body, because the resource to delete is perfectly identifiable using only the URL. Table C.4 contains the call properties.
URL |
HTTP method |
Request |
Response |
---|---|---|---|
/shopping/carts/{cartId}/products/{productId} | DELETE | Empty | Cart |
Task list:
Chapter 7 focused on only the shopping cart transactions to illustrate the concepts. In the project, you make a couple of other calls. From the product search view, the user can search for a game. When a game is found, it can be added to the cart via the button in the product display view.
On the product search view, the user types in a search term. This search term is a simple string that can be the entire game title or just part of it (see table C.5).
URL |
HTTP method |
Request |
Response |
---|---|---|---|
/games/search/{srchTerm} | GET | Empty | List of Game objects |
Task list:
After a list of search results is presented, the user clicks a title to display its information (see table C.6).
URL |
HTTP method |
Request |
Response |
---|---|---|---|
/games/id/{productId} | GET | Empty | Game |
Task list:
This section covers the server-side technologies used in our project and walks through the setup of Spring MVC. It also covers the Spring annotations used in our project.
Feel free to substitute any particular technology with another if you already work with something else and would prefer it. This list was used to create the example:
Tomcat supports only the Web Profile part of the Java EE specification, but this is enough for what you need here. Servers such as GlassFish, JBoss, WebLogic, and WebSphere support the whole specification.
The following dependencies are managed by Maven:
It’s also worth mentioning that Java version 8 is used. If you use a later version of any of the listed technologies, make sure that it’s compatible with whichever versions of Java and Tomcat you’re using.
Before you can get the application up and running, you need to work on configuring Spring MVC. Fortunately, the setup is minimal, because you won’t be using a database or consuming any external web services.
To begin, you need to create a dynamic web project in your IDE. If you’re using Eclipse, import the project and you’re ready to go. If you’re using another IDE, you can create a new dynamic web project in your IDE and copy the code from this archive. You can find everything you need, including pom.xml, in the downloadable source for chapter 7. See the readme.txt file for additional installation instructions.
After the workspace is set up, you can begin your configuration. In Spring 2.5.6 or higher, you can use either XML or Java classes for configuration. This example uses Java configuration. This is purely a design choice. Feel free to use XML configuration if you prefer (or mix the two). Starting with the Servlet 3.0 specification, you no longer even need a web.xml file, so this file isn’t necessary. It’s included in this case only to fulfill the Maven plugin’s needs. Remember, though, your container also has to support this configuration. Check the documentation for the server you’re using.
In our example, you’ll go that route to keep your configuration code to a minimum. To get your web application up and running without a web.xml file, you need a class that implements the WebApplicationInitializer interface. This interface is available in Spring 3.1 or later. The following listing shows the class that implements this interface. The package it’s placed in isn’t important. It’ll be detected automatically.
All of your requests from the front end will come through Spring MVC’s dispatcher servlet. To configure things purely in Java, without a web.xml file, you implement the WebApplicationInitializer interface and provide the implementation for the onStartup method. Spring hands the correct servlet context to this method. It’s where you define any bootstrap code to be executed during the servlet container’s start-up. You also need to let Spring know which class will be handling your MVC preferences. Listing C.1 defines WebMvcConfig as your MVC configuration class. The following listing contains its code.
Because you’ve defined WebMvcConfig as the MVC configuration class, you decorate it as such by using the @Configuration annotation. The class itself has no body. The real magic comes from the annotation @EnableWebMvc. This annotation sets up the Spring MVC defaults. If you need to override any of the defaults, you can implement WebMvc-Configurer in this configuration class and override any of its methods. Alternatively, Spring provides WebMvcConfigurerAdapter as a convenience to avoid having to implement all 16 WebMvcConfigurer methods. For your purposes, you need only a basic Spring MVC configuration so you’ll use WebMvcConfigurerAdapter.
Finally, you use the @ComponentScan annotation to tell Spring where to look for the other components used in the application. You have controller components in the controllers package and a single service component in the data services package. You’ll learn about both in the next section.
Figure C.3 shows your IDE’s workspace with the complete project configured and ready to run.
We’ve already discussed the annotations used in your Spring MVC setup. This section covers the other annotations you’re using in your controllers and your service. To show the annotations in action, you’ll use the shopping cart controller. You’ll start at the class level and then work your way down to the method level.
Your shopping cart controller class is decorated with two annotations: @RestController and @RequestMapping (see the following listing). In Spring MVC, more than one can be used in combination.
The @RestController is a convenience annotation. It’s the same as adding the annotations @Controller and @ResponseBody to the class.
The @Controller annotation lets Spring MVC know that this class is a controller and has methods to handle requests. With this annotation present, Spring MVC will scan your methods for request mapping annotations. We’ll cover these shortly.
The @ResponseBody is used when you want the object returned in your method to be bound to the response body of the call. This annotation can be applied either at the class level or at the method level. When this annotation is added at the class level, every method in the controller follows this behavior, so it can be omitted at the method level. When your shopping cart objects are returned, they’ll be sent back to the UI via the response body. Additionally, with the Jackson library in your classpath, it’ll automatically convert them to JSON-formatted text.
The @RequestMapping annotation maps incoming requests to particular classes and/or methods. It can decorate the class, the method, or both. In the case of your shopping cart, it’s defined at both places. This creates a kind of hierarchy in the request that’s being mapped. The annotation defined at the class level maps this entire class to any URL that begins (after the root) with the string /shopping.
The @RequestMapping annotation elsewhere in your controller maps the other part of the request URL after /shopping with a particular method. I’ll discuss these in the next section.
To see method-level annotations in action, you’ll use your shopping cart update. It contains the gamut of annotations used in all of the methods (see the following listing).
Decorating the method itself, you have the @RequestMapping annotation again. Its value is the part of the URL that’s used to map the request to this specific method. With this annotation already defined at the class level with part of the URL, the full path for this method is /shopping/carts/{cartId}.
You’ll also notice that, just as in the UI, you can define URL path parameters. They’re denoted with brackets {} and correspond to method parameters decorated with the @PathVariable annotation. Finally, in @RequestMapping, you’re defining the HTTP request method as PUT, because this is an update to your shopping cart.
@RequestMapping and @PathVariable allow you to easily define resources in the URL path through path variables and the type of HTTP request method for the method. As mentioned in chapter 7, the unique resource identifiers in the URL paths and the HTTP request methods that define the action requested come together to create a RESTful request.
The other method-level annotation you’re using here is @RequestBody. It binds the method parameter decorated with it to the object being sent in the body of the request. In the case of a cart update, the entire shopping cart is being sent in the request body. This annotation binds it to the ShoppingCart parameter. Because you have the Jackson library in your classpath, Spring automatically converts the JSON-formatted text of the request body to a native Java ShoppingCart object.
You always hope that your calls will succeed, but in case there’s an error, you can rely on annotations to turn the exception thrown into a meaningful response.
Another part of the REST architecture is defining HTTP statuses to let the client know the outcome of the call. This is particularly important when errors exist. In Spring MVC, you can associate Java exceptions with particular responses by using annotations as well. Here’s an example from the controller that takes any UnauthorizedAccess-Exception thrown and turns that into a proper response.
The @ExceptionHandler annotation can be used to specify what should be returned for a particular exception. In your shopping cart, you have a simplistic pseudo-authentication method you’re using in lieu of an action login. You’re comparing the ID of the cart passed in the request to the one stored on the session to demonstrate the use of exception-handling annotations. If any of the requests fail this check, the associated methods in your shopping cart controller throw the UnauthorizedAccessException, and this method automatically gets invoked. It returns a custom object you’ve created that holds a user-friendly message and the exception thrown. You’ve defined the 401/Unauthorized status as the status in this case by using the @ResponseStatus annotation.
The last couple of annotations you’ll look at are used to ask Spring to inject the data services component into your shopping cart controller.
In chapter 7, you moved your dummy data from the UI to the server-side code. You placed it into a class called DataServiceImpl. You’re using this class as a data store, a service, and a data access object (DAO) all rolled into one. Normally, your services create uniform APIs for any business-layer code, which, in turn, uses DAOs and other services to access the application’s data. Because you’re not using a database or any other web services, this class will assume multiple roles for simplicity’s sake.
Because this class is also used in the other controller you have for searching and displaying games, you don’t create a new instance of it directly in the shopping cart controller. Instead, you let Spring manage it and inject the service to whichever controller needs to use it.
This class itself doesn’t do anything special except provide methods to search and access your static inventory data and your users’ shopping carts. The source can be downloaded if you want to analyze it. What I want to point out here are the annotations used.
To define this class as an injectable service, you decorate your class with the @Service annotation. This allows it to be detected by Spring automatically when it performs its component scanning:
@Service public class DataServiceImpl implements DataService {
To use the service, you can decorate either a setter method or an instance variable with the @Autowired annotation in whichever class it’s to be injected into. Note that for autowiring, you use the class’s interface. In your shopping cart, you’ve defined an instance variable as the interface type DataService and you’ve decorated it with this annotation:
@Autowired private DataService dataService;
When Spring finds this annotation, it automatically assigns an instance of this service to this instance variable for you to use.
This project just scratches the surface of Spring MVC. If you want to know more, you can start with the friendly introduction at http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html.