Java Network 〜 Socket通信で受付を行う〜

Socket通信処理の受付

Socket通信処理の実装を行いました。Githubに下のようなコードをコミットしてあります。

今回の内容について

  • まずはコードを見る
  • 処理の概要について
  • 通信処理について
  • 受信処理について
  • 感想

以上のような内容を記載します。

まずはコードを見る

下のように実装しました。
メインメソッドは一番下にあります。色々と試していたら長いコードになってしまいました。

/**
 * 低レベルSocketサーバー。
 * サーバーとクライアントの関係を理解するためのサンプルコード。
 * 単体アプリとする
 * @author 作成者の名前
 */
public class NaturalBornServlet extends Thread {
    private static final boolean DEBUG = true;
    /** 受け付けるおポート番号 */
    public static final int PORT_NO = 8081;
    /** 自分自身のインスタンス */
    private static NaturalBornServlet main;

    /** リクエスト */
    private BufferedReader request;
    /** レスポンス */
    private PrintWriter response;

    /** サーバーソケット */
    private ServerSocket server;
    /** 改行コード */
    private final char SEP = (char) 10;

    /**
     * 外部からの起動を禁止する。プライベートコンストラクタ。
     */
    private NaturalBornServlet() {
        try {
            server = new ServerSocket(PORT_NO);
        } catch (IOException e) {
            System.out.println("*** サーバーソケットの起動に失敗しました。 ***");
            e.printStackTrace();
            System.exit(-1);
        }
    }

    /**
     * デストラクタ。
     * サーバーソケットのクローズ、メモリの開放を行う。
     */
    public void finalize() {
        try {
            server.close();
        } catch (IOException e) {
            System.out.println("*** サーバーソケットの終了に失敗しました。 ***");
            e.printStackTrace();
        } finally {
            server = null;
            main = null;
            System.exit(-1);
        }
    }

    /**
     * 起動した、サーバーソケットで待機を行う。
     */
    public void run()  {
        try {
            System.out.println("*** サーバーソケット起動 ***");
            Socket sock = server.accept();
            // リクエスト
            request = new BufferedReader(new InputStreamReader(sock.getInputStream()));
            // レスポンス
            response = new PrintWriter(new OutputStreamWriter(sock.getOutputStream()));
            // リクエストの読み込み
            while(true) {
                String inputTxt = readRequest(request);

                if (inputTxt.contains("HTTP/1.1")) {
                    System.out.println("HTTP: " + inputTxt);
                    inputTxt = getHttpResponse(inputTxt);
                } else if ("".equals(inputTxt) ) {
                    System.out.println("***> 空リクエスト: " + inputTxt);
                    inputTxt = "<html><body>Hello World!</body></html>";
                } else {
                    System.out.println("***> else: " + inputTxt);
                    if (isBye(inputTxt)) {
                        break;
                    }
                }
                if (DEBUG) System.out.println("*** サーバーソケット: リクエスト受信 " + inputTxt + "***");

                // レスポンスを返す
                response.write(inputTxt + SEP);
                response.flush();
                System.out.println("*** サーバーソケット: レスポンス送信 " + inputTxt + "***");
                inputTxt = null;
//              request.close();
//              response.close();
//              sock.close();
//              request = null;
//              response = null;
//              break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private boolean isBye(String inputTxt) {
        if (inputTxt != null && inputTxt.startsWith("bye")) {
            System.out.println("*** サーバーを終了します。 ***");
            return true;
        }
        return false;
    }

    private String getHttpResponse(String req) {
        StringBuilder response = new StringBuilder();

        response.append("200 OK" + SEP);
        response.append("Access-Control-Allow-Origin: *" + SEP);
        response.append("Connection: Keep-Alive" + SEP);
        response.append("Content-Encoding: gzip" + SEP);
        response.append("Content-Type: text/html; charset=utf-8" + SEP);
        response.append("Date: Mon, 18 Jul 2016 16:06:00 GMT" + SEP);
        response.append("Etag: \"c561c68d0ba92bbeb8b0f612a9199f722e3a621a\"" + SEP);
        response.append("Keep-Alive: timeout=5, max=997" + SEP);
        response.append("Last-Modified: Mon, 18 Jul 2016 02:36:04 GMT" + SEP);
        response.append("Server: NaturalBorn" + SEP);
        response.append("Set-Cookie: mykey=myvalue; expires=Mon, 17-Jul-2017 16:06:00 GMT; Max-Age=31449600; Path=/; secure" + SEP);
        response.append("Transfer-Encoding: chunked" + SEP);
        response.append("Vary: Cookie, Accept-Encoding" + SEP);
        response.append("X-Backend-Server: developer2.webapp.scl3.mozilla.com" + SEP);
        response.append("X-Cache-Info: not cacheable; meta data too large" + SEP);
        response.append("X-kuma-revision: 1085259" + SEP);
        response.append("x-frame-options: DENY" + SEP);

        return response.toString();
    }

    /**
     * 受信した、メッセージを読み込む。
     *
     * @param in Socketより取得した入力ストリーム
     * @return
     * @throws IOException
     */
    private String readRequest(BufferedReader in) throws IOException {
        if (DEBUG) System.out.println("*** サーバーソケット: readRequest() ***");
        int read = 0;
        StringBuilder inputTxt = new StringBuilder();
//      System.out.println("**** read() : " + in.read());
//      System.out.println("**** ready() : " + in.ready());
//      System.out.println("**** readLine() : " + in.readLine());

        // CRとCRLFの場合で入力が終了している時がある
        while((read = in.read()) > 0) {
            // 空の場合
            if (read == 10 || read == 13) {
                System.out.println("*** read break ***");
                break;
            }
            char ch = (char) read;
            inputTxt.append(ch);
        }
        if (DEBUG) System.out.println("*** サーバーソケット: 完了:readRequest(): " + inputTxt + " ***");
        return inputTxt.toString();
    }
    /**
     * メインメソッド、ここから始まる。
     * @param args
     */
    public static void main(String[] args) {
        main = new NaturalBornServlet();

        try {
            main.start();
        } catch (Exception e) {
            System.out.println("*** 例外が発生しました。 " + e.getMessage() + "***");
            e.printStackTrace();
        }

    }
}

処理の概要と受信処理

上記のコードは大まかに下のような処理を行っています。

  1. メインメソッドでメイン処理を実行します。このクラスはThreadクラスを継承しているので、マルチスレッド処理を行うことができます。

  2. メインメソッドでstart()`が呼び出されているので、`run()メソッドが起動します。

  3. run()`メソッドでは、ServerSocketで`accept()を呼び出し、リクエストの受付を行います。
    つまりは、リクエストを受け付けるまで処理を行わず待っている状態になります。

  4. リクエストをつけ付けたら次のコードに処理が進みます。Socketクラスを受け取り、さらに入力ストリームと出力ストリームを取得します。入力は受け付けたリクエストで、出力は返却するレスポンスになります。具体的には下のようなコードです。

    // リクエスト
    request = new BufferedReader(new InputStreamReader(sock.getInputStream()));
    // レスポンス
    response = new PrintWriter(new OutputStreamWriter(sock.getOutputStream()));
  5. リクエストを読み込み、受信した内容に応じてレスポンスを返します。

    // リクエストの読み込み
    while(true) {
    String inputTxt = readRequest(request);
    
    if (inputTxt.contains("HTTP/1.1")) {
        System.out.println("HTTP: " + inputTxt);
        inputTxt = getHttpResponse(inputTxt);
    } else if ("".equals(inputTxt) ) {
        System.out.println("***> 空リクエスト: " + inputTxt);
        inputTxt = "<html><body>Hello World!</body></html>";
    } else {
        System.out.println("***> else: " + inputTxt);
        if (isBye(inputTxt)) {
            break;
        }
    }
    if (DEBUG) System.out.println("*** サーバーソケット: リクエスト受信 " + inputTxt + "***");
    
    // レスポンスを返す
    response.write(inputTxt + SEP);
    response.flush();
    System.out.println("*** サーバーソケット: レスポンス送信 " + inputTxt + "***");
    inputTxt = null;
    }
  6. リクエストの読み込みを行っているのは下のコードです。

    /**
    * 受信した、メッセージを読み込む。
    *
    * @param in Socketより取得した入力ストリーム
    * @return
    * @throws IOException
    */
    private String readRequest(BufferedReader in) throws IOException {
    if (DEBUG) System.out.println("*** サーバーソケット: readRequest() ***");
    int read = 0;
    StringBuilder inputTxt = new StringBuilder();
    System.out.println("**** read() : " + in.read());
    System.out.println("**** ready() : " + in.ready());
    System.out.println("**** readLine() : " + in.readLine());
    
    // CRとCRLFの場合で入力が終了している時がある
    while((read = in.read()) > 0) {
        // 空の場合
        if (read == 10 || read == 13) {
            System.out.println("*** read break ***");
            break;
        }
        char ch = (char) read;
        inputTxt.append(ch);
    }
    if (DEBUG) System.out.println("*** サーバーソケット: 完了:readRequest(): " + inputTxt + " ***");
    return inputTxt.toString();
    }

    ポイントになるのは、文字列を読み込をするときにに読み込む文字がないことを確認するために「改行コード」の数値型の値を使用しているところです。改行コードのchar型の値は整数型(int)で表現すると「13」もしくは「10」になります。CRLFCRの存在があるため2つになります。

通信処理について

通信処理=レスポンスの送信処理部分に関しては出力ストリームを使用して、送信します。

// レスポンスを返す
response.write(inputTxt + SEP);
response.flush();
System.out.println("*** サーバーソケット: レスポンス送信 " + inputTxt + "***");

「inputTxt」はString型の変数で、リクエストの値を取得しています。
つまりはリクエストで受けた文字列をそのまま返却しているというわけです。

感想

この実装は、Socket通信の最も簡単な処理になります。いわゆる「Socket通信のハローワールド」を実装したようなものでなので、通信処理の土台になります、逆に言うとこれを基本にどのような処理も実装することが可能ということです。

それなりに大変なことがありますが。。。

まとめると、通信の基本というところです。これを理解すれば、いろいろな通信処理の実装を行うことも可能になります。
なぜかというと、通信の基本を学んだからです。

でわでわ。。。

関連ページ

Java Basic

  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 〜テストスイートの作り方〜

Java ウェブサーバー作り〜Soket通信アプリ作成〜

イントロダクション

世の中では、「ウェブサーバー」というものが「普通」に存在しています。というか多くの人が「常識のように」言葉として使用します。

しかし、その中身はどうなっているのでしょうか?ITエンジニアではない人ならば、知る必要ないと思うかもしれません。ITエンジニアであれば、知っていて当然みたいな雰囲気が感じられますが、実際はどうでしょうか?

何がいいたいかというと、「ウェブサーバー作って見ませんか?」ということです。当然、自分ウェブサーバーを作ったらウェブサーバーを理解しているのも必然です。

早い話が、作ってみれば理解できるということです。

ウェブサーバーを作る

ここで使用する言語はJavaです。自分がJava屋なのもありますが、ウェブ系のアプリといえば、だいたいJavaで実装していることが多いです。(業務アプリに関して。。。)

そして、今回作成したサーバーは、いまだに不完全です。SOcけt同士の通信ならば問題なくできるのですが、ブラウザからアクセスを受付た場合は、うまくいきません。セキュリティ的にアクセスが拒否られているようです。
Socketでの通院は、下のクラスを起動することでやり取りができます。

Client App

public class ClientMain {
    /** 自身のインスタンス */
    private static ClientMain main;
    /** クライアントソケット */
    private Socket sock = null;
    /** 送信用のクラス */
    private PrintWriter send;
    /** 受信用のクラス */
    private BufferedReader response;

    /** 改行コード */
    private static final char SEP = (char) 10;

    public ClientMain() {
        try {
            sock = new Socket("localhost", NaturalBornServlet.PORT_NO);
        } catch (IOException e) {
            System.out.println("*** ソケットで例外が発生しました。 ***");
        }
    }

    /**
     * デストラクタ
     */
    @Override
    public void finalize() {
        try {
            sock.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            sock = null;
        }
    }

    /**
     * 標準入力からサーバーソケットへデータを送信する。
     *
     * @return 終了時のメッセージ
     */
    public String execute() {
        try (Scanner scan = new Scanner(System.in)) {
            while(true) {
                System.out.println("*** クライアントソケット: 入力 ***");
                String input = scan.nextLine();

                // リクエストの送信
                sendRequest(input);

                if ("bye".equals(input)) {
                    System.out.println("*** クライアントアプリを終了します。***");
                    break;
                }
                // レスポンスを受信する
                System.out.println("クライアント: " + getResponse());
            }
        }

        return "クライアントを終了しました。";
    }

    private void sendRequest(String in) {
        try {
            //System.out.println("*** クライアントソケット: リクエスト送信" + in + " ***");
            send = new PrintWriter(sock.getOutputStream());

            send.write(in + SEP);
            send.flush();
//          send.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * サーバーからのレスポンスを受ける。
     * @throws IOException
     */
    private String getResponse() {
        StringBuilder build = new StringBuilder();
        try {
            // System.out.println("*** クライアントソケット: レスポンス受信 ***");
            if (response == null) {
                response = new BufferedReader(new InputStreamReader(sock.getInputStream()));
            }
            while (true) {
                int read = response.read();
                if (read == 13 || read == 10) {
                    break;
                }
                char ch = (char) read;
                build.append(ch);
            }
            //response.close();
        } catch (IOException e) {
            e.printStackTrace();
            build.append(" Errors... ");
        }
        // System.out.println("*** クライアントソケット: 完了:レスポンス受信 ***");
        return build.toString();
    }

    public static void main(String[] args) {
        ClientMain main = new ClientMain();
        String mes = main.execute();
        System.out.println(mes);
    }
 }

java.net.ServerSocket

Javaでのサーバー作成で最もベーシックな低レベルAPIがこのクラスです。巷で出回っているフレームワークも結局はこのテクノロジーを使用しています。

ServerSocketとは

このクラスはサーバー・ソケットを実装します。サーバー・ソケットは、ネットワーク経由で要求が送られてくるのを待ちます。これは、その要求に基づいていくつかの操作を実行します。その後、場合によっては要求元に結果を返します。
サーバー・ソケットの実際の処理は、SocketImplクラスのインスタンスによって実行されます。アプリケーションは、ソケット実装を作成するソケット・ファクトリを変更することで、ローカル・ファイアウォールに適したソケットを作成するようにアプリケーション自体を構成することができます。

このように解説がJavaDocドキュメントにはありますが、実装の方は下のようになります。

ServerSocketの実装

サーバーソケットの作成(インスタンス化)

実際に下のようにコーディングしました。これは、サーバーソケットのインスタンスを作成する処理です。

try {
    server = new ServerSocket(portNo);
    if (server.isBound() == false) {
        server.bind(new InetSocketAddress("localhost", portNo));
        server.setSoTimeout(3000);
    }
} catch (IOException e) {
    this.finalize();
    e.printStackTrace();
}

処理としては、以下の通りです。

  1. サーバーソケットをポート番号"portNo"で作成
  2. サーバーソケットがバインドされていない場合は、新たにバインドし直し
  3. サーバーソケットのタイムアウト時間を3秒に設定

サーバーソケットの送受信処理

インスタンスを作成したら、クライアントとの送受信を行います。手順は以下の通りです。

  1. サーバーを起動する
  2. クライアントアプリでアクセスする

なので、先にサーバーを作成します。そして、一番下にメインメソッドを作っています。

/**
 * コンストラクタで作成されたサーバーソケットで
 * 受付処理を開始する。
 */
public void startServer() {
    try {
        System.out.println("*** SocketServer start " + server.isBound() + "***");
        Socket recieve = server.accept();
        System.out.println("*** Server Get Request start***");
        // 受信データの読み込み
        StringBuilder responseTxt = new StringBuilder(" Response");
        // 受信状態
        System.out.println("クライアント: " + recieve.getRemoteSocketAddress());
        System.out.println("接続: " + recieve.isConnected());
        System.out.println("入力ストリームが閉じている: " + recieve.isInputShutdown());

        // 受信したリクエスト
        InputStream in = recieve.getInputStream();
        // 返却するレスポンス
        OutputStream writer = recieve.getOutputStream();
        System.out.print("Server recieve is ...");
        int c = 0;
        // CRとCRLFの場合で入力が終了している時がある
        while((c = in.read()) != -1) {
            char ch = (char)c;
            responseTxt.append(ch);
            // 空の場合
            if (c == 10 || c == 13) {
                break;
            }
        }
        System.out.println(responseTxt.toString());
        System.out.println("*** Server Send Response start***");
        // レスポンス送信
        writer.write((responseTxt.toString() + System.getProperty("file.separator")).getBytes());
        writer.flush();
        in.close();
        writer.close();
        System.out.println("*** SocketServer end ***");
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        // 開いたストリームを閉じる
        try {
            closeServer();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

/**
 * メインメソッド
 * @param args プログラム引数
 */
public static void main(String[] args) {
    SocketServerBasic serverSocket = new SocketServerBasic(8080);
    serverSocket.startServer();
}

次に、クライアントアプリの作成を行います。
クライアントの処理は、以下の通りです。

  1. クライアントソケットの作成(ローカルホスト、ポート番号指定)
  2. 受診するデータを準備(InputStream)
  3. 送信するデータを準備(OutputStream)
  4. リクエストの送信
// リクエスト送信
writer.write("ping...\n".getBytes());
writer.flush();
  1. サーバーのレスポンスを受信
            int c = 0;
            while((c = reader.read()) != -1) {
                System.out.print((char)c);
            }

ここで、注意点があります。受信時の処理で、BufferedReader#readLine()では、データの区切りが取得できないケースがあります。
そのような時は、下のように、改行文字をデータの区切りとして取得すれば、処理がループを抜けない状態を回避することができます。

// レスポンス
response = new PrintWriter(socket.getOutputStream());
int ch = -1;
StringBuilder build = new StringBuilder();
while((ch = request.read()) != -1) {
    build.append((char) ch);
    if (ch == 10 || ch == 13) {
        break;
    }
}
/**
 * コンストラクタ
 * @param portNo ポート番号
 */
public static void main(String[] args) {
    System.out.println("*** SocketClient start ***");
    try (Socket sock = new Socket(HOST, PORT)) {
        // 受信したレスポンス
        InputStream reader = sock.getInputStream();
        // 送信するリクエスト
        OutputStream writer = sock.getOutputStream();
        System.out.println("接続済み: " + sock.isConnected());
        System.out.println("接続サーバー: " + sock.getRemoteSocketAddress());
        // リクエスト送信
        writer.write("ping...\n".getBytes());
        writer.flush();

        System.out.println("*** Testing start " + sock.getInetAddress() + " ***");
        // レスポンス受信
        int c = 0;
        while((c = reader.read()) != -1) {
            System.out.print((char)c);
        }
        System.out.println("*** Testing end***");

        // 終了処理
        reader.close();
        writer.close();
        sock.close();
        System.out.println("*** SocketClient end ***");
    } catch (IOException e) {
        e.printStackTrace();
    }
}

これで、一応は動きます。「一応」というのは下のソースでは、while文が終わらないという事象に見舞われました。以下の部分です。

while((c = reader.read()) != -1) {
    System.out.print((char)c);
}

他のサイトを調べてみると、うまく動いているようですが、自分のところでは動きませんでした。

そして、悩んだ結果次のように修正しました。

// CRとCRLFの場合で入力が終了している時がある
while((read = in.read()) > 0) {
    // 空の場合
    if (read == 10 || read == 13) {
        System.out.println("*** read break ***");
        break;
    }
    char ch = (char) read;
    inputTxt.append(ch);
}

受信したデータの終わりがわからない状態になってしまうのでループ処理が終わらなかったというわけです。

これを解消するために、終わりを示す「改行」文字をINT型で判別しています。intの10, 13はchar型の改行コードの値に相当します。つまり、(10)という値は、LF改行のことを指します。

なので、改行コードと取得した値が同じ場合は処理を抜けるというわけです。

if (read == 10 || read == 13) {
System.out.println("*** read break ***");
break;
}

そして、最終的にはこちらのようなコードになりました。全体はGithubにあります。

try {
    System.out.println("*** サーバーソケット起動 ***");
    Socket sock = server.accept();
    // リクエスト
    request = new BufferedReader(new InputStreamReader(sock.getInputStream()));
    // レスポンス
    response = new PrintWriter(new OutputStreamWriter(sock.getOutputStream()));
    // リクエストの読み込み
    while(true) {
        String inputTxt = readRequest(request);

        if (inputTxt.contains("HTTP/1.1")) {
            System.out.println("HTTP: " + inputTxt);
            inputTxt = getHttpResponse(inputTxt);
        } else if ("".equals(inputTxt) ) {
            System.out.println("***> 空リクエスト: " + inputTxt);
            inputTxt = "<html><body>Hello World!</body></html>";
        } else {
            System.out.println("***> else: " + inputTxt);
        if (isBye(inputTxt)) {
            break;
        }
    }
    if (DEBUG) System.out.println("*** サーバーソケット: リクエスト受信 " + inputTxt + "***");

    // レスポンスを返す
    response.write(inputTxt + SEP);
    response.flush();
    System.out.println("*** サーバーソケット: レスポンス送信 " + inputTxt + "***");
    inputTxt = null;
// デバック用コード
//  request.close();
//  response.close();
//  sock.close();
//  request = null;
//  response = null;
//  break;
    }
} catch (IOException e) {
    e.printStackTrace();
}

実行結果は、後日アップロードします。。。

でわでわ。。。

関連記事

Java Network 〜Javaでホームページにアクセスする仕組み〜

今回は、JavaでWebページにアクセスする処理を作るときの内容を記載します。

サンプルコードはGithubにアップしてあります。

1.ウェブにアクセス

プログラムでウェブにアクセスする部分に関して記載します。コードの説明になりますが。。。

System.out.println("*** execute ***");
String url = "https://ja.wikipedia.org/wiki/%E6%AD%A6%E5%99%A8";
Document doc = null;
try {
    doc = Jsoup.connect(url).get();
} catch (IOException e) {
    e.printStackTrace();
}

変数の「url」にアクセスします。
処理の内容としては以下の通りです。

  1. アクセスするURLを指定します。つまり変数に代入します。
  2. そして、取得したHTMLをDocumentクラスに変換して取得します。doc = Jsoup.connect(url).get();
  3. 取得するときに例外(IOException)が出る可能性がある→メソッドの定義にthrows IOExceptionがある、のでtry chatchで囲む

2.HTMLの取得

これも同様に、コードから見ていきます。

Elements eles = doc.getElementById("toc").children();
for (int i = 0; i < eles.size(); i++) {
    Element item = eles.get(i);
    System.out.print("wholeText(): " + item.wholeText());
    System.out.println(" / text(): " + item.text());
    printIndex(item, i);
}

Jsoupのフレームワークを使うと言う部分になります。
ドキュメント(Document)クラスを中心にして取得します。

doc.getElementById("toc").children()

このコードでid="toc"と記述されたHTMLを取得します。
実際には[Wikiの「武器」ページ](https://ja.wikipedia.org/wiki/%E6%AD%A6%E5%99%A8)から目次の部分を取得します。

具体例参照するぺーじのHTML
![](http://zenryokuservice.com/wp/wp-content/uploads/2020/03/スクリーンショット-2020-03-23-20.49.38-300x192.png)

<div id="toc" class="toc" role="navigation" aria-labelledby="mw-toc-heading"><input type="checkbox" role="button" id="toctogglecheckbox" class="toctogglecheckbox" style="display:none"><div class="toctitle" lang="ja" dir="ltr"><h2 id="mw-toc-heading">目次</h2><span class="toctogglespan"><label class="toctogglelabel" for="toctogglecheckbox"></label></span></div>

目次のタグ部分です。はじめのタグ(一番外側のタグです)を取得しています。

よくJSで以下のような実装を行いますが、それと同じです。

var tag = document.getElementById("タグのID");

取得したタグからタグの中にある子供のタグを取得します。

## タグの取得
例えば、下のようなHTMLから。。。

<div class="toctitle" lang="ja" dir="ltr"><h2 id="mw-toc-heading">目次</h2><span class="toctogglespan">
    <label class="toctogglelabel" for="toctogglecheckbox"></label></span>
</div>

以下のようなコードを実行したとします。
```java
Document doc = Jsoup.connect(url).get();
// HTMLボディの取得
Element body = doc.body();
Elements eles = body.getElementById("toctitle");
eles.text();
```
と実装すると「目次」が取得できます。(間違ってたらごめんなさい。。。)大切なのは、子供のタグを取得(Elements)してElements#child()子供のタグを取得すると言うわけです。

## 結論から言うと
実装して動かしてみるのが一番ですが、サンプルコードとして。。。
```java
Element body = doc.body();
Elements eles = body.getElementsByTag("h2");
System.out.println("size: " + eles.size());
Elements eles = doc.getElementById("toc").children();
for (int i = 0; i < eles.size(); i++) {
Element item = eles.get(i);
System.out.print("wholeText(): " + item.wholeText());
System.out.println(" / text(): " + item.text());
printIndex(item, i);
}
```

## 関連ページ

Java Basic

  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 〜テストスイートの作り方〜


Java HTML解析 〜Wikipedia 武器 ページの解析3〜

前回は、目次の表示を行いました。

しかし、このままでは、インデックスがちゃんと表示されないので、インデックスをちゃんと表示できるように一工夫する必要があります。

インデックスがうまくいかない

前回のコードでは、「id=toc」のタグを取得してから中にあるタグを単純に表示するだけです。というか表示用のメソッドの記述がありませんでした。

それは、インデックスをちゃんと表示するためのメソッドを用意したためです。
対象になる部分は以下のような処理です。

// System.out.println("*** Get Content ***");
Elements eles = doc.getElementById("toc").children();
for (int i = 0; i < eles.size(); i++) {
    Element item = eles.get(i);
    printIndex(item, i);
}

「printIndex(item, i);」の部分です。
このメソッドを下のように変更すると単純にタグの中身を表示できます。
System.out.println(item.text());

インデックスの処理

結論から言うと、インデックス部分かどうかの判定をして、インデックスであれば。。。と言う処理を行ってやれば良いと言うところですが、ちょっと面倒でした。

作成した処理は以下のようなものになります。
Gitにアップしてあります

private void printIndex(Element row, int num) {
//      System.out.println("index" + num + ": " + row.text());
    if (row.childrenSize() != 0) {
        printChild(row.children());
    }
}

private void printChild(Elements eles) {
    for (Element ele: eles) {
        if (ele.childrenSize() != 0) {
            printChild(ele.children());
        } else {
            printElement(ele);
        }
    }
}
private void printElement(Element ele) {
    if (ele.text().contains(".")) {
        print(ele,"-   ", ": ");
    } else if (ele.text().matches("[0-9]{1,2}")) {
        print(ele,"", ": ");
    } else {
        if (ele.text().equals("")) {
            return;
        }
        println(ele, "", "");
    }
}
private void print(Element ele, String prefix, String safix) {
    if (safix != "") {
        System.out.print(ele.text() + safix);
    } else {
        System.out.print(prefix + ele.text());
    }
}
private void println(Element ele, String prefix, String safix) {
    if (safix != "") {
        System.out.println(ele.text() + safix);
    } else {
        System.out.println(prefix + ele.text());
    }
}

メソッド呼び出しの順番は以下のようになっています。

  1. printIndex(): タグの子供を取得
  2. printChild(): タグの子供がいる場合は再起処理、そうでない場合は文字を取得して表示
  3. printElement(): ⑴を参照
  4. print(改行なし) or println(改行あり)
⑴ 以下のような条件分岐を行う
A. 文字列に「.」を含む場合
B. 文字列が「0-9」の数字の場合
C. 上記以外の場合

それぞれに対し、下のような処理を行います。※改行しない場合

       if (safix != "") {
            System.out.print(ele.text() + safix);
        } else {
            System.out.print(prefix + ele.text());
        }

表示する文字の手前(prefix)とあと(safix)に値があればそれを表示すると言う処理を行っています。

このプログラムで、取得した値は以下のように表示されます。

*** execute ***
*** Get Content ***
目次
1: 武器のエネルギー
1.1: 運動エネルギー
1.2: 人力
1.3: 火・燃焼
1.4: 生物(兵器)
1.5: 電気
1.6: 光線
1.7: 毒・化学物質
1.8: その他
2: 武器の構造
2.1: 柄
2.2: 柄頭
2.3: 刃
2.4: 刀身・剣身
2.5: 鎖物・縄
2.6: 鉤
2.7: 暗器
2.8: 機械
3: 歴史
3.1: 石器・自然物
3.2: 金属製武器の登場
3.3: 銃の登場
3.4: 近代
3.5: 第二次大戦後
4: 日本の武器の歴史
4.1: 古代
4.2: 中世
4.3: 近世
4.4: 近代
4.5: 現代
4.6: 現在
5: 玩具としての武器
6: スポーツに用いられる武器
7: 象徴・祭器としての武器
8: 架空の武器
9: 武器の分類
10: 主な武器の種類
10.1: 刀剣類
10.2: 鈍器類
10.3: 竿状武器(ポールウェポン)
10.4: 投擲武器
10.5: 射出武器
10.5.1: 暗器・格闘武器
10.6: その他の武器
11: 脚注
12: 参考文献
13: 関連項目
14: 外部リンク

でわでわ。。。

関連ページ

Java Basic

  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 〜テストスイートの作り方〜


Java HTML解析 〜Wikipedia 武器 ページの解析2〜

前回は、とりあえずでWikiのページ(武器)を取得する処理を実装しました。
これは、以下のような処理を行っています。

  1. 単純にURLで対象のHTMLのH2タグを取得
  2. 文字列でコンソールに表示

しかし、これでは意味がないので取得したいものを取得できるようにWikiページの構成を考えていきます。

Wikiページの中身

とりあえずは目次を取得することを考えます。
Wikiページの「目次」に関して、タグの属性に注目してみます。目次部分のHTMLをはじめの部分を抜き出してみました。

<div id="toc" class="toc" role="navigation" aria-labelledby="mw-toc-heading">
<input type="checkbox" role="button" id="toctogglecheckbox" class="toctogglecheckbox" style="display:none"><div class="toctitle" lang="ja" dir="ltr"><h2 id="mw-toc-heading">目次</h2><span class="toctogglespan">
<label class="toctogglelabel" for="toctogglecheckbox"></label></span></div>
<ul>
<li class="toclevel-1 tocsection-1"><a href="#武器のエネルギー"><span class="tocnumber">1</span> <span class="toctext">武器のエネルギー</span></a>
<ul>
<li class="toclevel-2 tocsection-2"><a href="#運動エネルギー"><span class="tocnumber">1.1</span> 

これの構成を見てみると大元(一番上)のタグのidとclassに注目してみると目次部分のHTMLにはID=「toc」とあります。
そしてその「toc」内に全ての内容が記載されているのでこれを取得すれば、目次部分が取得できます。

そして、以下のような構成で内容が記載されています。

<div id="toc" class="toc" /> => 全体のタグ
    「目次」
    toclevel-1 => トピックレベル1の項目
    toclevel-? => トピックレベル?の項目
       tocsection-? => 各セクション1〜?までの項目

なので、Javaのコードでは以下のような処理を行います。

  1. 「id=”toc"」のタグを取得
  2. それぞれの値をコンソールに出力

Jsoupを使用するとここら辺が簡単にできます。

Javaでの処理

public void execute() {
    // System.out.println("*** execute ***");
    String url = "https://ja.wikipedia.org/wiki/%E6%AD%A6%E5%99%A8";
    Document doc = null;
    try {
        // Wikiページへアクセス、HTMLを取得する
        doc = Jsoup.connect(url).get();
    } catch (IOException e) {
        e.printStackTrace();
    }
    // System.out.println("*** Get Content ***");
    Elements eles = doc.getElementById("toc").children();
    for (int i = 0; i < eles.size(); i++) {
        Element item = eles.get(i);
        printIndex(item, i);
    }
}

これは自分が作成したものですが、以下のような処理を行っています。

  1. 「id="toc"」のタグを取得
  2. タグの子供(タグ内にあるタグ)
    <div id="toc" class="toc" role="navigation" aria-labelledby="mw-toc-heading"><input type="checkbox" role="button" id="toctogglecheckbox" class="toctogglecheckbox" style="display:none"><div class="toctitle" lang="ja" dir="ltr"><h2 id="mw-toc-heading">目次</h2><span class="toctogglespan"><label class="toctogglelabel" for="toctogglecheckbox"></label></span></div>
    <ul>
    <li class="toclevel-1 tocsection-1"><a href="#武器のエネルギー"><span class="tocnumber">1</span> <span class="toctext">武器のエネルギー</span></a>
    <ul>
    <li class="toclevel-2 tocsection-2"><a href="#運動エネルギー"><span class="tocnumber">1.1</span> <span class="toctext">運動エネルギー</span></a></li>

    上の「武器のエネルギー」などが含まれるタグを取得

  3. 取得したタグの文字列部分を取得

こんな感じの処理を行っています。

問題点

このままでは、取得したいタグの番号をつけている部分「1.1、2 ...」という数字があるので、混乱してしまいます。
本当であれば、これらは各項目のインデックスであり、項目の順番を示すものですので、これをちゃんと表示してやる必要があります。イメージとしては下のような感じです。

目次
1: 武器のエネルギー
1.1: 運動エネルギー
1.2: 人力
1.3: 火・燃焼
1.4: 生物(兵器)

これらの表示を行うために、頭をひねる必要があります。
これは次回にしようと思います。

でわでわ。。。

関連ページ

Java Basic

  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 〜テストスイートの作り方〜


Java HTML解析 〜Wikipedia 武器 ページの解析〜

タイトルにあるページの解析を行います。解析する内容は、表示されている武器の一覧を作るための情報を抜き取るような形です。

ページの解析

HTMLはタグで、ツリー状に出来上がっているので、そこを基準にして解析します。

そして、忘れてはいけないのが「目的」です。今回の目的は、武器の一覧を作成することですので、以下のような項目を取得することを目的にしようと思います。

  1. 武器の種類(刀、鉄砲、戦車etc...)
  2. 武器を使うためのエネルギー源
  3. 現実か、架空のものか( Yes or No)
  4. その武器に対する説明、逸話など

上のような解析をしたいと思います。
駄菓子菓子!自然言語処理ができるわけでもなし、完全に、独自理論での実装になります。

ステップアッププログラミング!

何はともあれ、いきなりすごいことはできないので一歩ずつ進みます。
千里の道も一歩から、プログラミングの良いところは「理解すれば、すぐできる」というところです。ギターとか、ドラムとかのように毎日の練習は必要ありません。その代わり勉強が必要かもしれないけど(笑)

タグを取得

タグを取得します。実装したコードはこちらになります。Githubですので、ダウンロードも可能です。

public void execute() {
    System.out.println("*** execute ***");
    String url = "https://ja.wikipedia.org/wiki/%E6%AD%A6%E5%99%A8";
    Document doc = null;
    try {
        doc = Jsoup.connect(url).get();
    } catch (IOException e) {
        e.printStackTrace();
    }
    System.out.println("*** Get Content ***");
    Element body = doc.body();
    Elements eles = body.getElementsByTag("h2");
    System.out.println("size: " + eles.size());
    for (int i = 0; i < eles.size(); i++) {
        Element item = eles.get(i);
        System.out.print("wholeText(): " + item.wholeText());
        System.out.println(" / text(): " + item.text());
    }
}

前回作成したコードよりもスッキリしています。シンプルに「h2タグ」を取得してそれをコンソールに出力しているだけです。

HTML解析 Lv1: ポイントでデータ取得

上のコードは、h2タグを取得しているだけですが、これを、「〜タグを取って、次は〜」というように、順番に必要なデータを取得していくのも1つの手段だと思います。小難しい「人工知能」など使わなくてもいけます(笑)多分ね。。。

そして、ちょいと考えてみたのが、下のような手順です。

  1. Wikiをターゲットにして、Wikiページから調べたい情報を取得するために、Wikiページの構成を調べる
  2. 構造を理解し、必要な情報を欲しい形で取得できるようにプログラム設計を行う
  3. 実装、テスト、成果物(実行結果)を使用してテキストRPGを作る

こんな感じの実装でいけると思います。
ダメだったら、また別な方法を考えます(笑)

そんなもんでしょう(笑)

関連ページ

Java Basic

  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 〜テストスイートの作り方〜


Java Network 〜HTMLからデータ取得2〜

今回は、HTMLからのデータ取得を行う処理を実装しようと思います。その2回目です。

HTMLからデータ取得

HTMLからデータを取得する、つまりインターネットにアクセスして特定のウェブページを見る(閲覧)などして自分らが必要な情報を取得する、ということをプログラムにやらせようという分けです。

前提として、プログラム(PC)は人間ほど柔軟な思考ができるわけでもなく、我々人間が指示(プログラム)した通りにしか動いてくれません。なので一工夫が必要になります。

最近では、人工知能なんてものもありますので、この分野は広く開拓できそうです。
初めから複雑なことはできないので、1つずつ段階的に実装していきます。

データ取得Lv2

前回は、データの取得、HTMLを取得するという部分を実装しました。ソースはGithubにアップしてあります。
下のようなコードを実装しました。

// ⑴ URLを指定する
String targetUrl = "https://ja.wikipedia.org/wiki/%E6%AD%A6%E5%99%A8";
// ⑵取得したHTMLをオブジェクトにするためのクラス
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
try {
    builder = factory.newDocumentBuilder();
} catch (ParserConfigurationException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
}
// ⑶ 指定したURLにアクセス、HTMLの取得
try {
    URL urlCls = new URL(targetUrl);
    urlCls.openConnection();
    InputStream inp = (InputStream) urlCls.getContent();
    Document html = builder.parse(inp);
} catch(MalformedURLException e) {
    e.printStackTrace();
} catch(IOException ie) {
    ie.printStackTrace();
} catch (SAXException e) {
    e.printStackTrace();
}

ここで使用しているクラスはJDKに入っているもので「〜.jar」をダウンロードとかしなくても使用できるコードになります。

そして、あくまでもHTMLを取得するまでの処理なのでここからがHTMLの読み込み、必要なデータの取得になります。

HTMLの読み込み

早速コードを見ていきます。

    try {
        URL urlCls = new URL(targetUrl);
        // 指定のURLにアクセス(コネクションの取得)
        urlCls.openConnection();
        // HTML文書の入力ストリーム(ファイルと同じ扱いです)
        InputStream inp = (InputStream) urlCls.getContent();
        Document html = builder.parse(inp);
        // 取得したHTMLの「ulタグ」を全て取得する
        NodeList nodes = html.getElementsByTagName("ul");
        for (int i = 0; i < nodes.getLength(); i++) {
           // 子ノードを取得し再起処理を行う loopPrint(nodes.item(i).getChildNodes());
        }

    } catch(MalformedURLException e) {
        e.printStackTrace();
    } catch(IOException ie) {
        ie.printStackTrace();
    } catch (SAXException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return "";
}
/** 再起処理を行うメソッド */
private void loopPrint(NodeList list) {
    String emp = System.getProperty("separator") + "\t\t";
    for (int i = 0; i < list.getLength(); i++) {
        Node node = list.item(i);
        if (node.hasChildNodes()) {
            loopPrint(node.getChildNodes());
        } else {
            if ("#text".equals(node.getNodeName())) {
                System.out.println("NodeName: " + node.getNodeName() + " -> Value: "+ node.getNodeValue());
            }
        }
    }
}

上の実装では「再起処理」がポイントになります。
取得したHTMLはタグで階層状になっているので階層をどんどん下がって、次のタグへ。。。というような処理が必要になります。このような時にしようするのが「再起処理」です。

つまるところは、以下のような処理です。

  1. ulタグのはじめの部分を取得
  2. タグの子ノードの有無を確認
  3. 子持ちなら、同じメソッドを呼び出す、そうでないなら中身をコンソールに表示
  4. これをルートノードの子供の数だけ繰り返す

こんな実装をしています。しかし、ulタグを取得しているだけなので、ちょっと実用的ではありません。

まとめ

駄菓子菓子、読み込み中身を取得しても、必要なデータのみを読み込むのに、色々と処理を書かないといけないので、ライブラリを使用して実装し直すことにします。使用するライブラリはJsoupです。
でわでわ。。。



Java Network 〜HTMLからデータ取得1〜

今回は、HTMLからのデータ取得を行う処理を実装しようと思います。

HTMLからデータ取得

HTMLからデータを取得する、つまりインターネットにアクセスして特定のウェブページを見る(閲覧)などして自分らが必要な情報を取得する、ということをプログラムにやらせようという分けです。

前提として、プログラム(PC)は人間ほど柔軟な思考ができるわけでもなく、我々人間が指示(プログラム)した通りにしか動いてくれません。なので一工夫が必要になります。

最近では、人工知能なんてものもありますので、この分野は広く開拓できそうです。俗に言う「自然言語解析」と言うやつです。
初めから複雑なことはできないので、1つずつ段階的に実装していきます。

データ取得Lv1

データの取得、HTMLを取得するという部分を実装します。
結論からいうと下のようなコードになります。

// ⑴ URLを指定する
String targetUrl = "https://ja.wikipedia.org/wiki/%E6%AD%A6%E5%99%A8";
// ⑵取得したHTMLをオブジェクトにするためのクラス
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
try {
    builder = factory.newDocumentBuilder();
} catch (ParserConfigurationException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
}
// ⑶ 指定したURLにアクセス、HTMLの取得
try {
    URL urlCls = new URL(targetUrl);
    urlCls.openConnection();
    InputStream inp = (InputStream) urlCls.getContent();
    Document html = builder.parse(inp);
} catch(MalformedURLException e) {
    e.printStackTrace();
} catch(IOException ie) {
    ie.printStackTrace();
} catch (SAXException e) {
    e.printStackTrace();
}


ここで使用しているクラスはJDKに入っているもので「〜.jar」をダウンロードとかしなくても使用できるコードになります。
処理の内容としては、以下の通りになります。

⑴ URLを指定する

これは、説明するまでもないような気もしますが、ポイントになるので。。。
文字列の変数「targetUrl」に、アクセスするURLを設定します。
現状のコードでは、固定値になりますが、今後この部分を引数に変更して動的なURLにアクセスできるように変更します。

⑵取得したHTMLをオブジェクトにするためのクラス

Documentクラスを使用して取得したHTMLから必要な情報を取得します。

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

実際にHTMLの文字列を取得することもできますが、取得したいデータは、記載されている内容なので、タグの部分は無視したいためこのような方法を使いました。
ちなみに、これ(Documentクラス)も余計な情報をふんだんに持っているので、今後はJsoupを使用して実装する予定です。これを使うにはリンク先のJARファイルをダウンロード、ビルドパスに設定という手順を踏む必要があります。→この部分に関してはこちらの記事を参照ください。この記事ではJSONライブラリ(json-path-2.1.0.jar)を追加しています。下のような記事です。

⑶ 指定したURLにアクセス、HTMLの取得

ここまできたら、あとはメソッドを呼び出すだけです。
ちょっと注意が必要なのはURL#getContent()の返り値がObujectなので「何でも返す」というところです。当然本当はStringを返しているのにFileで受け取ろうとすればExceptionがでます。このメソッドの用途を明確にして取得するもの(HTMLやイメージファイルなど)をはっきりさせて実装する必要があります。

まとめ

今回は、HTMLを取得するのに以下のクラスを使用してやりました。

  1. URLクラス: インターネット上のコンテンツ(HTMLなど)にアクセスする
  2. Documentクラス: 取得したコンテンツをドキュメント(HTMLやXML)として扱う ※同じ名前で違う機能のものがあるので注意が必要です。
  3. [InputStream](): 読み込み用、入力ストリームです。この「ストリーム」に関してはこちらの記事を参照ください。クラスの実装例でInputStreamを使用しています。
  4. DocumentBuilderFactory: DocumentBuilderクラスを取得するためのクラスです。
  5. DocumentBuilder: Documentクラスを取得するためのクラスです。

これらのクラスを使用して、インターネット上のHTMLファイルを読み込み、コンテンツ(HTML文書)を取得、までの実装になります。こちらのGitにあるソースは、文書の読み込みも実装しています。

目的の確認

HTMLをダウンロードしてその中身を解析することが目的なのでこの方法では、HTMLを取得するのに結構な手間がかかります。なのでフレームワークの利用を検討します。

次回は読み込み部分の処理について記載したいと思います。

でわでわ。。。



Java IoT 予備知識〜ラズパイにJava(Web)サーバーを立てる〜

ラズパイにIoT開発環境を構築するという自前のミッションがあるのですが、急遽ラズパイにJava製のWebサーバーを起動しようということになりました。※そのように考えた次第です。。。

具体的に、Iotの実装を行うためにはそれなりの開発環境を構築する必要があります。※JavaME環境

しかし、自分が持っているラズパイは古いので、遅い。。。開発環境を構築して作業を行うのはちょいと面倒なわけです。

ラズパイでの開発環境構築が必要な理由は、デバイス(USB、GPIOなど)へのアクセスが必要になるため実機での開発環境が必要になります。

なので、今回は古いラズパイ(RPi2 model B)での実装を行うので、Windows上で開発したJavaサーバーをラズパイに移植して起動しようという考えです。

具体的な手順

  1. Widnows上で開発、テストを行う
  2. JARファイル(実行ファイル)を出力して起動できる確認をする
  3. 作成したコードをGithubにコミットする
  4. ラズパイでGithubからソースをチェックアウトしてビルド、JARファイルを作成
  5. ラズパイの起動時に実行するシェル・スクリプトで手順4の処理を行う

上記のような手順で作業を行うと結果としては、下のように動くであろうというところです。

  1. ラズパイに電源を入れる
  2. 起動スクリプトが動く
  3. 作成したJavaサーバーが起動する

問題は、作成したJavaサーバーに何を行わせるか?というところです。

今回作成する、JavaサーバーはHTTPプロトコル以外でも受信し処理を行うことができるものを作成します。
「なぜそれが可能か?」というところですが、これは低レベルな実装なためHTTPだろうが、バイナリだろうが関係なく受信、レスポンスの送信を行うことが可能になります。

その代わり、以下のような部分を実装する必要があります。

  1. 受信したリクエストがHTTPなのか、それ以外なのか?を判別
  2. HTTPリクエストならばHTTPでレスポンスを返し、それ以外はそれぞれのレスポンスを返す
  3. それぞれのプロトコル(HTTP, FTPなど)で受信したときにどのような処理を行うのか?

通常というか身近にある「ウェブサーバー」と呼ばれているものはHTTPリクエストを受け、それに対応するHTMLを読みこんで、そのテキストデータ(HTML)を返却、ブラウザで表示というような処理を行っていますが、

今回作成するJavaサーバーは低レベルなため、大体のことは大体できますが、以下の部分を実装する必要があります。

HTTPリクエストを受け、それに対応するHTMLを読みこんで、そのテキストデータ(HTML)を返却

この部分を実装できるようになると、自作のフレームワークを作成したり一人で多くの作業を行おうとするときに「前もって作成しておく道具」として使用することができます。このような「道具」を作成しておくとやらなければいけいない作業が減り、いろいろなことができるのではないでしょうか?

注意点

上記のJavaサーバーは、ServerSocketを使用して作成しますが、これの実装をする前に理解しておく必要がいくつかあります。

  • サーバーとクライアントの関係に関する理解
  • Webサーバー、アプリケーションサーバー(APサーバー)、DBサーバーの関係性に対する理解
  • MVCモデルの概要に対する理解

まとめると次のようになります。

  1. リクエストの送信と受信を行うときに「サーバー」と「クライアント」の関係がある
  2. HTTP以外にもプロトコルがあり、ブラウザはHTTP、FTPなどのプロトコルを使用する
  3. HTTP以外のプロトコルで、Socket通信のようにバイトデータをそのまま送信することもある
  4. HTTP、それ以外、それぞれの通信方法で、それぞれに対応した処理を実装する必要がある

次はHttpServeltの実装について

ちょっと難しくなってしまったので、まずはJavaでのウェブサーバーを見ていきます。

JavaのWebサーバー

とりあえずはここのページを参考に作成しようと思います。

結論から言うと。。。

HttpServletクラスを拡張(extends)してリクエストを受け付ける常駐アプリを作成しようと言うことです。

とても、シンプルなJavaウェブサーバーです。Java出なくてもクライアントとサーバーの関連を学習したい人は一読作成して見ると、一発で理解できます。(理解できないと作成できません。)

このような、わりかし低レベルな実装は経験する機会があまりないので、Java学習者やウェブデザイナーなどウェブ・サーバーをよく使う人には一度やって見ると理解が早いです。

ちなみに、「通常実装するとき」というのは、SpringBoot(DispatcherServlet)、JavaEE(FacesServlet)のようなフレームワークを使用した実装のことを指しています。

今回作成するシンプルなJavaウェブサーバーというのは、一段レベルを下げて上記のようなサーブレットクラスの親クラス・インターフェース部分の実装を行うというところです。

ちなみに、FacesServletクラスはServletインターフェースを実装しています。なので、この部分に係る実装を行うということです。

具体的には、HttpServletクラスの子クラスを作成してこのクラスを拡張してやります。

大まかな仕組み

下のような図になります。

ふざけているのではありませんので。。。

  • クライアント(スマホやPC)からURLを指定してサーバーにアクセスします。
  • クライアントは、PCやスマホのことなので自分が持っている機械(デバイス)です。

そして、サーバーはどこかの会社とか、国の機関とかに置いてあるウェブサーバー(アプリ)を起動している機械(コンピュータ)にアクセスしてそのアプリが返却するHTMLを見ている状況です。一緒にJSなどもダウンロードされて画面(ブラウザ)に表示されます。

大まかに上のような処理を行う「ウェブサーバー」をJavaを使用して作成しようと言うことです。

サーバーはアプリのこと

サーバーはアプリケーションです。常駐して動き、何かしらのアクセスを待機しているアプリケーションのことを「サーバー」と呼びます。別な言い方をすると「常駐待機しているアプリケーション」ということになります。
具体的には、PCを動かすために起動する(画面を表示する)Xサーバーなんてものもありますし、電源を入れたらスマホの画面が開くのも常駐アプリなので「サーバー」の仲間に入ります。
全部がサーバーだと呼ぶのに不便なのでスマホアプリと言ったり、サーバーと言ったりして区別します。

ちなみに、サーバー(アプリケーション)を稼働させるためのコンピュータのことを「サーバー機」と呼びます、そして、基本情報などの説明書きには「サーバー」などと書かれていますが、「サーバー機」と「サーバー(アプリケーション)」とでは別物なので、注意してください。

Java版Webサーバー

通常は、TomcatとかApacheとかをダウンロードしてきてウェブサーバーとして稼働することが多いのですが、今回はこれをJavaで作成しようと思います、まずは調査から行きますが、TomcatはJavaでできているようです。

そして、よくある書籍などでは、下のようなコードで実装しています。

public class JspLlesson1 extends HttpServlet {

    public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
        res.setContentType("txtext/html; charset=UTF-8");
        PrintWriter write = res.getWriter();
        write.println("Hello World");
    }
}

HttpServletのポイント

このクラスはJavaDocにあるように、抽象クラスです。しかし、抽象メソッドが定義されていないので「必ずオーバーライド」をしなくてもよい形になっています。

意図としては、継承して使用してくださいということなのだと思います。※予想になります。。。

そして、「doGet()」を「doPost()」メソッドをオーバーライドすることでHTTPリクエストに対する処理を実装する事ができます。

上記の落書きのようなイメージにある、リクエストとレスポンスをハンドルする処理がこのクラス・メソッドに実装することになるというわけです。

具体的には、リクエストの種類が2つあり、それぞれ「GETリクエスト」「POSTリクエスト」になります。

GET(ゲット)リクエスト

ブラウザで、URLを叩いたときに「XXXX.html」のようなファイルを開くときに使用するリクエストです。
その名の通り、対象のファイル(HTMLファイル)をダウンロード、ブラウザで表示します。
もし、ブラウザではなくプログラムで対象のURLにアクセスしたときはどのようになるか?

下の画像は、次のコマンドをコマンドプロンプトでたたいたときの結果です。

curl https://zenryokuservice.com

POST(ポスト)リクエスト

これは、画面のキャプチャがとりずらく、イメージが取れませんでしたが、よくある「ログイン画面」を思い出してもらうとよいです。
これらの画面には、必ず「ログイン」などのような文言のある「ボタン」があると思います。

この「ボタン」はPOSTリクエストを送信するボタンになっていて、HTMLのみで書くとしたのようなHTMLコードになります。

HTMLソース
<form action="cgi-bin/abc.cgi" method="post">
<p>
名前:<input type="text" name="namae">
</p>
<p>
<input type="submit" value="送信する">
<input type="reset" value="入力内容をリセットする">
</p>
</form>

実際のブラウザ表示 ※このボタンを押下すると画面がリロードされるだけです。


HTMLソース

名前:



ちょっと補足を加えます。上記のHTMLは「formタグ」で囲っている内容をPOSTリクエストで送信しますという意味ですが、「formタグ」の属性(attribute)部分の「action」を見てみると「空」になっています。

このアクションが「空」になっているときは「このページにリクエストを送信しますよ」という意味になります。

同様に「post」の部分を見てみると「post」と書いてあります。これは「POSTリクエストを送信しますよ」という意味です。

そして、「inputタグ」にある「name」の部分はこの名前で、それぞれの値を送信するという意味になります。
つまりは、submitのボタンを押下したら、送信先へPOSTリクエストが送られるのですが、POSTリクエストはデータが一緒に送信されます、GETリクエストでも、データの送信ができますが、この場合はURLの後ろに「?変数名1=値,変数名2=値 ... 」のようにURLへ値を書く必要があります。

これでは、ログイン情報などの秘密にしたい情報が公開された状態でリクエストを送信することになるのでとても危険なのです。そのために「POSTリクエスト」を使用します。

JavaでのWebサーバー

このサイトを参考にしました。

結論から言うと、ServerSocketで受付(ポートを指定してリスン状態で待機)してHTTPメッセージを返却する。と言うものがWebサーバーの正体のようです。

シンプルなSocketサーバーは以前作成しました。

これを一度作ったことがあるならば(ServerSocketアプリのことです)わりかし簡単に作成することができると思います。

しかし、現時点では、HttpServletクラスを拡張した実装を行う方向で話を進めているのであくまでも下のようなコードをベースに考えてもらいたく思います。

public class JspLlesson1 extends HttpServlet {

    public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
        res.setContentType("txtext/html; charset=UTF-8");
        PrintWriter write = res.getWriter();
        write.println("Hello World");
    }
}

このコードは、Tomcatを使用したときのコードです。Eclipseで実行したのですが、作成した上のクラスファイルを右クリックして「で起動」をクリックすると実行する事ができます。

これで、「サーバー上で利用できるリソースがありませんでした。」のようなメッセージが表示されたら下の手順で、実行することができるようになります。

Tomcatの準備

Tomcatランタイムの追加

Eclipseの上部にあるメニューからウィンドウ -> 設定を選択、下のイメージのように 検索部分に「サーバー」と入力 -> 赤枠を選択します。

そして、Java8を使用しているので、Tomcatの8.5を選択します。

ここで、Tomcatがインストール(ダウンロード)されていない場合は、Apacheのサイトからダウンロードしてきます。

ダウンロードした、Tomcatを展開して、Eclipseの設定でそのフォルダーを指定します。

最後に完了を押下します。

サーバープロジェクトの追加

1.パッケージエクスプローラーを右クリック、そのほかのプロジェクトをクリック
2.下のイメージのように、その他から次へをクリック

3.同様に、完了をクリックする※設定を確認する

4.プロジェクトファセットの設定を行います。

5.プロジェクトを選択して「Altボタンを押しながらEnterを押下」すると下のような画面が見れます。

6.プロジェクトファセットを選択、下のイメージのようにJava1.8を設定、動的ウェブモジュールを設定します。

7.設定を適用します。

8.web.xmlを生成します。

web.xmlの設定を行う

書き方は以下のようになります。

<servlet>
  <servlet-name>サーブレット名</servlet-name>
  <servlet-class>クラスファイル名</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>サーブレット名</servlet-name>
  <url-pattern>呼び出す時につけるURLパス名</url-pattern>
</servlet-mapping>

classesフォルダを作成する

最終的に下のように、フォルダ構成を作ります。

JavaServletを実行する

この状態で、下のように、プログラムを実行します。

以下のURLにアクセス

localhost:8080/プロジェクト名/

今回作成したプロジェクト名が「StudyJavaBasic」なので下のようなURLにアクセスすると作成したサーブレットが起動できます。

http://localhost:8080/StudyJava/

Httpメッセージ

よく、「Httpヘッダー」とか「Httpボディ」とか言ったりしますがHttpメッセージの「ヘッダ」「ボディ」と言うのが正確な言い方です。

参考の処理内容

  1. ServerSocketをXXXポートで待機
  2. リクエストを受け付けたら、受け取ったメッセージ(Httpメッセージ)から相手のIPを取得
  3. IPを使用してHttpレスポンスを作成
  4. OuputStreamでリクエスト元に返却する(レスポンスを返却する)

と言うような流れで処理を作成しているようです。

レシピ

詳細に関しては、Java APIを参照してください。

  1. ServerSocket
  2. BufferedReader(Reader)
  3. DataOutputSream(OutputSream)

こんなくらいです。

webサーバー

  1. リクエストを受けて(SocketServer#accept())
  2. リクエストの値からファイルを読み込む
  3. HTTPメッセージボディにHTMLを書く
  4. データ(DataOutputSream)を返却

シンプルにこんな手順で処理を行えば良いと思います。

低レベルなAPIは、全て作成する必要がありますが、逆に言えば全てが想い通りに作れると言うところが魅力的(笑)

こんな感じで考えております。このアプリにどんな機能を追加するかは作成者の思うままですね。。。

何やろうかな?

でわでわ。。。



Java Socket 〜極小サーバーで通信の基本を学ぶ〜

java.net.ServerSocket

このクラスを使用してサーバーを作成します。
サーバー側のコードは以下の通りになります。
ちなみに通信がまともに繋がるまで、テストした時の残骸が残っております。


ハマったところ

ここで自分が詰まったのはクライアントからのデータを受信するときに「BufferedReader#readLine()]」を使用していたところです。

原因は。。。

データを送信するときに改行がないと受信時にデータの終わりが確認できないので「readLine()」のところで処理が止まってしまうところです。
とりあえずはこちらを参照して実装しました。
実装してみたところ、サーバーとクライアントの送受信で互いに「読み取り」処理の時の区切りが悪かった。。。なので下のように、送信データの終わりが明確にわかるように実装しました。

int c = -;
while((c = reader.read()) != -1) {
   char ch = (char) c;
   stBuilder.append(ch);
}

こんな感じで実装していたのですが、読み取るデータがいつになっても「-1」にならない事件が起きてしまい。。。
結局は下のようにコードを直しました。

int c = -;
while((c = reader.read()) != -1) {
   char ch = (char) c;
   stBuilder.append(ch);
   if(c == 10 || c == 13) {
       break;
   }
}

c == 10, 13の部分はchar型のint値です。10はLF(改行文字)で13はCR('改行文字)のようです。参考サイト
ソースコードはGitにアップしています。SocketServerBasic.java, ClientSocketBasic.javaをアップしてあります。

ネットワーク確認コマンド

コマンドプロンプトで下のようなコマンドを叩くと、使用しているポートがわかります。以下コマンドの書き方

netstat -nao | find "[ポート番号]"
netstat -a(使用している全ポートを一覧)

勘違いによるエラー

1.接続ポートを間違える

あたりまえだけど、サーバーがlocalhost: 2000で動いているならば、クライアントはlocalhost: 2000に接続する必要があります。「java.net.ConnectException」が出力されます。

2.テストしたときのコネクションが残っている

実装時に処理の起動確認を行いながらやりますが、処理の実行時にコネクションが消えていない、となると「Address already in use」とかエラーが出ます。

3.クライアントからの送信するデータの終わり

クライアントからサーバーへデータを送信するデータの終わりを示す文字として「改行コード」を入れてやる必要がある。でないといつまでもサーバーが受信待機する。

とりあえず完了

いやー、read()処理の部分でハマりました(笑)
昔はreadLine()とかで問題なく動いたのですが、ちょっと変わっているようです。今回の実装はJDK1.8での実装になります。
でわでわ。。。

やったこと一覧

  1. Eclipse+Gluonでスマホアプリを作る
  2. Micro:bitで遊ぶ
  3. Eclipseのセットアップ: 再生リスト
  4. LWJGLGitBook Chapter1-7
  5. IntelliJ IDEA〜セットアップなど〜
  6. Java Coord〜Java + Discord〜
  7. Java Basic〜Javaの基本〜: 再生リスト
  8. JavaDocJavaDocの解釈〜
  9. ラズパイ(RPi)関連〜RPiで遊んでみる〜
  10. JavaミニGame〜Java Console Game〜
  11. Eclipseアプリ作成〜家計簿アプリ作成〜
  12. OpenCv〜環境構築〜
  13. OoenCV + JavaFX
  14. JavaFXでハローワールド〜OpenCVチュートリアル迄〜
  15. Git操作〜Git関連〜
  16. JUnitJavaで遊ぶならこれ!〜
  17. TensorFlow〜Kerasで機械学習〜


ワンポイントレッスン的な

  1. JavaFX SceneBuilder〜ボタンにメソッドを割り当てるワンポイント〜
  2. JavaFX LineChart 〜グラフを描く、ワンポイントレッスン的な〜
  3. ND4J ベクトル生成〜ワンポイントレッスン的な〜

Micro:bitで遊ぶ

  1. Micro:bit(Chibi:bit) での開発環境セットアップ
  2. Micro:bit スマホでプログラミング〜ブラウザにアクセス〜
  3. Micro:bit スマホでプログラミング〜Bluetoothの設定〜
  4. PHP JS 〜WebSocketもどきの作成〜
  5. PHP ServerSocket 〜レンタルサーバーでSocket受信〜
  6. Python websocket client〜WebSocket送信処理を作る〜
  7. Micro:bit Python 〜マイクロビット→PCへシリアル通信〜
  8. ターミナル(コマンド)を使う 〜FTPSを使ってファイルアップロード〜
  9. Microbit リファレンス 〜サイトを眺めてみる〜
  10. Microbitで遊んでみる
  11. Microbitで遊ぶ〜ボタンを押す〜
  12. Microbitで遊ぶ〜シリアル通信をする〜
  13. Java Microbit Serial data connect 〜シリアル通信〜※中途半端です
  14. Microbit Python 〜シリアル通信データを受け取る〜
  15. Microbit Python HTTP リクエストを飛ばす
  16. Microbit花火〜MicrobitからWebServerまでの旅〜

Eclipse セットアップ

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Eclipse+Gluon(MobileApp)

  1. Eclipse Android〜Gluonでアプリを作る〜
  2. Eclipse Android〜Gluonでアプリを作る2〜
  3. Eclipse Android〜Gluonでアプリを作る3: 3Dモデル〜
  4. Eclipse Android〜Gluonでアプリを作る4: 普通に作る〜
  5. Eclipse Android〜Gluonでアプリを作る5: ゲーム部分を作る〜

LWJGL

  1.  Chapter1[外枠の表示のみ]
  2. Chapter2-1〜クラスの構成〜
  3. Chapter2-2〜インターフェースの使い方と詳細〜
  4. Chapter2-3〜GameEngineクラス(サンプルクラス)〜/li>
  5. Chapter2-4〜Windowクラス(サンプルクラス)〜
  6. Chapter3〜描画処理を読む〜
  7. Chapter4〜シェーダについて〜
  8. Chapter5-1〜レンダリングについて〜
  9. Chapter5-2〜レンダリング詳細〜
  10. Chapter6Projection(投影)
  11. Chapter7-1〜Cubeを作る〜
  12. Chapter7-2〜Texture〜
  13. Java 3DGame LWJGL Retry Lv1 〜動かして理解する〜
  14. Java 3DGame LWJGL Retry Lv2 〜動かして理解する2
  15. Java 3DGame LWJGL Retry Lv3 Texture〜動かして理解する3「負け越し」
  16. Java 3DGame LWJGL Retry Lv4 デバック〜動かして理解する4「黒星」
  17. Java 3DGame LWJGL Retry Lv5 遊んでみる〜動かして理解する5「引分け」
  18. Java 3DGame LWJGL Retry Lv6 遊んでみる2〜動かして理解する6「白星」
  19. ava 3DGame LWJGL Retry Lv7 遊んでみる3〜全部テクスチャにする〜

IntelliJ IDEA

  1. IntelliJ IDEA 環境構築 〜インストールと起動〜
  2. IntelliJ IDEA GitGitリポジトリからクローン〜
  3. IntelliJ IDEA 使い方〜Git接続 Java起動 etc
  4. IntelliJ IDEA Jarファイルを作る
  5. IntelliJ IDEA 使い方〜Maven Projectの作成〜
  6. IntelliJ IDEA 使い方〜Mavenでライブラリを追加する〜
  7. IntelliJ IDEA 使い方〜Javaのコンパイルレベル設定〜
  8. IntelliJ IDEA Gradleセットアップ〜コマンド入力部の表示〜
  9. IntelliJ IDEA Discord Botを作る〜Gradle環境のセットアップ〜

Java Discord

  1. IntelliJ IDEA Discord Botを作る〜Gradle環境のセットアップ〜
  2. Java Discord セットアップ〜Hello Discord
  3.  Java Discord ピンポン〜Discordプログラム〜
  4. Java Discord Listener実装〜コマンドを好きなだけ追加しよう〜

Java Basic

  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 〜テストスイートの作り方〜

JavaDoc

  1. Java Doc 読解 System
  2. Java Doc 読解〜System.out
  3. Java Doc読解 System.In
  4. JavaDoc 読解 Filesクラス
  5. Java Doc読解 BufferedReader
  6. Java Doc 読解〜BufferedWriter
  7. Java Doc 読解 List JavaDocList その1〜
  8. Java Doc 読解 Map
  9. Java Doc Classloader

ラズパイ(RPi)関連

  1. ラズパイ SSH接続メモ
  2.  ラズパイ Under-voltage detected! 〜エラー対処〜
  3.  ラズパイ(CUI)セットアップ
  4.  RPi Settingup Wifi in CUI ~ラズパイ CUI Wifi接続~
  5. Memos about Settingup RPi ~使用したコマンドメモ~
  6. RPi and JavaFX sample of deployment 〜ラズパイにサンプルデプロイ〜
  7.  RPi JavaFX execution ~ラズパイ JavaFX自動起動~
  8. RPi Install Git 〜ラズパイにGitのインストール〜
  9. RPi Java Swing〜ラズパイにJava Swingアプリを起動する〜※失敗しています。。。」
  10. RPi Maven Install 〜ラズパイでMeven
  11. Install XFCE4 on RPi 〜ラズパイに高速軽量デスクトップインストール〜

<Java Step1〜ミニゲーム作成>

  1. Java Hello World はじめのプログラム Step1-1
  2. Java 四則演算 演算子 Step1-2
  3. Java データ型 変数の扱い方〜Step1-2-1
  4. Java Basic Booleanなどの意味 Step1_2_2
  5. Java Basic for Step1_3_1
  6. Java Basic While Step1_3_2
  7. Java Basic try catch Step1_3_3
  8. Java Basic クラスとは〜Step2_1
  9. Java Basic API Listの使い方 Step2_2
  10. Java Basic インターフェース Step2_3
  11. Java Basic ミニゲーム作成 Step3_1
  12. Java Basic ミニゲーム作成 Step3_2

 家計簿アプリ作成

  1. Eclipse アプリ作成 Lv1〜家計簿を作る準備〜
  2. Eclipse アプリ作成 Lv2〜家計簿を作る土台作り〜
  3. Eclipse アプリ作成 Lv33Dグラフ用Cube作り〜
  4. Eclipse アプリ作成 Lv43Dグラフ用Cubeに高さを与える〜
  5. Eclipse アプリ作成 Lv5〜惨敗:CubeTextureを貼る〜
  6. Eclipse アプリ作成 Lv7Cubeを日付順に並べる〜

Git

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜

OpenCv

  1. Java OpenCV 環境セットアップ(on Mac)
  2. Java OpenCv Lv1 〜入門: 写真の表示〜
  3. Java OpenCV Lv2 〜画像を表示する〜
  4. Java OpenCV Lv3 〜画像の平滑化(smooth())
  5. Java OpenCV Lv3 〜画像にガウシアンフィルタ(GaussianBlur())
  6. Java OpenCV Lv3 〜画像に中央値フィルタ(medianBlur())
  7. Java OpenCV Lv4 〜画像の中身をみてみる〜
  8. Java OpenCV Lv5 Matクラスで描画処理〜
  9. Java OpenCV Lv6 Matクラスで背景から作成してみる〜
  10. Java OpenCV Lv7 MatクラスでEllipseしてみる〜
  11. Java OpenCV Lv9 〜画像編集「足し算」(cvAdd)
  12. Java OpenCV Lv9 〜画像編集「引き算」(cvSubtract)
  13. Java OpenCV Lv9 〜画像の掛け算〜
  14. Java OpenCV Lv10 〜行列演算Mat#submat()
  15. Java OpenCv Lv10〜画像の平均値をだす〜

OpenCv + JavaFX

  1. EclipseにSceneBuilderを追加する
  2. JavaFX SceneBuilder 〜EclipseとSceneBuilder連携~
  3. Java OpenCv Lv1 〜入門: 写真の表示〜
  4. Java OpenCV Lv2 〜JavaFXでの画像表示〜
  5. Java OpenCv ビデオキャプチャ〜カメラからの入力を表示〜
  6. OpenCV tutorial〜ヒストグラム〜
  7. OpenCV tutorial 解析 〜ヒストグラム〜
  8. OpenCV tutorial 解析2 〜ヒストグラム計算〜
  9. OpenCV tutorial 〜フーリエ変換など〜

JavaFXでハローワールド〜OpenCVまで

  1. Java 初めてでも大丈夫〜ステップアッププログラミングのススメ〜
  2. ステップアッププログラミング〜Java FxでHelloWorld解説〜
  3. Java StepUpPrograming〜JavaFX で四則計算〜
  4. Java StepUpPrograming〜JavaFXで画面切り替えを作る1〜
  5. Java StepUpPrograming〜JavaFXで画面切り替え2ボタン作成〜
  6. Java StepUpPrograming〜JavaFXで画面切り替え3アクション〜
  7. Java StepUpPrograming〜JavaFXで画面切り替え4Pane切り替え〜
  8. Java StepUpPrograming〜JavaFXで画面切り替え5WebEngine〜

JavaFX + ND4Jで機械学習準備

  1. JavaFX + ND4J〜数学への挑戦1:ND4Jのインストール〜
  2. JavaFX + ND4J〜数学への挑戦2: 行列の計算〜
  3. Java + ND4J 〜数学への挑戦3: ベクトル(配列)の作成方法〜
  4. ND4J ベクトル生成〜ワンポイントレッスン的な〜
  5. JavaFX + ND4J 〜数学への挑戦:5グラフを描く〜
  6. JavaFX + ND4J 〜グラフ作成の準備〜
  7. JavaFX + ND4J 〜グラフ作成:とりあえず表示〜
  8. JavaFX グラフ描画〜AreaChartを使う〜
  9. JavaFX + ND4J〜数学への挑戦6:グラフの土台を作る〜

JUnit関連

  1. Java Basic JUnit 〜テストスイートの作り方〜

TensorFLowを学ぶ

  1. Tensorflow Keras 〜初めてのKeras
  2. Tensorflow Keras Errors”python is not installed as a framework.”
  3. Python Tensorflow 〜初めての人工知能(TensorFlowインストール)
  4. Tensorflow Keras〜初めのトレーニング_1
  5. Tensorflow Keras〜初めのトレーニング_2:前処理〜
  6. TensorFlow Keras〜テキストの分類〜
    1. TensorFlow Keras 実行結果〜テキストの分類〜
  7. Python TensorFlow tutorial〜チュートリアルを進めるコツ、ワンポイント〜
  8. TensorFlow Keras〜回帰、準備から予測まで〜
  9. TensorFlow Java 環境構築〜JavaでもTensorFlow〜