Webアプリでは1つのアプリ上にユーザ向けのエリアと管理用のエリアを持つことがよくあると思います。そのときには、ユーザ画面向けと管理画面向けでデザインやエラー画面の内容を切り替える必要があります。
SkinnyFrameworkでそのようなユーザ画面と管理画面での表示内容を出し分ける方法を紹介します。
ベースのレイアウトを切り替える
LayoutSwitchFeatureトレイトは、ビューの基板となるレイアウトファイルを切り替える機能を提供します。
このトレイトをコントローラにmixinし、defaultLayoutを設定することでレイアウトを変更できます。
LayoutSwitchFeature.scala
trait LayoutSwitchFeature extends SkinnyWebPageControllerFeatures {
// コントローラに対するデフォルトレイアウト名(ex:"default.ssp")
protected def defaultLayout: Option[String] = None
/* レイアウトを設定するためにオーバーライド */
override def render(path: String)(implicit format: Format = Format.HTML): String = {
defaultLayout.foreach { l =>
layout(l)
}
super.render(path)(format)
}
}
エラー画面を切り替える
CustomErrorPageFilterは、haltWithBodyの呼び出しや例外発生時のエラー画面で使われるビューファイルのパスを変更します。
CustomErrorPageFilter.scala
package filter
import skinny.filter.SkinnyRenderingFilter
/**
* エラーハンドリング用フィルタ
*/
trait CustomErrorPageFilter extends SkinnyRenderingFilter {
protected def errorPagePath = ""
override protected def haltWithBody[A](httpStatus: Int)(implicit format: Format = Format.HTML): A = {
val body: String = format match {
case Format.HTML => render(s"${errorPagePath}/error/${httpStatus}")
case _ => renderWithFormat(Map("status" -> httpStatus, "message" -> ResponseStatus(httpStatus).message))
}
Option(body).map { b =>
halt(status = httpStatus, body = b)
}.getOrElse {
halt(status = httpStatus)
}
}
addRenderingErrorFilter {
case e: Throwable =>
logger.error(e.getMessage, e)
try {
status = 500
render(s"${errorPagePath}/error/500")
} catch {
case e: Exception => throw e
}
}
}
コントローラの基底クラス群
上記の2機能を用意した上で、コントローラの基礎部分を以下の様に作成します。
この例は、今回の内容のみに特化したシンプルなものですので、実際には各機能ごとに色々な拡張がされると思います。
// アプリ全体のコントローラ基底trait
trait ApplicationControllerFeature extends LayoutSwitchFeature
with AppErrorPageFilter
// ユーザ画面系のコントローラ基底trait
trait UserControllerFeature extends ApplicationControllerFeature
// 管理画面系のコントローラ基底trait
trait AdminControllerFeature extends ApplicationControllerFeature {
override protected val errorPagePath = "/admin"
override protected val defaultLayout = Some("admin.ssp")
}
// 管理画面用のSkinnyResource
trait AdminResource extends SkinnyResource {
override protected def resourcesBasePath = s"/admin/${toSnakeCase(resourcesName)}"
override protected def viewsDirectoryPath = s"/admin/${resourcesName}"
}
使い方
ここまでの準備ができてしまえば、実際のコントローラは以下の様に普通に実装して行けばよくなります。
// ユーザ画面のルートパス("/"下)に対応するコントローラ
class RootController extends SkinnyController
with UserControllerFeature {
def index = render("/index")
}
// 管理画面のルートパス("/admin/"下)に対応するコントローラ
class AdminRootController extends SkinnyController
with AdminControllerFeature {
def index = render("/admin/index")
}
ビューファイルに関しては、以下のようなファイルレイアウトになります。
src/main/webapp/WEB-INF/
+ layouts/
- default.ssp (ユーザ画面用レイアウト)
- admin.ssp (管理画面用レイアウト)
+ views/
+ root/ ("/"階層に対応する。ユーザ画面用のルートページ)
+ error/ (ユーザ画面用のエラーページ)
+ admin/ ("/admin"階層に対応する。管理画面用のページ)
+ error/ (管理画面用のエラーページ)