2015年1月9日金曜日

WebSocketについてしらべる

先日、グラフにAjaxを使って要素を追加するサンプルを作ってみた。


JAX-RSでJSONを出力してみた。


が、こいつをWebSocketでやれないかと。

イメージ的には、グラフのデータがサーバサイドで更新されたら即グラフに反映されるイメージ。
WebSocketについては聞いたことがある程度で実際のコードやら詳細な仕組みやらについては
詳しいわけではないので調査。ちょっと古い資料ではあるけれども
OracleのArun Guptaさん作成の資料があったので参考までに載せておく。



Java API for WebSocket 1.0: Java EE 7 and GlassFish from Arun Gupta

また、きしださんのサンプルもあったのでリンクを張っておく。

WebSocketをネタにJava EE 7正式版を試してみる

強引に実装する方法はなくもなさそうだけれども、あまりスマートな実装には
なりそうにないので、何とかいい方法はないかと調査中。。。

(2015/1/9 23:00 追記) ちょうど想定していたものを見つけた。
http://ameblo.jp/principia-ca/entry-11513826700.html

...と思ったが、もともと想定していた力押し実装だった(泣)

(↑と同時にさらに追記)
http://software.fujitsu.com/jp/technical/interstage/apserver/guide/pdf/WebSocket.pdf
こんな資料発見。目を通しておこう。

(2015/8/31 さらにさらに追記)
ごくごく簡単なアプリを作ってみたので今度追加します。※
※特にきしださんのものと変わんない(+ bootstrapつかってるくらい)のできしださんに怒られたら消します。技術的な側面についてはちゃんと解説したものを載せますね。




2015年1月8日木曜日

JAX-RSでJSONを出力してみた。

ほぼ自分用のメモ。
JAX-RSでJSONを出力してみました。

これを使えば、JAX-RS + AJAXの組み合わせで
ThinServerアーキテクチャライクなことができる...のか?


(手順)

  1. GlassFishでWebアプリケーションプロジェクトを作成。
  2. パターンからのRESTful Webサービスを作成する。
  3. 単純なルート・リソースを作成
  4. パスを指定(今回はSampleを設定)。* MIME-TYPEには application/jsonを指定。
  5. getJSONメソッド内でJSONを作り文字列にして返す。

* http://localhost:8080/アプリケーション名/webresources/パス がアクセスパスになる。
  RESTful Webサービスディレクトリ配下にあるクラス名を右クリックして
 テスト・リソースURIを選択すると、実行できる。(GlassFishをあらかじめ起動しておく必要がある)


以下、サンプルコードです。

SampleResourde.java

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package sample;

import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObjectBuilder;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.PathParam;
import javax.ws.rs.Consumes;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;

/**
 * REST Web Service
 *
 * @author USER
 */
@Path("Sample")
public class SampleResource {

    @Context
    private UriInfo context;

    /**
     * Creates a new instance of SampleResource
     */
    public SampleResource() {
    }

    /**
     * Retrieves representation of an instance of sample.SampleResource
     * @return an instance of java.lang.String
     */
    @GET
    @Produces("application/json")
    public String getJson() {
        String json;
        JsonArrayBuilder arrayBuilder = Json.createArrayBuilder();
        JsonObjectBuilder objBuilder = Json.createObjectBuilder();
        
        objBuilder.add("time", "2015/01/23 14:30:25");
        objBuilder.add("value", 45.5);
        arrayBuilder.add(objBuilder);
        
        objBuilder.add("time", "2015/01/23 14:30:25");
        objBuilder.add("value", 45.5);
        arrayBuilder.add(objBuilder);
        
        JsonArray jsonArray = arrayBuilder.build();
        json = jsonArray.toString();
        
        return json;
    }

    /**
     * PUT method for updating or creating an instance of SampleResource
     * @param content representation for the resource
     * @return an HTTP response with content of the updated or created resource.
     */
    @PUT
    @Consumes("application/json")
    public void putJson(String content) {
    }
}

出力はこんな感じになります。
(適宜改行入れてます。)

http://localhost:8080/アプリケーション名/webresources/Sample にアクセス。

[
    {
     "time":"2015/01/23 14:30:25",
     "value":45.5
    },{
     "time":"2015/01/23 14:30:25",
     "value":45.5
    }
]

2015年1月1日木曜日

jQuery+CSSでウィンドウの最小化を実現してみた(+最大化改善)

jQuery+CSSでウィンドウの最小化を実装。
ついでにウィンドウをドラッグしたときに移動できるようにもしてみました。



まともにテストしていない & 例外処理甘いです。
特定の操作組み合わせで変な動作します。


Window.html
<!DOCTYPE html>
<html>
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="./css/Window.css">
        <script src="./js/vendor/jquery-2.1.1.js"></script>
        <script src="./js/vendor/jquery-ui.js"></script>
        <script src="./js/Window.js"></script>
    </head>
    <body>
        
        <button class="show">ウィンドウを表示</button>
        
        <div class="window">
            <div class="title">
                ウィンドウのタイトル
            </div>
            <button class="minimize">-</button>
            <button class="maximize">□</button>
            <button class="close">×</button>
            <div class="content">
                コンテンツの内容はこんな感じですよ。
                コンテンツの内容はこんな感じですよ。
                コンテンツの内容はこんな感じですよ。
                コンテンツの内容はこんな感じですよ。
                コンテンツの内容はこんな感じですよ。
                コンテンツの内容はこんな感じですよ。
                コンテンツの内容はこんな感じですよ。
                コンテンツの内容はこんな感じですよ。
                コンテンツの内容はこんな感じですよ。
                コンテンツの内容はこんな感じですよ。
                
            </div>
        </div>
    </body>
</html>
Window.css
.window {
    position:absolute;
    width: 260px;
    height: 180px;
    border-style: solid;
    border-width: 2px;
    border-color: rgb(150, 150, 150);
    background: rgb(218, 218, 218);
}

.window > .title {
    position: absolute;
    left: 0px;
    display: inline-block;
    background-color: rgb(0, 0, 230);
    border-color: rgb(0, 0, 180);
    border-width: 2px;
    height: 20px;
    width: 260px;
    margin: 0px;
    color: white;
}

.window > button {
    position: absolute;
    display: inline-block;
    border-width: 2px;
    border-style: solid;
    border-color: rgb(150, 150, 150);
    background-color: rgb(218, 218, 218);
    height: 20px;
    margin: 0px;
}

.window > .minimize {
    right: 40px;
}
.window > .maximize {
    right: 20px;
}
.window > .close {
    right: 0px;
}

.window > .content {
    position: relative;
    display: block;
    overflow: scroll;
    top: 20px;
    width: 260px;
    height: 160px;
}

.show {
    position: relative;
    display: block;
    top: 0px;
    left: 0px;
}
Window.js
$(function(){
    
    var $window = $('.window'),
        $maximize = $window.find('.maximize'),
        $minimize = $window.find('.minimize'),
        $close = $window.find('.close'),
        $title = $window.find('.title'),
        $contents = $window.find('.content'),
        $showButton = $('.show'),
        $baseWindow = $(window);


        /*
         * ドラッグできるようにする。
         */
    jQuery('.window').draggable();
    
    /*
     * (ブラウザ全体の)ウィンドウサイズを取得する。
     */
    var width = $baseWindow.width(),
        height = $baseWindow.height();
    
    
    /*
     * もともと表示されているウィンドウサイズを取得する。
     */
    var originalWidth = $window.width(),
        originalHeight = $window.height();
    
    /*
     * ウィンドウの幅、高さ、位置を記録するための変数を準備
     */
    var windowWidth, windowHeight, windowOffset;     
    
    var duration = 750;
    
    
    /*
     * 初期サイズ合わせ。
     */
    windowWidth = $window.width();
    $title.css({ width: windowWidth+'px' });
    
    /*
     * 閉じるボタン(×)をクリック時の挙動
     */
    $close.on('click', function(){
        $window.css({ display: 'none' });
    });
    
    /*
     * 最大化ボタン(□)をクリックした時の挙動
     */
    $maximize.on('click', function(){
        width = $baseWindow.width();
        height = $baseWindow.height();
        /*
         * miximizedクラスを使って最大化フラグを管理
         */
        $(this).toggleClass('maximized');
        if($(this).hasClass('maximized')){
            /*
             * 最大化フラグがあるときは
             * ブラウザウィンドウの横幅、縦幅まで
             * ウィンドウサイズを拡張、
             * 位置は左上に移動する。
             */
            
            /*
             * 最大化解除の際の位置戻しができるように
             * ウィンドウの位置を事前に記憶しておく。
             */
            windowOffset=$window.offset();
            $window.stop(true).animate({
                top: '0px',
                left: '0px',
                width: width+'px',
                height: height+'px'
            }, {
                duration: duration,
                queue: false
            });
            $title.stop(true).animate({
                width: width+'px'
            },{
                duration: duration,
                queue: false
            });
            $contents.stop(true).animate({
                width: width+'px',
                height: height+'px'
            },{
                duration: duration,
                euque: false
            });
        } else {
            /*
             * ウィンドウの位置を記憶しておく。
             */
            $window.stop(true).animate({
                top: windowOffset.top+'px',
                left: windowOffset.left+'px',
                width: originalWidth+'px',
                height: originalHeight+'px'
            }, {
                duration: duration,
                queue: false
            });
            $title.stop(true).animate({
                width: originalWidth+'px'
            },{
                duration: duration,
                queue: false
            });
            $contents.stop(true).animate({
                width: originalWidth+'px',
                height: originalHeight+'px'
            },{
                duration: duration,
                euque: false
            });
        }
        $contents.css({display:'inline-block'});
    });
    
    /*
     * ウィンドウを表示 ボタンをクリックしたときの挙動
     */
    $showButton.on('click', function(){
        $window.css({ display: 'inline-block' });
    });
    
    

    /*
     * 最小化(-)ボタンをクリックしたときの挙動
     */
    $minimize.on('click', function(){
        var height = $(window).height();
        var titleHeight = $title.height();

        /*
         * minimizedクラスで最小化フラグを管理
         */
        $window.toggleClass('minimized');
        if($window.hasClass('minimized')){
            /*
             * 最小化フラグありの場合は
             * ウィンドウの現在位置を記録した後に
             * コンテンツ非表示、ウィンドウの横幅を
             * 変更した後に画面最下部に移動させる。
             */
            windowOffset= $window.offset();
            windowWidth = $window.width();
            windowHeight = $window.height();
            $contents.css({ display: 'none' });
            $window.animate({
                top: height - 20 +'px',
                left: '0px',
                width: originalWidth+'px',
                height: titleHeight+'px'
            },{
                duration: duration,
                queue: false
            });
            $title.animate({
                width: originalWidth+'px'
            },{
                duration: duration,
                queue: false
            });
        } else {
            /*
             * 最小化フラグを持たない場合は
             * コンテンツを再表示したのち、ウィンドウサイズ、位置を
             * 以前の状態に戻す。
             */
            $contents.css({ display: 'inline-block'});
            $window.animate({
                width: windowWidth+'px',
                height: windowHeight+'px',
                top: windowOffset.top+'px',
                left: windowOffset.left+'px'
            },{
                duration: duration,
                queue: false
            });
            $title.animate({
                width: windowWidth+'px'
            },{
                duration: duration,
                queue: false   
            });
        }
    });
});