この記事では
- slackの任意のチャンネルにボタン付きメッセージを送る
- ボタンの操作結果をwebサーバーで受け取る
という単純なサンプルについてメモを書いておきます
前提
- slackをすでに利用している
- httpsの利用可能なwebサーバーを公開できる
公式 Document
https://api.slack.com/docs/message-buttons
https://api.slack.com/interactive-messages
https://api.slack.com/docs/message-guidelines
#1. slackのアプリを作成する
ボタン付きメッセージを送るだけならアプリを作成する必要はありませんが、ボタンをクリックした結果を任意のwebサーバー側で受け取る場合はアプリを作成する必要があります。
##1-1. アプリの作成
https://api.slack.com/apps
にアクセスし、create new app からアプリを作成します。
「App Name」に任意の名前
「Development Slack Team」にはボタン付きメッセージを送りたいチャンネルのあるチームを選択します。
##1-2. Incoming Webhooksの設定
Incoming Webhooksを設定すると任意のslackチャンネルにメッセージを送ることができるようになります。
メニューのIncoming Webhooksをクリックし、Activate Incoming Webhooksの右にあるボタンをクリックしてActiavteをOnにします。
次に Incoming Webhooksのページ下部にある「Add New Webhook to Team」のボタンをクリックします。
「Post to」にメッセージを送りたいチャンネル名を入力し、「install」をクリックします。
installが終わるとIncoming Webhooksのページに戻り、設定したチャンネルへメッセージを送るためのWebhook URLが表示されます。
##1-3. Interactive Messagesの設定
Interactive Messagesを設定するとslackメッセージのボタン操作結果を任意のWebサーバーで受け取ることができます。
メニューのInteractive Messagesをクリックし、「Enable Interactive Messages」のボタンをクリックします。
Request URLに任意のURLを入力して「Enable Interactive Messages」のボタンをクリックします。設定したURLにslackでボタンを押した結果がリクエスト(http post)されるようになります。
#2. ボタン付きメッセージの送信
slackにボタン付きメッセージを送信します。宛先のチャンネルは1-2で設定したチャンネルとなります。
##2-1 curlを使ったサンプル
curlを使ったサンプル(下記はURLの一部伏字にしてますが、1-2で設定したWebhook URLとなります)
curl https://hooks.slack.com/services/***/***/*** -d'payload=
{
"text": "Slack Message Sample Text",
"attachments": [
{
"fallback": "fallback string",
"title": "title string",
"callback_id": "callback_id value",
"color": "#FF0000",
"attachment_type": "default",
"actions": [
{
"name": "btn1Name",
"text": "btn1",
"type": "button",
"style":"default",
"value": "btn1Value"
},
{
"name": "btn2Name",
"text": "btn2",
"type": "button",
"style":"danger",
"value": "btn2Value"
},
{
"name": "btn3Name",
"text": "btn3",
"type": "button",
"style":"primary",
"value": "btn2Value"
}
]
}
]
}'
#3. ボタンクリックの結果をハンドリング
ボタンを押した結果はWebhook URLに http POSTされてきます。
##3-1 ボタンクリック時のリクエストをログに出してみる
下記のようなJavaのコントローラを用意し、リクエストを受け取ってログ出力してみます。
package org.hoge.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
@Controller
@RequestMapping("slackReceive")
public class SlackReceiveController {
private Logger logger = LoggerFactory.getLogger(SlackReceiveController.class);
@PostMapping(value = "", consumes = "application/x-www-form-urlencoded")
ResponseEntity buttonAction(HttpServletRequest request, @RequestParam(value = "payload", required = true) String json) {
logger.info(json);
return new ResponseEntity(HttpStatus.OK);
}
}
ログの結果は以下です(btn1をクリックしています)
みづらいので整形した内容を記載します(idは全て伏字)
{
"actions": [
{
"name": "btn1Name",
"type": "button",
"value": "btn1Value"
}
],
"callback_id": "callback_id value",
"team": {
"id": "*****",
"domain": "*****"
},
"channel": {
"id": "*****",
"name": "******"
},
"user": {
"id": "*****",
"name": "*****"
},
"action_ts": "1498286982.378198",
"message_ts": "1498286913.724083",
"attachment_id": "1",
"token": "*****",
"is_app_unfurl": false,
"original_message": {
"text": "Slack Message Sample Text",
"bot_id": "*****",
"attachments": [
{
"callback_id": "callback_id value",
"fallback": "fallback string",
"title": "title string",
"id": 1,
"color": "FF0000",
"actions": [
{
"id": "1",
"name": "btn1Name",
"text": "btn1",
"type": "button",
"value": "btn1Value",
"style": "default"
},
{
"id": "2",
"name": "btn2Name",
"text": "btn2",
"type": "button",
"value": "btn2Value",
"style": "danger"
},
{
"id": "3",
"name": "btn3Name",
"text": "btn3",
"type": "button",
"value": "btn2Value",
"style": "primary"
}
]
}
],
"type": "message",
"subtype": "bot_message",
"ts": "1498286913.724083"
},
"response_url": "https://hooks.slack.com/actions/***/***/***"
}
actionsにクリックしたボタンの情報がありますので、こちらを利用することで処理の分岐が可能です。
##3-2 ボタンクリック時のリクエストを受けて元のメッセージを編集する
ボタンクリック時のリクエストに対し、webサーバー側(SlackReceiveController)からのresponse bodyにjsonを設定することで元のメッセージを書き換えることが可能です。
クリックしたボタンに応じて元のメッセージを書き換えるサンプルは下記の通り
package org.hoge.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.cloudfoundry.com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
@Controller
@RequestMapping("slackReceive")
public class SlackReceiveController {
private Logger logger = LoggerFactory.getLogger(SlackReceiveController.class);
@PostMapping(value = "", consumes = "application/x-www-form-urlencoded")
ResponseEntity buttonAction(HttpServletRequest request, @RequestParam(value = "payload", required = true) String json) {
//json文字列を雑にMap objectに変換
ObjectMapper mapper = new ObjectMapper();
HashMap<String, Object> payloadMap = null;
try {
payloadMap = mapper.readValue(json, HashMap.class);
} catch (IOException e) {
return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
}
//クリックされたactionsの取り出し
List<HashMap<String, String>> actions = (List<HashMap<String, String>>) payloadMap.get("actions");
String clickedBtn = actions.get(0).get("name");
//オリジナルメッセージの取り出しと書き換え
LinkedHashMap<String, Object> original_message;
original_message = (LinkedHashMap) payloadMap.get("original_message");
original_message.put("text", "Clicked: " + clickedBtn);
//bodyを設定
return new ResponseEntity(original_message, HttpStatus.OK);
}
}