3

我有这个Scala/Play应用程序,我必须通过AJAX获取一堆模板。我现在正在做这样的事情:Scala/Play:动态加载模板

def home = Action { 
    Ok(views.html.home()) 
} 

def about = Action { 
    Ok(views.html.about()) 
} 

def contact = Action { 
    Ok(views.html.contact()) 
} 

//etc 

但是,这只是为每个模板创建一个操作。我可以这样做,而不是:

def loadTemplate(templateName) = Action { 
    //Load template from "views" with name being value of parameter templateName 
} 

这是可能的Play框架?如果是的话那么如何?

播放框架2.2.1/2.9.3斯卡拉/ Java的8 64位

UPDATE:我原来的问题可能会被误解。我不想编译模板,我想以更动态的方式获取已编译的模板。

UPDATE2:我想我发现了一些很接近,如果不正是我需要的on this answer,但它在Java和我需要它在Scala中。

+1

嗯,_'I希望获取已编译的一个...'_是,意味着你的意见并不编译什么,他们只是准备使用的HTML页面? – biesior

+0

@biesior第二次更新中的链接几乎涵盖了我需要的内容,这只是我需要它在Scala中,而不是Java。 – Caballero

回答

0

它不太好主意,允许任何文本(出于安全原因)搜索视图因此可以在参数传递,相反,你可以解决这个与match声明非常简单 - 它可以让你限制请求允许的意见仅将处理错误的请求以及大概的Scala爱好者可以证明更好的代码,但是这会为你工作开箱:

def loadTemplate(templateName: String) = Action { 

    templateName match { 
    case "about" => Ok(about()) 
    case "home" => Ok(home()) 
    case "contact" => Ok(contact()) 
    case _ => NotFound(notFoundView()) 
    } 

} 

路线:

GET /load-template/:templateName controllers.Application.loadTemplate(templateName) 

额外的好处是,你可以从中获取更多数据请求,并根据templateName PARAM

+0

谢谢,我意识到我可以做到这一点,但我希望有一个更加动态的解决方案 - 不需要太多的case语句(在我的情况)。 – Caballero

+0

如果不重新部署,您无法添加新视图,可以吗?即使你将添加视图_zillion + 1_,你也需要重新启动'prod'应用程序,在这种情况下,将下一行添加到'loadTemplate'操作中不会成为问题。另一方面,如果你打算使用所有的视图而没有params(就像_static HTML pages_),你为什么不考虑将它们存储在数据库中?在这种情况下,您可以创建微型CMS来管理_zillion^10_,这样您就可以在航班上添加/编辑/删除页面。 – biesior

+1

我想我们在这里有一个误解。我不想编译任何模板 - 它们都是在应用程序启动时编译完成的。我想要的只是一种更动态的方式来获取它们 - 而不用硬编码所有这些案例陈述,就这些。 – Caballero

1

使用Scala的反射它传递到解决的观点:

object Application extends Controller { 

    import reflect.runtime.universe._ 
    val currentMirror = runtimeMirror(Play.current.classloader) 
    val packageName = "views.html." 

    def index(name: String) = Action { 
    val templateName = packageName + name 

    val moduleMirror = currentMirror.reflectModule(currentMirror.staticModule(templateName)) 
    val methodSymbol = moduleMirror.symbol.typeSignature.declaration(newTermName("apply")).asMethod 

    val instanceMirror = currentMirror.reflect(moduleMirror.instance)  
    val methodMirror = instanceMirror.reflectMethod(methodSymbol) 

    Ok(methodMirror.apply().asInstanceOf[Html]) 
} 

} 
+0

我试图用这个,但我得到一个错误:'执行异常[抛出:IllegalArgumentException:错误的参数数目]' – Caballero

+0

此代码假定你的模板不带任何参数。如果是的话那么你需要将它们传递给apply方法 – Nilanjan

+0

所以我想,如果所有的模板没有参数,这种方法只会工作,或者有相同的参数?你如何在你的例子中传递参数? – Caballero

0

在你的模板文件

general_template.scala.html

@(templateName : String = "none") 

@templateName match {  

case "about" => { //html elements} 

case "home" => {//html elements} 

case "contact" => {//html elements} 

case _ => { } 

} 

,并在您控制器

def loadTemplate(templateName) = Action { 
    Ok(views.html.general_template(templateName)) 
} 
0

基于@Nilanjan答案和播放2.4斯卡拉-2.11.7

def page(page: String) = Action.async { implicit request => 
    Future.successful(Ok(loadTemplate(page))) 
    } 

    import reflect.runtime.universe._ 
    import play.api._ 
    import play.twirl.api.Html 
    val currentMirror = runtimeMirror(Play.current.classloader) 
    val packageName = "views.html." 
    private def loadTemplate(name: String) = { 
    val templateName = packageName + name 
    val moduleMirror = currentMirror.reflectModule(currentMirror.staticModule(templateName)) 
    val methodSymbol = moduleMirror.symbol.info.member(TermName("apply")).asMethod 
    val instanceMirror = currentMirror.reflect(moduleMirror.instance) 
    val methodMirror = instanceMirror.reflectMethod(methodSymbol) 
    methodMirror.apply().asInstanceOf[Html] 
    }