• No results found

Spring Mobile technology preview

In document Spring (Page 118-128)

Building web applications with Spring Web MVC

3.6 Spring Mobile technology preview

Up to this point, we’ve focused on using Spring MVC to create normal web applica-tions. But what if you were asked to extend the capabilities of an existing Spring MVC application to provide a more customized user experience for mobile users or to create a completely new application that specifically targets mobile devices? In addition to detecting mobile devices, one of the most concerning problems that mobile web applications face is that both the screen size and capabilities of the each web browser vary significantly among today’s smartphone, PDA, tablet, and other mobile devices.

The Spring Mobile project provides extensions to Spring MVC for developing mobile web applications and offers server-side device detection, site preference man-agement, and site-switcher functionality out of the box. This gives you all the founda-tional tools necessary to enhance an existing web application or create a web application that provides a more customized user experience that mobile visitors will find more enjoyable and intuitive to use.

The Spring Mobile project provides two approaches for handling mobile devices:

Determine the type of device that initiated a web request. Provide the informa-tion to a web applicainforma-tion’s runtime that would provide the opportunity to cus-tomize its user experience. For example, you could cuscus-tomize the layout, Cascading Style Sheets (CSS), and JavaScript based on this information.

Determine the type of device that initiated a web request. Redirect the user to a separate site that caters specifically to mobile devices. A common pattern is to redirect users of mysite.com to domains such as m.mysite.com or mysite.mobi where the content is designed specifically for mobile devices.

The ability to detect a mobile device is something that is common to both approaches. We’ll take a deeper dive into the anatomy of an HTTP request in the next section. In the pages that follow, you’ll create a trivial Contact List sample application

that will demonstrate the first approach to handling mobile devices. At its core, this application is similar to the Spring MVC Roster sample application covered in sec-tion 3.2. As such, the process of constructing master/detail views in Spring MVC should already be familiar. You should focus on how easy it is to use Spring Mobile and a JavaScript library to create an interface that will be recognizable to existing smartphone users. Instead of building a full-blown application, we’ll focus on build-ing out the pieces that illustrate detectbuild-ing a mobile device as well as managbuild-ing site preferences (full versus mobile). Before we conclude our preview of Spring Mobile, we’ll show you the configuration required to implement the second approach to han-dling mobile devices.

As of this writing, Spring Mobile version 1.0.0.RC1 has been released. A word of warning: although the changes to the API have slowed considerably, additional changes may still occur before Spring Mobile finally becomes generally available. You can download the source code for this working application here: https://

github.com/springinpractice/sip03, branch 03. Let’s get started by talking about how mobile devices are detected on the server side using Spring Mobile.

3.6.1 A brief anatomy of an HTTP request

Spring Mobile’s DeviceResolvers use information present in an HTTP request to sniff out the presence of a mobile device. To give you an idea of how this works and what this information looks like, let’s look at how a typical HTTP request is made.

HTTP, like most network protocols, uses a client-server communication model. An HTTP client opens a connection and sends a request message to an HTTP server. The server then returns a response message that normally contains the resource that was originally requested. After the response is completed, the server closes the connection.

If you were to open your browser and type in http://www.google.com and press Enter, your browser would create a request message that looks something like this:

GET / HTTP/1.1 Host: www.google.com

User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:6.0.2) Gecko/20100101 Firefox/

6.0.2

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5

Accept-Encoding: gzip, deflate

Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive

In the first line of this message, you define that you’re using the GET HTTP method to obtain the resource at / and that you’re using HTTP 1.1. Following this initial request line is a list of header lines. Each line defines a header in the format Header-Name:

value. Note that in some cases, a header can have multiple values and span multiple lines. In addition, when using HTTP 1.1, only the Host header is required. This means all the other headers are optional.

The important header to focus on here is User-Agent. It identifies the program that is making the request. In the example, we used Firefox version 6.0.2 on Windows

NT 5.1 (Windows XP). If we were to make the same request using an iPhone, the User-Agent header might look like this:

User-Agent: Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_10 like Mac OS X;

en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8E600 Safari/6533.18.5

In the sample User-Agent header, you can now tell that the platform has changed from Windows NT 5.1 to iPhone. Each device leaves its own request fingerprint that may consist of information from only the User-Agent header or from a combination of information in the HTTP request. As you’ll see next, you don’t necessarily need to own or have access to these devices to get started developing mobile web applications.

SIMULATING A MOBILE DEVICE

Several browser-based plug-ins/extensions provide the ability to switch the User-Agent header that is supplied by the browser. For example, User Agent Switcher, a Firefox extension, provides a menu and toolbar button to switch the user agent of a browser to any number of values simulating mobile devices. This is useful for develop-ment and testing. If you’ll only be deploying the sample Contact List application to your desktop, you’ll need this or a similar plug-in for testing.

Now that you have an idea of the information available in an HTTP request and a mechanism to manipulate it, let’s see how Spring Mobile detects a mobile device.

3.6.2 Detecting a mobile device with Spring Mobile

Spring Mobile’s server-side device resolution functionality is based primarily on two interfaces, DeviceResolver and Device. The DeviceResolver interface attempts to determine which device created the current web request. We have omitted the com-ments in the code sample for brevity.

public interface DeviceResolver {

Device resolveDevice(HttpServletRequest request);

}

The default implementation of the DeviceResolver interface is the LiteDevice-Resolver, which attempts to detect the presence of a mobile device based on informa-tion in the request headers. LiteDeviceResolver looks for clues such as the use of the Wireless Access Protocol (WAP) or by comparing the contents of the User-Agent header to a list of 90 or so keywords or prefixes. For example, LiteDeviceResolver would find the keyword phone in the iPhone User-Agent string (case-insensitive) we dis-cussed earlier. Just as the name implies, LiteDeviceResolver only aims to determine if the device that created the current request is a mobile device. LiteDeviceResolver returns an instance of LiteDevice, which implements the Device interface:

public interface Device { boolean isMobile();

}

For more information, look at the WurflDeviceResolver. WURFL stands for Wireless Universal Resource FiLe and is a community effort focused on mobile device detection.

This DeviceResolver implementation provides specific device and feature informa-tion (screen size and other device specific capabilities).

Now that we’ve talked about Spring Mobile’s server-side device-resolution functional-ity, let’s get started building an example application.

3.6.3 Configuring Spring Mobile

Because Spring Mobile is an extension of Spring MVC, configuring the Contact List application will be a breeze. You start by configuring the Spring MVC DispatcherServlet in the web.xml file.

<?xml version="1.0" encoding="UTF-8"?>

<!-- Source project: sip03, branch: 03 (Maven Project) -->

<web-app

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns="http://java.sun.com/xml/ns/javaee"

xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">

<servlet>

<servlet-name>main</servlet-name>

<servlet-class>

org.springframework.web.servlet.DispatcherServlet </servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>main</servlet-name>

<url-pattern>/main/*</url-pattern>

</servlet-mapping>

</web-app>

As we talked about earlier, when configuring DispatcherServlet, Spring looks for a file in the WEB-INF directory of the web application by the name of main-servlet.xml

B

, unless a different name and location are explicitly configured. Let’s look at this file now.

Listing 3.12 web.xml

A quick note about WurflDeviceResolver

WurflDeviceResolver was originally part of the Spring Mobile project. It was re-moved after WURFL, which used to be free and open source software (FOSS), was changed to an AGPL license as of version 2.2. The original support for WURFL has been factored out of the Spring Mobile distribution and placed here: https://

github.com/kdonald/wurfl-spring. The team is currently looking to contribute this in-tegration to the official WURFL project.

Configures DispatcherServlet

B

<?xml version="1.0" encoding="UTF-8"?>

<!-- Source project: sip03, branch: 03 (Maven Project) -->

<beans:beans xmlns="http://www.springframework.org/schema/mvc"

<beans:bean class="org.springframework.mobile.device.

DeviceResolverHandlerInterceptor" />

</interceptors>

<resources mapping="/resources/**" location="/resources/" />

<beans:bean class="org.springframework.web.servlet.view.

InternalResourceViewResolver">

<beans:property name="viewClass"

value="org.springframework.web.servlet.view.JstlView"

/>

<beans:property name="prefix" value="/WEB-INF/jsp/" />

<beans:property name="suffix" value=".jsp" />

</beans:bean>

<context:component-scan base-package="com.springinpractice.ch03" />

</beans:beans>

The thing added in the Contact List application above and beyond a vanilla Spring MVC configuration is the DeviceResolverHandlerInterceptor at

B

. We talked about HandlerInterceptors in section 3.5.1. In short, HandlerInterceptors behave much like servlet filters. In this case, the preHandle() method of DeviceResolverHandler-Interceptor delegates to a DeviceResolver to resolve the device that originated the current request.

By default, DeviceResolverHandlerInterceptor delegates to a LiteDevice-Resolver that resolves the device to a LiteDevice. If you wanted to use the Wurfl-DeviceResolver we talked about earlier, you would inject this device resolver’s implementation into the HandlerInterceptor via constructor injection.

Based on this configuration alone, you can now detect when a mobile device is requesting a resource from the Contact List application. In the code, you can obtain a reference to the current device by using the DeviceUtils class:

Listing 3.13 main-servlet.xml

Configures DeviceResolverHandlerInterceptor

B

Configures InternalResourceViewResolver

Device device = DeviceUtils.getRequiredCurrentDevice(servletRequest);

if (device.isMobile()) { //Do something

}

If you want to have the Device passed in as an argument to one of your @Controller methods, you can configure a WebArgumentResolver. This is a Spring MVC feature that is new in version 3.1. You can do this by adding the following to the main-servlet.xml file.

<annotation-driven>

<argument-resolvers>

<beans:bean class="org.springframework.mobile.device.

DeviceWebArgumentResolver" />

<beans:bean class="org.springframework.mobile.device.site.

SitePreferenceWebArgumentResolver" />

</argument-resolvers>

</annotation-driven>

You configure two different WebArgumentResolvers. The DeviceWebArgument-Resolver

B

allows you to pass in the current device in your @Controller method like this:

@Controller

@RequestMapping("/contact")

public final class ContactController { ...

@RequestMapping("/list")

public void list(Model model, Device device) { if (device.isMobile()) {

//Do something }

} ...

We’ll talk more about the SitePreferenceArgumentResolver

C

in the next section.

Now that you have the ability to detect mobile devices in the Contact List applica-tion using Spring Mobile’s server-side device detecapplica-tion, you can control the user expe-rience based on this knowledge. For example, to optimize a user’s mobile expeexpe-rience, it’s possible to redirect the user to a mobile-specific version of the site. In most cases, this site may be a thinned-down version of the original site to accommodate a device’s smaller screen size. But what if the end user wants to visit the normal site?

3.6.4 Handling site preferences

The Spring Mobile team has provided a facility to handle user site preference man-agement as well. The code uses a pattern similar to the server-side device-detection

Listing 3.14 Configuring WebArgumentResolvers

Configures DeviceWeb-ArgumentResolver

B

Configures SitePreferenceWebArgumentResolver

C

code we talked about earlier. This time, instead of talking about DeviceResolverHan-dlerInterceptor, DeviceResolver, and Device, we’re talking about SitePrefer-enceHandlerInterceptor, SitePreferenceHandler, and SitePreference.

The SitePreferenceHandlerInterceptor is added to your configuration after the DeviceResolverHandlerInterceptor at

B

in listing 3.13. This interceptor delegates to an instance of SitePreferenceHandler. The default implementation, Standard-SitePreferenceHandler, checks to see if a user specified a SitePreference. If not, its value defaults to MOBILE if a mobile device has been detected or NORMAL if not. By default, this value is stored using the CookieSitePreferenceRepository, which is the default implementation of SitePreferenceRepository.

StandardSitePreferenceHandler supports query-parameter-based site-preference switching. For example, the following code can be used to set a user’s site preference:

<c:if test="${currentDevice.mobile}">

<c:choose>

<c:when test="${currentSitePreference.mobile}">

<a href="${currentUrl}?site_preference=normal">

Switch To: Normal Site </a>

</c:when>

<c:otherwise>

<a href="${currentUrl}?site_preference=mobile">

Switch To: Mobile Site </a>

</c:otherwise>

</c:choose>

</c:if>

Configuring site preference management is similar to configuring Spring Mobile’s server-side device detection. To configure the site-preference management in the Contact List application, you need to add the SitePreferenceHandlerInterceptor right after the DeviceResolverHandlerInterceptor in your main-servlet.xml file:

<interceptors>

<beans:bean

class="org.springframework.mobile.device.

DeviceResolverHandlerInterceptor" />

<beans:bean

class="org.springframework.mobile.device.site.

SitePreferenceHandlerInterceptor" />

</interceptors>

Based on this single configuration change, you can now detect an end-user’s explicit or default site preference when a resource is requested from your application. In your code, you can obtain a reference to the current device by using the SitePreferen-ceUtils class:

SitePreference sitePreference = SitePreferenceUtils

.getCurrentSitePreference(servletRequest);

if (SitePreference.MOBILE == sitePreference) { //Do something

}

Similar to how you handled the Device earlier, if you want the SitePreference passed in as an argument to one of your @Controller methods, you can configure an addi-tional WebArgumentResolver as seen at

C

in listing 3.14 to the main-servlet.xml file.

The SitePreferenceWebArgumentResolver allows you to pass in the current device in your @Controller method like this:

@Controller

@RequestMapping("/contact")

public final class ContactController { ...

@RequestMapping("/list")

public void list(Model model, SitePreference sitePreference) { if (SitePreference.MOBILE == sitePreference) {

//Do something }

} ...

The Contact List application is taking shape. You can now detect if a mobile device is accessing your site, and a mechanism lets users manage their own site preference (full versus mobile). This gives you the information you need to make decisions about how you might want to customize your site to provide a more enjoyable and intuitive user experience for your mobile visitors. In the next section, we’ll look at how you can use a JavaScript framework to do just this.

3.6.5 Using JavaScript frameworks for enhanced look and feel

The beauty of mobile JavaScript frameworks is that they let you use the HTML 5, CSS3, and JavaScript skills you already have. These frameworks offer an abstraction layer that simplifies mobile web development by providing a collection of cross-browser UI elements/widgets that often mimic the native device’s look and feel as well as a unified way to access native mobile OS features.

In the Contact List sample application, we chose to use jQuery Mobile (http://jquerymobile.com/). jQuery Mobile is a touch-optimized web framework for smart-phones and tablets that is built on top of jQuery and jQuery UI. Measuring in at 12 KB, the framework is relatively light-weight, a feature that is important for devices that may have limited bandwidth. Based on figures 3.4 and 3.5, you can see how you can turn normal HTML 5 into something that closely resembles a mobile devices look and feel.

To experiment with this trivial sample application and see all the items we talk about in action, download and

Figure 3.4 The Contact List sample application when viewed by a normal browser

run the source code for this chapter and point your browser to http://local-host:8080/sip/main/contact/list. As shown in figure 3.4, in a normal browser you see a rather vanilla-looking list of contacts.

When you view the same address using a mobile device browser or normal browser with a user-agent switcher to mimic a mobile device, you’ll see the view shown in fig-ure 3.5.

Figure 3.5 The Contact List sample application when viewed by a mobile device

As we mentioned at the beginning of section 3.6, Spring Mobile provides two different approaches to handling mobile devices. Although trivial, the Contact List sample application you just finished demonstrates how Spring Mobile can provide the infor-mation necessary to a web application’s runtime that can allow you to customize the layout, CSS, and JavaScript based on the type of device accessing the site. Before we conclude our Spring Mobile preview, let’s look at the out-of-the-box site-switching functionality that Spring Mobile provides. This secondary approach can be useful when you would like to detect mobile users and redirect them to an entire site that might be designed specifically to cater to the needs of mobile users. Let’s look at this additional approach next.

3.6.6 Switching to a separate mobile site

As opposed to using SitePreferenceHandlerInterceptor to manage preferences within the same site, you can use SiteSwitcherHandlerInterceptor to redirect mobile users to a separate site.

SiteSwitcherHandlerInterceptor provides convenient factory methods out of the box to handle redirecting users to either a site with an “m.” subdomain (such as m.yourdomain.com) or a “.mobi” top-level domain (TLD) (yourdomain.mobi). An example of each is provided in the following sections. Keep in mind that SiteSwitch-erHandlerInterceptor delegates to a SitePreferenceHandler internally so there is no need to configure a SitePreferenceHandlerInterceptor explicitly.

MDOT SITESWITCHER

You can use the mDot factory method to create an instance of the SiteSwitcherHan-dlerInterceptor that redirects users to a domain in the format m.yourdomain.com:

<interceptors>

<beans:bean class="org.springframework.mobile.device.

DeviceResolverHandlerInterceptor"/>

<beans:bean class="org.springframework.mobile.device.switcher.

SiteSwitcherHandlerInterceptor" factory-method="mDot">

<beans:constructor-arg value="yourdomain.com"/>

</beans:bean>

</interceptors>

DOTMOBI SITESWITCHER

You can use the dotMobi factory method to create an instance of SiteSwitcherHan-dlerInterceptor that redirects users to a domain in the format yourdomain.mobi:

<interceptors>

<beans:bean class="org.springframework.mobile.device.

DeviceResolverHandlerInterceptor"/>

<beans:bean class="org.springframework.mobile.device.switcher.

SiteSwitcherHandlerInterceptor" factory-method="dotMobi">

<beans:constructor-arg value="yourdomain.com"/>

<beans:constructor-arg value="yourdomain.com"/>

In document Spring (Page 118-128)