play24 の変更点   

  • 追加された行はこの色です。
  • 削除された行はこの色です。
  • play24 へ行く。

#author("2017-11-16T01:48:50+00:00","default:pentacle","pentacle")
play2.4 になってだいぶかわったので書き直し

JAVA 用です!~

----
* はじめに [#q9a7f043]

- activator 

''play コマンドがなくなって activator コマンドになった''

COLOR(RED):''activator コマンドがなくなって sbt コマンドになった(May/2017)(んもう!''

インストールも実行も全部 activator

 mkdir /usr/local/play24

 https://www.playframework.com/download

* install [#i2cb0429]

activator をダウンロードしてどこかに置く~
cygwin では実行するとエコーを奪われてしまうので戻す必要がある~


.bashrc 
 function activator(){
        /usr/local/play24/activator $@
        stty sane
 }
 function playkill(){
      ps aux -W |grep java |uniq | head -1 |awk '{print $1;}' |xargs kill 
 }
 alias activatordebug='activator -jvm-debug 9999 run'


* eclipse [#ee682e90]

[[eclipse]]

* hello world [#w30bce6c]
 activator 

 UI で、java のシンプルなテンプレートを選ぶ

 cd helloworld

** 2.4 でいろいろ変わった設定 [#n5574081]

- play eclipse がプリインストールではなくなりました。
- ebean がプリインストールではなくなりました。
- evolution がデフォではなくなりました
- PlayEbean がデフォではなくなりました

''project/plugins.sbt''
 addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "1.0.0")
 addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "4.0.0-RC2")

 activator 

 eclipse with-source=true
 exit

''build.sbt''
下記行を変更
 lazy val root = (project in file(".")).enablePlugins(PlayJava,PlayEbean)

 fork in run := false

 sources in (Compile,doc) := Seq.empty
  
 publishArtifact in (Compile, packageDoc) := false
 import com.typesafe.sbt.packager.Keys.scriptClasspath
 
 scriptClasspath := {
   val originalClasspath = scriptClasspath.value
   val manifest = new java.util.jar.Manifest()
   manifest.getMainAttributes().putValue("Class-Path", originalClasspath.mkString(" "))
   val classpathJar = (target in Universal).value / "lib" / "classpath.jar"
   IO.jar(Seq.empty, classpathJar, manifest)
   Seq(classpathJar.getName)
 }
 mappings in Universal += (((target in Universal).value / "lib" / "classpath.jar") -> "lib/classpath.jar")

libraryDependencies ++= に追加
   evolutions,
   filters,

''conf/application.conf''
 include "server.conf"

下記コマンドでシークレットを作成
 activator playGenerateSecret

''conf/server.conf''
新規作成して、下記行に、上記コマンドで作られたキーを入力
 play.crypto.secret = "xxxxxxxxxxxxxxxxxxxxx"

''conf/routes''
Play では基本的に html 等は jar にまとめられてしまうため、生のファイルをリンクしたい場合は下記行を追加
 GET     /files/*file               controllers.Assets.versioned(path="/files", file: Asset)


* eclipse でインポート [#v142ea51]
//- ビルド・パスに クラス・フォルダーの追加(scala template用)
// target/scala-2.11/classes
// target/scala-2.11/routes
// target/scala-2.11/twirl

* 実行 [#rd3a4cad]
 外部ツールの構成 -> プログラム

|ロケーション|c:\cygwin\usr\local\play24\activator.bat|
|作業ディレクトリー| ${project_loc} |
|引数| -Djava.net.preferIPv4Stack=true -jvm-debug 9999 run|

* DBをpostgres [#ncf74064]
- DBを作成しておく
 psql -U postgres

 create database play24base;

''build.sbt''
 libraryDependencies += "org.postgresql" % "postgresql" % "9.4-1201-jdbc41" 

 activator compile
 activator eclipse

''conf/server.conf''
 db.default.driver=org.postgresql.Driver
 db.default.url="jdbc:postgresql://localhost:5432/play24base"
 db.default.username="postgres"
 db.default.password="postgres"
 ebean.default=["models.*"]

* debug [#qe7b5584]
** break point [#k049ab9c]
 activator -jvm-debug 9999 run

 eclipse で 9999をデバッグポートに指定

* log [#jb1bd29e]
** ログに日付を [#b302d76e]
''conf/logback.xml''
 <pattern>%d{yyyy-MM-dd HH:mm:ss} [%-5level] - %logger - %message%n%xException</pattern>

** RAW SQL をログ出力 [#m516f750]
''conf/logback.xml''
  <logger name="org.avaje.ebean.SQL" level="TRACE"/> 

* dist [#qe22dd24]
デプロイ用パッケージの作成
 activator dist

下記に生成されている
 target\universal\xxxxx.zip

このファイルをサーバに持っていって展開~
bin 以下にある実行ファイルを実行~
~
ちなみに、conf 以下のフォルダはそのままパックされるのでもって行きたい外部ファイル等はconf 以下に置くと楽~
設定でかけるとは思うけれど・・~
public/ 以下の画像ファイル等は jar に固められている~

*** 起動スクリプト [#df60dbd7]
#pre{{
#!/usr/bin/bash

BIN=appname
APP=${BIN}-1.0-SNAPSHOT

ps -auxww |grep java |grep ${APP} |awk '{print $2;}' |xargs kill -9 2>/dev/null
rm -rf ${APP}/RUNNING_PID

rm -rf ${APP}
cp ~/${APP}.zip ./
unzip ${APP}.zip
cp service.conf ${APP}/conf/
rm -rf ${APP}/share

cd ${APP}
bin/${BIN} -Djava.net.preferIPv4Stack=true -Dfile.encoding=UTF-8 >> /var/log/application/${BIN}.log &

}}

本当の初回に evolution を一回だけやりたい場合は 
 bin/${BIN} -Dplay.evolutions.db.default.autoApply=true -Dplay.evolutions.db.default.autoApplyDowns=true

* SessionCache を永続化 [#g10c42fc]
''conf/ehcache.xml''
#pre{{
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd" updateCheck="false">

    <!-- ehcache 永続化ファイルのパスを指定 -->
    <diskStore path="user.dir/.ehcache" />

    <!-- diskPersistent="true" で永続化を有効にする (デフォルトは false) -->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="false"
            maxElementsOnDisk="10000000"
            diskPersistent="true"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
    /> 

</ehcache>

}}

* sample [#nbe20a7b]
** model [#ue9b4b05]

#pre{{

package models;

import java.util.Date;

import javax.persistence.*;
import com.avaje.ebean.*;
import com.avaje.ebean.annotation.*;
import play.data.validation.Constraints.*;

@Entity
public class Country extends Model {
	@Id
	public Long id;

	@Required
	public String name;

	//	@OneToMany(cascade = CascadeType.ALL)
	//	public List<Holiday> holidays;

	@CreatedTimestamp
	public Date created_date;

	@UpdatedTimestamp
	public Date updated_date;

	public static final Find<Long, Country> finder = new Find<Long, Country>() {
	};
}

}}

* テンプレートを velocity にしたい時 [#vbaa2b20]
''build.sbt''
 libraryDependencies += "org.apache.velocity" % "velocity" % "1.7"
 libraryDependencies += "velocity-tools" % "velocity-tools" % "1.4"

 activator eclipse

''Global.java''

#pre{{
import org.apache.velocity.app.Velocity;

import play.Application;
import play.GlobalSettings;

public class Global extends GlobalSettings {
	@Override
	public void onStart(final Application app) {
		Velocity.setProperty("file.resource.loader.path", "conf/templates/");
		Velocity.init();
	}
}

}}

* CSRF [#ie7717b5]
- build.sbt に filters を追加
- application.conf の play.crypto.secret を適切に設定

''Controller''
#pre{{
	@AddCSRFToken
	public Result form() {
		return ok(session().get("csrfToken"));
	}
        
	@RequireCSRFCheck
	public Result post() {
                Form<PostParam> form = Form.form(PostParam.class).bindFromRequest();
                PostParam query = form.get();
		return ok(query.name);
	}
	public static class PostParam {
		public String name;
	}

}}


* 外部プロジェクト [#xcb5db4a]

eclipse でプロジェクト参照しても activator 側で認識できない。

''build.sbt''
 lazy val PlayUtil = RootProject(file("../PlayUtil"))
 
 lazy val root = (project in file(".")).enablePlugins(PlayJava,PlayEbean).dependsOn(PlayUtil)

 activator eclipse

※ 注意: 参照される側のプロジェクトが単なるライブラリ的な存在の場合は application.conf が上書きで読み込まれるため消しておいたほうが良い

----
* cron [#n8cdf7e0]
''build.sbt''
 resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"
 libraryDependencies += "com.typesafe.akka" % "akka-remote_2.11" % "2.3.13"
 libraryDependencies += "com.typesafe.akka" % "akka-actor_2.11" % "2.3.13"
 libraryDependencies += "com.typesafe.akka" % "akka-kernel_2.11" % "2.3.13"
 libraryDependencies += "com.enragedginger" % "akka-quartz-scheduler_2.11" % "1.4.0-akka-2.3.x"

これだけだと scala-library の部分が eclipse に認識されない。~

今のところ手動で activator eclipse した後に、追加しているけれど・・
	<classpathentry kind="lib" path="scala-library-2.11.5.jar"/>


''application.conf''
#pre{{
akka {
  quartz {
    schedules {
      EveryMM {
        description = "毎分"
        expression = "0 * * ? * *"
        timezone = "Asia/Tokyo"
      }
    }
  }
}
}}

''actors/MinutelyActor.java''
#pre{{
public class MinutelyActor extends UntypedActor implements VelocityController {

	@Override
	public void onReceive(Object arg0) throws Exception {
		Logger.debug("CRON MINUTERY: " + new Unixtime().format("yyyy-MM-dd HH:mm"));

                //do something
	}

}
}}

''Global.java''
#pre{{
		try{
			ActorSystem system = ActorSystem.create("system");
			try{
				ActorRef ref = system.actorOf(Props.create(MinutelyActor.class), "MinutelyActor");
				QuartzSchedulerExtension scheduler = (QuartzSchedulerExtension) QuartzSchedulerExtension.get(system);
				scheduler.schedule("EveryMM", ref, "minutely");
			}catch(Exception e){
			}
		}catch(Exception e){
		}
}}

----
* web socket [#ke80f94d]
actor を使うので、build.sbt 等は上記の cron と同じ設定を行う。~

''conf/routes''
 GET      /connect                   controllers.SocketController.socket
 GET      /send                      controllers.SocketController.send(message)

''controllers/SocketController.java''
#pre{{
public class SocketController extends Controller {
	public WebSocket<String> socket() {
		return WebSocket.withActor(WebSocketActor::props);
	}

	public Result send(String message) {
		WebSocketActor.members.forEach(a -> a.send(message));
		return ok("OK");
	}
}
}}

''actors/WebSocketActor.java''
#pre{{
public class WebSocketActor extends UntypedActor {
	private final ActorRef out;

	public static List<WebSocketActor> members = new ArrayList<WebSocketActor>();

	public static Props props(ActorRef out) {
		return Props.create(WebSocketActor.class, out);
	}

	public WebSocketActor(ActorRef out) {
		this.out = out;
		members.add(this);
	}

	@Override
	public void onReceive(Object arg0) throws Exception {
		System.out.println(arg0);
	}

	@Override
	public void postStop() throws Exception {
		members.remove(this);
		System.out.println("bye");
	}

	public void send(String message) {
		out.tell(message, self());
	}

}
}}

*** test [#m81f6524]
 http://websocket.org/echo.html

 ws://localhost:9000/connect


---- 
* ebean [#e96f1559]
*** relation系 [#c074afc8]
|OneToOne  |public String   |cascade 使用すると子オブジェクトは親に従属|
|OneToMany |public String[] |cascade 使用すると子配列は親に従属        |
|ManyToOne |public String   |cascade は使用しない。子を保存する場合は子側で保存|
|ManyToMany|public String[] |cascade は使用しない。子配列を保存する場合は子側で保存|

*** date [#lc1a9121]
form からテキストで入ってきた date string を Date 型にする場合

''import play.data.format.Formats;''
 @DateTime(pattern = "yyyy/MM/dd")
 public Date date;

*** validate系 [#eddec6b0]
''import play.data.validation.Constaints;''
|@Required            |必須     |
|@Email               |email 型 |
|@MaxLength           |最大長   |
|@MinLength           |最小長   |
|@NotNull             |必須     |

*** DB系 [#i8b58755]
|@Table           |実際のDB上のテーブル名を指定できる                         |
|@SerializedName  |実際の DB上の field 名を指定できる                         |
|@Entity          |Model として認識するために必要                             |
|@MappedSuperclass|モデルの super class に作る。このモデルはテーブルを作らない|
|@Transient       |DB にフィールドを作らない(一時計算用のフィールド等)        |
|@Column          |DBに実際作られるフィールド (columnDefinition = "text") で256文字より長い文字       |

*** 前処理系 [#l9b373e6]
|@PostLoad  |select の後に呼ばれる callback|
|@PrePersist|insert の前に呼ばれる callback|
|@PreUpdate |update の前に呼ばれる callback|
|@PreRemove |delete の前に呼ばれる callback|

*** 基本フィールド [#n81e7ea5]
|@Id              |ユニークな値の方針を決めたりできる|
|@CreatedTimestamp|作成日が自動挿入される            |
|@UpdatedTimestamp|更新日が自動挿入される            |

* トラブルシュート [#c279c626]

*** https/http [#o29ae0a9]
 play.core.server.netty.PlayDefaultUpstreamHandler - Exception caught in Netty

-【原因】httpsの設定をしていないのに htpps でアクセスした
-【対応】http でアクセスする

*** memory [#c9217499]
 java.lang.OutOfMemoryError: Java heap space

-【原因】java に割り当てているメモリが足りない
-【対応】起動スクリプトに下記パラメータを追加する(dist環境)
 bin/【appname】 -J-Xmx4096M -J-Xms2048

----
* deploy [#q51bfec2]
 useradd sample
 mkdir /var/log/sample
 chown sample.sample /var/log/sample

''/etc/logrotate.d/sample''
#pre{{
/var/log/sample/sample.log {
       weekly
       dateext
       missingok
       rotate 52
       compress
       delaycompress
       copytruncate
       notifempty
       sharedscripts
}
}}

 su sample
 cd
 ln -s /var/log/sample logs

 cat > ~/.emacs

 (setq make-backup-files nil)
 (setq auto-save-default nil)

 cp sample-1.0-SNAPSHOT.zip ~/

''~/server.conf''
#pre{{

play.crypto.secret="sample"

# postgres
db.default.driver=org.postgresql.Driver
db.default.url="jdbc:postgresql://localhost:5432/sample"
db.default.username="sample"
db.default.password="sample"
ebean.default=["models.*"]

play.http.session.secure=false

}}

''~/deploy.sh''
#pre{{
#!/usr/bin/bash

BIN=sample
APP=${BIN}-1.0-SNAPSHOT
DB=sample
STAMP=`date '+%y%m%d%H%M'`
USER=sample

ps -auxww |grep java |grep ${APP} |awk '{print $2;}' |xargs kill -9 2>/dev/null
rm -rf ${APP}/RUNNING_PID

cp -rf ${APP}/conf backup/conf.bak.${STAMP}
rm -rf ${APP}
cp ${APP}.zip ./backup/${APP}.zip.${STAMP}
cp /home/${USER}/${APP}.zip ./

unzip ${APP}.zip
rm -rf ${APP}/share
rm -rf ${APP}/conf/files
cp -rfp conf/files ${APP}/conf
cp server.conf ${APP}/conf/

cd ${APP}
bin/${BIN} \
-J-Xmx2048M -J-Xms2048M \
-Djava.net.preferIPv4Stack=true \
-Dhttp.port=9000 \
-Dplay.evolutions.db.default.autoApply=true \
-Dfile.encoding=UTF-8 >> /var/log/${DB}/${DB}.log 2>&1 &

tail -f  /var/log/${DB}/${DB}.log

}}

 chmod +x deploy.sh

*** database [#c587a06a]
 createuser -U postgres sample 
 psql -U postgres -c "alter role sample with password 'sample';"

 psql -U postgres -c "create database sample;"
 psql -U postgres sample -c "create extension postgis;"
 psql -U postgres -c "alter database sample owner to sample;"