命令可用性

註冊的命令並非總是有效,這取決於應用程式的內部狀態。例如,可能有一個download命令,但它只有在使用者已透過connect連線到遠端伺服器後才可用。現在,如果使用者嘗試使用download命令,Shell 應該解釋該命令存在,但當前不可用。Spring Shell 允許你做到這一點,甚至可以提供命令不可用的簡短解釋。

程式設計式

透過程式設計式註冊,你可以使用 availability 方法,該方法接受一個 Supplier<Availability>

private boolean connected;

@Bean
public CommandRegistration connect(
		CommandRegistration.BuilderSupplier builder) {
	return builder.get()
		.command("connect")
		.withOption()
			.longNames("connected")
			.required()
			.type(boolean.class)
			.and()
		.withTarget()
			.consumer(ctx -> {
				boolean connected = ctx.getOptionValue("connected");
				this.connected = connected;
			})
			.and()
		.build();
}

@Bean
public CommandRegistration download(
		CommandRegistration.BuilderSupplier builder) {
	return builder.get()
		.command("download")
		.availability(() -> {
			return connected
				? Availability.available()
				: Availability.unavailable("you are not connected");
		})
		.withTarget()
			.consumer(ctx -> {
				// do something
			})
			.and()
		.build();
}

註解式

對於基於註解的命令,你可以結合使用 @CommandAvailabilityAvailabilityProvider

@Command
class MyCommands {

	private boolean connected;

	@Command(command = "connect")
	public void connect(String user, String password) {
		connected = true;
	}


	@Command(command = "download")
	@CommandAvailability(provider = "downloadAvailability")
	public void download(
	) {
		// do something
	}

	@Bean
	public AvailabilityProvider downloadAvailability() {
		return () -> connected
			? Availability.available()
			: Availability.unavailable("you are not connected");
	}
}

遺留註解式

命令有三種可能的方式來指示可用性。它們都使用一個無參方法,該方法返回一個 Availability 例項。請看下面的例子

@ShellComponent
public class MyCommands {

	private boolean connected;

	@ShellMethod("Connect to the server.")
	public void connect(String user, String password) {
		// do something
		connected = true;
	}

	@ShellMethod("Download the nuclear codes.")
	public void download() {
		// do something
	}

	public Availability downloadAvailability() {
		return connected
			? Availability.available()
			: Availability.unavailable("you are not connected");
	}
}

connect 方法用於連線到伺服器(省略細節),連線完成後透過 connected 布林值改變命令狀態。透過存在一個與 download 命令方法同名且帶有 Availability 字尾的方法,download 命令被標記為不可用,直到使用者連線成功。該方法返回一個 Availability 例項,透過兩個工廠方法之一構造。如果命令不可用,必須提供一個解釋。現在,如果使用者在未連線的情況下嘗試呼叫該命令,就會發生以下情況

shell:>download
Command 'download' exists but is not currently available because you are not connected.
Details of the error have been omitted. You can use the stacktrace command to print the full stacktrace.

關於當前不可用命令的資訊也會用於整合幫助。參見 幫助

當命令不可用時提供的理由,如果放在“Because”(因為)後面,應該讀起來順暢。

你不應該以大寫字母開頭或新增句號

如果將可用性方法命名為與命令方法同名不適合你,可以透過使用 @ShellMethodAvailability 註解來提供一個顯式名稱

@ShellMethod("Download the nuclear codes.")
@ShellMethodAvailability("availabilityCheck") (1)
public void download() {
}

public Availability availabilityCheck() { (1)
	return connected
		? Availability.available()
		: Availability.unavailable("you are not connected");
}
1 名稱必須匹配

最後,同類中的多個命令經常共享相同的內部狀態,因此應該作為一個組同時可用或不可用。與其在所有命令方法上都新增 @ShellMethodAvailability 註解,Spring Shell 允許你反過來,將 @ShellMethodAvailabilty 註解放在可用性方法上,並指定該方法控制的命令名稱。

@ShellMethod("Download the nuclear codes.")
public void download() {
}

@ShellMethod("Disconnect from the server.")
public void disconnect() {
}

@ShellMethodAvailability({"download", "disconnect"})
public Availability availabilityCheck() {
	return connected
		? Availability.available()
		: Availability.unavailable("you are not connected");
}

@ShellMethodAvailability.value() 屬性的預設值為 *。這個特殊的萬用字元匹配所有命令名稱。這使得使用單個可用性方法控制單個類的所有命令變得容易。

@ShellComponent
public class Toggles {

	@ShellMethodAvailability
	public Availability availabilityOnWeekdays() {
		return Calendar.getInstance().get(DAY_OF_WEEK) == SUNDAY
			? Availability.available()
			: Availability.unavailable("today is not Sunday");
	}

	@ShellMethod
	public void foo() {}

	@ShellMethod
	public void bar() {}
}
Spring Shell 對如何編寫命令和組織類沒有施加太多限制。然而,通常將相關命令放在同一個類中是一個很好的實踐,可用性指示器也能從中受益。