Configuring a controller with simple URL mapping

This recipe introduces the Spring MVC controller with its simplest implementation.

Getting ready

We will discover later on, and especially in Chapter 3, Working with Java Persistence and Entities, that Spring MVC is a great tool to build a REST API. Here, we will focus on how to create a controller that prints some content in the response.

Starting with this recipe, we will be using GIT to follow each iteration that has been made to develop the cloudstreetmarket application. After the initial setup, you will appreciate how smoothly you can upgrade.

How to do it...

This recipe comes with two initial sections for installing and configuring GIT.

Downloading and installing GIT

  1. To download GIT, go to the GIT download page at https://git-scm.com/download. Select the right product corresponding to your environment (Mac OS X, Windows, Linux, or Solaris).
  2. To install GIT for Linux and Solaris, execute the suggested installation commands using the system's native package manager.

For Mac OS X, double-click on the downloaded dmg file to extract the package on your hard drive. Navigate to the extracted directory and double-click on the pkg file. Select all the default options, one step after an other, up to the Successful Installation screen. Close the screen.

For Windows, execute the downloaded program and follow the default options for every step up to these screens:

  • Adjusting your PATH environment: Select the Use Git from the Windows Command Prompt option
  • Choosing the SSH executable: Select the Use OpenSSH option
  • Configuring the line endings conversions: Select the Checkout Windows-style and commit Unix-style line endings options
  • Configuring the terminal emulator to use Git Bash: Select Use Windows' default console window
  • Configuring experimental performance tweaks: Don't tick the Enable file system caching checkbox

Let the installation finish and click on the Finish button.

For verification, open your terminal and enter the following command:

git –version

This command should display the installed version. The presented installation guidelines were associated with GIT 2.6.3.

Configuring GIT in Eclipse

  1. We will first initialize the local repository from the terminal. Go to your workspace location: cd <home-directory>/workspace.

    Replace <home-directory> with your own home path.

  2. Enter the following command to create a local Git repository at this location:
    git init
    
  3. Enter the following command:
    git remote add origin https://github.com/alex-bretet/cloudstreetmarket.com
    
  4. Then, enter the git fetch command.
  5. Select both your parent projects and right-click on one of them. Go to Team | Add to index:
    Configuring GIT in Eclipse
  6. From the top-right panel, click on the Git perspective:
    Configuring GIT in Eclipse

    Add this perspective with the Configuring GIT in Eclipse button if you don't have it yet.

  7. From the left hierarchy (the Git perspective), select Add an existing local Git repository.
  8. A contextual window opens. Target the location of the local Git repository we just created (it should be the current workspace directory).
  9. A new repository should now appear in Git perspective.
  10. As shown in the following screenshot, right-click and select Checkout to see the latest version of the branch origin/v1.x.x.
    Configuring GIT in Eclipse
  11. When prompted, Checkout as New Local Branch:
    Configuring GIT in Eclipse
  12. The actual workspace should now be synchronized with the branch v1.x.x. This branch reflects the state of the environment at the end of Chapter 1, Setup Routine for an Enterprise Spring Application.
    Configuring GIT in Eclipse
  13. Right-click on zipcloud-parent to execute Run as | Maven clean and Run as | Maven install. Then, do the same operation on cloudstreetmarket-parent. You will observe BUILD SUCCESS each time.
  14. Finally, right-click on one project and go to Maven | Update Project. Select all the projects of the workspace and click on OK.
  15. If you still have a red warning in one of your projects (as shown in the previous screenshot), you will probably have to reattach a target runtime environment to cloudstreetmarket-api and cloustreetmarket-webapp (as per Chapter 1 , Setup Routine for an Enterprise Spring Application, 2nd recipe, 7th step).
  16. From the terminal, go to the local GIT repository:
     cd <home-directory>/workspace 
    
  17. Enter the following command:
     git pull origin v2.2.1
    
  18. Reiterate steps 13 and 14. (Be prepared to repeat these two steps every time after pulling new changes.)
  19. In the cloudstreetmarket-webapp module, a new package is now present:
     edu.zipcloud.cloudstreetmarket.portal.controllers.
    
  20. Inside this package, an InfoTagController class has been created:
    @Controller
    @RequestMapping("/info")
    public class InfoTagController {
      @RequestMapping("/helloHandler")
      @ResponseBody
      public String helloController(){
        return "hello";
      }
    }
  21. Make sure the two wars are deployed in the Tomcat server. Start the Tomcat server and access the http://localhost:8080/portal/info/helloHandler URL with your browser.

    Note

    You should see a simple hello displayed as HTML content.

  22. In the cloudstreetmarket-webapp/src/main/webapp/WEB-INF/dispatcher-context.xml file, the following bean definition is added:
    <bean id="webAppVersion" class="java.lang.String">
      <constructor-arg value="1.0.0"/>
    </bean>
  23. The following method and members in the InfoTagController class are also added:
    @Autowired
    private WebApplicationContext webAppContext;
    private final static LocalDateTime startDateTime = LocalDateTime.now();
    private final static DateTimeFormatter DT_FORMATTER =  DateTimeFormatter.ofPattern("EEE, d MMM yyyy h:mm a");
    @RequestMapping("/server")
    @ResponseBody
    public String infoTagServer(){
      return new StringJoiner("<br>")
        .add("-------------------------------------")
        .add(" Server: "+ 
        webAppContext.getServletContext().getServerInfo())
        .add(" Start date: "+ 
        startDateTime.format(DT_FORMATTER))
        .add(" Version: " + 
        webAppContext.getBean("webAppVersion"))
        .add("--------------------------------------")
        .toString();
    }
  24. Now, access the http://localhost:8080/portal/info/server URL with your browser.

    Note

    You should see the following content rendered as an HTML document:

    --------------------------------------------------
    Server: Apache Tomcat/8.0.14
    Start date: Sun, 16 Nov 2014 12:10 AM
    Version: 1.0.0
    ---------------------------------------------------
    

How it works...

We are going to draft an overview of Spring MVC as a Framework. We will then review how a Controller is configured from the DispatcherServlet, the controller-level annotations, and from the method-handler signatures.

Spring MVC overview

Spring MVC implements two common design patterns: the front controller design pattern and the MVC design pattern.

Front controller

A system designed as a Front controller exposes a single entry point for all incoming requests. In Java Web environments, this entry point is usually a servlet—a unique servlet that dispatches and delegates to other components.

Note

In the case of Spring MVC, this unique servlet is the DispatcherServlet.

Servlets are standards in the Java web. They are associated to predefined URL paths and are registered in deployment descriptors (the web.xml files). Parsing deployment descriptors, the servlet-container (such as Apache Tomcat) identifies the declared servlets and their URL mapping. At runtime, the servlet-container intercepts every HTTP client request and creates a new Thread for each one of them. Those Threads will call the matching relevant servlets with Java-converted request and response objects.

MVC design pattern

The MVC design pattern is more of an architectural style. It describes the application as a whole. It encourages a clear separation of concerns between three different layers that the request thread has to pass through: the Model, the View, and the Controller—the Controller, the Model, and then the View to be accurate.

MVC design pattern

When a client request is intercepted by the servlet-container, it is routed to the DispatcherServlet. The DispatcherServlet sends the request to one Controller (one controller method-handler), which has a configuration matching the request state (if a match is found).

The Controller orchestrates the business logic, the model generation and ultimately chooses a View for the model and the response. In this perspective, the model represents a populated data structure handled by the controller and given to the view for visualization purposes.

But the three components (Model, View, and Controller) can also be visualized at a Macro scale as independent static layers. Each of these components is a layer and a placeholder for every individual constituent, part of the category. The Controller layer contains all the registered controllers as well as the Web Interceptors and converters; the Model generation layer (and Business logic layer) contains the business services and data access components. The View layer encloses the templates (JSPs for example) and other web client-side components.

Spring MVC flow

The Spring MVC flow can be represented with the following diagram:

Spring MVC flow

We previously mentioned that Spring MVC implements a front controller pattern. The entry point is the DispatcherServlet. This DispatcherServlet relies on a HandlerMapping implementation. With different strategies and specificities, the HandlerMapping resolves a Controller method-handler for the request.

Once the DispatcherServlet has a Controller method-handler, it dispatches the request to it. The method-handler returns a View name (or directly the View itself) and also the populated model object to the DispatcherServlet.

With a View name, the DispatcherServlet asks a ViewResolver implementation to find and select a View.

With the request, a View, and a Model, the DispatcherServlet has everything to build the client response. The view is processed with all these elements and the response is finally returned to the servlet-container.

DispatcherServlet – the Spring MVC entrypoint

As explained, the DispatcherServlet is quite a central piece in Spring MVC. It intercepts the client requests that target predefined URL paths for the application. It maps them to handlers that belong to business logic operators (Controllers, Interceptors, Filters, and so on). It also provides a set of tools, available as beans for solving recurring web development issues and techniques such as serving a centralized and modular View layer, handling internationalisation, themes, handing exceptions, and so on.

Before everything, the DispatcherServlet is a servlet and is defined as such in the web.xml file with a servlet configuration and its servlet-mapping. The code is as follows:

<servlet>
  <servlet-name>spring</servlet-name>
   <servlet-class>
      org.springframework.web.servlet.DispatcherServlet
  </servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
   <servlet-name>spring</servlet-name>
   	<url-pattern>/*</url-pattern>
</servlet-mapping>

In our application, in the cloudstreetmarket-webapp, the DispatcherServlet is named spring and covers the full context-path of the application: /*.

We have already seen that each DispatcherServlet has a restricted-scope WebApplicationContext that inherits the beans from the root ApplicationContext.

By default, for the WebApplicationContext, Spring MVC looks in the /WEB-INF directory for a configuration file named {servletName}-servlet.xml. We have, however, overridden this default name and location through the initialization parameter contextConfigLocation:

<servlet>
 <servlet-name>spring</servlet-name>
   <servlet-class>
    org.springframework.web.servlet.DispatcherServlet
  </servlet-class>
   <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/dispatcher-context.xml</param-value>
   </init-param>
   <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

Still in the web.xml, you can see that the root application context (classpath*:/META-INF/spring/*-config.xml) starts with the ContextLoaderListener:

<listener>
  <listener-class>
    org.springframework.web.context.ContextLoaderListener
  </listener-class>
</listener>

Annotation-defined controllers

Spring MVC controllers are the place where client requests really start to be processed by the business-specific code. Since Spring 2.5, we have been able to use annotations on controllers so we don't have to explicitly declare them as beans in configuration. This makes their implementation much easier to extend and understand.

@Controller

A @Controller annotation tags a class as a Web controller. It remains a Spring Stereotype for presentation layers. The main purpose of defining a Spring Stereotype is to make a target type or method discoverable during the Spring classpath scanning which is activated by package with the following command:

<context:component-scan base-package="edu.zipcloud.cloudstreetmarket.portal"/>

There is not much custom logic related to this annotation. We could run a Controller with other Stereotype annotations (@Component or @Service) if we don't bother making the application a cleaner place.

@RequestMapping

The @RequestMapping annotations define handlers onto Controller classes and/or onto controller methods. These annotations are looked-up among stereotyped classes by the DispatcherServlet. The main idea behind the @RequestMapping annotations is to define a primary path mapping on the class-level and to narrow HTTP request methods, headers, parameters, and media-types on the methods.

To implement this narrowing, the @RequestMapping annotation accepts comma-separated parameters within parentheses.

Consider the following example:

@RequestMapping(value="/server", method=RequestMethod.GET)

Available parameters for @RequestMapping are summarized in the following table:

Parameter and type

Use/description (from JavaDoc)

name (String)

Assign a name to the mapping.

value (String[])

The path mapping URIs (for example, /myPath.do). Ant-style path patterns are also supported (for example, /myPath/*.do).

Path mapping URIs may contain placeholders (for example, /${connect}) against local properties and/or system properties and environment variables.

A path implements URI templates that give access to selected parts of a URL through patterns, variables, placeholders, and matrix variables (see section URI Templates).

At the method level, relative paths (for example, edit.do) are supported within the primary mapping expressed at the type level.

method

(RequestMethod[])

GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE.

params (String[])

A sequence of myParam=myValue style expressions.

Expressions can be negated using the != operator,as in myParam!=myValue.

headers (String[])

A sequence of My-Header=myValue style expressions.

Specifying only the header name (for example, My-Header) is supported (allowed to have any value).

Negating a header name (for example, "!My-Header") is also supported (the specified header is not supposed to be present in the request).

Also supports media type wildcards (*), for headers such as Accept and Content-Type.

consumes (String[])

The consumable media types of the mapped request.

Only mapped if the {@code Content-Type} matches one of these media types.

Negating an expression (for example, !text/xml) is also supported.

produces (String[])

The producible media types of the mapped request.

Only mapped if the {@code Accept} matches one of these media types.

Negating an expression (for example, !text/plain) is also supported. It matches all requests with a {@code Accept} other than "text/plain".

All these parameters can be used both at the type and method level. When used at the type level, all method-level parameters inherit the parent-level narrowing.

Controller method-handler signatures

Several constituents make a Controller method-handler. Here's another example of such a handler with Spring MVC:

@RequestMapping(value="/index")
public ModelAndView getRequestExample(ServletRequest request){
    ModelAndView mav = new ModelAndView();
    mav.setViewName("index");
    mav.addObject("variable1", new ArrayList<String>());
    return mav;
}

We have just talked about how to use the @RequestMapping annotation. With regard to the method signature, this annotation can only be placed before the return-type.

Supported method arguments types

Declaring specific types of arguments for handler methods can get Spring to automatically inject in them references to external objects. Objects related to the request lifecycle, the session, or to the application configuration. With the benefit of being scoped for the method, those argument types are presented in the following table:

Supported arguments

Use/description

Packages

ServletRequest /

HttpServletRequest

Injects the servlet request/response.

javax.servlet.http.*

ServletResponse /

HttpServletResponse

HttpSession

Injects the HTTP session bound to the servlet request. If null, Spring creates a new one.

synchronizeOnSession must be set on an AbstractController or in RequestMappingHandlerAdapter if sessions should be shared

concurrently across multiple requests.

WebRequest / NativeWebRequest

Injects a wrapper for access to request parameters and request/session attributes only.

org.springframework.web.context.request.*

Locale

Injects the local e of the request using the configured LocaleResolver.

java.util.*

InputStream / Reader

Provides a direct access to the request/response payload.

java.io.*

OutputStream / Writer

HttpMethod

Injects the current method of the request.

org.springframework.http.*

Principal

Using the Spring security context, it injects the authenticated account.

java.security.*

HttpEntity<?>

Spring converts and injects the inbound request to a custom type using HttpMessageConverter. It also provides access to the request headers.

org.springframework.http.*

Map

Instantiates for us a BindingAwareModelMap to be used in the view.

java.util.*

Model

org.springframework.ui.*

ModelMap

RedirectAttributes

Injects and repopulates a map of attributes and flash attributes maintained over request redirection

org.springframework.web.servlet.mvc.support.*

Errors

Injects the validation results of the argument located just before in the argument list.

org.springframework.validation.*

BindingResult

SessionStatus

Allows tagging with setComplete(Boolean), the completion of a session. This method clears the session attributes defined at the type level with @SessionAttributes.

org.springframework.web.bind.support.*

UriComponentsBuilder

Injects a Spring URL builder UriComponentsBuilder.

org.springframework.web.util.*

Supported annotations for method arguments

A set of native annotations for method-handler arguments has been designed. They must be seen as handles that configure the web behavior of controller methods in regard to incoming requests or the response yet to be built.

They identify abstractions for handy Spring MVC functions such as request parameter binding, URI path variable binding, injection-to-argument of request payloads, HTML form-parameter binding, and so on.

Supported annotation arguments

Use/description

Package

@PathVariable

Injects an URI Template variable into an argument.

org.springframework.web.bind.annotation.*

@MatrixVariable

Injects name-value pairs located in URI path segments into an argument.

@RequestParam

Injects a specific request parameter into an argument.

@RequestHeader

Injects a specific request HTTP Header into an argument.

@RequestBody

Allows direct access to the request payload injecting it into an argument.

@RequestPart

Injects the content of a specific part (meta-data, file-data…) of a multipart/form-data encoded request into an argument of the matching type (MetaData, MultipartFile…)

@ModelAttribute

Populates automatically an attribute of the Model using the URI template.

This binding is operated before the method handler processing.

These annotations have to be placed just before the method argument to be populated:

@RequestMapping(value="/index")
public ModelAndView getRequestExample(@RequestParam("exP1") String exP1){
   ModelAndView mav = new ModelAndView();
   mav.setViewName("index");
   mav.addObject("exP1", exP1);
   return mav;
}

Supported return Types

Spring MVC, with different possible controller method return Types, allows us to specify either the response sent back to the client or the necessary configuration for targeting or populating with variables an intermediate View layer. Depending upon what we want to do or the actual application state, we have the choice among the following:

Supported return Types

Use/description

Packages

Model

Spring MVC creates an implementation of the Model Interface for the handler method.

The Model objects are populated manually within the handler- method or with @ModelAttribute.

The view to render needs to be mapped to the request with RequestToViewNameTranslator.

org.springframework.ui.*

ModelAndView

A wrapper object for the Model with a View and a view name. If a view name is provided, Spring MVC will attempt to resolve the associated View. Otherwise, the embedded View is rendered.

The Model objects are populated manually within the method or with @ModelAttribute.

Map

Allows a custom Model implementation.

The view to render needs to be mapped to the request with RequestToViewNameTranslator.

java.util.*

View

Allows the rendering of a custom View object.

Spring MVC creates an implementation of the Model interface for the handler method.

The objects of the model are populated manually within the method or with the help of @ModelAttribute.

org.springframework.web.servlet.*

String

If a @ResponseBody annotation is not specified on the handler method, the returned String is processed as a View name (View identifier).

java.lang.*

HttpEntity<?> / ResponseEntity<?>

Two wrapper objects to easily manage the response headers and converted-by-Spring body (with HttpMessageConverters).

org.springframework.http.*

HttpHeaders

Provides a wrapper object for HEAD responses.

org.springframework.http .*

Callable<?>

Can produce asynchronously a typed object when the Thread is controlled by Spring MVC.

java.util.concurrent.*

DeferredResult<?>

Can produce asynchronously a Typed object when the Thread is not controlled by Spring MVC.

org.springframework.web.context.request.async.*

ListenableFuture<?>

org.springframework.util.concurrent.*

void

When the view is externally resolved with RequestToViewNameTranslator or when the method prints directly in the response.

 

There's more...

In the InfoTagController.infoTagServer() method-handler, we have used the @ResponseBody annotation before the return Type. This annotation has been borrowed from the REST-specific tools. When you don't need to process a View, the @ResponseBody directive will use the registered Spring converters to marshal the returned object into the expected format (XML, JSON, and so on). It will then write the marshalled content to the Response body (as the Response payload).

In the case of a String object with no more configurations, it is printed out as such in the Response body. We could have used the ResponseEntity<String> return Type to achieve the same goal.

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

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