Linux Install

Android

Linux Tools

Linux AV

Linux Memo

WINDOWS

PROGRAM

動画 Memo

音楽 Memo

モバイルアプリ Memo

FILE FORMAT

PROTOCOL

DEVICE

BookMark

その他


play24   

play2.4 になってだいぶかわったので書き直し

JAVA 用です!


はじめに

  • activator

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

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

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

mkdir /usr/local/play24
https://www.playframework.com/download

install

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

eclipse

hello world

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

2.4 でいろいろ変わった設定

  • 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 でインポート

実行

外部ツールの構成 -> プログラム
ロケーションc:\cygwin\usr\local\play24\activator.bat
作業ディレクトリー${project_loc}
引数-Djava.net.preferIPv4Stack=true -jvm-debug 9999 run

DBをpostgres

  • 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

break point

activator -jvm-debug 9999 run
eclipse で 9999をデバッグポートに指定

log

ログに日付を

conf/logback.xml

<pattern>%d{yyyy-MM-dd HH:mm:ss} [%-5level] - %logger - %message%n%xException</pattern>

RAW SQL をログ出力

conf/logback.xml

 <logger name="org.avaje.ebean.SQL" level="TRACE"/> 

dist

デプロイ用パッケージの作成

activator dist

下記に生成されている

target\universal\xxxxx.zip

このファイルをサーバに持っていって展開

bin 以下にある実行ファイルを実行



ちなみに、conf 以下のフォルダはそのままパックされるのでもって行きたい外部ファイル等はconf 以下に置くと楽

設定でかけるとは思うけれど・・

public/ 以下の画像ファイル等は jar に固められている

起動スクリプト

#!/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 を永続化

conf/ehcache.xml

<?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

model

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 にしたい時

build.sbt

libraryDependencies += "org.apache.velocity" % "velocity" % "1.7"
libraryDependencies += "velocity-tools" % "velocity-tools" % "1.4"
activator eclipse

Global.java

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

  • build.sbt に filters を追加
  • application.conf の play.crypto.secret を適切に設定

Controller

	@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;
	}

外部プロジェクト

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

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

akka {
  quartz {
    schedules {
      EveryMM {
        description = "毎分"
        expression = "0 * * ? * *"
        timezone = "Asia/Tokyo"
      }
    }
  }
}

actors/MinutelyActor.java

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

		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

actor を使うので、build.sbt 等は上記の cron と同じ設定を行う。

conf/routes

GET      /connect                   controllers.SocketController.socket
GET      /send                      controllers.SocketController.send(message)

controllers/SocketController.java

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

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

http://websocket.org/echo.html
ws://localhost:9000/connect

ebean

relation系

OneToOnepublic Stringcascade 使用すると子オブジェクトは親に従属
OneToManypublic String[]cascade 使用すると子配列は親に従属
ManyToOnepublic Stringcascade は使用しない。子を保存する場合は子側で保存
ManyToManypublic String[]cascade は使用しない。子配列を保存する場合は子側で保存

date

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

import play.data.format.Formats;

@DateTime(pattern = "yyyy/MM/dd")
public Date date;

validate系

import play.data.validation.Constaints;

@Required必須
@Emailemail 型
@MaxLength最大長
@MinLength最小長
@NotNull必須

DB系

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

前処理系

@PostLoadselect の後に呼ばれる callback
@PrePersistinsert の前に呼ばれる callback
@PreUpdateupdate の前に呼ばれる callback
@PreRemovedelete の前に呼ばれる callback

基本フィールド

@Idユニークな値の方針を決めたりできる
@CreatedTimestamp作成日が自動挿入される
@UpdatedTimestamp更新日が自動挿入される

トラブルシュート

https/http

play.core.server.netty.PlayDefaultUpstreamHandler - Exception caught in Netty
  • 【原因】httpsの設定をしていないのに htpps でアクセスした
  • 【対応】http でアクセスする

memory

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

deploy

useradd sample
mkdir /var/log/sample
chown sample.sample /var/log/sample

/etc/logrotate.d/sample

/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

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

#!/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

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;"