Scala 無縫整合 Servlet API,並以 XML 字面值、型別推論、函數式風格簡化 Web 開發。本文以漸進式範例展示 Scala Servlet 開發要點。
import javax.servlet.http.{HttpServlet, HttpServletRequest => HSReq, HttpServletResponse => HSResp}
class HelloScalaServlet extends HttpServlet {
override def doGet(req: HSReq, resp: HSResp) =
resp.getWriter().print(
"Hello, Scala! " +
"Hello, Scala! This is a servlet."
)
}
使用別名匯入縮短型別名稱。編譯需包含 servlet-api.jar,部署需 web.xml 映射 URL。
Scala 原生支援 XML 字面值,編譯期檢查語法正確性:
class HelloScalaServlet extends HttpServlet {
def message =
Hello, Scala!
Hello, Scala! This is a servlet.
override def doGet(req: HSReq, resp: HSResp) =
resp.getWriter().print(message)
}
內插表達式以大括號嵌入:
def message =
Hello, Scala! It's now { currentDate }
def currentDate = java.util.Calendar.getInstance().getTime()
XML 字面值編譯為 scala.xml.Node,輸出時自動轉字串。
初版手動提取:
override def doPost(req: HSReq, resp: HSResp) = {
val firstName = req.getParameter("firstName")
val lastName = req.getParameter("lastName")
resp.getWriter().print(message(firstName, lastName))
}
進版:基類自動將參數與 Header 收集為不可變 Map:
abstract class BaseServlet extends HttpServlet {
import scala.collection.mutable.{Map => MMap}
def message: scala.xml.Node
protected var param: Map[String, String] = Map.empty
override def doPost(req: HSReq, resp: HSResp) = {
val m = MMap[String, String]()
val e = req.getParameterNames()
while (e.hasMoreElements()) {
val name = e.nextElement().asInstanceOf[String]
m += (name -> req.getParameter(name))
}
param = Map.empty ++ m
resp.getWriter().print(message)
}
}
子類直接在 XML 中引用 param("firstName"),簡潔且型別安全。
override def message =
if (validate(param))
Hello, {param("firstName")} {param("lastName")}! It is now {currentTime}.
else
How can we be friends if you don't tell me your name?!?
def validate(p: Map[String, String]): Boolean = {
p foreach {
case ("firstName", "") => return false
case ("lastName", "") => return false
case (_, _) => ()
}
true
}
模式匹配讓驗證規則清晰可擴展。基類可提供預設驗證實現,子類覆寫即可。
本文示範的微型框架展現了 Scala 在 Servlet 開發上的優勢:XML 字面值實現編譯期安全的視圖分離,不可變資料結構利於並發,模式匹配簡化驗證邏輯。完整的 Web 框架(如 Lift)進一步發揮這些特性,提供更豐富的抽象。