LoginSignup
0
1

More than 1 year has passed since last update.

【Java, Slack】Spring で Slack メッセージ送信

Last updated at Posted at 2022-06-24

背景

  • 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("<", "&lt;");
			result = result.replaceAll(">", "&gt;");
		}
		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

以上、お疲れさまでした!

0
1
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
0
1