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のプロトコルと事前準備
プロトコルはWebsocketベースのSlackのRTM(Realtime Messaging API)で、ライブラリにはSimple Slack APIをベースにしたSlackletというラッパーライブラリを使います。
Slacklet
Slackletは以下からmaven/gradleまたは、jarの直接ダウンロードで取得可能です。
maven/gradle
slacklet.jarを直接ダウンロード
BOTをチャンネルに参加させる
まず、さきほど作成したBOTをinviteして任意のチャンネルに参加させます。
1.エコーを返すSlack bot
誰かが発言したら、そのままエコーを返すシンプルな例です。
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からエコーが返ってきます。
説明
上のように、SlackletServiceをつくり、#addSlackletでSlackletを追加します。
SlackletはServletみたいなもので、必要なメソッドをオーバーライドしてつかいます。
#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に対してダイレクトメッセージを送ると、返事がきます。
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の名前を指定してメンションしたときだけ、返事がきます。
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からのダイレクトメッセージが届きます。
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がメッセージを送ります。
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);
}
実行例
対話の回数をセッションに記憶するので対話が継続しているようにみえます。
ユーザー毎に固有に記憶されます。
拡張のヒント
【セッションの永続化】
本格的な対話を実装するときには確実に必要になるのがコンテキストです。
コンテキストは対話状態、各種ステータスなどを入れておきます。
Slackletのデフォルト実装では、セッションはオンメモリに保持されますので、プログラムを終了すると忘れてしまいます。セッションを永続化したい場合は永続化コードを含むSletPersistManagerを実装し、SlackletService#setSessionPersistenceManagerでセットします。
【マルチユーザー対応】
複数のユーザーとの対話を同時処理できるよう、ユーザー毎に別スレッドで処理していますが、BOTが扱うユーザー数に応じて、executorやスレッドプールの大きさを適宜調節すると良いとおもいます。
【ログを表示する】
以下のようにするとログをstderrに出力します
org.riversun.xternal.log.Logger.setEnabled(true);
【さらに深い拡張】
Slackletの下回りはSimple Slack APIを拡張して作られています。より深い拡張をしたい場合はSimple Slack APIを参考にされると良いとおもいます。