こう作ったら小綺麗に書けるってやりかたが、ある程度見えてきた気がするので、まとめておく。
環境
- Java 1.8.0_91
- Maven 3.3.9 (Maven wrapper)
- Spring Boot 1.4.3.RELEASE
- Apache Commons CLI 1.3.1
$ ./mvnw -version
Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-11T01:41:47+09:00)
Maven home: /Users/yo1000/.m2/wrapper/dists/apache-maven-3.3.9-bin/2609u9g41na2l7ogackmif6fj2/apache-maven-3.3.9
Java version: 1.8.0_91, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/jre
Default locale: ja_JP, platform encoding: UTF-8
OS name: "mac os x", version: "10.11.5", arch: "x86_64", family: "mac"
つかうもの
- Spring Boot
- Apache Commons CLI
依存関係の一部を抜粋。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<commons-cli.version>1.3.1</commons-cli.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>${commons-cli.version}</version>
</dependency>
</dependencies>
やること
- オプション付きパラメタの受け取り
- オプション無しパラメタの受け取り
- オプションに対するヘルプの表示
- パイプされた標準入力の受け取り
- エラーハンドリング
CLI アプリとして起動できるように構成
Spring Boot で、CLI アプリを作成する場合の基本中の基本。org.springframework.boot.CommandLineRunner
インターフェースを実装したコンポーネントを作成します。
このようなクラスを作成しておくと、ターミナルからアプリケーションを起動した場合に、run
メソッドが呼び出されるようになります。
@Component
public class DemoCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) {
// 以下 ここに処理を実装していく
}
}
パラメタの扱い
Apache Commons CLI を使用しているので、コマンドライン引数の扱いは非常に簡単です。以下の様なことができます。
Options options = new Options();
options.addOption("?", "help", false, "Print this message.");
options.addOption("o", "output", true, "Output directory.");
// void run(String... args) throws Exception {..}
CommandLine cl = new DefaultParser().parse(options, args);
if (cl.hasOption("o")) {..}
String output = cl.getOptionValue("o");
// どちらもパラメタの内容自体は同じ
String[] params = cl.getArgs();
List<String> paramList = cl.getArgList();
if (cl.hasOption("?")) {
new HelpFormatter().printHelp("demo [-o <arg>]", options)
}
以上のように、パラメタはとても簡単に扱うことができます。
標準入力の扱い
CLI アプリであれば、標準入力から値を受け取って、パイプでつなげて処理できたりすると、スマートな感じがして良いのですが、こちらは Apache Commons CLI では処理できません。System.in
を使って以下のようにすると、標準入力を扱えます。
// パイプされた標準入力を受け取ると、対話式 CLI に使用する System.console() は null を返す
if (System.console() == null) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
String stdin = reader.lines().collect(Collectors.joining());
} catch (IOException e) {
..
}
}
以上のように、パイプされた標準入力の扱いには一手間必要ですが、やり方さえわかってしまえば難しいことはないです。
エラーハンドリング
Spring を使っているので、AOP で例外をまとめて処理して、標準エラーに出力するのが簡単で良いです。
@Aspect
@Component
public class ExceptionHandlerAdvice {
@Around("execution(* org.springframework.boot.CommandLineRunner+.run(..))")
public void handleException(ProceedingJoinPoint joinPoint) {
try {
joinPoint.proceed()
} catch (Exception e) {
System.err.println(e.getMessage())
}
}
}
その他
Spring Boot を使用しているため、CLI アプリとしては、バナー表示やフレームワークログの出力などが気になるので、これらを抑制しておきます。
src/resources/
配下に、以下のファイルをそれぞれ配置することで、CLI アプリには望ましくないログ出力を抑制することができます。
spring:
main:
banner-mode: log
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<appender name="CONSOLE_APPENDER" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
</encoder>
</appender>
<root level="ERROR">
<appender-ref ref="CONSOLE_APPENDER"/>
</root>
</configuration>
起動方法
最後に、作成した CLI アプリの起動方法を確認しておきます。
実行可能 jar をまだ作成していない場合は、Maven から直接起動することになりますが、こちらの場合、パラメタの渡し方に一癖あります。
$ java -jar cli.jar -o oParam nonOptionParam
$ ./mvnw spring-boot:run -Drun.arguments=-o,oParam,nonOptionParam
以上で、Spring Boot を使用して、CLI アプリを作成する上で、必要になりそうな観点は一通り洗えたかと思います。
実際にこれらを取り入れた CLI アプリを作成したので、(Kotlin プロジェクトですが) こちらも参考にしてみてください。
https://github.com/yo1000/pdf2img