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