scala学習十servlet開発

6833 ワード

小さな例を挙げて、まずよく知っておきます.
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>")
}
これはJavaのバージョンに似ていますが、おなじみではないでしょうか
リクエストのタイプ名と対応するタイプを短縮するために、適切なインポートエイリアスを使用しています.それ以外は、このservletはJava servletとほぼ同じ形式です.コンパイルするときはservlet-apiを覚えておいてください.JAr(通常はservletコンテナとともにパブリッシュされます.Tomcat 6.0リリースではlibサブディレクトリに隠されています)に参照が含まれています.そうしないとservlet APIタイプが見つかりません.
これはまだ十分な準備ができていない.servlet仕様に従って、webを使用する必要があります.xmlデプロイメント記述子は、servletがどのURLに結合すべきかを記述するWebアプリケーションディレクトリ(または.warファイル)にデプロイメントされます.このような簡単な例では、かなり簡単なURLを使用して、それに合わせるのが最も簡単です.
<!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>

もちろん、フォーマットの良いHTMLはフォーマットの良いXMLと非常に似ています.この点に鑑みて、ScalaのXMLフォント値のサポートは、このservletの作成をより簡単にします(参考資料を参照).
)も参照してください.ScalaはHttpServletResponse
のStringに直接メッセージが埋め込まれています.論理と表現形式を分離できます(非常に簡単です).このサポートを使用してXMLインスタンスにメッセージを配置してから、次のように伝えます.
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オブジェクトメッセージとともに1つのscala.xml.Nodeに統合され、応答のWriterprintメソッドに渡すとStringに変換される.
この点を軽視しないでください.表現形式は論理から分離され、完全に1つのクラスの内部で行われます.このXMLメッセージはコンパイル時にチェックされ、構文が正しくフォーマットされていることを確認し、標準servlet(またはJSP)が備えていないいくつかのメリットを得ることができます.Scalaはタイプ推定が可能であるため、動的言語Groovy/Grailsのように、messageおよびcurrentDateに関する実際のタイプのメッセージを省略することができる.初めての使用は効果的です.
servletでクライアントから送信されたパラメータを取得する
この方法は、ユーザーインタフェースデザインコンテストで優勝することはありませんが、新しいScala servlet(sayMyNameの相対URLにバインドされた)にデータを送信するHTMLフォームです.これらのデータはservlet仕様に従って1つの名前-値ペアのセットに格納され、HttpServletRequest.getParameter()API呼び出しによって取得することができる.この呼び出しでは、FORM要素の名前をパラメータとしてAPI呼び出しに渡す.
class NamedHelloWorldServlet1 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 =
    java.util.Calendar.getInstance().getTime()

  override def doPost(req : HSReq, resp : HSResp) =
  {
    val firstName = req.getParameter("firstName")
    val lastName = req.getParameter("lastName")
  
    resp.getWriter().print(message(firstName, lastName))
  }
}

しかし、これは私が前に述べたメッセージ分離のいくつかのメリットに欠けています.メッセージ定義ではパラメータを明示的に使用する必要があるからです.firstName
およびlastName
;レスポンスgetで使用される要素の数が3つまたは4つを超えると、状況は複雑になります.また、doPost
メソッドは、メッセージにパラメータを渡す前に、各パラメータを自分で抽出する必要があります.このような符号化は煩雑で、エラーが発生しやすいです.
abstract class BaseServlet extends HttpServlet
{
  import scala.collection.mutable.{Map => MMap}
  
  def message : scala.xml.Node;
  
  protected var param : Map[String, String] = Map.empty
  protected var header : Map[String, String] = Map.empty
  
  override def doPost(req : HSReq, resp : HSResp) =
  {
    // Extract parameters
    //
    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
    
    // Repeat for headers (not shown)
    //
  
    resp.getWriter().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 = java.util.Calendar.getInstance().getTime()
}

もちろん、エラー処理はWebアプリケーションの処理ですFORM
の重要な部分であり、Scalaは関数言語として保存されている内容が式であり、メッセージを結果ページ(この入力が好きだと仮定)に書くか、エラーページ(この入力が好きでない場合)に書くことができることを意味します.だから、チェックfirstName
およびlastName
の非空状態の検証関数が可能
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 don't 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 (v.contains("e")) return false
	  case (_, _) => ()
    }
    true
  }

  def currentTime = java.util.Calendar.getInstance().getTime()
}

なお、モードマッチングは、比較的簡単な検証ルールの作成を容易にすることができる.パターンマッチングを使用して元の値(前の例など)にバインドするか、ローカル変数(前のコメントなど、名前に「e」がある人を排除するなど)にバインドします.
明らかに、やるべきことがある!Webアプリケーションを悩ませる典型的な問題の1つは、FORM転送されたエスケープされていないSQLコマンド文字によって導入され、データベースで実行される前にSQL構造を含む元の文字列に接続されるSQL注入攻撃です.scalaを使用する.regexパッケージの正規表現サポートは、FORM正しいかどうかを確認できます.実際には、検証プロセス全体がデフォルトの検証インプリメンテーションを使用するベースクラスにコミットされます.この検証インプリメンテーションでは、trueのみが返されます(Scalaは関数言語なので、良いオブジェクト設計方法を無視しないでください).