Is there any design pattern to switch between data depending on the device type?
Asked Answered
B

7

9

We have a spring MVC based web application. Now we need to modify this application so that it renders properly on the smartphones.

For this we are going to create separate JSP's for the smartphones. So, ones the request comes from the browser we will check if the request is coming from desktop then we will show the normal JSP or if the request is coming from mobile then we will show JSP's for smartphones.

We will be using spring Mobile for this.

In some cases we will also want to restrict the data on the smartphones. We may not show all the data in the JSP's.

e.g. We may need to show only few items in the menu. Desktop web application will show full menu while smartphones will show less menu items. Even though we will have different JSP for desktop menu and mobile menu, Menu items are coming from the database.

Is there any design pattern which will help us in this? We dont want to write those if else conditions to check for device type.

Backache answered 1/2, 2013 at 9:41 Comment(2)
Don't forget to allow the user to load the normal version if he wants toLeftist
Google the Strategy pattern. Seems like a fitUndecagon
S
1

if you see the menu problem from UI point of view, then you could use Abstract Factory design pattern. in general, you would have one common interface that produces menus:

interface MenuFactory {
    Object createMainMenu();
    Object createSomeOtherMenu();
}

and two implementations:

public class DesktopAppMenuFactory implements MenuFactory {
    public Object createMainMenu() {
         ask dao for menus intended for desktop variant
         return ...
    }

    public Object createSomeOtherMenu() {
         ask dao for menus intended for desktop variant
         return ...
    }
}

public class MobileAppMenuFactory implements MenuFactory {
    public Object createMainMenu() {
         ask dao for menus intended for mobile variant
         return ...
    }

    public Object createSomeOtherMenu() {
         ask dao for menus intended for mobile variant
         return ...
    }
}

then write a method that will create appropriate factory given client type:

public static MenuFactory createMenuFactory(String clientType) {
    if( clientType is desktop.. ) {
        return new DesktopAppMenuFactory();

    } else if( clientType is mobile.. ) {
        return new MobileAppMenuFactory();
    }
}

and use MenuFactory in your controllers and JSPs without bothering which variant it is. this one the only if-statements are in the ebove utility method createMenuFactory().

on the other hand, if you see the problem from data point of view, then Strategy Pattern applied to service layer would be appropriate. but the code code would end up very similar to the above with *Factory renamed to *Service and implementations being called strategies rather than factories.

Sabrasabre answered 4/2, 2013 at 7:54 Comment(0)
B
1

Have a look at the Sitemesh framework, a lightweight and flexible Java web application framework that applies the Gang of Four decorator pattern to allow a clean separation of content from presentation.

Below is an example that shows you how you could use it.


Configuration

pom.xml

<dependency>
    <groupId>opensymphony</groupId>
    <artifactId>sitemesh</artifactId>
    <version>2.4.2</version>
</dependency>

WEB-INF/web.xml

<filter>
    <filter-name>sitemeshFilter</filter-name>
    <filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>sitemeshFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

WEB-INF/sitemesh.xml

<?xml version="1.0" encoding="UTF-8" ?>
<sitemesh>
    <property name="decorators-file" value="/WEB-INF/sitemesh-decorators.xml" />
    <excludes file="${decorators-file}" />
    <page-parsers>
       <parser content-type="text/html" class="com.opensymphony.module.sitemesh.multipass.DivExtractingPageParser"/>
    </page-parsers>
    <decorator-mappers>
        <mapper class="com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper">
            <param name="decorator.parameter" value="decorator" />
        </mapper>
        <mapper
            class="com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper">
            <param name="decorator" value="none" />
            <param name="parameter.name" value="printable" />
            <param name="parameter.value" value="true" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
            <param name="property.1" value="meta.decorator" />
            <param name="property.2" value="decorator" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
            <param name="config" value="${decorators-file}" />
        </mapper>
    </decorator-mappers>
</sitemesh>

WEB-INF/sitemesh-decorators.xml

<?xml version="1.0" encoding="UTF-8" ?>
<decorators defaultdir="/WEB-INF/sitemesh">
    <decorator name="mobile" page="mobile.jsp" />
    <decorator name="tablet" page="tablet.jsp" />
    <decorator name="desktop" page="desktop.jsp" />
    <excludes>
        <pattern>*.html*</pattern>
        <pattern>*.json*</pattern>
        <pattern>*.xml*</pattern>
        <pattern>*.download*</pattern>
    </excludes>
</decorators>

Templates

WEB-INF/sitemesh/mobile.jsp

<%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator" 
%><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%><!DOCTYPE HTML>
<html>
    <head>
        <title>Mobile Template - <decorator:title /></title>
    </head>
    <body>        
        <nav class="mobile">
            <ul>
                <li>Menu 1</li>
                <li>Menu 2</li>
            </ul>
        </nav>
        <div id="wrapper">
            <decorator:body />
        </div>
    </body>
</html>

WEB-INF/sitemesh/tablet.jsp

<%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator" 
%><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%><!DOCTYPE HTML>
<html>
    <head>
        <title>Tablet Template - <decorator:title /></title>
    </head>
    <body>        
        <nav class="tablet">
            <ul>
                <li>Menu 1</li>
                <li>Menu 2</li>
                <li>Menu 3</li>
                <li>Menu 4</li>
            </ul>
        </nav>
        <div id="wrapper">
            <decorator:body />
        </div>
    </body>
</html>

WEB-INF/sitemesh/desktop.jsp

<%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator" 
%><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%><!DOCTYPE HTML>
<html>
    <head>
        <title>Desktop Template - <decorator:title /></title>
    </head>
    <body>        
        <nav class="desktop">
            <ul>
                <li>Menu 1</li>
                <li>Menu 2</li>
                <li>Menu 3</li>
                <li>Menu 4</li>
                <li>Menu 5</li>
                <li>Menu 6</li>
            </ul>
        </nav>
        <div id="wrapper">
            <decorator:body />
        </div>
    </body>
</html>

Mapping

HomeController.java

@RequestMapping("/")
public String home(Device device) {
    if (device.isMobile()) {
        return "mobile/home/index";
    } else if (device.isTablet()) {
        return "tablet/home/index";
    } else {
        return "desktop/home/index";       
    }
}

WEB-INF/views/mobile/home/index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%><head>
    <meta name="decorator" content="mobile" />
    <title>Mobile Home Page</title>
</head>
<body>
    <p>Mobile Page Content</p>
</body>

WEB-INF/views/tablet/home/index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%><head>
    <meta name="decorator" content="tablet" />
    <title>Tablet Home Page</title>
</head>
<body>
    <p>Tablet Page Content</p>
</body>

WEB-INF/views/desktop/home/index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%><head>
    <meta name="decorator" content="desktop" />
    <title>Desktop Home Page</title>
</head>
<body>
    <p>Desktop Page Content</p>
</body>
Birdlime answered 4/2, 2013 at 8:56 Comment(0)
Y
1

Most of the other suggested solutions are over engineered, follow the Keep It Simple principle.

Generate a standardise abstraction of a page in XML using JSP which chooses an appropriate different style sheet for inclusion based on client device type. This maintains a good separation of content from presentation, without tying yourself to a specific device.

Yeager answered 6/2, 2013 at 12:29 Comment(0)
M
0

If you are using Spring 3 MVC, and adheared to the normal pattern of having a Controller method return a View, then I think the easiest and most correct way would be to have either a separate method to handle the mobile devices OR have the same method, but return a different view (via your view resolver).

So, for instance, my method might do something like:

@RequestMapping
public String default(Model uiModel, HttpServletRequest request) {
  // Do common stuff here, like load your model

  if(request.getHeader("User-Agent").indexOf("Mobile") != -1) {
    return "normalForm";
  } else {
    return "mobileForm";
  }
}

You could even get fancy and dynamically build the names based on some pre-defined pattern, like iphones get "form_iphone" and Chrome gets "form_chrome".

Midge answered 1/2, 2013 at 19:26 Comment(2)
The OP said that he's using Spring Mobile.Birdlime
I read that, but I also assumed that Spring Mobile used views the same way. Consequently, having looked at the Spring Mobile site it seems like all the device detection is baked-in, so I am confussed as to why the OP couldn't just use the samples there...I was guess that the Spring folks would have examples showing the prefered design patterns.Midge
D
0

Suposing you intent to extend your support to any type of device I would create some kind of support to help this. I can think a simple approach, but i'm assuming a lot (your menu is rendered based on user permission by example...).

Change the permissions of the user based on his current device (desktop users can see everything, mobile users has less permission, and so, cannot see some itens on menu). You can log in the user, and post process his permission based on the device.

This could be created adding a column on your menu table or creating some kind of processor to remove elements of menu that cannot be rendered for some devices.

Derrik answered 4/2, 2013 at 17:16 Comment(0)
P
0

Remember smart phones come in multiple sizes , it means two views will not to enough. Have a look at HTML5. You may not even require two views. Have a responsive web page. A responsive page re-sizes itself to fit into small and large form factors. eg :http://twitter.github.com/bootstrap/index.html. Try re-sizing the pages in above link. You could have a menu which will compress itself (or remove some items) on smaller screens. If touch is important in your application look at java-script frameworks which do touch. Also see http://verekia.com/initializr/responsive-template

Pazia answered 8/2, 2013 at 16:38 Comment(0)
P
0

If your main objective is to add support for mobile web, an alternative that I would consider is to have just one version of your site that is responsive.

You can achieve that with many css frameworks, one of the most popular ones is Twitter's Bootstrap .

With this approach, the screen will resize accordingly given a smaller or bigger screen size. You can check out a fluid layout with this example: Bootstrap Fluid.

This way your web app resizes its layout and its content(including the menus and images) so that its usable on multiple screen sizes.

Printable answered 8/2, 2013 at 16:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.