Scala + Lift + HTML5

http://d.hatena.ne.jp/norio515/20101218/1292664211 を参考に、lift でファイル uploader を作成してみた。

ただし、HTML5 で追加されたフォームの機能を使い、複数ファイルのアップロードが可能であるようにした。

環境

手順

HtmlProperties、XHTML、および HTML5 | Lift Space | Assembla にあるように、

Boot.scala
    LiftRules.htmlProperties.default.set((r: Req) =>new Html5Properties(r.userAgent))

を追加する。

  • これで HTML5 の機能を使える。

はずなのだが、今回、これを追加しなくても、アプリケーションは問題なく作動した。

index.html は
<lift:surround with="default" at="content">
  You can upload any file.
  <lift:UploadSnippet.upload form="POST" multipart="true">
    <fieldset> 
      <legend>uploadingfiles</legend>
      <span>
	<form:submit/>
      </span>
      <span>
	<form:upload/>
      </span>
    </fieldset> 
  </lift:UploadSnippet.upload><br/><br/>
</lift:surround>

のように書く。

  • fieldset タグと legend タグはなくてもよいが、
  • span タグは必要。これがないと、input 要素が1つしか出力されない。
UploadSnippet.scala
package ireiz.uploader.snippet

import _root_.java.io.{File, FileOutputStream}
import _root_.scala.xml.NodeSeq
import _root_.net.liftweb.util.BindHelpers._
import _root_.net.liftweb.http.FileParamHolder
import _root_.net.liftweb.http.S
import _root_.net.liftweb.http.SHtml._

class Uploadsnippet {
  val filepath = "src/main/webapp/static/uploaded/"

  def upload(xhtml: NodeSeq): NodeSeq = {
    def save: FileParamHolder => Unit = {
      case FileParamHolder(_, _, fn, file) => {
	val dir = new File(filepath, fn)
	val output = new FileOutputStream(dir) {
	  write(file)
	  close
	}
	S.notice("Uploading succeeded.")
      }
    }
  
    bind("form", xhtml,
	 "submit" -> submit("Save", () => ()),
	 "upload" -> fileUpload(save, new BasicElemAttr("multiple", "multiple")))
  }
}

と書く。

  • fileUpload メソッドの第2引数で、multiple 属性を与えるのが、ポイント。
  • fileUpload メソッドは、アップロードされるファイル1つ1つにつき、呼び出される
  • クラス名は最初の文字以外、小文字でなければならない。この点間違えると、
Error processing snippet uploadsnippet.upload. 
Reason: Class Not Found XML causing this error:

とのエラーメッセージがブラウザ上に表示される。(test mode の場合)