How to Create a Slack Plugin in Java – 如何在Java中创建一个Slack插件

最后修改: 2020年 1月 31日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

Slack is a popular chat system used by people and companies around the world. One of the things that makes it so popular is the ability to write our own custom plugins that can interact with people and channels within a single slack. This uses their HTTP API.

Slack是一个流行的聊天系统,被世界各地的人和公司使用。使它如此受欢迎的原因之一是,我们能够编写自己的自定义插件,可以在一个slack内与人和频道进行互动。这使用了他们的HTTP API。

Slack doesn’t offer an official SDK for writing plugins with Java. However, there is an officially endorsed community SDK that we are going to use. This gives us access to almost all of the Slack API from a Java codebase without our needing to concern ourselves with the exact details of the API.

Slack并没有提供用于用Java编写插件的官方SDK。但是,有一个官方认可的社区SDK,我们将使用它。这使我们能够从Java代码库中访问几乎所有的Slack API,而不需要关注API的具体细节。

We’ll make use of this to build a small system monitoring bot. This will periodically retrieve the disk space for the local computer and alert people if any drives are getting too full.

我们将利用这一点建立一个小型的系统监控机器人。这将定期检索本地计算机的磁盘空间,并在任何驱动器变得太满时提醒人们。

2. Obtaining API Credentials

2.获取API凭证

Before we can do anything with Slack, we need to create a new App and a Bot and connect it to our channels.

在我们用Slack做任何事情之前,我们需要创建一个新的应用程序和一个机器人,并将其连接到我们的频道

Firstly, let’s visit https://api.slack.com/apps. This is the base from where we manage our Slack apps. From here we can create a new app.

首先,让我们访问https://api.slack.com/apps。这是我们管理Slack应用程序的基地。从这里我们可以创建一个新的应用程序。

When we do this, we need to enter a name for the app and a Slack workspace to create it in.

当我们这样做时,我们需要为该应用程序输入一个名称和一个Slack工作区来创建它。

Once we’ve done this, the app has been created and is ready for us to work with. The next screen allows us to create a Bot. This is a fake user that the plugin will be acting as.

一旦我们完成了这些,应用程序就已经创建,并准备好供我们使用了。下一个屏幕允许我们创建一个机器人。这是一个假的用户,插件将作为该用户行事。

As with any normal user, we need to give this a display name and a username. These are the settings that other users in the Slack workspace will see for this bot user if they ever interact with it.

和其他普通用户一样,我们需要给它一个显示名称和一个用户名。如果Slack工作区的其他用户与之互动,他们会看到这个机器人用户的这些设置。

Now that we’ve done this, we can select “Install App” from the side menu and add the App into our Slack workspace. Once we’ve done this, the app can interact with our workspace.

现在我们已经完成了这些,我们可以从侧面菜单中选择 “安装应用程序”,并将该应用程序添加到我们的Slack工作区。一旦我们这样做了,该应用程序就可以与我们的工作空间互动。

This will then give us the tokens that we need for our plugin to communicate with Slack.

然后,这将给我们提供我们的插件与Slack通信所需的令牌。

 

Each bot interacting with a different Slack workspace will have a different set of tokens. Our application needs the “Bot User OAuth Access Token” value for when we run it.

每个与不同Slack工作区互动的机器人都会有一组不同的令牌。我们的应用程序需要 “机器人用户OAuth访问令牌 “值,以便我们运行它。

Finally, we need to invite the bot to any channels it should be involved in. This works by simply messaging it from the channel — @system_monitoring in this case.

最后,我们需要邀请机器人进入任何它应该参与的频道。这可以通过简单地从频道中发送消息来实现–在这个例子中,@system_monitoring

3. Adding Slack to Our Project

3.将Slack添加到我们的项目中

Before we can use it, we first need to add the Slack SDK dependencies to our pom.xml file:

在使用它之前,我们首先需要将Slack SDK依赖项添加到我们的pom.xml文件。

<dependency>
    <groupId>com.hubspot.slack</groupId>
    <artifactId>slack-base</artifactId>
    <version>${slack.version}</version>
</dependency>
<dependency>
    <groupId>com.hubspot.slack</groupId>
    <artifactId>slack-java-client</artifactId>
    <version>${slack.version}</version>
</dependency>

3. Application Structure

3.应用结构

The core of our application is the ability to check for errors in the system. We’ll represent this with the concept of an Error Checker. This is a simple interface with a single method, triggered to check for errors and report them:

我们应用程序的核心是能够检查系统中的错误。我们将用错误检查器的概念来表示这一点。这是一个简单的接口,有一个单一的方法,被触发来检查错误并报告它们。

public interface ErrorChecker {
    void check();
}

We also want to have the means to report any errors that have been found. This is another simple interface that will take a problem statement and report it appropriately:

我们还希望有办法报告任何已经发现的错误。这是另一个简单的接口,它将接受一个问题声明并适当地报告它。

public interface ErrorReporter {
    void reportProblem(String problem);
}

The use of an interface here allows us to have different ways of reporting problems. For example, we might have one that sends emails, contacts an error reporting system, or sends messages to our Slack system for people to get an immediate notification.

这里使用的接口允许我们有不同的方式来报告问题。例如,我们可能有一个发送电子邮件,联系错误报告系统,或将信息发送到我们的Slack系统,让人们立即得到通知。

The design behind this is that each ErrorChecker instance is given its own ErrorReporter to use. This gives us the flexibility to have different error reporters for different checkers to use because some errors might be more important than others. For example, if the disks are over 90% full that may require a message to a Slack channel, but if they are over 98% full then we might instead want to send private messages to specific people instead.

这背后的设计是,每个ErrorChecker实例都有自己的ErrorReporter来使用。这给了我们灵活性,让不同的检查器使用不同的错误报告器,因为有些错误可能比其他的更重要。例如,如果磁盘超过90%满了,可能需要向Slack频道发送消息,但如果磁盘超过98%满了,那么我们可能反而要向特定的人发送私人消息。

4. Checking Disk Space

4.检查磁盘空间

Our error checker will check the amount of disk space on the local system. Any file system that has less than a particular percentage free is considered to be an error and will be reported as such.

我们的错误检查器将检查本地系统的磁盘空间数量。任何文件系统的可用空间低于特定的百分比,都被认为是一个错误,并将被报告为错误。

We’ll make use of the NIO2 FileStore API introduced in Java 7 to obtain this information in a cross-platform manner.

我们将利用Java 7中引入的NIO2 FileStore API,以跨平台的方式获得这些信息。

Now, let’s take a look at our error checker:

现在,让我们看一下我们的错误检查器。

public class DiskSpaceErrorChecker implements ErrorChecker {
    private static final Logger LOG = LoggerFactory.getLogger(DiskSpaceErrorChecker.class);

    private ErrorReporter errorReporter;

    private double limit;

    public DiskSpaceErrorChecker(ErrorReporter errorReporter, double limit) {
        this.errorReporter = errorReporter;
        this.limit = limit;
    }

    @Override
    public void check() {
        FileSystems.getDefault().getFileStores().forEach(fileStore -> {
            try {
                long totalSpace = fileStore.getTotalSpace();
                long usableSpace = fileStore.getUsableSpace();
                double usablePercentage = ((double) usableSpace) / totalSpace;

                if (totalSpace > 0 && usablePercentage < limit) {
                    String error = String.format("File store %s only has %d%% usable disk space",
                        fileStore.name(), (int)(usablePercentage * 100));
                    errorReporter.reportProblem(error);
                }
            } catch (IOException e) {
                LOG.error("Error getting disk space for file store {}", fileStore, e);
            }
        });
    }
}

Here, we’re obtaining the list of all file stores on the local system and then checking each one individually. Any that has less than our defined limit as usable space will generate an error using our error reporter.

在这里,我们要获得本地系统上所有文件存储的列表,然后逐个检查。任何少于我们定义的可用空间限制的文件将使用我们的错误报告生成一个错误。

5. Sending Errors to Slack Channels

5.向Slack频道发送错误信息

We now need to be able to report our errors. Our first reporter will be one that sends messages to a Slack channel. This allows anyone in the channel to see the message, in the hope that somebody will react to it.

我们现在需要能够报告我们的错误。我们的第一个报告人将是一个向Slack频道发送消息的人。这允许频道中的任何人看到该消息,希望有人能对其作出反应。

This uses a SlackClient, from the Slack SDK, and the name of the channel to send the messages to. It also implements our ErrorReporter interface so that we can easily plug it into whichever error checker wants to use it:

这使用了一个SlackClient,来自Slack SDK,以及要发送消息的频道名称。它还实现了我们的ErrorReporter接口,这样我们就可以很容易地将它插入任何想要使用它的错误检查器中。

public class SlackChannelErrorReporter implements ErrorReporter {
    private SlackClient slackClient;

    private String channel;

    public SlackChannelErrorReporter(SlackClient slackClient, String channel) {
        this.slackClient = slackClient;
        this.channel = channel;
    }

    @Override
    public void reportProblem(String problem) {
        slackClient.postMessage(
          ChatPostMessageParams.builder()
            .setText(problem)
            .setChannelId(channel)
            .build()
        ).join().unwrapOrElseThrow();
    }
}

6. Application Wiring

6.应用布线

We are now in a position to wire up the application and have it monitor our system. For the sake of this tutorial, we’re going to use the Java Timer and TimerTask that are part of the core JVM, but we could just as easily use Spring or any other framework to build this.

我们现在可以给应用程序布线,让它监控我们的系统。在本教程中,我们将使用Java TimerTimerTask,它们是核心JVM的一部分,但我们也可以很容易地使用Spring或其他框架来构建这个。

For now, this will have a single DiskSpaceErrorChecker that reports any disks that are under 10% usable to our “general” channel, and which runs every 5 minutes:

目前,这将有一个单一的DiskSpaceErrorChecker,向我们的 “一般 “通道报告任何低于10%可用的磁盘,并且每5分钟运行一次。

public class MainClass {
    public static final long MINUTES = 1000 * 60;

    public static void main(String[] args) throws IOException {
        SlackClientRuntimeConfig runtimeConfig = SlackClientRuntimeConfig.builder()
          .setTokenSupplier(() -> "<Your API Token>")
          .build();

        SlackClient slackClient = SlackClientFactory.defaultFactory().build(runtimeConfig);

        ErrorReporter slackChannelErrorReporter = new SlackChannelErrorReporter(slackClient, "general");

        ErrorChecker diskSpaceErrorChecker10pct = 
          new DiskSpaceErrorChecker(slackChannelErrorReporter, 0.1);

        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                diskSpaceErrorChecker10pct.check();
            }
        }, 0, 5 * MINUTES);
    }
}

We need to replace “<Your API Token>” with the token that was obtained earlier, and then we’re ready to run. As soon as we do, if everything is correct, our plugin will check the local drives and message the Slack if there are any errors.

我们需要将”<你的API令牌>”替换为之前获得的令牌,然后我们就可以运行了。一旦我们这样做,如果一切正确,我们的插件将检查本地驱动器,如果有任何错误,将向Slack发送信息。

7. Sending Errors as Private Messages

7.将错误作为私人信息发送

Next, we’re going to add an error reporter that sends private messages instead. This can be useful for more urgent errors since it will immediately ping a specific user instead of relying on someone in the channel to react.

下一步,我们将添加一个错误报告器,代替发送私人信息。这对更紧急的错误很有用,因为它将立即呼唤一个特定的用户,而不是依靠频道中的某个人做出反应

Our error reporter here is more complicated because it needs to interact with a single, targeted user:

我们的错误报告人在这里更为复杂,因为它需要与一个单一的目标用户进行互动。

public class SlackUserErrorReporter implements ErrorReporter {
    private SlackClient slackClient;

    private String user;

    public SlackUserErrorReporter(SlackClient slackClient, String user) {
        this.slackClient = slackClient;
        this.user = user;
    }

    @Override
    public void reportProblem(String problem) {
        UsersInfoResponse usersInfoResponse = slackClient
            .lookupUserByEmail(UserEmailParams.builder()
              .setEmail(user)
              .build()
            ).join().unwrapOrElseThrow();

        ImOpenResponse imOpenResponse = slackClient.openIm(ImOpenParams.builder()
            .setUserId(usersInfoResponse.getUser().getId())
            .build()
        ).join().unwrapOrElseThrow();

        imOpenResponse.getChannel().ifPresent(channel -> {
            slackClient.postMessage(
                ChatPostMessageParams.builder()
                  .setText(problem)
                  .setChannelId(channel.getId())
                  .build()
            ).join().unwrapOrElseThrow();
        });
    }
}

What we have to do here is to find the user that we are messaging — looked up by email address, since this is the one thing that can’t be changed. Next, we open an IM channel to the user, and then we post our error message to that channel.

我们在这里要做的是找到我们要发送消息的用户–通过电子邮件地址查找,因为这是一个不能改变的东西。接下来,我们为该用户打开一个IM通道,然后将我们的错误信息发布到该通道

This can then be wired up in the main method, and we will alert a single user directly:

然后,这可以在main方法中连接起来,我们将直接提醒一个用户。

ErrorReporter slackUserErrorReporter = new SlackUserErrorReporter(slackClient, "testuser@baeldung.com");

ErrorChecker diskSpaceErrorChecker2pct = new DiskSpaceErrorChecker(slackUserErrorReporter, 0.02);

timer.scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
        diskSpaceErrorChecker2pct.check();
    }
}, 0, 5 * MINUTES);

Once done, we can run this up and get private messages for errors as well.

一旦完成,我们就可以把这个运行起来,也可以得到错误的私人信息。

8. Conclusion

8.结论

We’ve seen here how we can incorporate Slack into our tooling so that we can have feedback sent to either the entire team or to individual members. There’s much more we can do with the Slack API, so why not see what else we can incorporate.

我们在这里看到,我们如何将Slack纳入我们的工具,以便我们可以将反馈发送到整个团队或个别成员。我们可以利用Slack的API做更多的事情,所以为什么不看看我们还可以结合什么。

As usual, the source code for this article can be found over on GitHub.

像往常一样,本文的源代码可以在GitHub上找到超过