Scalatraは、
Sinatraに近い軽量で高性能なWebフレームワークであり、RubyからScalaに移行するときの生活をより簡単にすることができます。 この記事では、認証機能を備えたシンプルなアプリケーションを作成する例に関するこの興味深いフレームワークについて、マニュアルがロシア語にない場合のギャップを埋めたいと思います。
設置
公式ドキュメントでは、事前に準備されたテンプレートから
giter8を使用してプロジェクトを作成することを提案しています。 ただし、不要なツールを使用せずに実行する場合は、次のようにsbtプロジェクトを簡単に作成できます。
プロジェクト\ plugins.sbtaddSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "1.1.0")
このプラグインを使用すると、特別な
sbtコマンドを使用してWebサービスを開始できます。
$ sbt > container:start
build.sbt val scalatraVersion = "2.4.0-RC2-2" resolvers += "Scalaz Bintray Repo" at "https://dl.bintray.com/scalaz/releases" lazy val root = (project in file(".")).settings( organization := "com.example", name := "scalatra-auth-example", version := "0.1.0-SNAPSHOT", scalaVersion := "2.11.6", scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature"), libraryDependencies ++= Seq( "org.scalatra" %% "scalatra-auth" % scalatraVersion, "org.scalatra" %% "scalatra" % scalatraVersion, "org.scalatra" %% "scalatra-json" % scalatraVersion, "org.scalatra" %% "scalatra-specs2" % scalatraVersion % "test", "org.json4s" %% "json4s-jackson" % "3.3.0.RC2", "javax.servlet" % "javax.servlet-api" % "3.1.0" % "provided" ) ).settings(jetty(): _*)
追加されたライブラリの目的はその名前から理解できます
。jsonや認証が必要ない場合は、不要なライブラリを安全に削除できます。
ルーティング
サービスが要求への応答を開始するには、最初に要求に応答するコントローラーを指定する必要があります。 このために次のファイルを作成しましょう。
src \ main \ webapp \ WEB-INF \ web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>user</servlet-name> <servlet-class> org.scalatra.example.UserController </servlet-class> </servlet> <servlet-mapping> <servlet-name>user</servlet-name> <url-pattern>/user/*</url-pattern> </servlet-mapping> </web-app>
xmlを嫌う場合は、この方法で同じことをよりコンパクトに記述できます。
src / main / scala / ScalatraBootstrap.scala import org.scalatra.example._ import org.scalatra._ import javax.servlet.ServletContext class ScalatraBootstrap extends LifeCycle { override def init(context: ServletContext) { context.mount(new UserController, "/user") } }
ここでは、
org.scalatra.example.UserControllerがパス
yoursite.example / userで始まるリクエストに応答することを決定し
ました 。 このファイルの仕組みを見てみましょう。
src \ main \ scala \ org \ scalatra \ example \ UserController.scala package org.scalatra.example import org.json4s.{DefaultFormats, Formats} import org.scalatra._ import org.scalatra.json.JacksonJsonSupport import scala.util.{Failure, Success, Try} class UserController extends ScalatraServlet with AuthenticationSupport with JacksonJsonSupport { protected implicit lazy val jsonFormats: Formats = DefaultFormats before() { contentType = formats("json") basicAuth() } get("/") { DB.getAllUsers } get("/:id") { Try { params("id").toInt } match { case Success(id) => DB.getUserById(id) case Failure(ex) => pass() } } }
このコードをさらに詳しく分析してみましょう。 まず、
Scalatraのすべてのコントローラーは
ScalatraServletを継承する必要があります。 サーブレットが応答するパスを決定するには、たとえば、要求のタイプに応じて、get、post、put、またはdeleteブロックを追加します。
get("/") { }
yoursite.example / userへのリクエストに応答します。 パラメータのいずれかがURLの一部である場合、次のようにパラメータを記述する必要があります。
get("/:id") { params("id") }
その結果、
params()メソッドを使用してgetブロック内でidパラメーターを使用できます。 同様に、残りのクエリパラメータを取得できます。
/ user / 52のように、同じ名前の複数のパラメーターを渡したい場合は、
Foo = uno&bar = dos&baz = three&foo = anotherfoo (fooパラメーターが2回使用されることに注意してください)、
multiParams()関数を使用して、均一に処理できますパラメーター、例えば:
multiParams("id")
Pass()メソッドは
UserControllerで使用されることに注意してください。 特定のルートでの処理をスキップして、次のルートに進むことができます(この場合、この方法に該当するハンドラーはこれ以上ありません)。 要求の処理を中断し、ユーザーにエラーページを表示する場合は、
halt()メソッドを使用します。このメソッドは、たとえば、リターンコードやエラーテキストなどのさまざまなパラメーターを取ることができます。
フレームワークによって提供される別の可能性は、たとえば次のように書くことで、プリハンドラーとポストハンドラーを設定することです。
before() { contentType = formats("json") basicAuth() }
応答のタイプ(この場合は
json )を指定し、ユーザーからの認証を要求できます(認証とjsonの操作については、以下のセクションで説明します)。
ルーティングの詳細については、
公式ドキュメントを参照してください 。
DBを使用する
前のセクションでは、BDクラスから取得したオブジェクトをコントローラーの応答として使用します。 ただし、
Scalatraには、データベースを操作するための組み込みフレームワークがありません。これに関連して、データベースを操作する模倣を残しました。
src \ main \ scala \ org \ scalatra \ example \ DB.scala package org.scalatra.example import org.scalatra.example.models.User object DB { private var users = List( User(1, "scalatra", "scalatra"), User(2, "admin", "admin")) def getAllUsers: List[User] = users def getUserById(id: Int): Option[User] = users.find(_.id == id) def getUserByLogin(login: String): Option[User] = users.find(_.login == login) }
src \ main \ scala \ org \ scalatra \ example \ models \ User.scala package org.scalatra.example.models case class User(id: Int, login:String, password: String)
ただし、これに問題があるとは思わないでください-公式
ドキュメントには、
Scala 、
MongoDB 、
Squeryl 、
Riakなどの最も一般的なデータベースと
ORMで
Scalatraを友達にする方法が記載されています。
ジョンソン
コントローラーは、
ケースクラスUserを直接返すか、オプション[ユーザー]およびリスト[ユーザー]でさえ返すことに注意してください。 デフォルトでは、
Scalatraは戻り値を文字列に変換し、リクエストへの応答として使用します。たとえば、/ユーザーリクエストへの応答は次のようになります。
List(User(1,scalatra,scalatra), User(2,admin,admin)).
サーブレットがjsonとの連携を開始するには、次のことを行う必要があります。
これらの簡単な手順を実行すると、同じ/ユーザーリクエストに対する応答は次のようになります。
[{"id":1,"login":"scalatra","password":"scalatra"},{"id":2,"login":"admin","password":"admin"}]
認証
最後に、ユーザー認証などのトピックに触れたいと思います。 これを行うには、
Scentに移植された
Wardenフレームワークである
Scentryフレームワークを使用することを提案します。これは、Rubyに精通している人々にとっても生活を楽にします。
UserControllerクラスをよく見ると、認証がすでに実装されていることがわかります。 これを行うために、
AuthenticationSupport特性がクラスに追加され、
basicAuth()メソッドが
before()フィルターで呼び出されます。
AuthenticationSupportの実装を見てください。
src \ main \ scala \ org \ scalatra \ example \ AuthenticationSupport.scala package org.scalatra.example import org.scalatra.auth.strategy.{BasicAuthStrategy, BasicAuthSupport} import org.scalatra.auth.{ScentrySupport, ScentryConfig} import org.scalatra.example.models.User import org.scalatra.ScalatraBase import javax.servlet.http.{HttpServletResponse, HttpServletRequest} class OurBasicAuthStrategy(protected override val app: ScalatraBase, realm: String) extends BasicAuthStrategy[User](app, realm) { protected def validate(userName: String, password: String)(implicit request: HttpServletRequest, response: HttpServletResponse): Option[User] = { DB.getUserByLogin(userName).filter(_.password == password) } protected def getUserId(user: User)(implicit request: HttpServletRequest, response: HttpServletResponse): String = user.id.toString } trait AuthenticationSupport extends ScentrySupport[User] with BasicAuthSupport[User] { self: ScalatraBase => val realm = "Scalatra Basic Auth Example" protected def fromSession = { case id: String => DB.getUserById(id.toInt).get } protected def toSession = { case usr: User => usr.id.toString } protected val scentryConfig = new ScentryConfig {}.asInstanceOf[ScentryConfiguration] override protected def configureScentry() = { scentry.unauthenticated { scentry.strategies("Basic").unauthenticated() } } override protected def registerAuthStrategies() = { scentry.register("Basic", app => new OurBasicAuthStrategy(app, realm)) } }
最初に行うことは、認証戦略(
ScentryStrategyインターフェイスを実装するクラス)を定義することです。 この場合、いくつかの標準メソッド
を実装する
BasicAuthStrategy [User]プリフォームを使用し
ました 。 その後、2つのメソッドを定義する必要があります
-validate() 、ログインが成功した場合にSome [User]を返すか、不正なデータの場合にNoneと
getUserId() 、応答ヘッダーにさらに追加するための文字列を返す必要があります。
次に行うことは、
OurBasicAuthStrategyと
ScentrySupportを
AuthenticationSupportトレイトに組み合わせること
です 。これをコントローラーと混合します。 その中で、認証戦略を登録し、(最も簡単な方法で)セッションからユーザーオブジェクトを取得し、逆にそのIDをセッションに追加する方法を実装しました。
その結果、ログインしていないユーザーが
UserControllerが処理するページに
アクセスする場合、ユーザーは最初にユーザー名とパスワードを入力する必要があります。
おわりに
この記事では、
Scalatraの選択的な機能の一部のみを示しました。 このフレームワークはロシア語圏のコミュニティではあまり人気がありませんが、実装された機能の範囲が広く、開発が容易なため、小さなWebサービスと大規模なサイトの両方を作成するのに非常に有望です。
記事を読んでもまだ質問がある場合は、コメントまたは次の記事で回答する準備ができています。
すべてのソースコードは
githubで入手できます。
素敵な勉強をしてください!