Appendix C. Chapter 7 server-side setup and summary

This appendix covers

  • Working with server objects and tasks
  • Setting up Spring MVC for the chapter 7 project
  • Using Spring annotations in the chapter 7 project

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.

C.1. Server-side objects

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.

Figure C.1. The shopping cart has a list of items that holds a number of games ranging from 0 to n.

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.

Figure C.2. The ErrorMessage object is used to relay errors back to the UI.

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.

C.2. Summary of server-side calls

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.

C.2.1. Viewing the cart

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.

Table C.1. Call to get the cart identified by the path variable

URL

HTTP method

Request

Response

/shopping/carts/{cartId} GET Empty Cart

Task list:

  • Get cart from memory —If a cart is found in your static map that matches the requested cart ID, your code will return the matching cart. If there’s no match, a new cart is created and added to the map of carts.
  • Return the cart as JSON —The retrieved cart is converted back to JSON and returned to the front end.

C.2.2. Adding an item to the cart

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.

Table C.2. Call to add a product item for a given cart

URL

HTTP method

Request

Response

/shopping/carts/{cartId}/products/{productId} POST Empty Cart

Task list:

  • Add the item —The cart is first checked to see whether the product being added from the product display view exists already in the cart. If it does, the count of the existing product is incremented by 1. If not, a new Game object instance is created by getting the requested game from the inventory. The total item count is also updated.
  • Update the cart in memory —The shopping cart in memory is updated to reflect the new state of the cart.
  • Return the cart as JSON —The retrieved cart with the updated product list and any quantity changes is converted back to JSON and returned to the front end.

C.2.3. Updating the cart

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.

Table C.3. Call to update the cart identified by the path variable

URL

HTTP method

Request

Response

/shopping/carts/{cartId} PUT Cart Cart

Task list:

  • Update quantities —The entire cart is sent for an update. Because a scaled-down version of the cart is generated from the $scope of the shopping cart view, any missing information is regenerated from the static inventory list that’s on the server. The total item count is also updated.
  • Update the cart in memory —The shopping cart in memory is updated to reflect the new state of the cart.
  • Return the cart as JSON —The retrieved cart with the updated item list and any quantity changes is converted back to JSON and returned to the front end.

C.2.4. Deleting an item

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.

Table C.4. Call to delete the item identified by the path variable

URL

HTTP method

Request

Response

/shopping/carts/{cartId}/products/{productId} DELETE Empty Cart

Task list:

  • Get cart from memory —You use the information in the URL to get the cart from memory.
  • Delete the item —In this call, you iterate over the items in the cart in memory until you find a match with the product ID in the URL. When the match is found, the item is removed.
  • Update cart total —After the item is removed, the item count is recalculated.
  • Return the cart as JSON —The retrieved cart with the updated item list and any quantity changes is converted back to JSON and returned to the front end.

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.

C.2.5. Searching for a product

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).

Table C.5. Call to search for a game

URL

HTTP method

Request

Response

/games/search/{srchTerm} GET Empty List of Game objects

Task list:

  • Search —The search term from the URL path is compared with all the game titles in your inventory for at least a partial match. The number of matches can range from 0 to n. This call returns a list of Game objects as a result.
  • Return the list as JSON —The retrieved list of games is returned as JSON to the UI.

C.2.6. Displaying a product

After a list of search results is presented, the user clicks a title to display its information (see table C.6).

Table C.6. Call to display the selected game’s information

URL

HTTP method

Request

Response

/games/id/{productId} GET Empty Game

Task list:

  • Retrieve game by ID —In this call, the product ID is passed in the URL. The code behind the call uses the ID to find the matching game in your inventory.
  • Return the cart as JSON —The retrieved game is returned as JSON to the UI.

C.3. The project

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.

C.3.1. Prerequisites

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:

  • Apache Tomcat —Tomcat is a freely available server that supports Java EE.[1] Version 7 supports the Servlet 3.0 specification, which matches the needs for our server application (though higher versions should work as well). This version of Tomcat supports the Servlet 3.0 specification. You can download it from http://tomcat.apache.org. Feel free to use something else if you prefer a different server, as long as it supports the Servlet 3.0 specification.

    1

    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.

  • Apache Maven 3.2.1 or later —Apache Maven is a software management tool. It can be found at http://maven.apache.org.

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.

C.3.2. Spring MVC configuration

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.

Listing C.1. WebAppInitializer.java

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.

Listing C.2. WebMvcConfig.java

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.

Figure C.3. Complete project workspace

C.3.3. Annotations used in our project

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.

Class-level annotations used by the controller

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.

Listing C.3. Class-level annotations

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.

Method-level annotations

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).

Listing C.4. Method-level annotations

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.

Exception-handling annotations

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.

Listing C.5. Exception-handling annotations

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.

Services and autowiring

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset