■User-Agentの取得方法
val userAgent:String = S.request.get.userAgent.get
など。
但し、Sオブジェクトの準備ができていないフェーズ(earlyフェーズなど)ではS.requestはEmptyなので、
val userAgent:String = request.asInstanceOf[HTTPRequest].header("User-Agent").open_!
などとします。
LiftはServletコードを分離するように構成されているので、生のServletRequestを触りたければ、
net.liftweb.http.Req
net.liftweb.http.provider.HTTPRequest
net.liftweb.http.provider.servlet.HTTPRequestServlet
これらの階層のAPIを追うことになります。
■レスポンスをSJISに変換
↓pomu0325さんのエントリに全て書いてあります。大変参考になりました!
Liftのテンプレートでutf-8以外のレスポンスを返す
class Boot {
def boot {
:
LiftRules.responseTransformers.append( responseEncoding )
:
}
}
//携帯ならレスポンスをSJISに変換
private def responseEncoding(org: LiftResponse): LiftResponse = {
if( isMobile(userAgent) ){
org match {
case x: XhtmlResponse =>
S.skipXmlHeader = true
val m = x.toResponse
val h = x.headers ::: ("Content-Type", "text/html; charset=Shift_JIS") :: Nil
InMemoryResponse(new String(m.data, "utf-8").getBytes("Shift_JIS"), h, m.cookies, m.code)
case _ => org
}
}else{
org
}
}
■リクエストパラメータをShift_JISに変換
class Boot {
def boot {
:
LiftRules.early.append( requestEncoding )
:
}
}
//携帯ならリクエストパラメータはSJIS
private def requestEncoding(request: HTTPRequest):Unit={
if( isMobile(userAgent) ){
request.setCharacterEncoding("Shift_JIS")
}else{
request.setCharacterEncoding("UTF-8")
}
}
POSTパラメータはこれでOK。
■GETパラメータに注意
GETのShift_JISパラメータがURLエンコードされてきます。
UTF-8以外のURLエンコードをサポートするかどうかはJavaコンテナ依存とされているので、コンテナの仕様を調査。
Tomcatの場合は、server.xmlで、
<Connector useBodyEncodingForURI="true"/>
Jettyの場合は、
マニュアルを参考に、次のようにコードを直す。
//携帯ならリクエストパラメータはSJIS
private def requestEncoding(request: HTTPRequest):Unit={
import _root_.org.mortbay.jetty.Request
if( isMobile(userAgent) ){
request.asInstanceOf[HTTPRequestServlet].
req.asInstanceOf[Request].setQueryEncoding("Shift_JIS")
request.setCharacterEncoding("Shift_JIS")
}else{
request.asInstanceOf[HTTPRequestServlet].
req.asInstanceOf[Request].setQueryEncoding("UTF-8")
request.setCharacterEncoding("UTF-8")
}
}
本来なら、ServletFilterなどで処理して、Jetty依存コードは追い出すのが良いと思います。
これだけではまだイケてなくて、S.paramは文字化けしたままなので、S.paramではなく生のHttpServletRequestから値を取得します。
object word extends RequestVar[String]( directParam("word") )
//SJISのGETパラメータの場合、S.paramから値を取れない。直接HttpRequestから取得すればOK。
def directParam(name:String):String = {
val value = S.request.open_!.
request.asInstanceOf[HTTPRequestServlet].
req.getParameter(name)
if( value != null ) value else ""
}
■ケータイ用のテンプレートに切り替える
PCブラウザでのページ構成をケータイ用にするケース。"mobile/"フォルダにPC版と同じ構成のテンプレートを用意します。
class Boot {
def boot {
:
LiftRules.viewDispatch.append {
case i1@List("index") => selector( i1 )
case i2@List("catalog", _ ) => selector( i2 )
}
:
}
}
List("index")などは、SiteMapに登録するURL表現。これにヒットするURLに、PCなら/index.htmlを、mobileなら /mobile/index.htmlを適用します。
//携帯ならmobile/フォルダ配下のテンプレートを選択
def selector(list:List[String]): Either[() => Box[scala.xml.NodeSeq], LiftView] = {
if( isMobile( userAgent ) ){
Left( () => TemplateFinder.findAnyTemplate( "mobile"::list ) )
}else{
Right( new LiftView{
def dispatch = {
case _ => () => TemplateFinder.findAnyTemplate( list )
}
})
}
}
他にもやり方いろいろあると思いますが、考えた結果、一番ラクそうなのはこんな感じでした。
■autoIncludeAjax
Liftではデフォルトで、コールバックなどのステートフルオブジェクトを監視するために、AjaxでPingを打つようになっています。
(ログに出てくる"GET:/ajax_request/liftAjax.js"がそれ)
これは特にケータイには不要。外すには、
class Boot {
def boot {
LiftRules.autoIncludeAjax = { session => false }
}
}
などとしますが、条件付きで外したい場合は、以下のように設定する。
LiftRules.autoIncludeAjax = { session => {
if( isMobile( userAgent ) ) false else true
}}
Lift超絶便利ですね! ;x; ブワッ
■余談
Scala2.8対応が待ち遠しかったLift2.0ですが、Scala2.8の開発遅延のため、Lift2.0はターゲットをScala2.7.7でFIXするそうです。残念ですが、しょうがないです。。
参照:Lift Release 2.0 count-down