Help us understand the problem. What is going on with this article?

Slack BotをJavaでお手軽に作る

More than 1 year has passed since last update.

SlackBotをJavaでお手軽に作る方法をご紹介します

紹介したソースコード一式は https://github.com/riversun/slacklet-examples.git にあります

BOT用API Tokenの取得

まず、こちらに行き、BOT用のAPI Tokenを取得します
https://my.slack.com/services/new/bot

  • BOTのusernameを決めたら、[Add bot integration]をクリックします

slack_reg_01.png

  • これで、API Tokenが生成されました。今後このAPI Tokenを使ってSlackBotを作っていきます。 slack_reg_02.png

Slackのプロトコルと事前準備

プロトコルはWebsocketベースのSlackのRTM(Realtime Messaging API)で、ライブラリにはSimple Slack APIをベースにしたSlackletというラッパーライブラリを使います。

Slacklet
Slackletは以下からmaven/gradleまたは、jarの直接ダウンロードで取得可能です。
maven/gradle
slacklet.jarを直接ダウンロード

BOTをチャンネルに参加させる

まず、さきほど作成したBOTをinviteして任意のチャンネルに参加させます。

ex00_00_join.png

1.エコーを返すSlack bot

誰かが発言したら、そのままエコーを返すシンプルな例です。

Example00.java
public class Example00 {

    public static void main(String[] args) throws IOException {

        String botToken ="取得したAPI Token" ;

        SlackletService slackService = new SlackletService(botToken);

        // slackletを追加する
        slackService.addSlacklet(new Slacklet() {

            @Override
            public void onMessagePosted(SlackletRequest req, SlackletResponse resp) {
                // メッセージがユーザーからポストされた

                // メッセージがポストされたチャンネルを取得する
                SlackChannel channel = req.getChannel();

                if ("random".equals(channel.getName())) {
                    // #randomチャンネルだった場合

                    // メッセージ本文を取得
                    String content = req.getContent();

                    // メッセージがポストされたチャンネルに対して、BOTからメッセージを送る
                    resp.reply("「" + content + "」て言いましたね。");

                }

            }
        });

        // slackletserviceを開始(slackに接続)
        slackService.start();

    }

}

このサンプルのソースコード

実行例

Slack上で「こんにちは」といったら、BOTからエコーが返ってきます。
ex00_01.png

説明

上のように、SlackletServiceをつくり、#addSlackletSlackletを追加します。
SlackletServletみたいなもので、必要なメソッドをオーバーライドしてつかいます。

#onMessagePostedはチャンネルにユーザーがメッセージをポストしたときに呼び出されます。
チャンネルを限定して返信したいときは上の例のようチャンネル名を識別して返信をします。

2.ダイレクトメッセージ(Direct Message)を受け取る

ユーザーがBOTに対してポストしたダイレクトメッセージを受け取りたい場合は以下のようにSlacklet#onDirectMessagePostedをオーバーライドします

@Override
public void onDirectMessagePosted(SlackletRequest req, SlackletResponse resp) {
    // BOT宛のダイレクトメッセージがポストされた

    String content = req.getContent();

    // メッセージを送信したユーザーのメンションを取得する
    String mention = req.getUserDisp();

    // ダイレクトメッセージを送信したユーザーに対して返信する
    resp.reply(mention + "さん、ダイレクトメッセージありがとう。\n「" + content + "」って言いましたね");
}

このサンプルのソースコード

実行例

以下のように、BOTに対してダイレクトメッセージを送ると、返事がきます。

ex01_00.png

3.@メンションされた場合のみ反応する

ユーザーがBOTをメンションしたメッセージ、たとえば@smilebot こんにちは」してポストしたメッセージを受け取りたい場合は以下のようにSlacklet#onMentionedMessagePostedをオーバーライドします

@Override
public void onMentionedMessagePosted(SlackletRequest req, SlackletResponse resp) {
    // あるチャンネルでこのBOTへのメンション付きメッセージがポストされた(例 「@smilebot おはよう」)

    String content = req.getContent();

    String mention = req.getUserDisp();
    resp.reply("こんにちは、" + mention + "さん。「" + content + "」って言いましたね。");
}

このサンプルのソースコード

実行例

@ユーザー名でBOTの名前を指定してメンションしたときだけ、返事がきます。

ex01_01_mentioned.png

4.ユーザーにダイレクトメッセージを送る

BOTからユーザーにダイレクトメッセージ(direct message)を送る例です。
ユーザーからのメッセージへの返信ではなく、BOTから先にメッセージを送りたい場合につかいます。

public class Example02 {

    public static void main(String[] args) throws IOException {

        String botToken ="取得したAPI Token"; 

        SlackletService slackService = new SlackletService(botToken);
        slackService.start();

        // ユーザーに対して、(返信ではなく)ダイレクトメッセージを送る
        String userName = "riversun";
        slackService.sendDirectMessageTo(userName, "こんちは~");

        // slackとの接続を終了
        slackService.stop();

    }

}

このサンプルのソースコード

実行例

実行すると、このようにBOTからのダイレクトメッセージが届きます。

ex02_00_direct_left.png

ex02_01_direct.png

5.指定したチャンネルにメッセージを送る

public class Example03 {

    public static void main(String[] args) throws IOException {

        String botToken = ResourceBundle.getBundle("credentials").getString("slack.bot_api_token");

        SlackletService slackService = new SlackletService(botToken);
        slackService.start();

        // チャンネルに対して、(返信ではなく)メッセージを送る
        String channelName = "random";
        slackService.sendMessageTo(channelName, "randomチャンネルの皆様、こんにちは!");

        slackService.stop();

    }

}

このサンプルのソースコード

実行例

#randomチャンネルに対してBOTがメッセージを送ります。
ex03.png

6.セッション機能(ユーザー固有のコンテクスト)を使う

Slackletはマルチユーザーを意識した設計にしています。あるユーザーがBOTと対話しているときに、他のユーザーも独立して対話が成り立つようにします。

これを実現するためユーザー毎の各種状態を保持するために、session機能があります。servletと同じくSlackletRequest .getSessionでセッションを取得し、その中に状態を保持します。

@Override
public void onDirectMessagePosted(SlackletRequest req, SlackletResponse resp) {

    String content = req.getContent();

    // セッションを取得する(セッションはユーザー毎に固有)
    SlackletSession session = req.getSession();

    // 発言回数カウント用のintegerをセッションから取得する。未だ何も入れていないときは、デフォルト値1とする
    Integer num = (Integer) session.getAttribute("num", 1);

    resp.reply(req.getUserDisp() + "さんは" + num + "回目に「" + content + "」って言いました。");

    // 回更をインクリメントして、セッションを更新する
    num++;
    session.setAttribute("num", num);

}

このサンプルのソースコード

実行例

対話の回数をセッションに記憶するので対話が継続しているようにみえます。
ユーザー毎に固有に記憶されます。
ex04.png

拡張のヒント

セッションの永続化
本格的な対話を実装するときには確実に必要になるのがコンテキストです。
コンテキストは対話状態、各種ステータスなどを入れておきます。

Slackletのデフォルト実装では、セッションはオンメモリに保持されますので、プログラムを終了すると忘れてしまいます。セッションを永続化したい場合は永続化コードを含むSletPersistManagerを実装し、SlackletService#setSessionPersistenceManagerでセットします。

マルチユーザー対応
複数のユーザーとの対話を同時処理できるよう、ユーザー毎に別スレッドで処理していますが、BOTが扱うユーザー数に応じて、executorやスレッドプールの大きさを適宜調節すると良いとおもいます。

ログを表示する
以下のようにするとログをstderrに出力します

org.riversun.xternal.log.Logger.setEnabled(true);

さらに深い拡張
Slackletの下回りはSimple Slack APIを拡張して作られています。より深い拡張をしたい場合はSimple Slack APIを参考にされると良いとおもいます。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away