ビールとプリンとプログラミング。

頭の悪いプログラマのぼやき。

はじめてのJPAでちょっと怖い勘違い

はい。タイトル通りです。

JPAに触れ始めて3年近く経ちます。

どうも、私です。




昔、私も勘違いしていたこと。そして、つい先日もプロジェクト内であった間違い。

検証気力がないのでメモ程度に。

続きを読む

javascriptのスコープ

みなさん、お疲れ様です。

ということで、
本日は
Valtech (バルテック) Advent Calendar 2016
投稿記事です。

Webアプリケーションの開発に携わらせて頂いて3年となりました。

Javarista × JSerの私です。

今年はjavascriptの基本的な部分について、
主に研修生の皆様へ向けて書かせて頂きます。

javascriptのスコープ』について。

続きを読む

JAX-RSでmultipart/form-dataを受け取るために

久しぶりに時間ができたので、ビールを飲みながらメモします。


どうも、私です。




仕事でJavaEE7を使用しているんですが、
1年目から、業務をこなすのにいっぱいいっぱい。
実はあまり理解してなかったりしてます。


そこで、勉強がてら、家で触ってみたりしてるんですけども、なかなか理解が追い付かず・・・。



JavaEE7関連で、最近、読んでて面白い記事を見つけたのでご紹介。


enterprisegeeks.hatenablog.com



中途半端な知識で、何となく使ってた機能とか、仕組みとか、
ストンとお腹の中に落ちてきていい感じです。




しかし、勉強不足だなあ。





さて、

今日は、はまったところを、メモしておこうかと思います。



JAX-RSを利用したmultipart/form-dataの取り扱いについてです。




前述のとおり、JavaEE7を利用して、色々と遊んでます。

最近、画像のアップロード機能を実装したいなあ、なんて思いまして、しかし、色々と苦戦しました。なんとか「とりあえずでけた」程度のモノを実装することができましたので、記録しておきます。



私のために。


環境

私が開発を楽しんでる環境は

です。
…あれ、環境って何書けばいいんだ。

JAX-RSの実装とMaven

今回はJAX-RSを利用したWebアプリケーションを想定していますが、
JAX-RSはそのものは、仕様を指しているようです。

JAX-RS - Wikipedia

で、GlassFishで基本的なものは実装されている…程度の認識で、
JSONタイプ(application/json)等々のやり取りは、特に気にせず実装できると思うんですが、
今回やりたい「画像のアップデート」については、「multipart/form-data」を使用する必要があり、
特に気にせず実装することができませんでした。

ということで、
今回はJAX-RSのリファレンス実装であるJerseyを利用したいと思います。



Mavenを使ってビルドします。
pom.xmlのdependenciesに以下を追加しちゃいます。

<dependency>
  <groupId>org.glassfish.jersey.media</groupId>
  <artifactId>jersey-media-multipart</artifactId>
  <version>2.13</version>
</dependency>
<dependency>
  <groupId>org.glassfish.jersey.core</groupId>
  <artifactId>jersey-server</artifactId>
  <version>2.22.1</version>
</dependency>

versionについては、今の最新を利用しています。特に意味はありません。


今回の主役はjersey-media-multipartさんでしょうか。
jersey-media-multipartのライブラリを組み込むことで、
multipartなデータをオブジェクトとして扱えるようにします。

そしてjersey-serverさん。
どうやら、multipartなデータを扱うには「JerseyのApplicationクラス」を利用する必要があるみたいです。
「JerseyのApplicationクラス」を利用するにはjersey-serverのライブラリを組み込む必要があります。

JerseyのApplicationクラス

通常、NetbeansさんでJavaEE7なRESTを構成しようとすると、以下のようなクラスが自動生成されると思います。

@javax.ws.rs.ApplicationPath("webresources")
public class ApplicationConfig extends Application {

@Override
public Set<Class<?>> getClasses() {
  Set<Class<?>> resources = new java.util.HashSet<>();
  addRestResourceClasses(resources);
  return resources;
}

/**
 * Do not modify addRestResourceClasses() method.
 * It is automatically populated with
 * all resources defined in the project.
 * If required, comment out calling this method in getClasses().
 */
private void addRestResourceClasses(Set<Class<?>> resources) {
  resources.add(jp.rued.webapptest.app.resource.FileResource.class);
}


この場合「FileResource」クラスに「GET」「POST」等のRESTなメソッドを作ることになりますが、
このRESTを構成するクラスは、Netbeansを使用している場合、
javax.ws.rs.Pathアノテーションを付けると、ApplicationクラスであるApplicationConfigクラスに自動で追加されます。

ところが、これでは「multipart/form-data」のデータを受け取ることができません。

「multipart/form-data」のデータを受け取るためには「JerseyのApplicationクラス」を使用する必要があるようです。
「JerseyのApplicationクラス」とは、org.glassfish.jersey.server.ResourceConfigのことです。
さらに、Applicationクラスにorg.glassfish.jersey.media.multipart.MultiPartFeatureを登録する必要があるようです。

Netbeansで自動追加される機能を生かしつつ、「multipart/form-data」のデータを受け取るために、以下のように改変してみました。

@javax.ws.rs.ApplicationPath("webresources")
public class ApplicationConfig extends extends ResourceConfig {

public ApplicationConfig() {
  super(MultiPartFeature.class);
  Set<Class<?>> resources = new java.util.HashSet<>();
  addRestResourceClasses(resources);
  super.registerClasses(resources);
}

/**
 * Do not modify addRestResourceClasses() method.
 * It is automatically populated with
 * all resources defined in the project.
 * If required, comment out calling this method in getClasses().
 */
private void addRestResourceClasses(Set<Class<?>> resources) {
  resources.add(jp.rued.webapptest.app.resource.FileResource.class);
}

Resourceクラスの実装

上記のライブラリの読み込みと、Applicationクラスの修正を行えば、あとは難しくはないです。
クライアント側から送られてくるmultipartなデータをmultipartなオブジェクトとして受け取れるようになります。

サーバーサイド

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Path("/upload")
public void upload(@FormDataParam("file") InputStream file,
                   @FormDataParam("file") FormDataContentDisposition dispoosition) {
                   
  // InputStreamでファイルの中身を参照できる。
  
  // FormDataContentDispositionでファイルの名前等を参照できる。
}


クライアントサイド

<form id="form" method="post" action="webresources/file/upload" enctype="multipart/form-data">
  <input type="file" name="file" />
  <p><input type="submit" value="Send it!"></p>
</form>


漠然としたイメージですが、こんな感じで使用できます。
具体的な使い方は割愛。というか、まだあまり把握しきれてないのが現実。。。











と、こんな感じで画像のアップロード等を実現することができるわけですね。
終わってみれば大したことないんですが、なかなかはまってしまいました。


参考にさせていただいた方の記事も載せておきます。


qiita.com

yumix.hatenablog.jp





JerseyのApplicationクラスを利用しないで実装しているコードも見かけたような気がするので、別の方法があるのかもしれないのですが、そちらのやり方がいまいちわからない。

純粋にjavax.ws.rs.core.Applicationだけで実装できるなら、それに越したことはないと思うんですよね。




いろんなところをつまみ食いしながら実装していったので、
わりとめちゃくちゃなことをやっているかもしれませんが、
もし何か良いアドバイスがあれば、指摘していただけると嬉しいです。







いずれにせよ、Facebookに画像を投稿することができたので満足!

JAX-RS Clientの使い方がさっぱりなので、誰か教えてください。



以上、yusuke_s24でした。

javascriptのフレームワーク「Knockout.js」

みなさん、お疲れ様です。

ということで、
本日は
バルテック アドベントカレンダー2015 Advent Calendar 2015 - Adventar
投稿記事です。

『ITに関連するタメになる知識やタメになるサイトの紹介』

と言える記事になるかはわかりませんが、入社して1年目にとあるプロジェクトで出会ったKnockout.jsを紹介したいと思います。


javascriptフレームワークといえば、みんな大好きjQuery
現在、プログラミング研修中の方はピンと来ないかもしれませんが、javascriptにもJAVAPHPのようにフレームワークと呼ばれるものがあります。初めて出会うと、感動します。

そんな、みんな大好きjQueryとも共存できるフレームワークがKnockoutさんです。
私が初めてプログラマとして入った新規開発のプロジェクトで使っていたのですが、プロジェクトで働いていた諸先輩方もKnockout.jsを初めて使うようで、あまり使われていないフレームワークなのかなあと思いつつも、私にとってみれば、jQueryより先に出会ったフレームワークなので、世界に広まれ!と願っています。
なんか初めてって、好きになりますよね。理由なく。

◆Knockout.jsって何?

さて、Knockout.jsとはどんなフレームワークなのでしょうか。
それを知るのに最適なウェブサイトがこちらです。

kojs.sukobuto.com

本家ウェブサイトを鋭意翻訳してくださっているサイトです。
本命中の本命のウェブサイトですが、わからなくなったらココ探れば色々と何とかなります。
私は英語が苦手なので、このドキュメントが頼りです。

◆動かしてみよう

Knockout.jsがどんなフレームワークであるかという事を文章で書けるほど精通していないし、技術もありませんので、実際にどんな動きするのかを軽くやってみようかと思います。



基本的なこととして、Knockout.jsはViewModelというオブジェクトを作り、そのデータをHTMLのDOMにバインドさせて利用します。

まずはjavascriptの方はこんなイメージ。

// ユーザーオブジェクトを定義します。
var UserObject = function() {
  this.name = ko.observable("");
  this.age = ko.observable("");
};

// ViewModelを定義します。
var ViewModel = function() {
  this.user = new UserObject();
};

// ViewModelを生成します。
var viewModel = new ViewModel();

// DOM構築後にviewModelをバインドします。
$(document).ready(function(){
  ko.applyBindings(viewModel);
});

そしてHTMLはこんなイメージ。

…省略…
<div>
  名前を入力してください。<br />
  <input type="text" data-bind="value: user.name" />
</div>
<div>
  わたしの名前は<span style="color: red;" data-bind="text: user.name"></span>です。
</div>
…省略…


実際に動かすと下のような動きをします。テキストボックスに適当な値を入れてフォーカスを外してみてください。

名前を入力してください。
わたしの名前はです。



はい、何の意味もないウェブサイトの完成です!

ポイントは、

  • HTMLのDOMと連携したいデータの変数をko.observable("**ここに値**")にする。
  • ko.observable()にした変数はすべてのDOMを構築した後にko.applyBindings()でバインドする。(今回はjQuery使ってますが、htmlの一番下に置くだけで問題ないはずです。)
  • HTML上にdata-bind="value: user.name"data-bind="text: user.name"を記載するだけで値の変更を自動的に反映してくれる。

と、いった感じでしょうか。
これをjQueryでやると、inputのDOMをとってきて、inputのchangeイベントで、spanのDOMをとってきて、textメソッドで反映する!みたいなことを書かないといけませんね。

入力したデータは、もちろんjavascript内でも違和感なく使用できます。

alert("私は" + viewModel.user.name() + "です!");

といった具合に。 やってみる

◆配列も簡単

ko.observableArray()を使用すれば直感的に配列を扱えます。追加や削除といった操作を簡単に行うことができ、追加・削除の結果を自動的に反映してくれます。HTML上で簡単に繰り返しデータを扱うことができるのです。

// さっきのViewModelを改築します。
viewModel.users = ko.observableArray();
viewModel.push = function() {
  // 新たに追加するユーザーオブジェクトを生成します。
  var newUser = new UserObject();
  newUser.name = viewModel.user.name();
  newUser.age = viewModel.user.age();
  viewModel.users.push(newUser);
  
  // 入力用のユーザーオブジェクトは初期化します。
  viewModel.user.name("");
  viewModel.user.age("");
};
viewModel.remove = function(user) {
  // 第1引数にはforeach中の各オブジェクトが渡されます。
  viewModel.users.remove(user);
};
…省略…
<div>
  名前<input type="text" data-bind="value: user.name" />
  年齢<input type="text" data-bind="value: user.age" />
  <button data-bind="click: push">追加する</button>
</div>
<table style="border-style:dush" data-bind="foreach: users">
  <tr>
    <td>名前:<span data-bind="text: name"></td>
    <td>年齢:<span data-bind="text: age"></td>
    <td><button data-bind="click: $parent.remove">削除する</button></td>
  </tr>
</table>
…省略…


名前 年齢
名前: 年齢:

こんな感じですかね。適当に触ってみてください。
多分jQueryだと、javascriptでDOM生成を自分で書くことになりますが、Knockoutでは意識する必要がないです。

◆ということで

今までjQueryを使用し続けて居た方にしてみれば慣れるまで少し大変だったようです。ですが、慣れてしまうとKnockoutの方がわかりやすいと個人的には思っています。
JAVAPHPで静的なページを生成する場合は、そこまで重宝されないかもしれませんが、jQueryajaxで動くページの構築には力を発揮してくれるのではないでしょうか。


注意点としてはjQuery等で操作しているDOMにKnockoutでバインドしたデータを使わないことですかね。
逆にKnockoutが操作するDOMに対して、なるべくjQueryで他の場所から操作を行うのも避けたほうがいいです。
やれますけど、用心深くするべきです。わりと辛いです。





なかなかKnockout.jsを使用する場面というのはないのかもしれませんが、

今後参加するプロジェクトで「Knockout.js」という単語を見たときに、ふと思い出していただけると幸いです。




以上!

Java使ってPOSTとかやる

最近、Javaを使って、必死にHTTP通信をしようとしているんだけど色々と詰まる。




詰まる。




とりあえず、
HttpURLConnectionを使ってやってみます。


しかし、詰まる。




まあ、色々とあるんですけども。



まずは、リクエスト時のパラメータについて。




GETメソッドを使用するときはそのままだった。

URLの後に付ければいけますよね。


http://~~~~~/get?user_id=yusuke_24&field=message


的なURLオブジェクトを生成すれば、素直に行きます。
うん、見たまんま。



POSTメソッドは、というと、頭の悪い私には、そのままというわけにはいかなかったですね。

いや、よく考えたらPOSTメソッドなので、当たり前なんですけど、
どうしてもAjax通信風なPOSTを考えると、JSONチックなKey&Valueで渡して送信できればいいのに。


とか、思ってしまうんですよ。



まあ、でも、そうですよね。それじゃダメですよね。


って事で、書いてみました。

// 接続先のURL
String urlStr = "http://localhost/BeerAndPudding/app/test/print";
String paramsStr = "user_id=yusuke_24&message=今日も元気だビールがうまい!";
try {
  // URLクラスを生成
  URL createdUrl = new URL(urlStr);

  // URLクラスからコネクションを生成。HttpURLConnectionにキャスト。
  HttpURLConnection connection = (HttpURLConnection) createdUrl.openConnection();
  // HttpURLConnectionの設定。今回はPOSTメソッドの実験。
  connection.setRequestMethod("POST");
  connection.setDoOutput(true);
  connection.setRequestProperty("Content-Type", "text/plain");

  // POSTメソッドはOutputStreamを取得して書き込みを行います。
  try(OutputStream out = connection.getOutputStream();) {
    out.write(paramsStr.getBytes("UTF-8"));
  }

  // POSTしてみます。
  connection.connect();
  connection.getInputStream();

} catch(MalformedURLException e) {
  e.printStackTrace();
} catch(IOException e) {
  e.printStackTrace();
}


POSTできてることを確認するために『http://localhost/BeerAndPudding/app/test/print』なテストサーバーを起動。

こんな感じ。受け取った文字列をそのままコンソールに出してます。
f:id:yusuke_s24:20151128230720p:plain



で、送信した結果。
f:id:yusuke_s24:20151128230724p:plain



ちゃんと、送られていますね。

接続先のURLからURLオブジェクトを生成して、
そのURLオブジェクトからHttpURLConnectionオブジェクトを生成。
HttpURLConnectionの『getOutputStream』でOutputStreamを取得して、そこに書き込むんですね。

OutputStreamなんで、そこから先はいろんな方法で書き込めると思われます。


なるほど。
わかれば当たり前なんだけど、なんだかメンドウクサイナア。とも思います。




さて、
HttpURLConnectionですが、サーバーエラーが発生した時が、また厄介でした。

これ、かなり引っかかりました。


『getInputStream』したときに接続に失敗してたりすると『IOException』が発生するんですが、
エラーコードが帰ってる時も、『IOException』となるんですよね。



そーーなのーーー?



エラーコード帰ってきてても、エラーが発生するのーー?





これにわりとはまりました。


さっきのコードで接続先を『http://localhost/BeerAndPudding/app/test/print/err』に変更してみます。
接続先はというと、こんな感じ。
f:id:yusuke_s24:20151128230728p:plain



先ほどとほぼ同じですが、最後にサーバーエラーとしてリクエストをお返ししております。



結果は、、、
f:id:yusuke_s24:20151128230730p:plain


f:id:yusuke_s24:20151128230734p:plain





『IOException』が発生してます。




ほえー。



ここでキャッチして処理するしかないんですかね。





『getResponseCode』であらかじめ成功しているか、失敗しているかを取得できるので、
その辺でごにょごにょできるとは思うんだけども。





通信系は大変だなあ。

HttpURLConnectionとか普通は使わないのかしら。






もう少しHttpURLConnectionさんとは戯れる必要がありそう。

java.util.loggingで見るWeakReference

炬燵付きノートパソコンが欲しいです。寒いです。
どうも、yusuke_s24です。





今日はJavaに関するメモ。

世の中には、便利なloggingに関するフレームワークがたくさんあると思いますが、 今回使おうとしているのが標準APIであるjava.util.loggingです。

java.util.loggingの使い方は、 ・・んーわりと複雑。 あまりログとかを、しっかりと触ったことがない僕には難しいのですが、 その中でも「へ~」と思ったのがWeakReferenceクラスの存在。





とりあえず、標準APIを使用してログを吐き出してみる。

public void ログを出力してみる() {
    Logger.getLogger(this.getClass().getName()).fine("これはログです。");
}


こんな感じで、getLogger()メソッドに名前を指定してあげれば、名前に紐づくLoggerを取得してこれる感じですかね。
結果がこちら。
f:id:yusuke_s24:20151122152943p:plain

はい、何も出力されません。 僕の環境では、出力レベルFINEはコンソールに出力されないんですね。 そこで、出力するログのレベルを変えてみます。

public void 今度こそログを出力してみる() {
    Logger.getLogger(this.getClass().getName()).warning("これはログです。");
}


結果はこちら。 f:id:yusuke_s24:20151122152948p:plain

はい、出力されました。 当然ですね。

で、今回は、 Loggerさんの出力レベルをプログラム中で変更したいわけなんです。 warningじゃなくてfineで出力したいんです。 fineなんです!


public void レベルを変えてみる() {
    // ロガーの出力レベルを変更する。
    Logger.getLogger(this.getClass().getName()).setLevel(Level.ALL);
    // 親ロガーのハンドラの出力レベルを変更する。
    Logger.getLogger(this.getClass().getName()).getParent().getHandlers()[0].setLevel(Level.ALL);

    // ログを出力してみる
    Logger.getLogger(this.getClass().getName()).fine("これはFINEですよ。");
    Logger.getLogger(this.getClass().getName()).warning("これはWARNINGですよ。");
}

f:id:yusuke_s24:20151122152951p:plain

java.util.logging.Loggerさんは出力レベルを設定することができます。
setLevel(Level.ALL)でレベルを変更しました。
ALLですので、すべてのレベルが出力されますね。v

と、これだけではダメなんです。
LoggerさんはHandlerさんを持っていて、そのHandlerさんの出力レベルも同じように変える必要があります。


そのHandlerなんですが、今回使用しているLoggerは新しく生成されたものなので持っていません。 じゃあ、なんで出力できるのかっていうと、親Loggerが持ってるからです。 Loggerさんは親LoggerのHandlerを使用しています。なので、親Loggerを取得して、その親LoggerのHandlerを取得して、出力レベルを変えて、、、、、あれ、そもそも親Loggerの設定tt、、、、、、



要するにLoggerの設定を変えたら両方ログがでた!


問題はここからです。

タイミングとか、詳しいことはわからないですが、
Javaですので、どっかしらでガベージコレクションされることってある気がしてるんですけど、
そんな時に、今まで同様、名前で取得するとどうなるか。


public void ガベージコレクションが発生する() {
    // ロガーの出力レベルを変更する。
    Logger.getLogger(this.getClass().getName()).setLevel(Level.ALL);
    // 親ロガーのハンドラの出力レベルを変更する。
    Logger.getLogger(this.getClass().getName()).getParent().getHandlers()[0].setLevel(Level.ALL);

    // ログを出力してみる
    Logger.getLogger(this.getClass().getName()).fine("これは1回目のFINEですよ。");
    Logger.getLogger(this.getClass().getName()).warning("これは1回目のWARNINGですよ。");

    // ガベージコレクションが発生
    System.gc();

    // ログを出力してみる
    Logger.getLogger(this.getClass().getName()).fine("これは2回目のFINEですよ。");
    Logger.getLogger(this.getClass().getName()).warning("これは2回目のWARNINGですよ。");
}



結果はこちら。 f:id:yusuke_s24:20151122152955p:plain



2回目のFINEが出力されなくなりました。 これだけだと、そうだとは言い切れないですけど、おそらく

Logger(A)がデフォルトで生成される

Logger(A)の設定を変える

GCでLogger(A)が消える

Logger(A')がデフォルトで生成される

と、なってるんでしょうか。

どうやら、弱い参照というのがキーワードみたいです。

qiita.com

d.hatena.ne.jp

参考にさせてもらった記事から、

* 弱い参照からだけで参照されているインスタンスは消える
* java.util.loggingはWeakReferenceを使用した弱い参照となっている

ということでしょうか。

ということで、メソッド内の変数でLoggerを参照してみました。 ただし、参照しているだけで、毎回getLogger()メソッドで名前を指定してLoggerを呼び出す部分は変えないことにします。

public void ロガーを強参照で保持する() {
    Logger logger = Logger.getLogger(this.getClass().getName());
    // =========ここより下は全く同じソースコード=========

    // ロガーの出力レベルを変更する。
    Logger.getLogger(this.getClass().getName()).setLevel(Level.ALL);
    // 親ロガーのハンドラの出力レベルを変更する。
    Logger.getLogger(this.getClass().getName()).getParent().getHandlers()[0].setLevel(Level.ALL);

    // ログを出力してみる
    Logger.getLogger(this.getClass().getName()).fine("これは1回目のFINEですよ。");
    Logger.getLogger(this.getClass().getName()).warning("これは1回目のWARNINGですよ。");

    // ガベージコレクションが発生
    System.gc();

    // ログを出力してみる
    Logger.getLogger(this.getClass().getName()).fine("これは2回目のFINEですよ。");
    Logger.getLogger(this.getClass().getName()).warning("これは2回目のWARNINGですよ。");
}



結果はこうなりました。 f:id:yusuke_s24:20151122152958p:plain

ちゃんと、両方出力されました。
ガベージコレクション発生時に消されなかったようですね。
メソッド内の変数で保持していたから消えなかった…という所でしょうか。


実際は、Loggerを毎回名前で呼び出すことは少ないかもしれませんが、
僕にとっては「へ~」という内容でした。

はじめまして。

そして、こんにちは。

ブログを作る必要ができたので作りました。

気ままに書いていこうかと思ってます。

プログラマの端くれなので、 忘備メモ代わりにソースコードも貼り付けたりしていけたら。

なんて思いつつ。

以上。yusuke_s24でした。

続きを読む