9

我们有一个基于 Spring MVC 的 Web 应用程序。现在我们需要修改这个应用程序,以便它在智能手机上正确呈现。

为此,我们将为智能手机创建单独的 JSP。因此,如果请求来自浏览器,我们将检查请求是否来自桌面,然后我们将显示正常的 JSP,或者如果请求来自移动设备,那么我们将显示智能手机的 JSP。

我们将为此使用spring Mobile。

在某些情况下,我们还希望限制智能手机上的数据。我们可能不会显示 JSP 中的所有数据。

例如,我们可能只需要在菜单中显示几个项目。桌面 Web 应用程序将显示完整的菜单,而智能手机将显示较少的菜单项。尽管我们将有不同的 JSP 用于桌面菜单和移动菜单,但菜单项来自数据库。

有什么设计模式可以帮助我们吗?我们不想写那些 if else 条件来检查设备类型。

4

7 回答 7

1

如果您从 UI 的角度看到菜单问题,那么您可以使用抽象工厂设计模式。通常,您将拥有一个生成菜单的通用界面:

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

和两个实现:

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 ...
    }
}

然后编写一个方法,该方法将在给定客户端类型的情况下创建适当的工厂:

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

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

并在您的控制器和 JSP 中使用 MenuFactory,而不用担心它是哪个变体。这是唯一的 if 语句在 ebove 实用程序方法createMenuFactory()中。

另一方面,如果您从数据的角度来看问题,那么将策略模式应用于服务层将是合适的。但是代码最终会与上面的代码非常相似,*Factory重命名为*Service并且实现被称为策略而不是工厂。

于 2013-02-04T07:54:16.860 回答
1

大多数其他建议的解决方案都是过度设计的,遵循保持简单的原则。

使用 JSP 在 XML 中生成页面的标准化抽象,该 JSP 根据客户端设备类型选择适当的不同样式表以包含在内。这保持了内容与演示的良好分离,而无需将自己绑定到特定设备。

于 2013-02-06T12:29:26.950 回答
1

看看Sitemesh 框架它是一个轻量级且灵活的 Java Web 应用程序框架,它应用了 Gang of Four 装饰器模式来实现内容与表示的清晰分离

下面是一个示例,向您展示如何使用它。


配置

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>

模板

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>

映射

家庭控制器.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>
于 2013-02-04T08:56:19.703 回答
0

如果您的主要目标是添加对移动网络的支持,我会考虑的另一种选择是只拥有一个响应式网站版本。

您可以使用许多 css 框架来实现这一点,其中最流行的框架之一是Twitter 的 Bootstrap

使用这种方法,屏幕将根据更小或更大的屏幕尺寸相应地调整大小。您可以通过以下示例查看流体布局:Bootstrap Fluid

这样,您的 Web 应用程序会调整其布局和内容(包括菜单和图像)的大小,以便在多种屏幕尺寸上使用。

于 2013-02-08T16:57:03.517 回答
0

如果您使用的是 Spring 3 MVC,并且遵守让 Controller 方法返回 View 的正常模式,那么我认为最简单和最正确的方法是使用单独的方法来处理移动设备或使用相同的方法,但返回不同的视图(通过您的视图解析器)。

因此,例如,我的方法可能会执行以下操作:

@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";
  }
}

您甚至可以根据一些预定义的模式获得幻想并动态构建名称,例如 iphone 获得“form_iphone”而 Chrome 获得“form_chrome”。

于 2013-02-01T19:26:43.197 回答
0

记住智能手机有多种尺寸,这意味着两个视图是不够的。看看 HTML5。您甚至可能不需要两个视图。有一个响应式网页。响应式页面会重新调整自身大小以适应大小尺寸。例如: http: //twitter.github.com/bootstrap/index.html。尝试重新调整以上链接中的页面大小。你可以有一个菜单,它会在较小的屏幕上自我压缩(或删除一些项目)。如果触摸在您的应用程序中很重要,请查看确实触摸的 java 脚本框架。另请参阅http://verekia.com/initializr/responsive-template

于 2013-02-08T16:38:49.230 回答
0

假设您打算将您的支持扩展到任何类型的设备,我会创建某种支持来帮助实现这一点。我可以想到一个简单的方法,但我假设很多(您的菜单是根据示例的用户许可呈现的......)。

根据当前设备更改用户的权限(桌面用户可以看到所有内容,移动用户权限较少,因此无法在菜单上看到某些项目)。您可以登录用户,并根据设备对他的权限进行后期处理。

这可以通过在菜单表上添加一列或创建某种处理器来删除某些设备无法呈现的菜单元素来创建。

于 2013-02-04T17:16:42.130 回答