Slick+PlayFramework2.1でDBアクセスしjsonで出力

実際の業務では、サンプルなどでよく見かける、データの作成、更新、参照、削除という流れは実際ではあまりなく、既にあるデータを参照するだけとか祖いうのが多いかと思います。

前回までで、既存データベースに入っているデータを取得することができたので、JSON形式で出力してみます。

GSON

sjsonやPlay標準のJSONなど何種類かあるようですが、ちょっと試したところうまくいかなかったので、GSONを使用することにしました。

あらかじめGSONをダウンロードしておきeclipseのパスに追加しておきます。

http://code.google.com/p/google-gson/

mysql

use data
;
create table price(
code varchar(10) not null,
date datetime not null,
open int ,
high int,
low int,
close int
)
;
create unique index price1 on price(code,date)
;

application.conf

db.default.driver=com.mysql.jdbc.Driver
db.default.url="jdbc:mysql://localhost/data"
db.default.user=root
db.default.password=
slick.default="models.*"
evolutionplugin=disabled

routes

GET /data/price/:code	controllers.Data.OHLC(code:String)

controllers.Data.scala

package controllers
import play.api._
import play.api.mvc._
import models._
import com.google.gson._

object Data extends Controller {
	val gson:Gson=new GsonBuilder().setDateFormat("yyyy-MM-dd").create // 日付のフォーマットをしておく
	def OHLC(code:String)=Action {
		Ok(views.html.json(gson.toJson(Prices.select(code))))
	}
}

models.Price.scala

package models
import scala.slick.driver.H2Driver.simple._
import Database.threadLocalSession

import play.api.db._
import play.api.Play._

import scala.slick.jdbc.{GetResult, StaticQuery => Q}
import Q.interpolation

case class Price(code:String,date:java.sql.Date,open:Int,high:Int,low:Int,close:Int) extends Ordered[Price]{
	def compare(that:Price):Int={
		date.getTime().compare(that.date.getTime())
	}
}

object Prices extends Table[Price]("price") {
	val DATE_TERM=180 // 180日分とる
	
	def code=column[String]("code",O.PrimaryKey)
	def date=column[java.sql.Date]("date",O.PrimaryKey)
	def open=column[Int]("open")
	def high=column[Int]("high")
	def low=column[Int]("low")
	def close=column[Int]("close")
	def * = code ~ date ~ open ~ high ~ low ~ close <> (Price,Price.unapply _)

	implicit val getPrice=GetResult(rs=>Price(rs<<,rs<<,rs<<,rs<<,rs<<,rs<<))
	
	def select(code:String)= connectDB{
		val list=sql"select * from price where code=$code order by date desc limit $DATE_TERM".as[PriceHistAdj].list.sorted
		// sort 逆順なので並べ替える、GSON用にArrayList化
		val ary=new java.util.ArrayList[Price]
		for(l<-list)ary.add(l)
		ary
	}
	def connectDB[Any](f: => Any): Any = {
		Database.forDataSource(DB.getDataSource("data")) withSession {
			f
		}
	}
}

views.json.scala.html

jsonp用

@(json:String)
callback(@json);

Slick+PlayFramework2.1でDBアクセス#2

既存のデータベースにアクセスしてみます。

DBのコネクションをPlayFrameworkから与えることでモデル側でコネクションを作成しません

MySQL

create table OHLC(
code varchar(10) not null,
date datetime not null,
open int null,
high int null,
low int null,
close int null,
unique key OHLC1(code,date) 
)

application.conf

db.default.driver=org.gjt.mm.mysql.Driver
db.default.url="jdbc:mysql://localhost/live?useOldAliasMetadataBehavior=true" 
db.default.user=root
db.default.password="" 
slick.default="models.*"
evolutionplugin=disabled

routes

GET /:code controllers.Application.price(code:String)

controllers.Application.scala

package controllers

import play.api._
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
import models._

object Application extends Controller {
	def price(code:String) = Action{
		Ok(views.html.index(Price.select(code)))
	}
}

models.Price.scala

package models
import scala.slick.driver.H2Driver.simple._
import Database.threadLocalSession

import play.api.db._
import play.api.Play._

import scala.slick.jdbc.{GetResult, StaticQuery => Q}
import Q.interpolation


case class Price(code:String,date:java.sql.Date,open:Int,high:Int,low:Int,close:Int)

object Prices extends Table[Price]("OHLC"){
	def scode=column[String]("code",O.PrimaryKey)
	def date=column[java.sql.Date]("date",O.PrimaryKey)
	def open=column[Int]("open")
	def high=column[Int]("high")
	def low=column[Int]("low")
	def close=column[Int]("close")

	def * = code ~ date ~ open ~ high ~ low ~ close <> (Price,Price.unapply _)

	implicit val getPrice=GetResult(rs=>Price(rs.nextString,rs.nextDate,rs.nextInt,rs.nextInt,rs.nextInt,rs.nextInt))
	
	def price(code:String):List[Price]= connectDB{
		sql"select * from OHLC where code=$code".as[Price].list
	}
	
	def connectDB[Any](f: => Any): Any = {
		Database.forDataSource(DB.getDataSource("default")) withSession {
			f
		}
	}
}

views.index.scala.html

@(prices: List[Price])
				@prices.map { price =>
						@price.code,
						@price.date
						@price.open
}

Slick+PlayFramework2でデータベースアクセス

ScalaでPlayFrameworkを使う場合にDBアクセスにはanormとslickがあるようです。

slickはscalaQueryと呼ばれていたものが進化した模様。

scala2.9まではscalaQuery,それ以降はslickらしいです

http://d.hatena.ne.jp/tototoshi/20121204/1354615421

Build.scalaに必要なモジュールを書いてインストールするのが一般的らしいですが、うまくいかなかったので手動インストールで作成してみます。

slick

https://github.com/freekh/play-slick

からZIPでダウンロードし解凍

 $ cd slick-1.0.1
 $ sbt
 > compile
 > package
 $ find .|grep jar
	./slick-testkit/target/scala-2.10/slick-testkit_2.10-1.0.1.jar
	./target/root/scala-2.10/root_2.10-1.0.1.jar
	./target/scala-2.10/slick_2.10-1.0.1.jar

play-slick

プラグインなのでこちらも入れます

https://github.com/freekh/play-slick

 $ cd play-slick-master
 $ sbt
 > compile
 > package
 $ find .|grep jar
 ./target/scala-2.10/play-slick_2.10-0.3.3-SNAPSHOT.jar

プロジェクト作成

$ play new sample
			 _						_
 _ __ | | __ _ _	_| |
| '_ \| |/ _' | || |_|
|	__/|_|\____|\__ (_)
|_|						|__/

play! 2.1.2 (using Java 1.7.0_25 and Scala 2.10.0), http://www.playframework.org

The new application will be created in /Users/admin/Documents/workspace/play_sample/sample

What is the application name? [sample]
> sample

Which template do you want to use for this new application? 

	1						 - Create a simple Scala application
	2						 - Create a simple Java application

> 1
OK, application sample is created.

Have fun!

$ cd sample
$ play eclipse
$ mkdir lib
$ cp slick-1.0.1/target/scala-2.10/slick_2.10-1.0.1.jar .
$ cp play-slick-master/target/scala-2.10/play-slick_2.10-0.3.3-SNAPSHOT.jar .

Eclipse

  • eclipseの既存プロジェクトの読み込みで読み込む
  • プロジェクトのプロパティからslick_2.10-1.0.1.jar、play-slick_2.10-0.3.3-SNAPSHOT.jarのライブラリを追加

PlayFramework

http://takashima0411.hatenablog.com/entry/2012/11/28/231817

こちらの方のサンプルをそのままいただきました

Application.scala
package controllers

import play.api._
import play.api.mvc._

import play.api.data._
import play.api.data.Forms._

import models._

object Application extends Controller {

	val taskForm = Form(
		"label" -> nonEmptyText)

	def index = Action {
		Redirect(routes.Application.tasks)
	}

	def tasks = Action {
		Ok(views.html.index(Tasks.all(), taskForm))
	}

	def newTask = Action { implicit request =>
		taskForm.bindFromRequest.fold(
			errors => BadRequest(views.html.index(Tasks.all(), errors)),
			label => {
				Tasks.create(label)
				Redirect(routes.Application.tasks)
			})
	}

	def deleteTask(id: Long) = Action {
		Tasks.delete(id)
		Redirect(routes.Application.tasks)
	}

}
Task.scala
package models

import scala.slick.driver.H2Driver.simple._
import Database.threadLocalSession

case class Task(id: Long, label: String)

object Tasks extends Table[Task]("TASK") {

	def id = column[Long]("ID", O.PrimaryKey, O.AutoInc)
	def label = column[String]("LABEL", O.NotNull)
	def * = id ~ label <> (Task, Task.unapply _)
	def ins = label returning id

	def all(): List[Task] = connectDB {
		Query(Tasks).sortBy(_.id).list
	}

	def create(label: String) = connectDB {
		Tasks.ins.insert(label)
	}

	def delete(id: Long) = connectDB {
		Tasks.where(_.id === id).delete
	}

	def connectDB[Any](f: => Any): Any = {
		Database.forURL("jdbc:h2:mem:play", driver = "org.h2.Driver") withSession {
			f
		}
	}

}
Global.scala
import play.api._
import models._
import scala.slick.driver.H2Driver.simple._
import Database.threadLocalSession

import models._
import java.sql.{Date,Time,Timestamp}

object Global extends GlobalSettings {

	override def onStart(app: Application) {
		Logger.info("Application has started")

		Database.forURL("jdbc:h2:mem:play", driver = "org.h2.Driver") withSession {

			Tasks.ddl.create

		}

	}

	override def onStop(app: Application) {
		Logger.info("Application shutdown...")
	}

}
index.scala.html

@(tasks: List[Task], taskForm: Form[String])

@import helper._


		
		

@tasks.size task(s)

    @tasks.map { task =>
  • @task.label @form(routes.Application.deleteTask(task.id)) { }
  • }

Add a new task

@form(routes.Application.newTask) { @inputText(taskForm("label")) }
routes
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~

# Home page
GET		 /													 controllers.Application.index
GET		 /index											controllers.Application.index
GET		 /tasks											controllers.Application.tasks
GET		 /newTask										controllers.Application.newTask
GET		 /deleteTask/:id								 controllers.Application.deleteTask(id:Long)

# Map static resources from the /public folder to the /assets URL path
GET		 /assets/*file							 controllers.Assets.at(path="/public", file)
application.conf
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"


slick.default="models.*"

# Evolutions
# ~~~~~
# You can disable evolutions if needed
evolutionplugin=disabled

これでとりあえず動きます

Eclipse4.3 Kepler で逆コンパイル

eclipseの逆コンパイルのjd-clipseですが、いつの頃からかデフォルトで動かなくなってしまいました。

以下の方法で動くようになりました

  • MacOS 10.8
  • Eclipse 4.3

Jd-clipseよりこちらが良さそうです

Mchr3k – JDEclipse-Realign

http://mchr3k.github.com/jdeclipse-realign/

1.EclipseについてーInstallation DetailsからJD-Eclipseをアンインストール

2.HelpーInstall New Softwareでhttp://mchr3k-eclipse.appspot.com/からインストール(Java Decomplier Eclipse PluginだけでOK)

3.Eclipse環境設定ーGeneralーEditorsーFileAssociationsでclassとclass witiout sourceにClassFileEditorを追加しdefault にする

これでOKのはず

JavaScriptでコールバック関数に引数をとりAjaxでデータを取得してみる

JavaScriptでコールバック関数の実装ですが、いろいろなところで書かれているのですがちょっとよくわからなかったので試してみました。

a.html


	  
	

これで

	a=d,b=c

と表示されます。

ここでjQueryを使ってAjaxでデータを取得してみます。

b.txt

test

これを用意しておきhttpで取得してみます


    


a=test,b=d

うまくとれましたが、これでいいのかどうか。

統計ソフトRを使用して株価チャートを簡単に作成(4)

ようやくチャートが描ける準備が整ったので分析に入ります。

まずは自分で作成した計算式で作成した値をチャートに書いてみます

library(RFinanceYJ)
library(quantmod)
stockCode<-"6758.t"
today<-Sys.Date()
sinceDate<-today-100 #100日分
stockData<-quoteStockTsData(stockCode,since=sinceDate)
colnames(stockData)<-c("Date","Open","High","Low","Close","Volume")
stockData.zoo<-read.zoo(stockData)
candleChart(stockData.zoo,theme="white")
#とりあえず平均値をチャート領域に書いてみる
mydata<-data.frame(Date=stockData$Date,Close=mean(stockData$Close))
mydata.zoo<-read.zoo(mydata)
addTA(mydata.zoo,on=1,col="red")