Spring Mobile is an extension to Spring MVC for development of mobile web applications. The Spring Mobile Device module provides a feature (DeviceResolver / LiteDeviceResolver) to detect devices like mobile and tablet in the server side.
Device aware view management is very useful specially when it is required to serve different optimized versions of same website based on request generating device type or specific devices.
Another feature called site preference management allows user to set his / her preference (SitePreference) to view a particular site in either "normal", "mobile" or "tablet" mode from a particular device.
Spring mobile also provides different types of site switchers (like mDot, dotMobi and urlPath SiteSwitcher) which automatically redirect users to the device specific site based on the device generating the request and site preference set by the user.

Tools and Technologies used in this article

  1. Spring Mobile 1.1.0.M2 Released
  2. Spring Tool Suite 3.1
  3. JDK 1.6
  4. Tomcat 7

Note:  Spring 3 requires at least JDK 5. So, make sure you have JDK 5 or above.

1. Create a Java Web Project using m2e

Select from the menu File --> New --> Other --> Maven --> Maven Project. Browse to the workspace location and click 'Next' button.
Select project name and location

Type 'webapp' in the 'Filter' field and select archetype 'maven-archetype-webapp' to generate a simple java web application using Maven. Click 'Next' button.
Select an Archetype

Specify archetype parameters (Group Id, Artifact, Version and Package) and click 'Finish' button.
Specify Archetype parameters

2. Add Project Dependencies in pom.xml

Add Spring MVC and Spring Mobile dependencies in Maven pom.xml.

File: pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.srccodes.spring</groupId>
    <artifactId>SpringMobileHelloWorld</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>SpringMobileHelloWorld Maven Webapp</name>
    <url>http://maven.apache.org</url>
  
    <properties>
        <org.springframework.version>3.2.0.RELEASE</org.springframework.version>
        <spring-mobile-device-version>1.1.0.M2</spring-mobile-device-version>
    </properties>
  
    <dependencies>
        <!-- Spring MVC depends on spring-core, spring-beans, spring-context, spring-web -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
         
        <dependency>
            <groupId>org.springframework.mobile</groupId>
            <artifactId>spring-mobile-device</artifactId>
            <version>${spring-mobile-device-version}</version>
        </dependency>
    </dependencies>
     
    <repositories>
        <repository>
            <id>spring-milestone</id>
            <name>SpringSource Milestone Repository</name>
            <url>http://repo.springsource.org/milestone</url>
        </repository>
    </repositories>
     
    <build>
        <finalName>SpringMobileHelloWorld</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Note:
Spring MVC depends on spring-core, spring-beans, spring-context, spring-web. If we add 'spring-webmvc' dependency in pom.xml then all the required dependencies / libraries will be automatically downloaded and added to the project's classpath by Maven. We also need to add 'SpringSource Milestone Repository' as we have used milestone version (1.1.0.M2) of spring-mobile-device module.

3. Controller Class and Request Mapping

Create a spring controller class called SpringMobileHelloController in package 'com.srccodes.spring.controller' and copy following code into it.

File: SpringMobileHelloController.java

package com.srccodes.spring.controller;
 
 
import java.util.logging.Logger;
 
import org.springframework.mobile.device.Device;
import org.springframework.mobile.device.site.SitePreference;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
 
/**
 * @author Abhijit Ghosh
 * @version 1.0
 */
@Controller
public class SpringMobileHelloController {
    private static final Logger logger = Logger.getLogger(SpringMobileHelloController.class.getName());
     
    @RequestMapping("/")
    public String sayHello(SitePreference sitePreference, Device device, Model model) {
        logger.info("SitePreference : " + sitePreference);
        logger.info("Device : " + device);
         
        model.addAttribute("message", "Hello World!");
         
        return "helloWorld";
    }
}

@Controller annotation indicates that this class serves the role of a controller. The Servlet dispatcher scans @Controller annotated Controller classes for mapped handler methods and detects @RequestMapping annotations.
@RequestMapping annotation specifies that this handler method will process all requests beginning with '/' in the URL and return the logical view name.
'org.springframework.ui.Model' object is a map which is passed by the Spring container while invoking the handler method 'printHelloWorld'. The message string 'Hello World!' has been added to 'Model' object against the key 'message'. This model object is available in the view. We can use the key 'message' to get the value and display the same in the UI.

Note:
To pass current SitePreference and Device as arguments to @Controller method 'sayHello', it is required to configure (Step #5) SitePreferenceWebArgumentResolver and DeviceWebArgumentResolver in spring configuration file.

4. Create a JSP page as View

Now we need to create three helloWorld.jsp pages one under each of 'WEB-INF/pages', 'WEB-INF/pages/m' and 'WEB-INF/pages/t' directories for normal, mobile and tablet device view.

File: WEB-INF/pages/helloWorld.jsp

<html>
<title>Site for Desktop</title>
<body>
    <h2>${message}</h2>
    <br/>
    Site preference: ${currentSitePreference} | ${currentDevice}
    <br/><br/>
    View: <a href="?site_preference=tablet">Tablet</a> | <a href="?site_preference=mobile">Mobile</a>
</body>
</html>

File: WEB-INF/pages/t/helloWorld.jsp

<html>
<title>Site for Mobile</title>
<body>
    <div style="width:320px; height: 480px;background-color:#fff4c8;vertical-align:top;border-radius:10px;margin:3px;padding:7px">
        <h2>${message}</h2>
        <br/>
        Site preference: ${currentSitePreference} | ${currentDevice}
        <br/><br/>
        View: <a href="?site_preference=tablet">Tablet</a> | <a href="?site_preference=normal">Normal</a>
    </div>
</body>
</html>

File: WEB-INF/pages/t/helloWorld.jsp

<html>
<title>Site for Tablet</title>
<body>
    <div style="width:800px; height: 480px;background-color:#CEECF5;vertical-align:top;border-radius:10px;margin:3px;padding:7px">
        <h2>${message}</h2>
        <br/>
        Site preference: ${currentSitePreference} | ${currentDevice}
        <br/><br/>
        View: <a href="?site_preference=normal">Normal</a> | <a href="?site_preference=mobile">Mobile</a>
    </div>
</body>
</html>

Note:
currentSitePreference is the name of the request attribute that holds the current user's site preference. currentDevice is the name of the request attribute that holds the device that originated the web request. Site preference can be changed by passing different value (e.g. normal, mobile and tablet) in site_preference request parameter.

5. Add Spring Configuration File

Create an xml file called dispatcher-servlet.xml under 'WEB-INF' directory and copy the following content.

File: dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
         
    <context:component-scan base-package="com.srccodes.spring.controller" />
 
    <mvc:annotation-driven>
        <mvc:argument-resolvers>
            <bean class="org.springframework.mobile.device.site.SitePreferenceWebArgumentResolver" />           
            <bean class="org.springframework.mobile.device.DeviceWebArgumentResolver" />
        </mvc:argument-resolvers>
    </mvc:annotation-driven>
      
    <mvc:interceptors>
        <!-- Resolve the device which has generated the request -->
        <bean class="org.springframework.mobile.device.DeviceResolverHandlerInterceptor" />
     
        <!-- User's site preference -->
        <bean class="org.springframework.mobile.device.site.SitePreferenceHandlerInterceptor" />
     
        <!-- Redirects users to the device specific site -->
        <bean class="org.springframework.mobile.device.switcher.SiteSwitcherHandlerInterceptor" factory-method="urlPath">
            <constructor-arg value="/m" />
            <constructor-arg value="/t" />
            <constructor-arg value="/SpringMobileHelloWorld" />
        </bean>
    </mvc:interceptors>
     
    <!-- Device aware view resolving -->
    <bean id="liteDeviceDelegatingViewResolver" class="org.springframework.mobile.device.view.LiteDeviceDelegatingViewResolver">
        <constructor-arg>
            <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <property name="prefix" value="/WEB-INF/pages/" />
                <property name="suffix" value=".jsp" />
            </bean>
        </constructor-arg>
     
        <property name="mobilePrefix" value="m/" />
        <property name="tabletPrefix" value="t/" />
        <property name="enableFallback" value="true" />
    </bean>
     
</beans>

The above configuration file provides context information to the Spring container. 'context:component-scan' enables the auto-detection of annotated components (like Controller, Service etc). So spring container will scan and load all the annotated component (e.g. SpringMobileHelloController) from the package 'com.srccodes.spring.controller' and it's subpackages.

'mvc:annotation-driven' specifies that we are using annotation based configuration.

'SitePreferenceWebArgumentResolver' and 'DeviceWebArgumentResolver' are configured, so that 'SitePreference' and 'Device' can be used as arguments to @Controller method 'sayHello'.

'DeviceResolverHandlerInterceptor' is used to resolve the device that originated the web request and 'SitePreferenceHandlerInterceptor' to enable site preference management. 'CookieSitePreferenceRepository' (default implementation of SitePreferenceRepository) stores the user's preference in client side cookie so that it can be used for the future requests made by that user. SiteSwitcherHandlerInterceptor redirect users to device specific site. There are different types of site switchers available like mDot, dotMobi and urlPath SiteSwitcher. Bute here we have used urlPath SiteSwitcher which redirects users to different paths within the application based on the device and site preference.

ViewResolver provides a mapping between logical view name and actual view. Here we have used device aware view resolver ('LiteDeviceDelegatingViewResolver') that delegates to InternalResourceViewResolver allowing for resolution of device specific view names by adjusting view name by adding prefix (say 'm/' and 't/' for mobile and tablet) or suffix without the need for defining separate mapping for each device specific view. In our case, 'sayHello' handler method returns view name 'helloWorld' which gets adjusted to 'm/helloWorld' by adding 'm/' prefix for mobile. Then it gets resolved to the path 'WEB-INF/pages/m/helloWorld.jsp' by the 'InternalResourceViewResolver' by adding prefix '/WEB-INF/pages/' and suffix '.jsp' to the adjusted view name 'm/helloWorld'.

There may be cases where device specific views for a particular page may not be available. There Fallback resolution ('enableFallback') comes into picture. If adjusted view name can not be resolved then original view is used by the ViewResolver.

6. Integrate Spring with Web Application

Copy the following content in your web.xml file.

File: web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    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>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
  
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
        <url-pattern>/m/*</url-pattern>
        <url-pattern>/t/*</url-pattern>
    </servlet-mapping>
</web-app>

We need to add '/', '/m/*' and '/t/*' in the web.xml for the normal, mobile and tablet site paths as SiteSwitcher redirects user to those path based on user's site preference and the device that originates the web request.

7. Overall Project Structure

Overall Project Structure

8. Deploy and Run the Application

Right click on the project 'SpringMobileHelloWorld' and select from context menu 'Run As' --> 'Run on Server'. Select the existing tomcat server. If not available then manually define a new web server. Click "Finish" button. The web application will be deployed in the tomcat web server and a device specific view will be opened with 'Hello World!' message, site preference and device type information along with a option to switch to different mode (like mobile, tablet). You can trying switching between different view.

http://localhost:8080/SpringMobileHelloWorld/
Browser Output

Developer Tools (Ctrl+Shift+J) of Google's Chrome browser can be used to test device (mobile / tablet) specific view.

Developer Tools of Chrome Browser
Developer Tools of Chrome Browser

Mobile View
Mobile View

Tablet View
Tablet View

Note:
For live demo of Spring mobile, browse srccodes.com which is implemented using this technology only. You can switch between desktop or mobile site using the link "View: Desktop | Mobile" available in the bottom of this site.

Download SrcCodes

All code samples shown in this post are available in the following link SpringMobileHelloWorld.zip

References