Configuring a fallback controller using ViewResolver

This recipe introduces some more advanced concepts and tools related to Controllers such as ViewResolvers, URI Template Patterns, and Spring MVC's injection-as-argument. The recipe is quite simple but there is more to talk about.

Getting ready

We will keep working from the same codebase state as the previous recipe where we have pulled the v2.2.1 tag from the remote repository. It will only be about creating one Controller with its handler method.

How to do it...

  1. In the cloudstreetmarket-webapp module and in the package edu.zipcloud.cloudstreetmarket.portal.controllers, the following DefaultController has been created:
    @Controller
    public class DefaultController {
      @RequestMapping(value="/*", method={RequestMethod.GET,RequestMethod.HEAD})
      public String fallback() {
        return "index";
      }
    }

    Note

    We will explain in detail how this method-handler serves as a fallback interceptor.

  2. Access the http://localhost:8080/portal/whatever or http://localhost:8080/portal/index URL with your browser.

    You should also receive the HTML content we saw earlier:

    How to do it...

How it works...

This second recipe revisits the use of the @RequestMapping annotation. With no longer a fixed URI as a path value but with an opened-pattern (fallback). The recipe also makes use of the configured View resolver that we didn't use before.

URI template patterns

The template word is recurring in the Spring terminology. It usually refers to generic support Spring APIs to be instantiated in order to fill specific implementations or customisations (REST template to make REST HTTP requests, JMS template to send JMS messages, WS template to make SOAP webservices requests, JDBC template, and so on). They are bridge the developer needs to Spring core features.

Under this light, URI templates allow configuring generic URIs with patterns and variables for controller end points. It is possible to instantiate URI builders that will implement URI templates but developers probably mostly use URI templates in the support they provide to @RequestMapping annotations.

Ant-style path patterns

We have made use of these types of pattern to define the path value for our fallback handler method:

@RequestMapping(value="/*", ...)

This specific case, with the * wildcard, allows whichever request URI starts with a / after the application display name to be eligible for being handled by this method.

The wildcard can match a character, a word, or a sequence of words. Consider the following example:

/portal/1, /portal/foo, /portal/foo-bar

A limitation would be to use another slash in the last sequence:

/portal/foo/bar

Remember the difference with the table here:

/*

All resources and directories at the level

/**

All resources and directories at the level and sublevels

We have been using the single wildcard on purpose in the cloudstreetmarket-webapp application. It might be more suited for other types of applications to redirect every unmatched URI to a default one. In our case of a single page application that will be strongly REST oriented, it is nicer to inform the client with a 404 error when a resource hasn't been found.

It is not the only option to use wildcards at the end of path patterns. We could have implemented the following type of pattern if needed:

/portal/**/foo/*/bar  	

(not for fallback purposes, though).

We will see that Spring MVC, to select one handler compares, all the matching Path patterns and selects the most specific of them.

Tip

At the Controller type-level, we haven't specified a @RequestMapping. If we had done so, the specified path for the method-level would have been concatenated to type-level one (implementing a narrowing).

For example, the following definition would have defined the path pattern /portal/default/* for our fallback controller:

@RequestMapping(value="/default"...)
@Controller
public class DefaultController…{
      @RequestMapping(value="/*"...)
      public String fallback(Model model) {...}
}

Path pattern comparison

A pathpattern comparison is done by Spring MVC when a given URL matches more than one registered path-pattern, to choose which handler the request will be mapped to.

Note

The pattern considered the most specific will be selected.

The first criterion is the number of counted variables and wildcards in the compared path patterns: the pattern having the lowest number of variables and wildcards is considered the most specific.

To discriminate two path-patterns that have the same cumulated number of variables and wildcards, remember that the one with the lowest number of wildcards will be the most specific and then the longest path will be the most specific.

Finally a pattern with double wildcards is always less specific than a pattern without any.

To illustrate this selection, let's consider the following hierarchy going from the most to the least specific:

/portal/foo

/portal/{foo}

/portal/*

/portal/{foo}/{bar}

/portal/default/*/{foo}

/portal/{foo}/*

/portal/**/*

/portal/**

ViewResolvers

In dispatcher-context.xml of cloudstreetmarket-webapp, we have defined the viewResolver bean:

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
  <property name="prefix" value="/WEB-INF/jsp/" />
  <property name="suffix" value=".jsp" />
</bean>

A viewResolver bean is a specific instance of a predefined class used to serve an organized and uniform set of view layers. In the case that we have configured, the viewResolver bean is an instance of InternalResourceViewResolver, which can serve JSP pages, handle the JSTL and tiles. This class also inherits UrlBasedViewResolver that can navigate the application resources and can bind a logical view name to a View resource file. This capability prevents the creation of extramappings.

In our configuration, we have defined the view repository (/WEB-INF/jsp/*.jsp) and we can directly refer to index.jsp with the String index.

It is better practice to set up the JSP repository under /WEB-INF so those JSPs cannot be targeted publicly. Rather than a JSP templating, we could have used Velocity or Freemarker respectively using the view resolvers VelocityViewResolver or FreeMarkerViewResolver.

Also, we will talk about the ContentNegotiatingViewResolver later on when we build the REST API.

There's more...

This section highlights particularly the @PathVariable annotation. This annotation is an annotation for controller method-handler arguments (we have introduced all of them in the previous recipe).

@PathVariable to read variables in URI template patterns

You will find later, on several examples, the method-level @RequestMapping annotations . Those annotations will sometimes be related to @PathVariable annotations on the method-handler arguments. For now, let's consider the following example:

@RequestMapping(value="/example/{param}")
public HttpEntity<String> example(@PathVariable("param") String parameter) {
  return new HttpEntity<>(parameter);
}

As announced before, @PathVariable tells Spring MVC where and how to realize its injection-as-argument from the request URI. The framework will parse the current URI Template pattern to extract the variable named param and will inject the matching value in the current URI into the targeted method-argument.

We also declare an HTTPEntity to be returned as a response. This HTTPEntity will be a wrapper of a String generic type. Inside the method-handler, we instantiate this wrapper with the necessary String element.

If we would call for the /portal/example/foo URI, it would be displayed as a response from the body of the returned HTTPEntity: the String foo.

With another interesting feature, we could have built this last scenario with the following declaration for @PathVariable:

@RequestMapping(value="/example/{param}")
public HttpEntity<String> example(@PathVariable String param) {
  return new HttpEntity<>(param);
}

Tip

Not providing a value to the annotation, Spring MVC will by default look in the URI Template pattern for a variable of the same name as the targeted argument.

We will explore other features with regard to @RequestMapping and @PathVariable.

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

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