熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

面向Java開發人員的Scala指南: Scala和servlet

2013-11-23 18:46:45  來源: Java核心技術 

  為了讓一門語言適用於 現實並且使其 輝煌起來該語言必須能夠服務於現實環境和應用程序在這一期的 面向 Java 開發人員的 Scala 指南 系列中Ted Neward 將介紹 Scala 在現實環境中的使用即解釋 Scala 如何與核心 Servlet API 交互甚至可能會對其進行一些改正

  Scala 顯然是一門有趣的語言很適合體現語言理論和創新方面的新思想但最終它要用在 現實 環境中它必須能滿足開發人員的某些需求並在 現實 環境中有一定的實用性

  了解 Scala 語言的一些核心功能之後就能認識到 Scala 語言的一些靈活性並能放心使用 Scala 創建 DSL現在我們進入實際應用程序使用的環境看看 Scala 如何適應環境在本系列的新階段中我們將首先討論大部分 Java? 應用程序的核心Servlet API

  Servlet 回顧

  回憶一下 Servlet 課程和教程servlet 環境的核心實際上就是通過一個套接字(通常是端口 )使用 HTTP 協議的客戶機服務器交換客戶機可以是任何 用戶代理(由 HTTP 規范定義)服務器是一個 servlet 容器servlet 容器在我編寫的一個類上查找加載和執行方法該類最終必須實現 javaxservletServlet 接口

  通常實際的 Java 開發人員不會編寫直接實現接口的類因為最初的 servlet 規范是用於為 HTTP 之外的其他協議提供一個通用 API所以 servlet 命名空間被分為了兩部分

  一個 通用 包(javaxservlet)

  一個特定於 HTTP 的包(javaxservlethttp)

  這樣將在一個稱為 javaxservletGenericServlet 的抽象基類的通用包中實現一些基本的功能然後在派生類 javaxservlethttpHttpServlet 中實現其他特定於 HTTP 的功能該類通常用作 servlet 實際 內容 的基類HttpServlet 提供了一個 Servlet 的完整實現將 GET 請求委托給一個將要被覆蓋的 doGet 方法將 POST 請求委托給一個將要被覆蓋的 doPut 方法依此類推

  

  關於本系列

  Ted Neward 將和您一起深入探討 Scala 編程語言在這個新的 developerWorks 系列 中您將了解有關 Scala 的所有最新討論並在實踐中看到 Scala 的語言功能在進行相關比較時Scala 代碼和 Java 代碼將放在一起展示但是(您將發現)Scala 與 Java 中的許多東西都沒有直接的關聯這正是 Scala 的魅力所在!如果用 Java 代碼就能夠實現的話又何必再學習 Scala 呢?

  Hello Scala 與 Hello Servlet

  顯然任何人編寫的第一個 servlet 都是普遍的 Hello World servletScala 的第一個 servlet 示例也是如此回憶一下許多年之前介紹的 servlet 教程當時基本的 Java Hello World servlet 只是輸出清單 所示的 HTML 響應

  清單 預期的 HTML 響應

  

  <HTML>
   <HEAD><TITLE>Hello Scala!</TITLE></HEAD>
   <BODY>Hello Scala! This is a servlet</BODY>
</HTML>

  用 Scala 編寫一個簡單的 servlet 來實現這個操作非常簡單而且這個 servlet 與其相應的 Java 形式幾乎一樣如清單 所示

  清單 Hello Scala servlet!

  

  import javaxservlethttp{HttpServlet
  HttpServletRequest => HSReq HttpServletResponse => HSResp}

class HelloScalaServlet extends HttpServlet
{
  override def doGet(req : HSReq resp : HSResp) =
    respgetWriter()print(<HTML> +
      <HEAD><TITLE>Hello Scala!</TITLE></HEAD> +
      <BODY>Hello Scala! This is a servlet</BODY> +
      </HTML>)
}

  注意我使用了一些適當的導入別名來縮短請求的類型名稱和相應類型除此之外這個 servlet 幾乎與其 Java servlet 形式一樣編譯時請記得在 servletapijar(通常隨 servlet 容器一起發布在 Tomcat 發行版中它隱藏在 lib 子目錄中)中包含一個引用否則將找不到 servlet API 類型

  這還准備得不夠充分根據 servlet 規范它必須使用一個 webxml 部署描述符部署到 Web 應用程序目錄中(或一個 war 文件中)該描述符描述 servlet 應該與哪個 URL 結合對於這樣一個簡單的例子使用一個相當簡單的 URL 來配合它最容易如清單 所示

  清單 部署描述符 webxml

  

  <!DOCTYPE webapp
    PUBLIC //Sun Microsystems Inc//DTD Web Application //EN
    app__dtd>
<webapp>
  <servlet>
    <servletname>helloWorld</servletname>
    <servletclass>HelloScalaServlet</servletclass>
  </servlet>
  <servletmapping>
    <servletname>helloWorld</servletname>
    <urlpattern>/sayHello</urlpattern>
  </servletmapping>
</webapp>

  從這裡開始我假設讀者會在必要時調整/修改部署描述符因為這跟 Scala 沒有關系

  當然格式良好的 HTML 與格式良好的 XML 非常相似鑒於這一點Scala 對 XML 字面值的支持使編寫這個 servlet 簡單得多(參閱 參考資料 中的 Scala 和 XML 一文)Scala 不是在傳遞給 HttpServletResponse 的 String 中直接嵌入消息它可以分離邏輯和表示形式(非常簡單)方法是利用此支持將消息放在 XML 實例中然後再傳遞回去

  清單 Hello Scala servlet!

  

  import javaxservlethttp{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) =
    respgetWriter()print(message)
}

  Scala 的內聯表達式求值工具使用 XML 字面值這意味著能夠輕松地使 servlet 更有趣例如將當前日期添加到消息中與將 Calendar 表達式添加到 XML 中一樣簡單不過增加了幾行 { Text(javautilCalendargetInstance()getTime()toString() ) }這似乎顯得有點冗長如清單 所示

  清單 Hello timed Scala servlet!

  

  import javaxservlethttp{HttpServlet
  HttpServletRequest => HSReq HttpServletResponse => HSResp}

class HelloScalaServlet extends HttpServlet
{
  def message =
    <HTML>
      <HEAD><TITLE>Hello Scala!</TITLE></HEAD>
      <BODY>Hello Scala! Its now { currentDate }</BODY>
    </HTML>
  def currentDate = javautilCalendargetInstance()getTime()

  override def doGet(req : HSReq resp : HSResp) =
    respgetWriter()print(message)
}

  實際上Scala 編譯器與 XML 對象消息一起整合到一個 scalaxmlNode 中然後在將它傳遞給響應的 Writer 的 print 方法時將其轉換為一個 String

  不要小看這一點 — 表達形式從邏輯中分離出來完全在一個類內部進行這條 XML 消息將進行編譯時檢查以確保語法正確和格式良好並獲得一些標准 servlet(或 JSP)不具備的好處由於 Scala 可以進行類型推斷因此可以省略有關 message 和 currentDate 的實際類型消息使得這就像動態語言 Groovy/Grails 一樣初次使用效果不錯

  當然只讀 servlet 相當麻煩

  Hello Scala這些是參數

  大多數 servlet 不會只返回類似靜態內容或者當前日期和時間的簡單消息它們帶有 POST 形式的內容檢查內容並進行相應的響應例如可能 Web 應用程序需要知道使用者的身份並詢問其姓名

  清單 挑戰!

  

  <HTML>
  <HEAD><TITLE>Who are you?</TITLE></HEAD>
  <BODY>
Who are you? Please answer:
<FORM action=/scalaExamples/sayMyName method=POST>
Your first name: <INPUT type=text name=firstName />
Your last name: <INPUT type=text name=lastName />
<INPUT type=submit />
</FORM>
  </BODY>
</HTML>

  這個方法不會在任何用戶界面設計大賽中奪冠但是它達到了目的這是一個 HTML 表單它會將數據發送給一個新的 Scala servlet(綁定到 sayMyName 的相對 URL)這些數據將根據 servlet 規范存儲在一個名稱值對集合中可通過 HttpServletRequestgetParameter() API 調用獲得在此調用中我們將 FORM 元素的名稱作為一個參數傳遞給 API 調用

  從 Java 代碼直接轉換相對容易一些如清單 中的 servlet 所示

  清單 響應(v

  

  class NamedHelloWorldServlet extends HttpServlet
{
  def message(firstName : String lastName : String) =
    <HTML>
      <HEAD><TITLE>Hello {firstName} {lastName}!</TITLE></HEAD>
      <BODY>Hello {firstName} {lastName}! It is now {currentTime}</BODY>
    </HTML>
  def currentTime =
    javautilCalendargetInstance()getTime()

  override def doPost(req : HSReq resp : HSResp) =
  {
    val firstName = reqgetParameter(firstName)
    val lastName = reqgetParameter(lastName)
 
    respgetWriter()print(message(firstName lastName))
  }
}

  但這缺少了我之前提到的消息分離的一些好處因為現在消息定義必須顯式使用參數 firstName 和 lastName如果響應 get 中使用的元素個數超過 個或 情況就會變得比較復雜此外doPost 方法在將參數傳遞給消息進行顯示之前必須自行提取每一個參數 — 這樣的編碼很繁瑣並且容易出錯

  一種解決方法是將參數提取和 doPost 方法本身的調用添加到一個基類如清單 中的版本 所示

  清單 響應(v

  

  abstract class BaseServlet extends HttpServlet
{
  import llectionmutable{Map => MMap}
 
  def message : scalaxmlNode;
 
  protected var param : Map[String String] = Mapempty
  protected var header : Map[String String] = Mapempty
 
  override def doPost(req : HSReq resp : HSResp) =
  {
    // Extract parameters
    //
    val m = MMap[String String]()
    val e = reqgetParameterNames()
    while (ehasMoreElements())
    {
      val name = enextElement()asInstanceOf[String]
      m += (name > reqgetParameter(name))
    }
    param = Mapempty ++ m
   
    // Repeat for headers (not shown)
    //
 
    respgetWriter()print(message)
  }
}
class NamedHelloWorldServlet extends BaseServlet
{
  override def message =
    <HTML>
      <HEAD><TITLE>Hello {param(firstName)} {param(lastName)}!</TITLE></HEAD>
      <BODY>Hello {param(firstName)} {param(lastName)}! It is now {currentTime}
      </BODY>
    </HTML>

  def currentTime = javautilCalendargetInstance()getTime()
}

  這個版本使 servlet 顯示變得比較簡單(相對上一版本而言)而且增加了一個優點即 param 和 header 映射保持不變(注意我們可以將 param 定義為一個引用請求對象的方法但這個請求對象必須已經定義為一個字段這將引發大規模的並發性問題因為 servlet 容器認為每一個 do 方法都是可重入的)

  當然錯誤處理是處理 Web 應用程序 FORM 的重要部分而 Scala 作為一種函數性語言保存的內容都是表達式這意味著我們可以將消息編寫為結果頁面(假設我們喜歡這個輸入)或編寫為錯誤頁面(如果我們不喜歡這個輸入)因此檢查 firstName 和 lastName 的非空狀態的驗證函數可能如清單 所示

  清單 響應(v

  

  class NamedHelloWorldServlet extends BaseServlet
{
  override def message =
    if (validate(param))
  <HTML>
<HEAD><TITLE>Hello {param(firstName)} {param(lastName)}!
             </TITLE></HEAD>
<BODY>Hello {param(firstName)} {param(lastName)}!
                It is now {currentTime}</BODY>
  </HTML>
    else
      <HTML>
        <HEAD><TITLE>Error!</TITLE></HEAD>
        <BODY>How can we be friends if you dont tell me your name?!?</BODY>
      </HTML>

  def validate(p : Map[String String]) : Boolean =
  {
    p foreach {
      case (firstName ) => return false
      case (lastName ) => return false
  //case (lastName v) => if (ntains(e)) return false
  case (_ _) => ()
    }
    true
  }

  def currentTime = javautilCalendargetInstance()getTime()
}

  注意模式匹配可以使編寫比較簡單的驗證規則變得很容易利用模式匹配綁定到原始值(比如上一個例子)或者綁定到一個本地變量(比如我們要排除任何姓名中有 e 的人比如上一個注釋)

  顯然還有事情需要做!困擾 Web 應用程序的典型問題之一是 SQL 注入攻擊它由通過 FORM 傳入的未轉義 SQL 命令字符引入並且在數據庫中執行之前連接到包含 SQL 結構的原始字符串使用 scalaregex 包中的正則表達式支持或者一些解析器組合子(在本系列最後三篇文章中討論)可以確認 FORM 驗證是否正確事實上整個驗證過程會提交給使用默認驗證實現的基類該驗證實現默認情況下只返回 true(因為 Scala 是函數性語言所以不要忽略好的對象設計方法)

  結束語

  雖然 Scala servlet 框架的功能不像其他一些 Java Web 框架的那樣完整但是我這裡創建的這個小 Scala servlet 有兩個基本用途

  ●  展示以有趣的方式利用 Scala 的功能使 JVM 編程更簡單

  ●  簡單介紹將 Scala 用於 Web 應用程序這自然會引入 lift 框架(參見 參考資料 小節)

下載

   描述 名字 大小  下載  本文的樣例 Scala 代碼  jscalazip  KB  點擊

  參考資料

  ●  您可以參閱本文在 developerWorks 全球網站上的 英文原文

  ●  Scala 和 XML(developerWorks 月)說明如何使用 Scala 導航和處理解析的 XML並詳述了對內置到該語言中的 XML 的良好支持

  ●  wiki on the Scala lift framework這是用於編寫 Web 應用程序的框架它演示了框架的著名理論(SeasideRailsDjango 和 Wicket 等)這是一本 入門教程


From:http://tw.wingwit.com/Article/program/Java/hx/201311/25711.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.