Scalaで自転車を発明する-フレームワークORM、WebServer(RESTfulおよびMVC)

この記事は、 Javaで自転車を発明する-フレームワーク(DI、ORM、MVCなど)を作成する 、前回の投稿の論理的な続きです。 私の最初のJavaフレームワークが公開されてから数ヶ月が経ちました。 運が良かったので、開発を商用プロジェクトに適用しました。 実際には、それを使用することがどのように便利かについての私の多くの仮定が間違っていることが判明しました。 しかし、私はライブラリをfi罪し、書き直し、補足しませんでした。 私の最初の記事のAPIと現在ライブラリにあるAPIを比較すると、進行状況がわかります。



しかし、Scalaに戻ります。 PlayフレームワークとSprayフレームワークがどのように機能するかを見ました。 Highloadを提供するために、すべてがアクター(アクター)スタイルのアーキテクチャに焦点を当てているという傾向に気付きました。 もちろんこれは大丈夫で有望です。 しかし、何らかの理由で、これを追求することでプロジェクトのコーディングが少し複雑になりました。 通常の非Highloadプロジェクトがある場合、PlayとSprayはまったく得られず、Scalaの利点の1つを実装する代替手段はなく、Javaよりも少ない文字を書くことが判明しました。 特に、Springブート、Spring Dataなどに注目してください。 そこはすべてかわいい、短くて美しい。 また、Scalaでは、アクタースタイルのライブラリは、使いやすさの点で最初のJ2EEバージョンに似ています。



画像





私はSchorの研究を、Horstman K.-せっかちな人のためのScala(ロシア語版があります)を読むことから始めました。 その後、数ヶ月の休憩があり、その間にJavaでフレームワークを磨き、疑いなくScalaの良さを思い出しました。 しかし、最終的には、私はまだScalaでライブラリを作成することを決定し始めました。 私は2つのニュアンスに気付きました。





最初は、JavaライブラリーをScalaでラップしました(Jsonと連携)。 その後、Jettyを使用してJava実装の奥深くでアーキテクチャ機能に明らかに出会ったので、このセクションをJavaからScalaに書き直しました。 あちらこちらで素晴らしい経験をしました。 私は個人的にScalaでコードを書くのが本当に短くて速いことを確認しました(特に言語構文を覚えているとき)。 また、既存のJavaライブラリとフレームワークの蓄積されたすべての荷物をScalaプロジェクトで簡単に使用できます。 私はあなたがDSL(Subject-Oriented Language)を作ることを可能にするScalaマジックについて話しているのではありません。 OOP(Object-Oriented Programming)の登場の理由を思い出してください。これは、人間が読み取り可能な表現のレベルでコードを読み取り可能かつ理解可能にしたいという願望です。 Scalaでは、これをより高いレベルで実行できます。 たとえば、if、for、switchなどに似た制御構造を記述することができます(これをトランザクションのORMで使用)。



結果として、githubフレームワークコードgithub.com/evgenyigumnov/scala-common



github.com/evgenyigumnov/example-scala githubでこのフレームワークを使用するWebサービスの例



構造例:

./: build.sbt ./javascript: user.js ./pages: index.html layout.html login.html ./sql: 1.sql ./locale: messages_en.properties ./src/main/scala/com/igumnov/scala-2.11/example: ExampleUser.scala SiteServer.scala
      
      







build.sbt

 name := "example-scala" version := "1.0" scalaVersion := "2.11.7" libraryDependencies += "com.igumnov.scala" % "scala-common_2.11" % "0.5" //    libraryDependencies += "com.h2database" % "h2" % "1.4.187" //   //  Bootstrap, AnglularJS    webjars  libraryDependencies += "org.webjars" % "angular-ui-bootstrap" % "0.12.0" libraryDependencies += "org.webjars" % "angularjs" % "1.3.8" libraryDependencies += "org.webjars" % "bootstrap" % "3.3.1"
      
      







SiteServer.scala

 package com.igumnov.scala.example import java.util.Calendar import com.igumnov.scala._ import com.igumnov.scala.webserver.User object SiteServer { def main(args: Array[String]) { //      ( 3 ) ORM.connectionPool("org.h2.Driver", "jdbc:h2:mem:test", "SA", "", 1, 3) //             ORM.applyDDL("sql") //      WebServer.setPoolSize(5,10) //    - WebServer.init("localhost", 8989) //       WebServer.loginService((name) => { val user = ORM.findOne[ExampleUser](name) if (user.isDefined) { Option(new User(user.get.userName, user.get.userPassword, Array[String]("user_role"))) } else { Option(null) } }) //           URL- WebServer.securityPages("/login", "/login?error=1", "/logout") //        user_role WebServer.addRestrictRule("/*", Array("user_role")) //        WebServer.addAllowRule("/static/*") //        classpath  webjars WebServer.addClassPathHandler("/static", "META-INF/resources/webjars") //       Java Script- WebServer.addAllowRule("/js/*") //         Java Script WebServer.addStaticContentHandler("/js", "javascript") //        (      ) //           -  WebServer.locale(Map("en" -> "locale/messages_en.properties"), (rq,rs)=>{ "en" }) //          WebServer.templates("pages",0) //     "/",        ,    index.html WebServer.addController("/", (rq, rs,model) => { model += "time" -> Calendar.getInstance.getTime "index" }) //     "/login",  ,    login.html WebServer.addController("/login", (rq, rs,model) => { "login" }) //  REST-   "/rest/user"      POST/PUT  JSON-  ExampleUser WebServer.addRestController[ExampleUser]("/rest/user", (rq, rs, obj) => { rq.getMethod match { case "GET" => { //  GET  ORM.findAll[ExampleUser]() //    } case "POST" => { //  POST  val user = obj.get user.userPassword = WebServer.crypthPassword(user.userName, user.userPassword) ORM.insert(obj.get) //     } case "DELETE" => { //  DELETE  val user = ORM.findOne[ExampleUser](rq.getParameter("userName")) //   demo    if(user.get.userName == "demo") throw new Exception("You cant delete demo user") ORM.delete(user.get) user.get } } }) //            JSON      Error WebServer.addRestErrorHandler((rq, rs, e) => { object Error{ var message:String =_ } Error.message = e.getMessage Error }) val users = ORM.findAll[ExampleUser] //      if(users.size==0) { //      val user = new ExampleUser user.userName="demo" user.userPassword=WebServer.crypthPassword(user.userName, "demo") ORM.insert(user) //  demo/demo    } //             Exception,   - :) WebServer.start } }
      
      







ExampleUser.scala

 //     JSON          package com.igumnov.scala.example import com.igumnov.scala.orm.Id class ExampleUser { @Id(autoIncremental = false) var userName: String = _ var userPassword: String = _ }
      
      







1.sql

 #         ORM   ExampleUser.class CREATE TABLE ExampleUser (userName VARCHAR(255) PRIMARY KEY, userPassword VARCHAR(255))
      
      







login.html

 <!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd"> <!--      layout  layout.html --> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout"> <body> <!--         layout.html --> <div layout:fragment="content"> <form name="form" action="/j_security_check" method="POST"> <div class="modal-header"> <h3 class="modal-title" th:text="#{login.title}"></h3> <!--       --> </div> <div class="modal-body"> <div class="form-group"> <input type="text" name="j_username" class="form-control" value="" placeholder="Login"/> </div> <div class="form-group"> <input type="password" name="j_password" class="form-control" placeholder="Password"/> </div> <div class="form-group"> <button type="submit" id="login" class="btn btn-primary">OK</button> </div> </div> </form> </div> </body> </html>
      
      







index.html

 <!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd"> <!--      layout  layout.html --> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout"> <body> <!--         layout.html --> <div layout:fragment="content"> <!--     AngularJS--> <script src="/js/user.js"></script> <h1 th:text="${time}"></h1> //       <!--      UserCtrl --> <div ng-controller="UserCtrl"> <table class="table"> <thead> <tr> <th>Name</th> <th>Password</th> <th></th> </tr> </thead> <tbody> <!--      --> <tr ng-repeat="user in users"> <td>{{user.userName}}</td> <td>{{user.userPassword}}</td> <!--            --> <td><a href="#"><span class="glyphicon glyphicon-remove" tooltip="Delete" ng-click="deleteUser(user)"/></a></td> </tr> </tbody> </table> <div ng-model="user"> <!--    --> <div class="form-group"> <input type="text" class="form-control" ng-model="user.userName" placeholder="Login"/> </div> <div class="form-group"> <input type="password" class="form-control" ng-model="user.userPassword" placeholder="Password"/> </div> <div class="form-group"> <!--           --> <button class="btn btn-primary" ng-click="addUser(user)">Add</button> </div> </div> </div> </div> </body> </html>
      
      







layout.html

 <!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd"> <!--      AngularJS --> <html ng-app="com.igumnov.common.example"> <head> <title>Title</title> <link rel="stylesheet" href="/static/bootstrap/3.3.1/css/bootstrap.min.css" /> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> </head> <body> <script src="/static/angularjs/1.3.8/angular.min.js"></script> <script src="/static/angularjs/1.3.8/angular-resource.min.js"></script> <script src="/static/angular-ui-bootstrap/0.12.0/ui-bootstrap-tpls.min.js"></script> <div class="container"> <!--      --> <div layout:fragment="content"></div> </div> </body> </html>
      
      







user.js

 angular.module('com.igumnov.common.example', ['ui.bootstrap', 'ngResource']) .factory('User', ['$resource', function ($resource) { //  REST- User return $resource('/rest/user', {}, { list: { //   method: 'GET', cache: false, isArray: true //    }, add: { //   method: 'POST', cache: false, isArray: false //     }, delete: { //   method: 'DELETE', cache: false, isArray: false //     } }); }]) .controller('UserCtrl', function ($scope, User) { //    UserCtrl $scope.users = User.list({}); //       $scope.addUser = function (user) { //    User.add({},user,function (data) { //  REST- $scope.users = User.list({}); //   ,    }, function (err) { alert(err.data.message); //   ,   }); } $scope.deleteUser = function (user) { //    User.delete({"userName" : user.userName},user,function (data) { //  REST- $scope.users = User.list({}); //   ,    }, function (err) { alert(err.data.message); //   ,   }); } });
      
      







messages_en.properties

 login.title=Login
      
      







結論として、ScalaはJavaで書かれた商用プロジェクトに実装されると言えます。 Javaで行ったことから何も書き直しませんが、間違いなくScalaで新しいモジュールを書きます。 この決定の理由:Scalaはより速く、より便利で、よりクリーンなコードです。 一般に、それは効果的です。



PS Scalaを初めて使用するので、コードで批判を聞いてうれしいです。 私が間違っていることを理解するには、フィードバックが必要です。



All Articles