Scala語言中的Scala Servlet
為了讓一門語言適用于 “現(xiàn)實”,并且使其 “輝煌起來”,該語言必須能夠服務(wù)于現(xiàn)實環(huán)境和應(yīng)用程序。在這一期的 面向 Java 開發(fā)人員的 Scala 指南 系列中,Ted Neward 將介紹 Scala 在現(xiàn)實環(huán)境中的使用,即解釋 Scala 如何與核心 Servlet API 交互,甚至可能會對其進行一些改正。
Scala 顯然是一門有趣的語言,很適合體現(xiàn)語言理論和創(chuàng)新方面的新思想,但最終它要用在 “現(xiàn)實” 環(huán)境中,它必須能滿足開發(fā)人員的某些需求并在 “現(xiàn)實” 環(huán)境中有一定的實用性。
了解 Scala語言的一些核心功能之后,就能認識到 Scala語言的一些靈活性,并能放心使用 Scala 創(chuàng)建 DSL.現(xiàn)在我們進入實際應(yīng)用程序使用的環(huán)境,看看 Scala 如何適應(yīng)環(huán)境。在本系列的新階段中,我們將首先討論大部分 Java? 應(yīng)用程序的核心:Servlet API.
Servlet 回顧
回憶一下 Servlet 101 課程和教程,servlet 環(huán)境的核心實際上就是通過一個套接字(通常是端口 80)使用 HTTP 協(xié)議的客戶機-服務(wù)器交換??蛻魴C可以是任何 “用戶-代理”(由 HTTP 規(guī)范定義),服務(wù)器是一個 servlet 容器。servlet 容器在我編寫的一個類上查找、加載和執(zhí)行方法,該類最終必須實現(xiàn) javax.servlet.Servlet 接口。
通常,實際的 Java 開發(fā)人員不會編寫直接實現(xiàn)接口的類。因為最初的 servlet 規(guī)范是用于為 HTTP 之外的其他協(xié)議提供一個通用 API,所以 servlet 命名空間被分為了兩部分:
一個 “通用” 包(javax.servlet)
一個特定于 HTTP 的包(javax.servlet.http)
這樣,將在一個稱為 javax.servlet.GenericServlet 的抽象基類的通用包中實現(xiàn)一些基本的功能;然后在派生類 javax.servlet.http.HttpServlet 中實現(xiàn)其他特定于 HTTP 的功能,該類通常用作 servlet 實際 “內(nèi)容” 的基類。HttpServlet 提供了一個 Servlet 的完整實現(xiàn),將 GET 請求委托給一個將要被覆蓋的 doGet 方法,將 POST 請求委托給一個將要被覆蓋的 doPut 方法,依此類推。
Hello, Scala 與 Hello, Servlet
顯然,任何人編寫的第一個 servlet 都是普遍的 “Hello, World” servlet;Scala 的第一個 servlet 示例也是如此?;貞浺幌略S多年之前介紹的 servlet 教程,當時基本的 Java “Hello, World” servlet 只是輸出清單 1 所示的 HTML 響應(yīng):
清單 1. 預期的 HTML 響應(yīng)
- <HTML>
- <HEAD><TITLE>Hello, Scala!</TITLE></HEAD>
- <BODY>Hello, Scala! This is a servlet.</BODY>
- </HTML>
用 Scala 編寫一個簡單的 servlet 來實現(xiàn)這個操作非常簡單,而且這個 servlet 與其相應(yīng)的 Java 形式幾乎一樣,如清單 2 所示:
清單 2. 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("<HTML>" +
- "<HEAD><TITLE>Hello, Scala!</TITLE></HEAD>" +
- "<BODY>Hello, Scala! This is a servlet.</BODY>" +
- "</HTML>")
- }
注意,我使用了一些適當?shù)膶雱e名來縮短請求的類型名稱和相應(yīng)類型;除此之外,這個 servlet 幾乎與其 Java servlet 形式一樣。編譯時請記得在 servlet-api.jar(通常隨 servlet 容器一起發(fā)布;在 Tomcat 6.0 發(fā)行版中,它隱藏在 lib 子目錄中)中包含一個引用,否則將找不到 servlet API 類型。
這還準備得不夠充分;根據(jù) servlet 規(guī)范,它必須使用一個 web.xml 部署描述符部署到 Web 應(yīng)用程序目錄中(或一個 .war 文件中),該描述符描述 servlet 應(yīng)該與哪個 URL 結(jié)合。對于這樣一個簡單的例子,使用一個相當簡單的 URL 來配合它最容易,如清單 3 所示:
清單 3. 部署描述符 web.xml
- <!DOCTYPE web-app
- PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
- "http://java.sun.com/dtd/web-app_2_3.dtd">
- <web-app>
- <servlet>
- <servlet-name>helloWorld</servlet-name>
- <servlet-class>HelloScalaServlet</servlet-class>
- </servlet>
- <servlet-mapping>
- <servlet-name>helloWorld</servlet-name>
- <url-pattern>/sayHello</url-pattern>
- </servlet-mapping>
- </web-app>
從這里開始,我假設(shè)讀者會在必要時調(diào)整/修改部署描述符,因為這跟 Scala 沒有關(guān)系。
當然,格式良好的 HTML 與格式良好的 XML 非常相似;鑒于這一點,Scala 對 XML 字面值的支持使編寫這個 servlet 簡單得多(參閱 參考資料 中的 “Scala 和 XML” 一文)。Scala 不是在傳遞給 HttpServletResponse 的 String 中直接嵌入消息,它可以分離邏輯和表示形式(非常簡單),方法是利用此支持將消息放在 XML 實例中,然后再傳遞回去:
清單 4. Hello, Scala Servlet!
- import javax.servlet.http.{HttpServlet,
- HttpServletRequest => HSReq, HttpServletResponse => HSResp}
- class HelloScalaServlet extends HttpServlet
- {
- def message =
- <HTML>
- <HEAD><TITLE>Hello, Scala!</TITLE></HEAD>
- <BODY>Hello, Scala! This is a servlet.</BODY>
- </HTML>
- override def doGet(req : HSReq, resp : HSResp) =
- resp.getWriter().print(message)
- }
Scala 的內(nèi)聯(lián)表達式求值工具使用 XML 字面值,這意味著能夠輕松地使 servlet 更有趣。例如,將當前日期添加到消息中與將 Calendar 表達式添加到 XML 中一樣簡單,不過增加了幾行 { Text(java.util.Calendar.getInstance()。getTime()。toString() ) }.這似乎顯得有點冗長,如清單 5 所示:
清單 5. Hello, timed Scala Servlet!
- import javax.servlet.http.{HttpServlet,
- HttpServletRequest => HSReq, HttpServletResponse => HSResp}
- class HelloScalaServlet extends HttpServlet
- {
- def message =
- <HTML>
- <HEAD><TITLE>Hello, Scala!</TITLE></HEAD>
- <BODY>Hello, Scala! It's now { currentDate }</BODY>
- </HTML>
- def currentDate = java.util.Calendar.getInstance().getTime()
- override def doGet(req : HSReq, resp : HSResp) =
- resp.getWriter().print(message)
- }
實際上,Scala 編譯器與 XML 對象消息一起整合到一個 scala.xml.Node 中,然后在將它傳遞給響應(yīng)的 Writer 的 print 方法時將其轉(zhuǎn)換為一個 String.
不要小看這一點 — 表達形式從邏輯中分離出來完全在一個類內(nèi)部進行。這條 XML 消息將進行編譯時檢查,以確保語法正確和格式良好,并獲得一些標準 servlet(或 JSP)不具備的好處。由于 Scala 可以進行類型推斷,因此可以省略有關(guān) message 和 currentDate 的實際類型消息,使得這就像動態(tài)語言 Groovy/Grails 一樣。初次使用效果不錯。以上是Scala語言中的Scala Servlet一個小小的介紹,希望對大家有用。
【編輯推薦】