JavaME 開発方法 〜JavaMEの開発環境構築〜

前回(JavaME SDK)、前々回(Codename one)とJavaMEでの開発環境構築に失敗していますが、今回はうまくいくであろうと思っています。(やって見ないとわからないのが世の常。。。)

目的

Microbit〜ラズパイ〜MIDI音源と通信をしてMicrobitから音を鳴らそうというものです。

EclipseME

このプラグインを試してみたいと思います。
しかし、古い情報しか見当たらず。。。断念

NetBeansを使用する

Net Beansを見ると行けそうな感じがしました。
細かい説明のあるページも見つけました。が、NetBeansでやるのは嫌なので他を探すことにします。

開発方法を見直す

本当は、PC上でソースコードを書いて、テスト実行して、ラズパイにデプロイ。。。というように作業をしたかったのですが、色々探しても、適当なものが見つからないので諦めることにしました。

PCでコーディング→ラズパイでテスト

諦めて上のような実装方法にしようと思います。
ポイントは以下のようになります。

  1. JDKのバージョンをPCとラズパイで揃える(Java1.8で後に続く_XXX-XX)というのは無視
  2. Eclipseで通常通りに実装、PC上(のコンパイラ)で実行およびテスト
  3. ラズパイで作成したコードをGit経由でダウンロード、ビルドして実行(テスト)

このようにやって行こうと思います。
色々調べたけれど、結局はこの方法に落ち着きました。。。

というわけで、PC上でJavaMEを実行することを考えて環境構築を行います。

色々と調べて、Eclpse Kuraを使用するとか、あるのですがいまいちしっくりきていないのでもう少し調査します。

今回は、ここまでにしておきます。。。



Javaスキル36房〜第35房: はじめの一歩〜

Javaの布教を企んでいます。そしてシンプルにゴールが見える形で学習を進める方法がないか考えていました。

少林寺36房をモデルにする

少林寺拳法など、中国の古い文化は「教育」という部分でとても優れたシステムを持っているように思います。
その中で注目したのがこの「少林寺36房」です

正直のところ、内容は知りませんがポイントとしては以下のようなことです。

学習する時のポイント

  1. 段階的に学習(修行)レベルを上げていく
  2. 基本の理解を進める中で「奥義」の片鱗を見つけられる
  3. やる気(やって面白い)

実際に学習をするのに「コード」を書かないと始まらないのでソースをコンパイルしたりなんだりと必要なことが多いのですが、ここら辺の問題をクリアするのが「ウェブコンパイラ」だと思いました。

上のキャプチャをクリックするとコードをコンパイルできるページに遷移することができます。

第35房

【問題】
上記のリンク(キャプチャ)から画面遷移してコードを書き下の文言を出力するプログラムを書いてください。
"こんにちは、世界"

ポイント

  1. 「ハローワールドを起動する。」(初めにあるプログラム)
  2. 「"」(ダブルクォーテーション)を表示する

参考ページ
はじめの一歩〜ハローワールド〜

実際に上のキャプチャをクリックするとそのページへ移動できますが、コードを書いて起動するのは自分自身です。
ハローワールドのコードが書いてあります。

注意点

Java以外の言語でも共通して必要なコードがあります。
import文です。
例えば、Listとか、Fileなどの操作を行いたいときにはそれぞれの使用するためのAPIが用意されているのでそれらを使用しますが、使用するときには以下のようにインポートする必要があります。
import java.util.List;

この35房をクリアできたら次は第34房です。



Java はじめて29 〜JUnitでのテスト駆動型開発6: ファイル読み込みのテスト〜

今回は、今迄作成した「ファイル存在チェック」と「ファイル作成、更新」処理を繋げてテストします。

この段階で、ようやくテストらしいテストになります。ちなみにこのテストケースも実装前に作成出来ますが、小さなレベルで、テスト仕様を考える→実装→テスト実施…とやった方が早い気がします。

口座作成処理

ようやく、仕様レベルの話に戻って来ました。このテストケースはコーダー銀行に口座を開設する処理に当たりますので、実際に動かす時と同じような入力(テストなのでデータ)を渡して実行します。テストコードは下のようになります。

このテストケースが通ったらとりあえずは、製造完了です。お疲れ様でした。

ひと段落したので、一旦休むも良し、このまま突走るのも良し。

他の事に着手してみるも良し!

動く事が大事

何が言いたいかと言うと、プログラムは何かを作る、仕組みを作るなどに使用する。若しくは単純に触りたいだけ…など色々あると思いますが、ちゃんと動くモノを作った方が、実力もつくし、作ったもので遊べるし、良い事ずくめだと思うので、色々と作ってみるのが良いと思います。

今迄やって来ているのは、サンプルなので…主な目的は「Javaの学習」になっています、あまり作りたいものには届かないと思います。しかし、基礎を学べる様になっているのと、コンソールアプリなので応用はいくらでも出来ます。早い話が、コンソールアプリが作れれば、あとは環境が違うだけなので大まかな流れは理解できるずです。。。

続き

前置きは、このくらいにして、続きをやります。

早い話が、今迄作成したメソッドを続けて呼び出し、それらが想定通りに動くか?の確認を行います。

作成したメソッドは以下のものです。

そして、上のメソッドを結合してやる場合のテストケースから考えます。

データの読み込み

仕様

  • ファイル存在チェックを行いファイルが存在すれば読み込む
  • 存在しなければファイル作成を行う

仕様に関してはこの部分のみをみていましたが、ファイルの読み込みをした後に、データが入っているはずなので、これを取得する必要があります。

この部分は実装していないので、実装が必要です。とりあえずは、目の前のテストを片付けてしまいます。テストコードは下の様になりました。テストを実施しながら実装するので手直しをするからこうなりました。と言う表現を使いました。

テストが通ったので、次の事を考えます。つまり、ここまでは想定通りに行ったという事です。

データの取得

次は、読み込んだファイルのデータをクラスに設定してやる事を考えます。

ファイルに保存してあるデータを読み込んで、プログラムで使いやすい様にデータクラスを使ってデータを保持します。「保持」と言うのは、プログラムが止まると消えてしまう情報なので「保持」と言う言葉を使いました。

ちなみに、ファイルに保存すれば、プログラムが止まっても情報は残しておけます。

現状では、Dataクラスを使用してファイルにデータを書き込んでいます。
ちなみにデータクラスは下の様なコードになります。

public class Data {
    /** ユーザー名 */
    private String name;
    /** パスワード */
    private String password;

    /** 
     * コンストラクタ。口座情報を保持するクラスのインスタンスを生成。
     * 
     * @param name 口座のユーザー名
     * @param password 口座のパスワード
     */
    public Data(String name, String password) {
        this.name = name;
        this.password = password;
    }
    /**
     * @return the name
     */
    public String getName() {
        return name;
    }
    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * @return the password
     */
    public String getPassword() {
        return password;
    }
    /**
     * @param password the password to set
     */
    public void setPassword(String password) {
        this.password = password;
    }
}

データクラスは、フィールドとGetter, Setterのみのクラスです。

読み込み時にも同じクラスが使えます。
まとめると以下の様な手順でファイルを読み込みます。
1. ファイルを開く(コンストラクタで実装ぞ済み)
2. ファイルを1行ずつ読み込みDataクラスへ設定
3. データクラスをリストにして返却する

以上の様な手順でファイルからデータを取得します。
そして、これをテストケースにします。
## テスト仕様
上の手順そのままですがこれを確認するためのテストケースを作成します。そしてこれもとりあえずは「スタブメソッド」を作成します。

/**
 * ファイルを読み込みデータをリストにして返却する
 * @return List CSVファイルのデータリスト
 */
public List readFile() {
    return null;
}

このメソッドはJavaDocコメントにある様に、リストにしてデータを返しますので、java.util.Listインターフェースを使用してデータを返却します。
Listインターフェースの配列型リスト=ArrayListクラスを生成してデータをセットする様に実装します。コードは以下の様になります。

public void testFileRead() {
    List dataList = target.readFile();
    // データは1件
    assertEquals(1, dataList.size());
    // ファイルにあるデータ
    Data data = dataList.get(0);
    assertEquals("test", data.getName());
    assertEquals("passwd", data.getPassword());
}

このテストケースを実行しエラーが出ない様なコードを作成します。一応、CSVファイルはファイル作成時に出力したデータが設定されていることを確認しています。

Java はじめて17 〜設計後の部品を実装する1〜

今回は、役割分担を行なった後にクラス(部品)をどのように組み合わせてアプリを作成するか?について記載したいと思います。
【補足】
アプリの規模がとても小さく、処理内容も少ないのでちゃんとした「設計書」の類は作成しません。

<ユースケース>
【前提】
コンソール画面のATMとします。
ユーザー認証は行いません。
単純に金額を入金、引き出しができるものを作ります。

【仕様】
アプリを起動してコンソールから「引き出す」「入金」を選択する
それぞれの処理に対して「預金額」から足し算、引き算を行いその結果を表示する

<部品候補>

  1. メインメソッドを持ち、入力の受付も行うクラス
  2. 入金、引き出しを行う計算処理クラス

部品を作る

<部品候補>からクラスを2つ作成します。クラス名はアルファベットで作成する必要がある(全角の文字でも作成できますが、なんとなく嫌なので。。。)

  1. MainBankクラス(メインメソッドを持つ)
  2. Calcurationクラス(引出し、入金を管理する)

上のように名前をつけます。このように「役割分担」をしてやれば、いざ修正するときにどちらかのクラスの一部を修正してやれば、デグレート(修正したらおかしな事になる)する事もないように作ることができます。

ここのポイントとしては、書く処理の依存度をなるべく低くしてやることです。依存度が高いと下のようなコードになります。

public static void main(String[] args) {
   MainBank main = new MainBank();
   Scanner input = new Scanner(System.in);
   String inStr = input.nextLine();
   if ("in".equals(inStr)) {
       // 入金処理を行う
   }
      ・
      ・
      ・
}

入力を受けたあとに入金処理を同じクラスの中に書き始めると、結局のところは全部の処理をMainBankクラスに書くことになります。
ソースを読む時は全部読まないといけないし、修正するときも、あちこち直さなくてはいけません。。。
残業パラダイス必至のコードです。平和のためにこのような作成方法はやめましょう。。。

依存度を下げるために

クラスを複数作成し、役割分担をしてやります。
今回のコンソールアプリを作るのには以下のような2つの処理が必要です。

  1. コーダー銀行の受付(入金、引出し)を行う(判定)する処理
  2. 入金処理、引出し処理のそれぞれを行う。

ポイント

  1. 受付部分は共通なので、MainBankで行う
  2. 入金処理、引出し処理は独立させることができるので分割する

そんなわけで

  1. MainBankクラス
  2. Calcurationクラス

上記のクラスを作成することにしました。

MainBankクラス

アプリケーションの起動とコーダー銀行の受付処理を行います。
処理の詳細に関しては、以下の通りになります。

  1. コーダー銀行の受付文言をコンソールに表示
  2. デフォルトの預金金額¥1000-を表示する
  3. 入金(in)、引出し(out)の判定を行い、処理終了する時は「bye」の入力で処理を終了する
  4. そのほかの入力はエラーメッセージを表示してサイド入力を促す表示を行う

Calcurationクラス

入金、引出し処理を担当するクラスです。このクラスには預金額を管理するためのフィールド変数が必要になります。
そして、入金処理、引出し処理では以下のような処理が必要になります。

  1. 入金・引出し処理を行う旨を表示する。
  2. それぞれの処理を行った後の預金額を表示する。
  3. 受付〜各処理への状態が変化していることをプログラム的に区別する必要がある。

上の3番に関して、「プログラム的に〜」と記載している部分は「状態」を管理することにより処理クラスを変更、管理しやすいのです。この設計手法に関してはGOFのデザインパターンなどを読んでみるととても参考になります。
良いデザイン(設計)をできるようになると、色々と楽ができます。

でわでわ。。。



PGボックス 記事一覧

PGボックス記事一覧

Java Basic Lv1-10

Java Basic Step1-3

目標達成プロジェクト (サンプル2)

ND4J

Twitter API

Google Maps

JS Google Maps API 〜オリジナル・データマップを作ろう〜




JS GoogleMap 〜既存ソースの修正〜

イントロダクション

前回、GoogleMapのJavaScript APIの使い方について触れました。

今回は、今迄に作成したソースに改修を加えます。

サンプル作成中のページはこちらです。

改修内容

「作成したSELECTボックスの値をDBに登録する。」です。
現状の画面は下のような感じです、表示するには「ログイン」を行う必要があります。

![](http://zenryokuservice.com/wp/wp-content/uploads/2019/08/スクリーンショット-2019-08-28-21.20.41-300x188.png)

#### 追加する処理
1. 作成したSELECTボックスの値を取得する処理
2. 取得した値をサーバー(PHP)に送信する処理(実際には値を設定するだけ)
3. ・JS(クライアントサイド)から送信した値を、サーバ(PHP)で受け取る
4. ・受け取ったデータをDBへの登録処理に追加する
### 具体的に
1. データ送信ボタンを押下した時に、SELECTボックスの値を取得する
2. 選択された値をAjaxでの送信するデータオブジェクトへ設定する
3. PHP.送信されたリクエストを取得、その時の項目を追加する
4. 追加した項目の値をSQL(登録処理)に追加する

以上のような処理を実装します。現状は下のような画面が表示されています。下のセレクトボックスは値を変更しても何も変わりません。
![](http://zenryokuservice.com/wp/wp-content/uploads/2019/08/スクリーンショット-2019-08-28-21.18.00-300x145.png)

### 現状のJS

/** セットしたデータをPHPに送信する */
function postData() {
    ajaxPost();
}

/** Ajax送信処理 */
function ajaxPost() {
    xhr.open('POST', 'https://zenryokuservice.com/XXXXX.php', true);
    // xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;  charset=UTF-8"');
    xhr. responseType = 'text';
    xhr.onreadystatechange = recieveResponse;
    // POSTデータを設定する
    var data = createJSON();
    console.log(data);
    try {
        xhr.send(data);
    } catch(e) {
        console.log(e);
    }
}

/** POST送信するデータ(JSON)を作成する */
function createJSON() {
    var data = new FormData(document.getElementById("mapData"));
    return data;
}

よく見たら。。。formから直接送信データを作成しているようでした(笑)
つまり、SELECTボックスに名前をつけて、PHP側でそれを取得するようにしてやれば良いということです。

### 修正箇所

SELECTボックスの属性部分に name="categoryId" を追加します。

// 20190828
$statement->bindParam(":categoryId", $categoryId);

INSERT INTO テーブル名(追加項目名) VALUES(: categoryId)のようにSQLに項目を追加します。
画面からテストがてらにデータ追加!キャプチャ取ったがよくわからないです。。。すいません。。。

![](http://zenryokuservice.com/wp/wp-content/uploads/2019/08/スクリーンショット-2019-08-28-21.51.29-300x14.png)

登録した結果は下のように表示されます。

![](http://zenryokuservice.com/wp/wp-content/uploads/2019/08/スクリーンショット-2019-08-28-21.52.50-262x300.png)

[対象のページはこちらです。](https://zenryokuservice.com/sample/js/SampleMap.html)

## まとめ
今回の改修作業は、以下の点を変更するものでした。
1. 画面の入力項目にカテゴリを追加する
2. Formでデータを送信するのでSELECTボックスに名前をつける
3. PHPで受信したデータを取得
4. SQLに項目を追加、パラメータも追加

他の処理は触りませんでした。下手に触ると。。。というのもありますが、せっかく作ったものですので、余計な改修はしたくありません。手間もかかるし。。。
つまり、設計をある程度ちゃんとやっておけば最低限の修正で済むし、作ったもの(コード)を長く使用できるというわけです。

でわでわ。。。



Java Mid Basic 〜Lv2_6_Javaの基本(プロパティファイルを読む)ゲームループ付き〜

イントロダクション

前回までに以下のような事をやってきました。

  1. Java Mid Basic 〜Lv1Javaの基本を理解する(ゲームループ付き)〜
  2. Java Mid Basic 〜Lv2_Javaの基本(コードの書き方)ゲームループ付き〜
  3. Java Mid Basic 〜Lv2_1_Javaの基本(四則計算)ゲームループ付き〜
  4. [Java Mid Basic 〜Lv2_2_Javaの基本(リファクタリング)ゲームループ付き〜]()
  5. Java Mid Basic 〜Lv2_3_Javaの基本(リファクタリング実践)ゲームループ付き〜
  6. Java Mid Basic 〜Lv2_4_Javaの基本(Dirコマンドを作る)ゲームループ付き〜
  7. Java Mid Basic 〜Lv2_5_Javaの基本(コマンド履歴を作る)ゲームループ付き〜

<各項目の概要と目的>

  1. ハローワールドを行い、コードを書いて動かす:これによりメインメソッドの存在とコンソールへの出力方法を知ります。
  2. 動かしてみたので、その内容を理解します。
  3. とりあえずのレベルで内容を理解したので、実際にコードを書いて動かします。自分でコードを考えて実装→起動を行うとプログラミングの面白みも見えてくるかと思います。
  4. 書いたコードをレベルアップします。今後この「リファクタリング」はどのレベルになってもついてきます。レベルが高ければ高いほど難易度も上がっていきます。
  5. 理論的なことをやったのであとは実践です。これも「どのように整理してやれば「拡張性、保守性、パフォーマンス」の面で良いものができるか考えるのである意味「永遠のテーマ」です。(笑)
  6. 今度は、入力した文字によっていろんな処理を実装できるようにプログラムを改造していきます。サンプルとして「Dirコマンド」のようなカレントディレクトリ(現在いるフォルダ)のファイル一覧を取得する処理を実装しました。
  7. javaに初めからついているクラス「List」を使用してコマンド履歴を出力するプログラムを作成します。ここではjava.utilパッケージについて記載しています、今後はこのパッケージにあるクラスを何個か使用します。

プロパティファイル

プロパティファイルを使用するのもjava.utilパッケージにあるクラスを使用します。「プロパティファイル」とは拡張子がproperiesのファイルを指します。「*.properties」
このファイルはキーと値がセットになっています。具体的には下のような感じです。

ads="グーグルアドセンス"
win="ウィンドウズ"
mac="マッキントッシュ"

このようなファイルを作成し、これを読み込んでプログラム中で使用します。
今回の使い方は「コマンドをキーにして値を表示する」というような形でやろうと思います。

IN: ads
OUT: グーグルアドセンス

設計

前提として、前回までのコードに追加修正を加える形で実装します。

  1. コンストラクタでプロパティファイルを読み込みます。
  2. プロパティファイルにあるキー(コマンド)を入力した時はプロパティファイルの値を表示
  3. それ以外のコマンド(キー)は前回までと同じ動き

つまり

プロパティフィルにあるキーが存在すればそれを出力して、それ以外はいままで通りということです。

実装

今回のポイントはプロパティファイルを読み込むところです。
プログラムが動き始めたら即ファイルを読み込んでおきたいので、コンストラクタで読み込むように実装します。
そして、Propertiesクラスはフィールド変数として使用します。
ちなみにファイルまでのパスを指定しますが、ビルドパスを基準にパスを記載するのでちょいと注意が必要です。
resources/test.properties>resources/test.propertiesを読み込みたい場合は「ビルドパスがresourcesにつながっていることを確認します。

そしてコードは下のような感じです。

/** コンストラクタ */
public Lv2_6_Properties() {
    commandList = new ArrayList();
    prop = new Properties();
    try {
        // resources/
        prop.load(getClass().getResourceAsStream("test.properties"));
    } catch (IOException e) {
        e.printStackTrace();
        // エラーコード-1をセットしてプログラム終了
        System.exit(-1);
    }
}

ポイントの部分はprop.load(getClass().getResourceAsStream("test.properties"));の部分です、ここではPropertiesクラスのload()メソッドを使用してInputStreamからプロパティファイルを読み込みます。
getClass().getResourceAsStream("パス")で対象ファイルのInputStreamを取得します。
具体的にはビルドパスにつながっているディレクトリがルート「/」になるので「/test.properties」が対象のパスになりますが、環境によりルートが違う場合があります。
作成したコードはこちらです。
そして、実行結果です。



Java Mid Basic 〜Lv2_Javaの基本(コードの書き方)ゲームループ付き〜

イントロダクション

前回は、とりあえず入力して画面に表示するものを作成しました。こんな感じです。

動画は、作成中にデバッックしたものです。ちなみにバグもあります。
とりあえずは「動いた!」という感動を味わっていただきたく思い中途半端ですが、アプリとして動くものを作成しました。
コードはGitにアップしています。

最終的にはコンソールゲームを作ります。

AP概要Lv2

標準入力を受け付けて、以下のような動きをします。

  1. 入力された文字が「hello」の時はコンソールに「Hello World!」と表示する。
  2. そのほかの文字を入力したら「想定外の入力です」を表示する。

四則計算をする

今回のメインになる実装を行います。前回の記事で問題を出しました。ちょっと難しい問題でした。上の動画はデバック中の動画になります。バグも残っています(笑)。

まずは書いたコードの理解

前回作成したコードをもう一度眺めてみます。

public class Lv2HelloWorld {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        while(true) {
            System.out.print("入力してください: ");
            String inStr = input.nextLine();
            if ("hello".equals(inStr)) {
                System.out.println("Hello World!");
            } else {
                System.out.println("想定外の入力です");
                break;
            }
            System.out.println("Next command ... ");
        }
        System.out.print("AP is fiinished. Bye!");
    }
}

頭(行の先頭)からコードの意味を記載していきます。

クラスの定義

上のコードで行くと、下の部分がクラス定義になります。

public クラス名{ .... }

このクラス名はなんでも良いのですが、下のルール(大雑把な規約)にしましょう。ちなみにCheckStyleというEclipseのプラグイン(標準装備)を使用すると簡単に規約違反が見つけられるので便利です。参考サイト

  • メタ文字:%/\&'*)など、これらはEclipseなどのIDE(開発ツール)を使用するとエラーが出るので安心です。
  • Javaのクラスはアッパーキャメルケース("AppaKyameru"のように書く)を使用します。
  • Javaのメソッドはキャメルケース("appaKyameru"のように書く)を使用します。

とりあえずはこんなところを気をつけましょう。

メイン・メソッドの定義

まずは動かしたいので「メインメソッド」を作成します。メインメソッドは以下のような特徴があります。

  1. メソッドの定義は1つだけ、ほかの書き方はない。
  2. 必ずこのメソッドが動く
  3. 引数は「プログラム引数」になる

プログラム引数

プログラム引数はEclipseで使用する場合は下のように値を渡してあげます。つまりString[] argsの部分が引数であり、下のように設定してアプリを起動すると変数「args」に"プログラム引数1"のように値を渡せます。
注意として、プログラム引数は「String」型のデータになります。

ちなみに「データ型」に関しては後々に触れますが、現在使用しているデータ型は「int」「String」があります。

int型

調べてみると「???〜???までの整数」などのように記載されてますが、早い話が、範囲指定はあるけど(正負の)整数です。Stringなどの「オブジェクト型」とか「参照型」など(同義です)と違い、直接の値(メモリの領域)を保持します。

String型

これはjava.lang.Stringというクラスの型になります。intと違い「クラス」なので「null」が存在します。よく「参照型」とか「オブジェクト型」などと呼ばれます。早い話が「NULLが存在する型」なんだな!と理解してくれればOK!今後深く理解していきます。int型などのように直接、値を持つ変数と違いオブジェクトへの参照(ポインタ)を変数に持ちます。だからNULLがあるのです。

次は実装

すでに書いたコードに追記・編集していきます。前回作成したメインメソッド部分では「Hello World」と「想定外 ....」を出力するだけだったので、この部分を拡張します。
元のコード

public static void main(String[] args) {
    System.out.println("プログラム引数のサイズ:" + args.length);
    for (int i = 0; i < args.length; i++) {
        System.out.println("プログラム引数:" + args[i]);
    }
    Scanner input = new Scanner(System.in);

    while(true) {
        System.out.print("入力してください: ");
        String inStr = input.nextLine();
        if ("hello".equals(inStr)) {
            System.out.println("Hello World!");
        } else {
            System.out.println("想定外の入力です");
            break;
        }
        System.out.println("Next command ... ");
    }
    System.out.print("AP is fiinished. Bye!");
}

編集後のコード

public static void main(String[] args) {
    // 今回は作成したこのクラスを使用します。
    Lv2_1_Calculatie myClass = new Lv2_1_Calculatie();

    Scanner input = new Scanner(System.in);

    while(true) {
        System.out.print("入力してください: ");
        String inStr = input.nextLine();
        if ("hello".equals(inStr)) {
            System.out.println("Hello World!");
        } else if (inStr.matches("[0-9].*")) {
            int answer = myClass.calculate(inStr);
            System.out.println("答えは:" + answer + "です。");
        } else {
            System.out.println("想定外の入力です");
            break;
        }
        System.out.println("Next command ... ");
    }
    System.out.print("AP is fiinished. Bye!");
}

具体的に下の部分が変わりました。

Lv2_1_Calculatie myClass = new Lv2_1_Calculatie();
} else if (inStr.matches("[0-9].*")) {
    int answer = myClass.calculate(inStr);
    System.out.println("答えは:" + answer + "です。");

new Lv2_1_Calculatie()の部分は作成したクラスのインスタンスを取得しています。
インスタンス化すると「インスタンスメソッド」が使えるようになります。

インスタンスメソッドとスタティックメソッド

インスタンスメソッド:A a = new A();のように「new」してから使用する
スタティックメソッド:A.staticMethod()のようにクラス名.メソッド名で呼ぶことができる
上のような違いがあります。

まとめ

クラスとメソッドの書き方、メソッドの種類について触れました。結局計算する部分には触れませんでしたので次回触れようと思います。
でわでわ。。。



  1. Java Basic Level 1 Hello Java
  2. Java Basic Level2 Arithmetic Calculate
  3. Java Basic Level3 About String class
  4. Java Basic Level 4Boolean
  5. Java Basic Level 5If Statement
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 Traning of If statement
  8. Java Basic Level8 How to use for statement
  9. Java Basic Level 8.5 Array
  10. Java Basic Level 9Training of for statement
  11. Java Basic Level 10 While statement
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1
  17. Java Basic JUnit 〜テストスイートの作り方〜

JS 非同期 POST 〜非同期通信でのPOSTリクエスト〜

イントロダクション

前回KMLファイルがなんたら。。。と記載しましたが、結局のところはGoogle Mapの選択した位置にピンを落とす処理を追加しました。

現在の作成物はこちらのURL

https://zenryokuservice.com/sample/js/SampleMap.html

非同期通信処理(Ajax)

今回は、ここから非同期で記載した情報をサーバーに送信、JSONファイルを出力する処理を実装しようと思います。
早速ですが、非同期通信について触れておきます。

非同期通信とは

<同期通信>
HTMLフォームを使用して画面を遷移したり画面をリロードしたりするようなURLを更新するような通信のことを同期通信と言います。まぁ通常のリクエスト送信だと思っていただいて間違い無いと思います。

<非同期通信>
それに対して、非同期は何が違うのかというと画面の一部分を更新するときによく使います。
画面を表示したときに「loading ....」なんて表示されているのがこれです。
<同期通信の場合>
リクエスト送信した後に「レスポンス(次のページを受け取る)を待ちます。
<非同期通信>
リクエスト送信した後に「レスポンス」を待ちません。
なので「loading ...」なんて処理を行いながら「レスポンスが帰ってくる」のを待っています。

ポイント

レスポンスを待たなくて良いので次の処理が実行できるというわけです。「待ち」の時間が減るのでユーザーに優しい実装になります。

今回の用途

地図上の情報を取得、写真をサーバーに送信しJSONという形で保存しようという処理を実装しよう、というお思惑です。
前回記載しました内容の処理を実装します。

JavaScript

最近ではAngluarとかJQueryとかいろんなもの(フレームワーク?)がありますが、面倒なので使用しません。HTML5の仕様読みましたが、かなりの範囲を網羅する形でAPIが提供されているので、わざわざ他のJSライブラリなどを使用しなくて良いと思った次第です。
→話(使用する部品)がややこしくなるのであまり使いたくありません(笑)。

XmlHttpRequest

久しぶりに使用します。非同期通信を行うときに使用するオブジェクトです。他のライブラリなどはこいつを使用しているのでハナっからこの部品を使ってしまいます。APIドキュメントはこちらにあります。ドキュメントページからコードを失敬。。。
こいつをベースにして、ファイルなどのデータを送信する処理を実装しようと思います。

あとは、ソースを眺めながら考えます(笑)。

実装の流れ

先にサーバー側の実装を行います。これはクライアント(画面)からAjaxのリクエストを飛ばし、サーバー側で受けるので、受け口を先に作る…というわけです。ファイルの受け取りを行うので、とりあえず受信が出来ているか確認するものを作ります。

サンプル(クライアント)は下のリンクからアクセス出来ます。

https://zenryokuservice.com/sample/js/SampleMap.html

でわでわ。。。


/*  https://developer.mozilla.org/ja/docs/DOM/XMLHttpRequest#sendAsBinary() */

if (!XMLHttpRequest.prototype.sendAsBinary) {
  XMLHttpRequest.prototype.sendAsBinary = function(sData) {
    var nBytes = sData.length, ui8Data = new Uint8Array(nBytes);
    for (var nIdx = 0; nIdx < nBytes; nIdx++) { ui8Data[nIdx] = sData.charCodeAt(nIdx) & 0xff; } /* send as ArrayBufferView...: */ this.send(ui8Data); /* ...or as ArrayBuffer (legacy)...: this.send(ui8Data.buffer); */ }; } /* https://developer.mozilla.org/ja/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest * This framework is released under the GNU Public License, version 3 or later. * https://www.gnu.org/licenses/gpl-3.0-standalone.html * */ var AJAXSubmit = (function () { function ajaxSuccess () { /* console.log("AJAXSubmit - Success!"); */ console.log(this.responseText); /* you can get the serialized data through the "submittedData" custom property: */ /* console.log(JSON.stringify(this.submittedData)); */ } function submitData (oData) { /* the AJAX request... */ var oAjaxReq = new XMLHttpRequest(); oAjaxReq.submittedData = oData; oAjaxReq.onload = ajaxSuccess; if (oData.technique === 0) { /* method is GET */ oAjaxReq.open("get", oData.receiver.replace(/(?:\?.*)?$/, oData.segments.length > 0 ? "?" + oData.segments.join("&") : ""), true);
      oAjaxReq.send(null);
    } else {
      /* method is POST */
      oAjaxReq.open("post", oData.receiver, true);
      if (oData.technique === 3) {
        /* enctype is multipart/form-data */
        var sBoundary = "---------------------------" + Date.now().toString(16);
        oAjaxReq.setRequestHeader("Content-Type", "multipart\/form-data; boundary=" + sBoundary);
        oAjaxReq.sendAsBinary("--" + sBoundary + "\r\n" +
            oData.segments.join("--" + sBoundary + "\r\n") + "--" + sBoundary + "--\r\n");
      } else {
        /* enctype is application/x-www-form-urlencoded or text/plain */
        oAjaxReq.setRequestHeader("Content-Type", oData.contentType);
        oAjaxReq.send(oData.segments.join(oData.technique === 2 ? "\r\n" : "&"));
      }
    }
  }

  function processStatus (oData) {
    if (oData.status > 0) { return; }
    /* the form is now totally serialized! do something before sending it to the server... */
    /* doSomething(oData); */
    /* console.log("AJAXSubmit - The form is now serialized. Submitting..."); */
    submitData (oData);
  }

  function pushSegment (oFREvt) {
    this.owner.segments[this.segmentIdx] += oFREvt.target.result + "\r\n";
    this.owner.status--;
    processStatus(this.owner);
  }

  function plainEscape (sText) {
    /* How should I treat a text/plain form encoding?
       What characters are not allowed? this is what I suppose...: */
    /* "4\3\7 - Einstein said E=mc2" ----> "4\\3\\7\ -\ Einstein\ said\ E\=mc2" */
    return sText.replace(/[\s\=\\]/g, "\\$&");
  }

  function SubmitRequest (oTarget) {
    var nFile, sFieldType, oField, oSegmReq, oFile, bIsPost = oTarget.method.toLowerCase() === "post";
    /* console.log("AJAXSubmit - Serializing form..."); */
    this.contentType = bIsPost && oTarget.enctype ? oTarget.enctype : "application\/x-www-form-urlencoded";
    this.technique = bIsPost ?
        this.contentType === "multipart\/form-data" ? 3 : this.contentType === "text\/plain" ? 2 : 1 : 0;
    this.receiver = oTarget.action;
    this.status = 0;
    this.segments = [];
    var fFilter = this.technique === 2 ? plainEscape : escape;
    for (var nItem = 0; nItem < oTarget.elements.length; nItem++) { oField = oTarget.elements[nItem]; if (!oField.hasAttribute("name")) { continue; } sFieldType = oField.nodeName.toUpperCase() === "INPUT" ? oField.getAttribute("type").toUpperCase() : "TEXT"; if (sFieldType === "FILE" && oField.files.length > 0) {
        if (this.technique === 3) {
          /* enctype is multipart/form-data */
          for (nFile = 0; nFile < oField.files.length; nFile++) {
            oFile = oField.files[nFile];
            oSegmReq = new FileReader();
            /* (custom properties:) */
            oSegmReq.segmentIdx = this.segments.length;
            oSegmReq.owner = this;
            /* (end of custom properties) */
            oSegmReq.onload = pushSegment;
            this.segments.push("Content-Disposition: form-data; name=\"" +
                oField.name + "\"; filename=\"" + oFile.name +
                "\"\r\nContent-Type: " + oFile.type + "\r\n\r\n");
            this.status++;
            oSegmReq.readAsBinaryString(oFile);
          }
        } else {
          /* enctype is application/x-www-form-urlencoded or text/plain or
             method is GET: files will not be sent! */
          for (nFile = 0; nFile < oField.files.length;
              this.segments.push(fFilter(oField.name) + "=" + fFilter(oField.files[nFile++].name)));
        }
      } else if ((sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") || oField.checked) {
        /* NOTE: this will submit _all_ submit buttons. Detecting the correct one is non-trivial. */
        /* field type is not FILE or is FILE but is empty */
        this.segments.push(
          this.technique === 3 ? /* enctype is multipart/form-data */
            "Content-Disposition: form-data; name=\"" + oField.name + "\"\r\n\r\n" + oField.value + "\r\n"
          : /* enctype is application/x-www-form-urlencoded or text/plain or method is GET */
            fFilter(oField.name) + "=" + fFilter(oField.value)
        );
      }
    }
    processStatus(this);
  }

  return function (oFormElement) {
    if (!oFormElement.action) { return; }
    new SubmitRequest(oFormElement);
  };

})();