背景
- Springプロジェクトで Slack にメッセージを送りたい(Apache Velocity テンプレートで)
環境
- Spring Framework 4
- slack-api-client 1.XX
- Apache Velocity 1.7
- Java 8
参考リンク
基底クラス
- AbstractSlackService:使いたいサービスで extend して使うイメージ
AbstractSlackService.java
public abstract class AbstractSlackService {
// ダミー用TS
public static final String SLACK_DUMMY_TS = "0.0";
protected Logger logger = Logger.getLogger(this.getClass());
// 環境取得用:本番用、テスト用なのか判別するためのもの(環境に依存するのでここでは割愛)
private EnvironmentService environmentService;
// メッセージテンプレートに Velocity を使うため(利用しない場合は不要)
protected VelocityEngine velocityEngine;
// 本番用環境じゃなくても強制的に送信するフラグ (application.propertiesに記載)
protected boolean sendForce = false;
// Slackメッセージ用文字列エスケープ
public static String escape(String string) {
String result = "";
if (StringUtils.isNotEmpty(string)) {
result = string.replaceAll("&", "&");
result = result.replaceAll("<", "<");
result = result.replaceAll(">", ">");
}
return result;
}
// SlackID をメンション用文字列にする
public static String id2Mention(String id) {
return String.format("<@%s>", id);
}
// レスポンスがOKかどうか
public static boolean responseIsOk(Object slackResponse) {
if (slackResponse == null) {
return false;
}
if (slackResponse instanceof SlackApiTextResponse) {
SlackApiTextResponse response = (SlackApiTextResponse)slackResponse;
return response.isOk();
}
return false;
}
// メッセージ送信(チャンネルID,Slackトークン,メッセージ内容)
protected ChatPostMessageResponse chatPostMessageInternal(String channel, String token, String text) {
if (StringUtils.isBlank(channel) ||
StringUtils.isBlank(token) || StringUtils.isBlank(text)) {
return null;
}
// 初期化
Slack slack = Slack.getInstance();
// API メソッドのクライアントを上のトークンと共に初期化
MethodsClient methods = slack.methods(token);
// API リクエスト内容を構成
ChatPostMessageRequest slackRequest = ChatPostMessageRequest.builder()
.channel(channel)
.text(text)
.blocks(
asBlocks(
section(section -> section.text(markdownText(text)))
)
)
.build();
// API リクエストを送信
return slackChatPostMessage(methods, slackRequest);
}
// メッセージ送信
protected ChatPostMessageResponse slackChatPostMessage(MethodsClient methods, ChatPostMessageRequest slackRequest) {
ChatPostMessageResponse slackResponse = null;
if (environmentService.isProduction() || sendForce) {
// API リクエストを送信
try {
slackResponse = methods.chatPostMessage(slackRequest);
if (!slackResponse.isOk()) {
logger.error(String.format("Slack送信に失敗:%s", ReflectionToStringBuilder.toString(slackResponse)));
return slackResponse;
}
logger.info(String.format("Slack送信完了。:%s\n%s",
slackRequest.getChannel(), slackRequest.getText()));
} catch (Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
logger.error(sw.toString());
return slackResponse;
}
}
else {
slackResponse = new ChatPostMessageResponse();
slackResponse.setChannel(slackRequest.getChannel());
slackResponse.setTs(SLACK_DUMMY_TS);
slackResponse.setOk(true);
logger.info(String.format("本番環境でないため、送信はしない。:%s\n%s",
slackRequest.getChannel(), slackRequest.getText()));
}
return slackResponse;
}
// メッセージリンク取得
protected ChatGetPermalinkResponse getChatPermalinkInternal(String token, String channel, String messageTs) {
if (StringUtils.isBlank(channel) ||
StringUtils.isBlank(token) || StringUtils.isBlank(messageTs)) {
return null;
}
// 初期化
Slack slack = Slack.getInstance();
// API メソッドのクライアントを上のトークンと共に初期化
MethodsClient methods = slack.methods(token);
ChatGetPermalinkRequest permalinkRequest = ChatGetPermalinkRequest.builder()
.token(token)
.channel(channel)
.messageTs(messageTs)
.build();
return slackChatPermalink(methods, permalinkRequest);
}
// メッセージリンク取得
protected ChatGetPermalinkResponse slackChatPermalink(MethodsClient methods, ChatGetPermalinkRequest permalinkRequest) {
ChatGetPermalinkResponse slackResponse = null;
if (environmentService.isProduction() || sendForce) {
try {
slackResponse = methods.chatGetPermalink(permalinkRequest);
if (!slackResponse.isOk()) {
logger.error(String.format("Slackメッセージリンク取得に失敗:%s", ReflectionToStringBuilder.toString(slackResponse)));
return slackResponse;
}
logger.info(String.format("Slackメッセージリンク取得完了。:%s\n%s:%s",
permalinkRequest.getChannel(), permalinkRequest.getMessageTs(), slackResponse.getPermalink()));
} catch (Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
logger.info(sw.toString());
return slackResponse;
}
} else {
slackResponse = new ChatGetPermalinkResponse();
slackResponse.setChannel(permalinkRequest.getChannel());
slackResponse.setOk(true);
logger.info(String.format("本番環境でないため、送信はしない。:%s\n%s",
permalinkRequest.getChannel(), permalinkRequest.getMessageTs()));
}
return slackResponse;
}
public EnvironmentService getEnvironmentService() {
return environmentService;
}
@Autowired
public final void setEnvironmentService(EnvironmentService environmentService) {
this.environmentService = environmentService;
}
public VelocityEngine getVelocityEngine() {
return velocityEngine;
}
@Autowired
public final void setVelocityEngine(VelocityEngine velocityEngine) {
this.velocityEngine = velocityEngine;
}
public boolean getSendForce() {
return sendForce;
}
@Value("${slack.sendForce}")
public final void setSendForce(boolean sendForce) {
this.sendForce = sendForce;
}
}
サービス用クラス
- ExtendedSlackService
ExtendedSlackService.java
@Component
@Configuration
@PropertySource(value= {"classpath:application.properties"})
public class ExtendedSlackService extends AbstractSlackService {
@Autowired
private Environment environment;
/*
* メッセージ送信(テンプレート利用)
*/
public ChatPostMessageResponse chatPostMessage(String channel, String templateName, Map<String, Object> replaceModel) {
String token = environment.getProperty("slack.token");
String text = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine,
"path/to/templateDir/" + templateName + ".slack.vm", "utf-8", replaceModel);
return chatPostMessageInternal(channel, token, text);
}
/*
* メッセージ送信(直接)
*/
public ChatPostMessageResponse chatPostMessageDirect(String channel, String message, Map<String, String> replaceModel, String mentions) {
if (StringUtils.isBlank(message)) return null;
String token = environment.getProperty("slack.token");
for (Map.Entry<String, String> entry: replaceModel.entrySet()) {
message = message.replace("${"+entry.getKey()+"}", entry.getValue());
}
if (!StringUtils.isBlank(mentions)) {
message = mentions + "\n" + message;
}
return chatPostMessageInternal(channel, token, message);
}
/*
* メッセージリンク取得
*/
public ChatGetPermalinkResponse getChatPermalink(String channel, String messageTs) {
String token = environment.getProperty("slack.token");
return getChatPermalinkInternal(token, channel, messageTs);
}
public Environment getEnvironment() {
return environment;
}
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}
application.properties
application.properties
# for slack
slack.sendForce=false
slack.token=XXXX-XXXXXXXXXXXX
以上、お疲れさまでした!