playのviewでローカル変数を宣言したり、それを使ったりのメモ書き。
(javaのクラスのstaticなメソッドとフィールドなら、直感的にできたんだけどね・・・)

こんな感じで変数を宣言して表示ができる。HogeBeanはサービス側のjava自作クラス

<div>
@{
val hogeval = "hoddfsfdsgehoge"
var hogeInt = 123
var hogeBean = new HogeBean
<div class="bar">
{hogeval}
{hogeInt}
</div>
}
</div>

これもできる。

<div>
@{
val hogeval = "hoddfsfdsgehoge"
var hogeInt = 123
var hogeBean = new HogeBean
<div class="bar">
{hogeval}
{hogeInt}
</div>
<div class="bar">
{hogeval}
{hogeInt}
</div>
}
</div>

途中で変数値を変更しようとすると、コンパイラエラーが出る「Overloaded method value [apply] cannot be applied to (Unit)」

<div>
@{
val hogeval = "hoddfsfdsgehoge"
var hogeInt = 123
var hogeBean = new HogeBean
<div class="bar">
{hogeval}
{hogeInt}
</div>
{ hogeInt = 23432 }
<div class="bar">
{hogeval}
{hogeInt}
</div>
}
</div>


あと、下だと「121」としか表示されない。一つ目の{no}は式として評価されているみたい。

@{
var no = 1

{no = no + 10}
{no}
{no = no + 10}
{no = no + 100}
{no}

}

下だと、Overloaded method errorが出る。

@{
var no = 1

{no = no + 10}
<div>{no}</div>
{no = no + 10}
{no = no + 100}
<div>{no}</div>

}

下だと、両方の{no}が表示されて「11」「121」。

@{
var no = 1

<div>{no = no + 10}</div>
<div>{no}</div>
<div>{no = no + 10}</div>
<div>{no = no + 100}</div>
<div>{no}</div>

}

よくわからん。もう少し調べないとだめだ。

さらに実験。今度はpage scope?の変数が欲しい。これは大丈夫。

@myTitle = @{ if(true) "true question" else "create question" }
@myTitle

<br/>

@myTitle2 = @{ "hoge edit question" }
@myTitle2

<br/>

@myTitle2

これは二つ目の@myTitle2=で、コンパイルエラーが出る。
method myTitle2 is defined twice conflicting symbols both originated
エラメを見ると、メソッドとして定義されているみたいだ。そして、二重定義はできないらしい。
@myTitle2で文字列を表示できるのは、メソッドの実装が"hoge edit question"を返すってことなのだろう。なるほど。

@myTitle = @{ if(true) "true question" else "create question" }
@myTitle

<br/>

@myTitle2 = @{ "hoge edit question" }
@myTitle2

<br/>

@myTitle2 = @{ "hoge edit question" }
@myTitle2

引数を伴う関数の定義と利用について。
@heading(title:String) = {
<div class="heading">
<h2>@title</h2>
</div>
}

@heading("Welcome3333333333339999999999999!")

なんかvalとvarはそれぞれ違うらしい。最初に書いた例でもvalとvarが混ざってた。varが変数でvalが定数らしい。valに再代入しようとするとreassignment to valっていうエラーがでる。紛らわしい。

う~ん、page scope の変数とか拡張for文のループ変数を使いたいだけなんだけど・・・


下みたいに書けば、拡張for文じゃなくてループ変数を作れる。けど、ループの中でオブジェクトを変数にセットして、その表示と取得がしたいんだけどわからん(hogeBeanはオブジェクト、hogeListはList)
@for(i <- 0 until hogeBean.hogeList.size) {

hoge / @{i+1}<br/>

@hogeBean.hogeList.get(i)
}

なんか、scalaの基本的な構文をはき違えている気がする。

scalaだとListにzipWithIndexを使えば、Listのオブジェクトとループ変数を同時に使えるらしい。下みたいな感じ。

@for((mdo, index) <- hogeBean.hogeList.zipWithIndex) {
<tr>
<td>@{index+1}</td>
<td>@mdo.hogeField</td>
</tr>
}

できたのはいいけど、ますます訳がわからなくなった。何度も言うけど、ページスコープの変数を使いたいだけなんだけど・・・scala勉強しよう、便利そうだから。

[追記]
@for( i <- 1 to 9; j <- 1 to 9 ) {
@(i * j)
@Html( if( j == 9 ) "<br>" else "" )
}
参考:play2.0(scala)を導入してみる

調べれば一時間で解るものを調べず、それで一週間悶々と頭の片隅に残す。
作れば三時間で終わるものを作らず、同じくそれで一週間悩む。
一時間かければ完成度は80%、一日かければ完成度は90%のものを一日かける。

3つ目はケースバイケースでプログラマとして重要かもしれないが、もう少し、合理的な行動をしたい。そして、優先度と集中力。頭ではわかってるんだけどな・・・同じ行動を繰り返す。このままじゃ間違いなく潰れる。
javaのロギングツールslf4j(Simple Logging Facade For Java)、logbackについて。

slf4j(公式)
logback(公式)

そのまえに、javaのロギングについての前知識。参考:javaのろがーが多すぎて訳がわからないので整理してみました。

とりあえず、mavenなしで設定。実行環境はeclipseでただのjavaプロジェクト。公式からzipを落として来たら、たくさんjarが入ってる。とりあえずログを出力するだけなら、slf4jからslf4j-api-1.7.5.jar、logbackからlogback-access-1.0.13.jar、logback-classic-1.0.13.jar、logback-core-1.0.13.jarが必要になる。これで下のコードみたいに書けば、標準出力にログがでる。

private static final Logger logger = LoggerFactory.getLogger(TestEntry.class);
logger.info("infoです。");

どのjarが必要か?はここの図 が参考になると思う。

ログレベルは、緩い方からTRACE,DEBUG,INFO,WARN,ERROR。

ログの設定ファイルlogback.xmlを使い時は、デフォルトだとsrc直下に置いとけば自動で読み込んでくれる。このあたりや書式は下が参考になる。
logback.xmlを設定して、運用する
Logbackの構成 - logback.xml

ログをファイル出力したい場合、logback.xmlをこんな感じで。

<configuration>

<appender name="FILE2" class="ch.qos.logback.core.FileAppender">
<File>testLogfile.log</File>
<Append>true</Append>
<Encoding>UTF-8</Encoding>
<BufferedIO>false</BufferedIO>
<ImmediateFlush>true</ImmediateFlush>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy.MM.dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</layout>
</appender>

<root level="INFO">
<appender-ref ref="FILE2" />
<appender-ref ref="STDOUT" />
</root>

</configuration>

これだと、srcディレクトリ直下にtestLogile.logが出力される。出力するログファイルのフルパスも指定できる。
<File>/var/testLogfile.log</File>

(*注)rootタグをappenderタグより先に書いたら、ログを出力できなかった。

■読み込むlogback.xmlのパスを指定したい場合(設定ファイルを外だしして、jarやwarに変更を加えたくない時とか)

main文の最初にこんな感じで。

LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(lc);
lc.reset();
try {
configurator.doConfigure("/var/logback.xml");
} catch (JoranException e1) {
// TODO 自動生成された catch ブロック
e1.printStackTrace();
}

参考:slf4j+logbackを使ってみる

・例外のprintstacktraceをログ出力したい時はこんな感じ。log4jと一緒。slf4jがIFだから当たり前か。
logger.error("", e);

■ログフォーマット
・ログに時間、クラス名、メッセージを出力。プレースホルダもできる。例えば、したみたいな感じ。
<pattern>%d{yyyy.MM.dd HH:mm:ss} [%thread] %-5level %logger{36} [%method] - %msg%n</pattern>

・参考:logbackwiki。パターン定数、プレースホルダ。

■プレースホルダ
プレースホルダはこんな感じ。
int iLog = 42342;
String sLog = "hgoelog";
logger.warn("■■■ {} プレーステスト {} hoge {} {}",iLog, 5233, sLog, "testlog");

■UTF8日本語文字化け
文字コードutf8でログを出力したいと思っていたら問題発生。eclipse上ではutf8で文字化けなしでいけたのに、何故かjarにしたらsjisで出力されてしまう。下みたいにlogback.xmlに<encoderタグと<charset>タグを追加したら、utf8で出力できた。

<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy.MM.dd HH:mm:ss} [%thread] %-5level %logger{30} - %msg%n</pattern>
</layout>
<charset>UTF-8</charset>
</encoder>

■ログファイル名に日付を入れてログローテしたい時。

こんな感じ?初日はtestbacklog.logしか作られないから数日間様子見する。
<file>/test/testbacklog.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>testbacklog_%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>200</maxHistory>
</rollingPolicy>

ここ が参考になる。

■あるライブラリ内部でjava.util.loggingを使ってログを標準出力している場合、JDKからSLF4j経由でLogbackへログ出力を委譲したい時について。

slf4jのjul-to-slf4j-1.7.5.jarが必要。

mirageなどのormはpureJava(util.loggin)を使って、sqlログを標準出力している。このログをSLF4jでハンドリング、委譲したい。

SLF4JBridgeHandlerを使い、main文の最初に以下を書く。

SLF4JBridgeHandler.removeHandlersForRootLogger(); // (since SLF4J 1.6.5)
SLF4JBridgeHandler.install();

この二行だけでできる。util.loggingのsqlログは標準出力で赤字だったけど、黒字に変わるから変化にすぐ気づく。また、設定ファイルでもできるらしい。ここ が参考になる

■ほか
・標準出力にはログレベルWARN以上、ログファイルにはINFO以上を出力したい時は?
・アスペクトがしたい。メソッド実行前後のログとか。他のライブラリも必要?
・ログ出力ファイルを掴んでいるとログが出ない。エラーも出ない

■参考
logback
java好き(SLF4J+LOGBACK)
SLF4jとLogbackでログ出力してみたよ
・コピペで始めるSLF4J&Logback
SLF4J - Javaロギング実装・ライブラリの柔軟な切り替え・効率化を実現するロギング Facade
mirageのインストールとSLF4Jの設定
CSE、heighSQLとツールを周りで使ってる人が多いけど、\Gが使えないのはきつい。無理して使う必要もない。
replace intoは便利。

insertとupdateを合わせたようなsql。データが存在する場合は既存のレコードを置換(update)し、存在しない場合はinsertする。わざわざ、selectで取ってきて値があるかどうか確認してupdateかinsertする、なんてことはしなくていい。

上でupdateと書いたけど、mysqlのreplace intoは内部ではupdateではなくdelete-intoをしてるらしい。だから、auto_incrementなフィールドは値が変わってしまうので注意。キーがauto_incrementの場合はdelete-intoでもupdateと結果が一緒だから問題ないが。ほかのDBはしらん。
replaceコマンドではまりました。

■参考
データ置換(replace文)