LoginSignup
6
6

More than 5 years have passed since last update.

attachments付きのメッセージをJavaで投稿する

Posted at

はじめに

今回Javaで作っているプログラムでSlackに投稿したいことがありました。
GASでなら以前やったのでそこからコピペ等すれば簡単ですが、Javaでの投稿は未経験でした。
Javaでのやり方はネットを探すも見つけられなかったので記事にします。
(海外のサイトやGitHubなどを漁ればあるだろうとは思いますが。)
試行錯誤している最中のコードも載せていますが、"失敗談はどうでもいいから結果が知りたい"という人は最後の方まで飛ばしてください。

ちなみに、どうにか送れるようになるまで私は1日ほどかかりました。

失敗その1 - チャンネルがない

次のようなメソッドを実行してみました。
(JSONのインデントや改行は必須ではないと思います。)

試作コード1
private static void testSlack(){
    String json = "{\n" +
            "    \"channel\":\"bot−test\"," +
            "    \"username\":\"テスト\",\n" +
            "    \"text\": \"テスト\",\n" +
            "    \"attachments\": [\n" +
            "        {\n" +
            "            \"color\": \"#89ceeb\",\n" +
            "            \"text\": \"テスト\"\n" +
            "        }\n" +
            "    ]\n" +
            "}";
    try {
        URL url = new URL("https://slack.com/api/chat.postMessage?token=トークン");
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");
        connection.setDoOutput(true);
        connection.setRequestProperty("Content-type", "application/json");
        OutputStream stream = connection.getOutputStream();
        PrintStream ps = new PrintStream(stream);
        ps.print(json);
        ps.close();
        BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        String str = "";
        String body;
        while ((body = reader.readLine()) != null) {
            str += body + "\n";
        }
        System.out.println(str);
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (ProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

結果は次の通り。
(見やすいよう整形しています。)

結果1
{
  "ok": false,
  "error": "channel_not_found",
  "warning": "missing_charset"
}

なぜかチャンネルがないと言われてしまいました。
実際に存在するチャンネル名なのでそのはずがありません。
もしかしたら多分名前はNGでチャンネルIDの方を渡さないといけないのかもしれません。
GASの時はそんなことなかったのですが・・・。

charsetがないというのは警告なのでとりあえずスルーします。

失敗その2 - テキストがない

Slack APIは項目をパラメータとして渡せれば良いので、チャンネルはURLのパラメータにしてみました。

試作コード2
private void testSlack(){
    String json = "{\n" +
            "    \"username\":\"テスト\",\n" +
            "    \"text\": \"テスト\",\n" +
            "    \"attachments\": [\n" +
            "        {\n" +
            "            \"color\": \"#89ceeb\",\n" +
            "            \"text\": \"テスト\"\n" +
            "        }\n" +
            "    ]\n" +
            "}";
    try {
        URL url = new URL("https://slack.com/api/chat.postMessage?token=トークン&channel=%23bot-test");
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");
        connection.setDoOutput(true);
        connection.setRequestProperty("Content-type", "application/json");
        OutputStream stream = connection.getOutputStream();
        PrintStream ps = new PrintStream(stream);
        ps.print(json);
        ps.close();
        BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        String str = "";
        String body;
        while ((body = reader.readLine()) != null) {
            str += body + "\n";
        }
        System.out.println(str);
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (ProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

今度はテキストがないと言われました。

結果2
{
  "ok":false,
  "error":"no_text",
  "warning":"missing_charset"
}

そこでテキストもパラメータにと思いましたが、日本語はエンコードしないといけないので保留。
そもそもJSONのPOSTがうまくいっていないような気がします。

そもそもJavaでJSONを送信するには?

JavaでJSONを送信する方法について調べてみました。

どちらも試してみたのですが、どちらもテキストがないと・・・。
(Gsonは試してません。)

cURL経由で送信する

JavaからcURLのコマンドを実行してみることにしました。

コマンド
curl -XPOST --data-urlencode 'payload={"attachments":[{"color":"#89ceeb","text":"テスト"}],"text":"テスト","username":"テスト"}' https://slack.com/api/chat.postMessage?token=トークン&channel=%23bot-test

Javaのコードはこんな感じです。

試作コード5
private void testSlack() {
    String json = "{\n" +
            "\"username\":\"テスト\"," +
            "\"text\": \"テスト\"," +
            "\"attachments\": [" +
            "{" +
            "\"color\": \"#89ceeb\"," +
            "\"text\": \"テスト\"" +
            "}" +
            "]" +
            "}";
    String command = "curl -XPOST --data-urlencode 'payload=" + json + "' https://slack.com/api/chat.postMessage?token=トークン&channel=%23bot-test";
    try {
        Process p = Runtime.getRuntime().exec(command);
        p.waitFor();
        InputStream input = p.getInputStream();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(input))) {
            String lines = "";
            for (String line = reader.readLine(); line != null; line = reader.readLine()) {
                lines += line + "\n";
            }
            System.out.println(lines);
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

その結果は次の通り。

結果5
{
  "ok": false,
  "error": "invalid_arg_name"
}

今度は引数の名前がおかしいみたいです。
ヘッダーをきちんと指定しても同様でした。
このコマンドをターミナルで実行するとまたチャンネルがないと言われてしまうという・・・。

どうにかcURL経由で送れるようになった

Slack APIはJSONで指定することは必須ではなく、URLのパラメータで指定することも可能です。
attachmentsをパラメータにできたらなぁと思い、中身をURLエンコードした次のようなコードを実行してみました。
ちなみにエンコード後の文字列はこちらのサイトを利用して用意しました。

試作コード7
private void testSlask(){
    String command = "curl -XPOST  https://slack.com/api/chat.postMessage?token=トークン&channel=%23bot-test&text=test&attachments=%5B%7B%22color%22%3A%22%2389ceeb%22%2C%22text%22%3A%22%E3%83%86%E3%82%B9%E3%83%88%22%7D%5D";
    try {
        Process p = Runtime.getRuntime().exec(command);
        p.waitFor();
        InputStream input = p.getInputStream();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(input))) {
            String lines = "";
            for (String line = reader.readLine(); line != null; line = reader.readLine()) {
                lines += line + "\n";
            }
            System.out.println(lines);
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

結果は次の通りです。

結果7
{
  "channel": "チャンネルID",
  "ok": true,
  "message": {
    "attachments": [{
      "color": "89ceeb",
      "text": "テスト",
      "id": 1,
      "fallback": "NO FALLBACK DEFINED"
    }],
    "subtype": "bot_message",
    "text": "test",
    "type": "message",
    "bot_id": "BOT ID",
    "username": "Slack API Tester",
    "ts": "1463901412.000002"
  },
  "ts": "1463901412.000002"
}

ついに送れるようになりました。 :tada:

cURLを使わずにJavaで投稿する

今度はエンコードをJavaで行い投稿も最初のHttpURLConnectionでの方法にしました。

試作コード8
private void testSlack() {
    String attachments = "[" +
            "{" +
            "\"color\": \"#89ceeb\"," +
            "\"text\": \"テスト\"" +
            "}" +
            "]";
    try {
        attachments= URLEncoder.encode(attachments,"UTF-8");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    try {
        URL url = new URL("https://slack.com/api/chat.postMessage?token=トークン&channel=%23bot-test&text=test&attachments=" + attachments);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");
        connection.setDoOutput(true);
        BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        String str = "";
        String body;
        while ((body = reader.readLine()) != null) {
            str += body + "\n";
        }
        System.out.println(str);
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (ProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

あとがき

ずっとSlackへの投稿はJSONをPOSTすることしか考えていなかったので、トータル半日以上その線を探り続けていました。
諦めかけて他のことしてた時間を入れると1日くらいになると思います。
最後は、JSONを外部ファイル化するとか、GASのプロジェクトにPOSTしてそっちで投稿するとか、とにかく諦めて未完で結論書いて記事投稿しようとか考えたりもしました。
チャンネル・ユーザー名・テキストはパラメータ指定で行けることを知っているのでattachmentsを諦めようと思ったのですが、諦める必要はありませんでした。

URLアクセスで完結するAPIはいいですね。

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6