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