Рубрики
Без рубрики

CLI с весенней оболочкой

Быстрый и практичный пример построения простого CLI с Spring Shell.

Автор оригинала: baeldung.

1. Обзор

Проще говоря, весенняя оболочка проект обеспечивает интерактивную оболочку для обработки команд и создания полноправного CLI с использованием модели весеннего программирования.

В этой статье мы изумим его особенности, ключевые классы и аннотации, а также реализуем несколько пользовательских команд и настроеок.

2. Зависимость от Maven

Во-первых, мы должны добавить пружинная оболочка зависимость от нашей пом.xml :


    org.springframework.shell
    spring-shell
    1.2.0.RELEASE

Последнюю версию этого артефакта можно найти здесь .

3. Доступ к оболочке

Есть два основных способа получить доступ к оболочке в наших приложениях.

Во-первых, загрузить оболочку в точку входа нашего приложения и позволить пользователю ввести команды:

public static void main(String[] args) throws IOException {
    Bootstrap.main(args);
}

Во-вторых, получить JLineShellComponent и выполнить команды программно:

Bootstrap bootstrap = new Bootstrap();
JLineShellComponent shell = bootstrap.getJLineShellComponent();
shell.executeCommand("help");

Мы собираемся использовать первый подход, так как он лучше всего подходит для примеров в этой статье, однако, в исходным кодом вы можете найти тестовые случаи, которые используют вторую форму.

4. Команды

В оболочке уже есть несколько встроенных команд, таких как четкие , помочь , выход и т.д., которые обеспечивают стандартную функциональность каждого CLI.

Пользовательские команды могут быть выставлены путем добавления методов, отмеченных @CliCommand аннотация внутри весеннего компонента, реализуя Командный маркер интерфейс.

Каждый аргумент этого метода должен быть отмечен @CliOption аннотация, если мы не сделаем этого, мы будем сталкиваться с несколькими ошибками при попытке выполнить команду.

4.1. Добавление команд в оболочку

Во-первых, мы должны сообщить оболочке, где находятся наши команды. Для этого требуется файловое META-INF/весна/весна-оболочка-плагин.xml чтобы присутствовать в нашем проекте, там мы можем использовать функциональность сканирования компонентов Spring:


    

После того, как компоненты зарегистрированы и мгновенно к весне, они регистрируются с оболочкой парсер, и их аннотации обрабатываются.

Давайте создадим две простые команды: одну, чтобы захватить содержимое URL-адреса и отобразить их, а другую сохранить содержимое файла:

@Component
public class SimpleCLI implements CommandMarker {

    @CliCommand(value = { "web-get", "wg" })
    public String webGet(
      @CliOption(key = "url") String url) {
        return getContentsOfUrlAsString(url);
    }
    
    @CliCommand(value = { "web-save", "ws" })
    public String webSave(
      @CliOption(key = "url") String url,
      @CliOption(key = { "out", "file" }) String file) {
        String contents = getContentsOfUrlAsString(url);
        try (PrintWriter out = new PrintWriter(file)) {
            out.write(contents);
        }
        return "Done.";
    }
}

Обратите внимание, что мы можем передать более одной строки в значение и ключевые атрибуты @CliCommand и @CliOption соответственно, это позволяет нам разоблачить несколько команд и аргументов, которые ведут себя одинаково.

Теперь давайте проверим, работает ли все так, как ожидалось:

spring-shell>web-get --url https://www.google.com

web-save --url https://www.google.com --out contents.txt
Done.

4.2. Наличие команд

Мы можем использовать @CliAvailabilityIndicator аннотация о методе возвращения булеан измениться во время выполнения, если команда должна подвергаться воздействию оболочки.

Во-первых, давайте создадим метод для изменения доступности веб- команда:

private boolean adminEnableExecuted = false;

@CliAvailabilityIndicator(value = "web-save")
public boolean isAdminEnabled() {
    return adminEnableExecuted;
}

Теперь давайте создадим команду, чтобы изменить АдминистрируемыйИсследоваемый переменная:

@CliCommand(value = "admin-enable")
public String adminEnable() {
    adminEnableExecuted = true;
    return "Admin commands enabled.";
}

Наконец, давайте проверим это:

spring-shell>web-save --url https://www.google.com --out contents.txt
Command 'web-save --url https://www.google.com --out contents.txt'
  was found but is not currently available
  (type 'help' then ENTER to learn about this command)
spring-shell>admin-enable
Admin commands enabled.
spring-shell>web-save --url https://www.google.com --out contents.txt
Done.

4.3. Необходимые аргументы

По умолчанию все аргументы команды являются необязательными. Тем не менее, мы можем сделать их необходимыми с обязательный атрибут @CliOption аннотация:

@CliOption(key = { "out", "file" }, mandatory = true)

Теперь мы можем проверить, что если мы не введем его, приводит к ошибке:

spring-shell>web-save --url https://www.google.com
You should specify option (--out) for this command

4.4. Аргументы по умолчанию

Пустой ключевые значение для @CliOption делает этот аргумент по умолчанию. Там мы получим значения, введенные в оболочке, которые не являются частью какого-либо названного аргумента:

@CliOption(key = { "", "url" })

Теперь давайте проверим, работает ли он так, как ожидалось:

spring-shell>web-get https://www.google.com

4.5. Помощь пользователям

@CliCommand и @CliOption аннотации обеспечивают помочь атрибут, который позволяет нам направлять наших пользователей при использовании встроенного помочь команды или при вкладке, чтобы получить автоматическое завершение.

Давайте изменим наши веб-получить для добавления пользовательских сообщений справки:

@CliCommand(
  // ...
  help = "Displays the contents of an URL")
public String webGet(
  @CliOption(
    // ...
    help = "URL whose contents will be displayed."
  ) String url) {
    // ...
}

Теперь пользователь может точно знать, что делает наша команда:

spring-shell>help web-get
Keyword:                    web-get
Keyword:                    wg
Description:                Displays the contents of a URL.
  Keyword:                  ** default **
  Keyword:                  url
    Help:                   URL whose contents will be displayed.
    Mandatory:              false
    Default if specified:   '__NULL__'
    Default if unspecified: '__NULL__'

* web-get - Displays the contents of a URL.
* wg - Displays the contents of a URL.

5. Настройка

Существует три способа настройки оболочки путем реализации БаннерПредидер , Провидедер и ИсторияFileNameПровидер интерфейсы, все из них с реализацией по умолчанию уже предусмотрено.

Кроме того, мы должны использовать @Order аннотация, чтобы позволить нашим поставщикам иметь приоритет над этими реализациями.

Давайте создадим новый баннер, чтобы начать нашу настройку:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleBannerProvider extends DefaultBannerProvider {

    public String getBanner() {
        StringBuffer buf = new StringBuffer();
        buf.append("=======================================")
            .append(OsUtils.LINE_SEPARATOR);
        buf.append("*          Baeldung Shell             *")
            .append(OsUtils.LINE_SEPARATOR);
        buf.append("=======================================")
            .append(OsUtils.LINE_SEPARATOR);
        buf.append("Version:")
            .append(this.getVersion());
        return buf.toString();
    }

    public String getVersion() {
        return "1.0.1";
    }

    public String getWelcomeMessage() {
        return "Welcome to Baeldung CLI";
    }

    public String getProviderName() {
        return "Baeldung Banner";
    }
}

Обратите внимание, что мы также можем изменить номер версии и приветственное сообщение.

Теперь давайте изменим подсказку:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SimplePromptProvider extends DefaultPromptProvider {

    public String getPrompt() {
        return "baeldung-shell";
    }

    public String getProviderName() {
        return "Baeldung Prompt";
    }
}

Наконец, давайте изменим название файла истории:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleHistoryFileNameProvider
  extends DefaultHistoryFileNameProvider {

    public String getHistoryFileName() {
        return "baeldung-shell.log";
    }

    public String getProviderName() {
        return "Baeldung History";
    }

}

Файл истории будет записывать все команды, выполненные в оболочке, и будет помещен вместе с нашим приложением.

Со всем на месте, мы можем назвать нашу оболочку и увидеть его в действии:

=======================================
*          Baeldung Shell             *
=======================================
Version:1.0.1
Welcome to Baeldung CLI
baeldung-shell>

6. Преобразователи

До сих пор мы использовали только простые типы в качестве аргументов для наших команд. Общие типы, такие как Интегер , Дата , Энум , Файл и т.д., есть преобразователь по умолчанию уже зарегистрированы.

Реализуя Конвертер интерфейс, мы также можем добавить наши преобразователи для получения пользовательских объектов.

Давайте создадим преобразователь, который может преобразовать Струнные в URL :

@Component
public class SimpleURLConverter implements Converter {

    public URL convertFromText(
      String value, Class requiredType, String optionContext) {
        return new URL(value);
    }

    public boolean getAllPossibleValues(
      List completions,
      Class requiredType,
      String existingData,
      String optionContext,
      MethodTarget target) {
        return false;
    }

    public boolean supports(Class requiredType, String optionContext) {
        return URL.class.isAssignableFrom(requiredType);
    }
}

Наконец, давайте изменим наши веб-получить и веб- Команды:

public String webSave(... URL url) {
    // ...
}

public String webSave(... URL url) {
    // ...
}

Как вы уже догадались, команды ведут себя одинаково.

7. Заключение

В этой статье мы кратко осмотреть основные особенности проекта Spring Shell. Мы смогли внести свои команды и настроить оболочку с нашими поставщиками, мы изменили доступность команд в соответствии с различными условиями выполнения и создали простой преобразователь типа.

Полный исходный код этой статьи можно найти более на GitHub .