狠狠撸

狠狠撸Share a Scribd company logo
第41回長岡IT技術者勉強会
1週周遅れのScala入学
2015/4/11
@nemuzuka
自己紹介
? 片桐 一宗(かたぎり かずむね)
? id:nemuzuka
? @nemuzuka
? サーバサイドにJavaを使用したWebアプリケーションの
開発を主にしております
? フリーランス(vss.jp.net)
厂肠补濒补再入学のきっかけ
システムを新しく構築するチャンス
? AWSのサービス使用
? S3 / CloudSearch / CloudFront…
? 全ての操作で画面切り替えとかちょっと…
? AjaxでDOM書き換え
? HTML5
? IE?最新しかサポートしない!
? スケジュールがタイト
? 要望がコロコロ変わりそう…
そこで選んだのが
? サーバサイドはJava
? Tomcat
? Seasar2
? SAStruts
? S2Dao
+今まで培ってきた
??diconファイル
??薄いラッパー
ちょっと
開発のパワーが足りないから
外部の人の協力を得よう
『新規なのにJavaなんですか』
『新規なのにSeasar2
なんですか(??_ゝ`)』
えもいわれぬ老害感
結局Javaの構成で
無事カットオーバー
できましたが...
何か新しいこと
やらないといけないかな
選択肢は2つ
? 別のフレームワークを学ぶ
? JavaEE
? Spring
? Play Framework
? 新しい言語を学ぶ
? 静的型付けが良い
? IDEが使えた方が良い
あっ!
入学してた。
当時は「できない子」
? bot写経で躓き、「ガッ」できなかった
? みんなの「XXXのコード見せてください」の画面切り
替えが早すぎて追いつけなかった
? 単纯に手が遅い
再入学の後押し
? Javaの資産が使える
? Apache Commonsとか
? AWSのSDKだって使える
? 関数型プログラミングもオブジェクト指向プログラミングもサポート
? とりあえず「使う」だけなら関数脳にならなくても良い
? 型推論でスクリプト言語のようにも見える
? でも、IDEで追いやすい
「Javaやってます」
よりも
「Scalaやってます」
の方がなんとなく仕事が来そう
というわけで
Scala再入学することに
どうやって再入学したか?
? 今更、NullPoGaBot作ってもなー
? どうせやるなら何か案件が始まった時に使えるものにし
たい
S2でやってたことを
Scalaでやるならどうするか
に置き換えてみよう
フレームワークの置き換え
機能 JAVA SCALA
WEBフレームワーク SAStruts
Scalatra

+

scalata-forms
テンプレートエンジン JSP
Scalate

(SSP)
ORM S2Dao Slick
こんなときどうする(1)
~トランザクション管理~
トランザクション
? DBの変更を
? 適用する(commit)
? 取り消す(rollback)
? これをそれぞれのプログラムで行うと
? DBに対する操作とビジネスロジックが混在する
? ソースコードの見通しも良くない
? コネクションの解放漏れ等にも繋がる
S2だと DI
? S2の仕組みに乗れば自動的にトランザクションが効く
? @Bindingを付与して実装クラスをInjection
? 正常終了(何も例外が発生しない)時commit
? 例外が発生すればrollback
? DI使うのに外部XMLは不要
? コネクションプールもdiconに書くだけで使える
Scala(Scalatra)だと ?lter
? Scalatraのinitでコネクションプール設定
? ?lterでトランザクション制御
? トランザクション開始
? 処理呼び出し
? 正常終了(何も例外が発生しない)時commit
? 例外が発生すればrollback
ソースはこんな感じ
//Filter class
class TransactionFilter(db: Database) extends Filter {
def doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain): Unit = {
db withDynTransaction { // 1. トランザクションを開始し、ThreadLocalにSessionを格納
chain.doFilter(req, res) // 2. Servletの処理を行う
} // 3. 正常時commit、例外発生時rollback
}
}
DB
Database.dynamicSession
をimport
ThreadLocal
取得して処理を行うことが可能
class ScalatraBootstrap extends LifeCycle {
val cpds = new ComboPooledDataSource() // 1.設定ファイルを元にコネクションプールを生成
override def init(context: ServletContext) { // 2.Scalatra起動時に一回だけ呼ばれるメソッド
val db = Database.forDataSource(cpds) // 3. Slick用データソースの取得
context.addFilter("transactionFilter", new TransactionFilter(db)) // 4. TransactionFilterを?lterとして登録
context.getFilterRegistration(“transactionFilter").addMappingForUrlPatterns(
util.EnumSet.allOf(classOf[DispatcherType]), true, “/*")
// 5. Servletの定義が続く…
}
}
これでこんなLayer設計ができます
?Servlet
?Service
?→DBアクセスしないので、Sessionをコード上で意識しない
?Dao
?→ThreadLocalからSessionを取得してSQL発行
こんなときどうする(2)
~認証?認可チェック~
認証?認可
? 認証
? リクエストを送ってきた人が正規のユーザであることを確認すること
? ID / パスワードでログインしている
? 本人しかしらない筈なので、正規のユーザとみなす
? 認可
? その機能を利用する権限の有無を確認すること
? 管理者権限を所有していないのに、管理者機能を使用できるのはNG
? Webアプリの場合、URLを直接叩かれる可能性があるので、特に注意する必要あり
S2だと S2AOP
? ログイン成功時、HttpSessionにログイン情報を設定
? 受けたリクエストが認証済みでなければならない場合
? Interceptorを使用して、Actionの呼び出し前にログイン情報がHttpSessionに存在するか
チェック
? 存在しなければログイン画面へリダイレクト
? 存在するが、そのActionを使用する権限をユーザが持っていない場合、不正アクセスが
来たとみなし、しかるべき画面にリダイレクト
? AOPの定義はdiconファイルに定義
? パッケージ、クラス名等の正規表現で定義できる
Scala(Scalatra)だと ?lter
? ログイン成功時、HttpSessionにログイン情報を設定
? リクエストURIを元に受けたリクエストが認証済みで無ければならな
い場合
? ?lterでログイン情報がHttpSessionに存在するかチェック
? 存在しなければログイン画面へリダイレクト
? 存在するが、そのServletを使用する権限をユーザが持っていな
い場合、不正アクセスが来たとみなし、しかるべき画面にリダ
イレクト(これは、Servlet側機能)
こんなときどうする(3)
~コード自動生成~
ER図を常に信じられる状態にしたい
3.ソースコード
(絶対に手動で修正しない)
2.RDBMS
1.ER図
? S2Dao-CodeGen
? Slick code generator
S2だと
Scala(Slick)だと
こんなときどうする(4)
~動的SQL発行~
画面に入力された項目だけwhere句に追加
未入力の場合、その項目はwhere句に含めない
S2だと IFコメント
? 条件に応じてSQLを変更することが可能
? /* IF 条件 */…/*END*/
? 条件がtrueの場合、/*IF*/と/*END*/に囲まれた部分が評価
される
/*IF hoge != null*/hoge = /*hoge*/‘abc’/*END*/
引数hogeがnullでない場合にのみ、
hoge = hogeの値
がSQL文に追加される
Scala(Slick)だと 生Preparedstatement
? ゴニョゴニョ頑張れば他のやり方でできる気もするけど、こっちの方が確実だと思
う
? where句のカラムが動的に変わらないのであれば、StaticQueryを使用した方が良い
? 複雑なテーブル結合する場合はStaticQueryやPreparedstatement使ったほうが余計
なことにハマらなくて良いかも
? S2Dao使ってる時でも生SQLを発行してた
? ORMは楽になるところだけ使う
def coffeeByName(name: String) = sql"select * from coffees where name = $name".as[Coffee]
println("Coffee Colombian: " + coffeeByName("Colombian").?rstOption)
まだいろいろあるけど、
ドキュメント読めば何とかなります
闯补惫补使いが厂肠补濒补と戯れた感想
型推論
? 変数名定義の時にクラス名の有無でこんなに違うかーっ
てくらいスッキリします
[Scala]
val credentials = new BasicAWSCredentials(accessKey, secretKey)
val s3client = new AmazonS3Client(credentials)
val localFile = new File("ローカルファイルパス")
val bucketName = "バケット名"
val ?lePath = "S3のアップロード先のパス"
val upReq = new PutObjectRequest(bucketName, ?lePath, localFile)
s3client.putObject(upReq)
[Java]
AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
AmazonS3 s3client = new AmazonS3Client(credentials);
File localFile = new File("ローカルファイルパス");
String bucketName = "バケット名";
String ?lePath = "S3のアップロード先のパス";
PutObjectRequest upReq = new PutObjectRequest(bucketName, ?lePath, localFile);
s3client.putObject(upReq);
名前付き引数
? 大好きです。Javaにもあれば良いのに
? 使う側が意識して設定するようになるのがイイと思います
? 引数の順番が変わった時にも追従してくれます
? 特にSlickのデータモデル(case class)のインスタンスを生成するときは嬉しい
? カラムの追加や順番を変更することが多いので
[Scala]
case class User(age:Int, name:String)
?
?
?
val hanako = User(7, “はなこ”) // ①
val jiro = User(age = 38, name = “二郎”) // ②
val taro = User(name = “太郎”, age = 17) // ③
→全てUserクラスのインスタンスが生成可能だが、
case class User(name:String, age:Int)
と変更した場合、①はコンパイルエラーになる
index付きループ
? Javaにもあれば良いのに
? Javaだと拡張forを諦めてfor(int i = 0; i < list.size(); i++)
[Scala]
val list = List("A", "B", "C")
for((e, index) <- list.zipWithIndex) {
// eには該当要素、indexには該当indexが格納される
?
?
?
}
まだまだあるよ
? if とか for は式なので値を返せる
? 「このifで何をしたいんだっけ?」が見えるようになるのがイイ!
? 複数の戻り値を返せる(タプル)
? わざわざ戻り値用のclass作らなくてもいいんです
? traitでmix-inがすごい
? チェック例外がない
? 個人的にはあってもいいと思うけど…(設計思想変える必要あり)
? Either(さっきのヤツ!)
? 比較は「==」でOK
? equalsを使わなくて怒られる新人減ります
? breakが変
? もなど / かりー?→?よくわかりません
再入门に準备したもの
purchase from
https://gist.github.com/Shinpeim/6740436
まとめ
? 結構面白いです、Scala
? 潤沢なメモリ+SSD必須
? 金食い虫なので仕事に使うなら上の理解が必要かも
? 次はテスト周りをしっかりと

More Related Content

1周遅れのScala入学 #nds41