Contents

Java Airline 库简介

1. 简介

在本教程中,我们将介绍Airline ——一个用于构建命令行界面 (CLI) 的注解驱动的 Java 库。

2. 场景

在构建命令行应用程序时,很自然地会创建一个简单的界面以允许用户根据需要塑造输出。几乎每个人都使用过 Git CLI,并且可以感受到它的强大而简单。唉,在构建这样的界面时,很少有工具能派上用场。

该Airline旨在减少通常与 Java 中的 CLI 相关联的样板代码,因为大多数常见行为都可以通过注解和零用户代码实现。

我们将实施一个小型 Java 程序,该程序将利用 Airline 的功能来模拟通用 CLI。它将公开用于设置程序配置的用户命令,例如定义数据库 URL、凭据和记录器详细信息。我们还将深入了解我们的库,并使用比其基础知识更多的内容来探索它是否可以处理一些复杂性。

3. 设置

首先,让我们将Airline 依赖项添加到我们的pom.xml 中:

<dependency>
    <groupId>com.github.rvesse</groupId>
    <artifactId>airline</artifactId>
    <version>2.7.2</version>
</dependency>

4. 一个简单的 CLI

让我们为应用程序创建入口点——CommandLine类:

@Cli(name = "blogdemo-cli",
  description = "Blogdemo Airline Tutorial",
  defaultCommand = Help.class)
public class CommandLine {
    public static void main(String[] args) {
        Cli<Runnable> cli = new Cli<>(CommandLine.class);
        Runnable cmd = cli.parse(args);
        cmd.run();
    }
}

通过一个简单的*@Cli*注解,我们定义了将在我们的应用程序上运行的默认命令——Help命令。

Help类作为 Airline 库的一部分出现,并使用*-h–help*选项公开默认帮助命令。 就这样,基本设置就完成了。

5. 我们的第一个命令

让我们实现我们的第一个命令,一个简单的LoggingCommand类,它将控制我们日志的详细程度。我们将使用*@Command注解该类,以确保在用户调用setup-log*时应用正确的命令:

@Command(name = "setup-log", description = "Setup our log")
public class LoggingCommand implements Runnable {
    @Inject
    private HelpOption<LoggingCommand> help;

    @Option(name = { "-v", "--verbose" }, 
      description = "Set log verbosity on/off")
    private boolean verbose = false;
    @Override
    public void run() {
        if (!help.showHelpIfRequested())
            System.out.println("Verbosity: " + verbose);
        }
    }
}

让我们仔细看看我们的示例命令。

首先,我们已经设置了一个描述,这样我们的助手,由于注入,将在请求时显示我们的命令选项。

然后我们声明了一个boolean变量verbose,并用*@Option对其进行了注解 以为其命名、描述,以及一个别名-v/–verbose* 来表示我们控制冗长的命令行选项。

最后,在run方法中,我们指示我们的命令在用户请求帮助时停止。

到目前为止,一切都很好。现在,我们需要通过修改*@Cli*注解将我们的新命令添加到主界面:

@Cli(name = "blogdemo-cli",
description = "Blogdemo Airline Tutorial",
defaultCommand = Help.class,
commands = { LoggingCommand.class, Help.class })
public class CommandLine {
    public static void main(String[] args) {
        Cli<Runnable> cli = new Cli<>(CommandLine.class);
        Runnable cmd = cli.parse(args);
        cmd.run();
    }
}

现在,如果我们将setup-log -v传递给我们的程序,它将运行我们的逻辑。

6. 约束和更多

我们已经看到 Airline 如何完美地生成 CLI,但是……还有更多!

我们可以为我们的参数指定约束(或限制)来处理允许的值、要求或依赖性等。

我们将创建一个DatabaseSetupCommand类,它将响应setup-db命令;和我们之前做的一样,但我们会添加一些香料。

首先,我们将请求数据库类型,通过*@AllowedRawValues*只接受 3 个有效值:

@AllowedRawValues(allowedValues = { "mysql", "postgresql", "mongodb" })
@Option(type = OptionType.COMMAND,
  name = {"-d", "--database"},
  description = "Type of RDBMS.",
  title = "RDBMS type: mysql|postgresql|mongodb")
protected String rdbmsMode;

当使用数据库连接时,毫无疑问,用户应该提供一个端点和一些凭证来访问它。我们将让 CLI 通过一个(URL 模式)或多个参数(host模式)来处理这个问题。为此,我们将使用*@MutuallyExclusiveWith*注解,用相同的标签标记每个参数:

@Option(type = OptionType.COMMAND,
  name = {"--rdbms:url", "--url"},
  description = "URL to use for connection to RDBMS.",
  title = "RDBMS URL")
@MutuallyExclusiveWith(tag="mode")
@Pattern(pattern="^(http://.*):(d*)(.*)u=(.*)&p=(.*)")
protected String rdbmsUrl = "";

@Option(type = OptionType.COMMAND,
  name = {"--rdbms:host", "--host"},
  description = "Host to use for connection to RDBMS.",
  title = "RDBMS host")
@MutuallyExclusiveWith(tag="mode")
protected String rdbmsHost = "";

请注意,我们使用了*@Pattern*装饰器,它可以帮助我们定义 URL 字符串格式。

如果我们查看项目文档,我们会找到其他有价值的工具来处理需求、事件、允许值、特定案例等,使我们能够定义我们的自定义规则

最后,如果用户选择了主机模式,我们应该要求他们提供他们的凭据。这样,一个选项依赖于另一个选项。我们可以使用*@RequiredOnlyIf*注解实现此行为:

@RequiredOnlyIf(names={"--rdbms:host", "--host"})
@Option(type = OptionType.COMMAND,
  name = {"--rdbms:user", "-u", "--user"},
  description = "User for login to RDBMS.",
  title = "RDBMS user")
protected String rdbmsUser;
@RequiredOnlyIf(names={"--rdbms:host", "--host"})
@Option(type = OptionType.COMMAND,
  name = {"--rdbms:password", "--password"},
  description = "Password for login to RDBMS.",
  title = "RDBMS password")
protected String rdbmsPassword;

如果我们需要使用一些驱动程序来处理数据库连接怎么办?而且,假设我们需要在一个参数中接收多个值。我们可以将选项类型更改为OptionType.ARGUMENTS 或者 - 甚至更好 - 接受一个值列表:

@Option(type = OptionType.COMMAND,
  name = {"--driver", "--jars"},
  description = "List of drivers",
  title = "--driver <PATH_TO_YOUR_JAR> --driver <PATH_TO_YOUR_JAR>")
protected List<String> jars = new ArrayList<>();

现在,我们不要忘记将数据库设置命令添加到我们的主类中。否则,它将无法在 CLI 上使用。

7.运行

我们做到了!我们完成了我们的项目,现在我们可以运行它了。

正如预期的那样,在不传递任何参数的情况下,将调用help

$ blogdemo-cli
usage: blogdemo-cli <command> [ <args> ]
Commands are:
    help        Display help information
    setup-db    Setup our database
    setup-log   Setup our log
See 'blogdemo-cli help <command>' for more information on a specific command.

如果我们改为执行setup-log –help,我们会得到:

$ blogdemo-cli setup-log --help
NAME
        blogdemo-cli setup-log - Setup our log
SYNOPSIS
        blogdemo-cli setup-log [ {-h | --help} ] [ {-v | --verbose} ]
OPTIONS
        -h, --help
            Display help information
        -v, --verbose
            Set log verbosity on/off

最后,为这些命令提供参数将运行正确的业务逻辑。