Play Framework 2 - 针对不同设备的不同视图

时间:2014-06-23 15:26:23

标签: playframework-2.0

我正在构建一个需要拥有2个不同版本的Play 2.1.0(Java)应用程序:桌面Web应用程序和移动Web应用程序。我正在寻找一种不会修改控制器的方法。逻辑,但依赖于路由。理想的行为应该是:

  • 桌面和移动设备的路由相同
  • 桌面和移动设备的控制器相同
  • 移动设备和桌面视图不同,但共享命名约定。

我是否可以通过路由行为进行连接,例如,将.mob附加到视图名称,以便呈现视图为main.scala.html用于桌面,main.scala.mob.html用于移动设备?这将是理想的,因为控制器不需要更改(或丑陋的ifs),并且每个视图都需要拥有它自己的移动版本。我想我此时需要请求来执行设备检测。如果没有针对特定操作实施移动视图,它甚至可以回退到桌面视图。

有什么想法吗?

谢谢, 贡萨洛

2 个答案:

答案 0 :(得分:1)

我最终编写了需要移动版本和其他操作的操作。为了实现这一点,我创建了一个@Mobile运行时注释,我用它来注释这些动作和移动视图的名称。所有带注释的操作都将由以下MobileAction组成,它执行设备检测:

public class MobileAction extends Action<Mobile> {
    public MobileAction() {
    }

    public MobileAction(Mobile configuration, Action<?> delegate) {
        this.configuration = configuration;
        this.delegate = delegate;
    }

    @Override
    public Result call(Http.Context ctx) throws Throwable {
        final Http.Request request = ctx.request();
        final String userAgent = request.getHeader("User-Agent");

        // See https://developer.mozilla.org/en-US/docs/Browser_detection_using_the_user_agent
        if (userAgent.contains("Mobi")) {
            ctx.args.put("viewName", configuration.value());
        }

        return delegate.call(ctx);
    }
}

我实现了一个DynamicRendered类,它查找viewName参数(可选择由@Mobile注入)并使用反射来呈现相应的视图。

public class DynamicRenderer {

    public static Html render(String viewName, Object... args) {
        final Map<String, Object> ctxArgs = Http.Context.current().args;
        final String view = ctxArgs.containsKey("viewName") ? ((String) ctxArgs.get("viewName")) : viewName;

        // Get argument classes
        final Class[] argClasses = new Class[args.length];
        for (int i=0; i<args.length; i++) {
            argClasses[i] = args[i].getClass();
        }

        try {
            // Get view render method and invoke
            final Class<?> clazz = Class.forName(view);
            final Method render = clazz.getDeclaredMethod("render", argClasses);
            final Html html = ((Html) render.invoke(null, args));

            return html;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
}

然后,我打电话给ok(viewName.render(...))

,而不是在控制器中调用ok(DynamicRenderer.render("viewName", ...))

答案 1 :(得分:0)

听起来你需要的是使用CSS + JS样式库,如Foundation 5或Bootstrap。通过在生成的html中使用css标记,可以允许您指定视图在不同屏幕大小中的显示方式。 Lookup Foundation文档,他们解释了如何做到这一点。