【Golang】httpサーバを立ててリクエストによって表示を変更する

今回のゴール

httpリクエストに付与されたパラメータを取得して表示に組み込む

ソースコード

package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/user", handler)
	http.ListenAndServe(":8080", nil)
}

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "{user_name=\"%s\", age=%s}", r.FormValue("user_name"), r.FormValue("age"))
}

前回との差分だけ解説します。

要はhandler関数の以下だけです。。。
fmt.Fprintf(w, "{user_name=\"%s\", age=%s}", r.FormValue("user_name"), r.FormValue("age"))

リクエストパラメータの取得は「r.FormValue("キー文字列")」と書きます。

前回と分けた意味はAndroid側の記事で使いたいからってだけです。。。

今回のソースは以下にあります。
https://github.com/k-shimoju/golang/tree/master/retrofit

【Golang】httpサーバを立ててみる

今回のゴール

ブラウザでアクセスしたら固定の文言を表示する
※Go言語は勉強を始めたばかりなので、誤りがあればお知らせください。

ソースコード

package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "{user_name=\"test\", age=10}")
}

http.HandleFunc("/", handler)
の部分で待ち受けるurlと連動する関数を紐付けています。
上記だとhttp://localhost/*を意味します。

http.ListenAndServe(":8080", nil)
これはポートの指定です。

合わせるとhttp://localhost:8080/で始まるuriへのアクセスがあれば、
handlerと言う関数を呼ぶ事を意味します。

最後にhandler関数で文言表示を行っています。
fmt.Fprintf(w, "{user_name=\"test\", age=10}")

今回のソースコードは以下にあります。
https://github.com/k-shimoju/golang/tree/master/test

【Android】Volleyで通信をしよう(StringRequest編)

Google社員が作った通信ライブラリVolleyの紹介です。
機能が多いので、今回はStringRequestに限定します。

使うメリット

Googleによる検証で最速の通信ライブラリらしいです。
フルスクラッチで書くより早い?!

使い方

gradleの設定
build.gradleに以下を記載します。

compile 'eu.the4thfloor.volley:com.android.volley:2015.05.28'


Applicationクラスの子クラスを作成

public class AppController extends Application {

    public RequestQueue mRequestQueue;

    @Override
    public void onCreate() {
        super.onCreate();
        mRequestQueue = Volley.newRequestQueue(getApplicationContext());
    }
}

RequestQueueをシングルトンかつ、早めにインスタンス生成するためにここに書きます。
※個人的にはRequestQueueをprivateにしてgetter作る方が好きですが、手抜きしました。

Getリクエスト用のクラスを作成

public class GetRequest extends StringRequest {

    private Map<String, String> mParams;
    private static final String URL = "http://api.openweathermap.org/data/2.5/weather";

    public GetRequest(Response.Listener<String> listener, Response.ErrorListener errorListener, Map<String, String> mParams) {
        super(Method.GET, URL, listener, errorListener);
        this.mParams = mParams;
    }

    @Override
    public String getUrl() {
        return super.getUrl() + makeGetParameter();
    }

    private String makeGetParameter() {

        String param = "?";
        boolean isFirst = true;

        for (Map.Entry<String, String> entry : mParams.entrySet()) {
            if (isFirst) {
                param += entry.getKey() + "=" + entry.getValue();
            } else {
                param += "&" + entry.getKey() + "=" + entry.getValue();
            }
        }

        return param;
    }
}

※ここではgetUrlをオーバーライドしてますが、パラメータ付きのurlを引数に受ける作りで問題ないです。

Postリクエスト用のクラスを作成

public class PostRequest extends StringRequest {

    private Map<String, String> mParams;
    private static final String URL = "http://ave.bolyartech.com/params.php";

    public PostRequest(Response.Listener<String> listener, Response.ErrorListener errorListener, Map<String, String> params) {

        super(Method.POST, URL, listener, errorListener);
        mParams = params;
    }

    @Override
    protected Map<String, String> getParams() throws AuthFailureError {

        return mParams;
    }
}

※Postリクエストにパラメータ付与するにはgetParamsメソッドをオーバーライドして、Map形式で返してあげるようにします。

Getリクエストを投げます。

    @OnClick(R.id.btn_get)
    protected void btnGet(View view) {

        Map<String, String> params = makeParameter();
        AppController app = (AppController)getApplication();
        GetRequest request = new GetRequest(new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                txtResult.setText(response);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Toast.makeText(MainActivity.this, error.getMessage(), Toast.LENGTH_SHORT).show();
            }
        }, params);

        app.mRequestQueue.add(request);
    }

※ここでStringRequestをnewしてあげれば、上記GetRequestクラスは無くても平気です。
⇒個人的にはクラス作るのが良いと思ってるだけです。
あと、解説するのに見やすい(はず)

Postリクエストを投げます。

    @OnClick(R.id.btn_post)
    protected void btnPost(View view) {

        Map<String, String> params = makeParameter();
        AppController app = (AppController)getApplication();
        PostRequest request = new PostRequest(new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                txtResult.setText(response);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Toast.makeText(MainActivity.this, error.toString(), Toast.LENGTH_SHORT).show();
            }
        }, params);

        app.mRequestQueue.add(request);
    }

※Postリクエストもクラス化しないで、こっちに書いてもいいです。

Android3.0からUI(メイン)スレッドで通信はNGになりましたが、
裏で勝手にやってくれるのでActivityでもFragmentでも気にせず投げてください

通信処理の補足
引数に指定しているResponse.Listenerが通信が正常終了した時に呼ばれるリスナです。
なので、Response.ErrorListenerは通信エラー時に呼ばれます。
エラーリスナは共通化して、リトライダイアログを出したりしてもいいです。
(エラー内容で分岐させる)

今回はここまでですが、実際はjson形式でやりとりが多いと思うので、実はこの記事ってあまり役に立ちませんw

今回のソースコード一式は以下にあります。
https://github.com/k-shimoju/android/tree/master/volley_string

【Android】realmの使い方

高速かつ簡単にデータ保存ができるNoSQLライブラリのrealmを紹介します。

使うメリット

Sqliteよりも手続きが簡単で速度が速いので便利です。

使うデメリット

  • カラム変更は自分でプログラムをゴリゴリ書く必要があるので面倒です。
  • ListViewなどに超大量データを表示する時などはCursorAdapterにするのが好みですが、Sqliteじゃないので使えないです。

使い方

gradleの設定
さっそくbuild.gradleのdependenciesに以下を記載

compile 'io.realm:realm-android:0.80.3'

ソースコード

public class TestModel extends RealmObject {

    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

DBの構造に合わせたモデルを用意します。
※セッターとゲッター以外のメソッドは記載してはいけません

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RealmResults<TestModel> results = null;

        addTestData();
        addTestdataBestVer(2, "test2");
        addTestdataBestVer(3, "test3");
        results = getTestData();

        for (final TestModel model : results) {
            Log.d("REALM_TEST", String.format("ID: %s  NAME: %s", model.getId(), model.getName()));
        }

        updateTestData(results);
        deleteTestData(results);

        for (final TestModel model : getTestData()) {
            Log.d("REALM_TEST2", String.format("ID: %s  NAME: %s", model.getId(), model.getName()));
        }
    }

    private void addTestData() {

        Realm realm = Realm.getInstance(this, "test_realm");
        TestModel model = null;

        realm.beginTransaction();
        model = realm.createObject(TestModel.class);
        model.setId(1);
        model.setName("test");

        realm.commitTransaction();
    }

    private void addTestdataBestVer(int id, String name) {

        TestModel model = new TestModel();
        model.setId(id);
        model.setName(name);

        addTestDataBestVer(model);
    }

    private void addTestDataBestVer(TestModel model) {

        Realm realm = Realm.getInstance(this, "test_realm");

        realm.beginTransaction();
        realm.copyToRealm(model);
        realm.commitTransaction();
    }

    private RealmResults<TestModel> getTestData() {

        Realm realm = Realm.getInstance(this, "test_realm");
        RealmQuery<TestModel> query = realm.where(TestModel.class);

//        query.equalTo("name", "test");
//        query.or().equalTo("id", 2);
//        query.or().equalTo("id", 3);

        return query.findAll();
    }

    private void deleteTestData(RealmResults<TestModel> result) {

        Realm realm = Realm.getInstance(this, "test_realm");
        TestModel model = result.get(0);

        realm.beginTransaction();
        result.remove(1);

        model.removeFromRealm();

//        result.clear();
        realm.commitTransaction();
    }

    private void updateTestData(RealmResults<TestModel> result) {

        Realm realm = Realm.getInstance(this, "test_realm");
        TestModel model = result.get(2);

        realm.beginTransaction();
        model.setName("UPDATE");
        realm.commitTransaction();
    }
}

Realm realm = Realm.getInstance(this, "test_realm");
のようにしてインスタンスを生成します。

INSERTはaddTestData、addTestDataBestVerメソッド
SELECTはgetTestDataメソッド
UPDATEはupdateTestDataメソッド
DELETEはdeleteTestDataメソッドを見てもらえれば分かるかと思います。

補足として、SELECTのコメントされている以下をコメント解除するとWHERE区付きとして動作します。

//        query.equalTo("name", "test");
//        query.or().equalTo("id", 2);
//        query.or().equalTo("id", 3);

また、DELETEのresult.clear();を実行するとデータを全件削除します。
※初めて触った時に知らないで実行してビックリした経験有り

この記事に書いたソースコード一式は以下にあります。
https://github.com/k-shimoju/android/tree/master/realm

【Android】GsonでJsonを高速にいじろう

GsonとはGoogleが作ったJsonとオブジェクトの変換を高速にやってくれる優秀なライブラリです。

使うメリット

2014年にAndroidで使えるJsonパーサの速度比較をした時には最速でした。
プログラムも書きやすく、パフォーマンスもいいのでオススメです。
Jsonの内容によってどのパーサが早いか変わるので速度重視なら実際のJsonで速度比較するべきです。

使い方

gradleの設定
build.gradleのdependenciesに以下を記載します。

compile 'com.google.code.gson:gson:2.3.1'
<||

<b>ソースコード</b>
Jsonと紐づくモデルを作ります。
>|java|
public class JsonModel {

    @SerializedName("user_name")
    private String userName;
    private int age;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
<||
javaの変数名はキャメルケースですが、jsonのキー名はスネークケースで書く事が多いと思います。
その場合は@SerializedNameアノテーションでjsonのキー名を指定してあげれば紐づけてくれます。

実際にjsonとモデルを変換しているのが以下のクラスです。
>|java|
public class MainActivity extends Activity {

    @Bind(R.id.edit_json)
    EditText txtJson;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
    }

    private JsonModel makeJsonModel() {

        JsonModel model = new JsonModel();

        model.setUserName("TAROH YAMADA");
        model.setAge(93);

        return model;
    }

    @OnClick(R.id.btn_to_json)
    protected void clickToJson(View view) {

        Gson gson = new Gson();
        String json = gson.toJson(makeJsonModel());

        txtJson.setText(json);
    }

    @OnClick(R.id.btn_format_json)
    protected void clickFormatJson(View view) {

        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        String json = gson.toJson(makeJsonModel());

        txtJson.setText(json);
    }

    @OnClick(R.id.btn_from_json)
    protected void clickFromJson(View view) {

        String json = txtJson.getText().toString();
        Gson gson = new Gson();
        JsonModel model = null;

        if (json == null || "".equals(json.trim())) {
            Toast.makeText(this, "JSONを入力してください", Toast.LENGTH_SHORT).show();
            return;
        }

        model = gson.fromJson(json, JsonModel.class);
        Toast.makeText(this, "user_name: " + model.getUserName() + " age: " + model.getAge(), Toast.LENGTH_SHORT).show();
    }

    @OnClick(R.id.complexity_to_json)
    protected void clickComplexityToJson(View view) {

        ComplexityModel model = new ComplexityModel();
        JsonModel jsonModel = makeJsonModel();
        List<JsonModel> modelList = makeModelList();
        String json = null;
        Gson gson = new Gson();

        model.setModel(jsonModel);
        model.setModelList(modelList);
        json = gson.toJson(model);

        txtJson.setText(json);
    }

    @OnClick(R.id.complexity_from_json)
    protected void clickComplexityFromJson(View view) {

        Gson gson = new Gson();
        String json = txtJson.getText().toString();
        ComplexityModel model = null;

        if (json == null || "".equals(json.trim())) {
            Toast.makeText(this, "JSONを入力してください", Toast.LENGTH_SHORT).show();
            return;
        }

        model = gson.fromJson(json, ComplexityModel.class);
    }

    private List<JsonModel> makeModelList() {

        List<JsonModel> modelList = new ArrayList<>();

        for (int i=0; i<10; i++) {
            modelList.add(makeJsonModel());
        }

        return modelList;
    }
}
<||

モデルをjson(String文字列)にするには以下です。
>|java|
Gson gson = new Gson();
String json = gson.toJson(makeJsonModel());
<||
※makeJsonModel()メソッドはモデルに値をセットしてるだけです。

逆にjsonをモデルにするのは以下です。
>|java|
Gson gson = new Gson();
JsonModel model = gson.fromJson(json, JsonModel.class);
<||

テストの時や設計書にjsonのサンプルを書く時などに便利な
見やすくフォーマットしてくれたjson文字列にしてくれる方法もあります。
>|java|
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(makeJsonModel());
<||
Gsonのインスタンス生成の方法が変わるだけです。
※でも逆に忘れやすい

階層が深いJsonやArrayを使う場合は以下です。
>|java|
public class ComplexityModel {

    private JsonModel model;
    private List<JsonModel> modelList;

    public JsonModel getModel() {
        return model;
    }

    public void setModel(JsonModel model) {
        this.model = model;
    }

    public List<JsonModel> getModelList() {
        return modelList;
    }

    public void setModelList(List<JsonModel> modelList) {
        this.modelList = modelList;
    }
}
<||

今回のソースコード一式は以下にあります。

【Android】ButterKnifeの使い方

オープンソースのライブラリで超便利なButterKnifeの使い方を紹介します。

使うメリット

面倒なfindViewByIdやsetOnClickListenerを書かなくてよくなります。

使い方

gradleの設定
さっそくbuild.gradleのdependenciesに以下を記載

compile 'com.jakewharton:butterknife:7.0.1'

ソースコード

public class MainActivity extends Activity {

    @Bind(R.id.textView)

    TextView textView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        ButterKnife.bind(this);

        Toast.makeText(this, textView.getText(), Toast.LENGTH_SHORT).show();
    }


    @OnClick(R.id.button)

    protected void onButtonClick(View view) {


        Toast.makeText(this, "PUSH", Toast.LENGTH_SHORT).show();

    }

}


onCreateでButterKnife.bind(this);を実行します。

※Fragmentの場合はonCreateViewで実行します。


あとはclickイベントで実行したい処理を書いたメソッド

@OnClick(R.id.button)こんなアノテーションを指定すればOKです。

複数指定も可能です。


TextViewなどは見ての通り、変数にアクセスすれば自由にいじれます。


この記事に書いたソースコード一式は以下にあります。

https://github.com/k-shimoju/android/tree/master/ButterKnie