1.什么是Picocli?
Picocli是一个单文件命令行解析框架,它允许您创建命令行应用而几乎不需要代码。使用 @Option
或 @Parameters
在您的应用中注释字段,Picocli将分别使用命令行选项和位置参数填充这些字段。使用Picocli来编写一个功能强大的命令行程序。
痛点
- 没有成熟的框架来封装参数接收 、参数提示 以及参数校验
- 很难处理参数的互斥 以及特定命令的相互依赖关系
- 无法进行命令自动补全
- 由于JVM解释执行字节码,并且JIT无法在短时执行 中发挥作用,Java命令行程序启动缓慢
- 集成SpringBoot及其它组件后,启动更加缓慢
2.代码工程
实现目的:使用Picocli编写一个邮件发送命令
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springboot-demo</artifactId>
<groupId>com.et</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>picocli</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli-spring-boot-starter</artifactId>
<version>4.7.6</version>
</dependency>
<!--email-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
</dependencies>
<!--<build>
<finalName>demo1</finalName>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.et.picocli.MySpringMailer</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
启动类
package com.et.picocli;
import com.et.picocli.command.MailCommand;
import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import picocli.CommandLine;
import picocli.CommandLine.IFactory;
@SpringBootApplication
public class MySpringMailer implements CommandLineRunner, ExitCodeGenerator {
private IFactory factory;
private MailCommand mailCommand;
private int exitCode;
// constructor injection
MySpringMailer(IFactory factory, MailCommand mailCommand) {
this.factory = factory;
this.mailCommand = mailCommand;
}
@Override
public void run(String... args) {
// let picocli parse command line args and run the business logic
exitCode = new CommandLine(mailCommand, factory).execute(args);
}
@Override
public int getExitCode() {
return exitCode;
}
public static void main(String[] args) {
// let Spring instantiate and inject dependencies
System.exit(SpringApplication.exit(SpringApplication.run(MySpringMailer.class, args)));
}
}
service
package com.et.picocli.service;
import java.util.List;
public interface IMailService {
void sendMessage(List<String> to, String subject, String text);
}
package com.et.picocli.service;
import org.slf4j.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.*;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
import java.util.List;
@Service("MailService")
public class MailServiceImpl implements IMailService {
private static final Logger LOGGER= LoggerFactory.getLogger(MailServiceImpl.class);
private static final String NOREPLY_ADDRESS = "noreply@picocli.info";
@Autowired(required = false)
private JavaMailSender emailSender;
@Override
public void sendMessage(List<String> to, String subject, String text) {
LOGGER.info(" start Mail to {} sent! Subject: {}, Body: {}", to, subject, text);
try {
SimpleMailMessage message = new SimpleMailMessage(); // create message
message.setFrom(NOREPLY_ADDRESS); // compose message
for (String recipient : to) { message.setTo(recipient); }
message.setSubject(subject);
message.setText(text);
emailSender.send(message); // send message
LOGGER.info(" end Mail to {} sent! Subject: {}, Body: {}", to, subject, text);
}
catch (MailException e) { e.printStackTrace(); }
}
}
command
package com.et.picocli.command;
import com.et.picocli.service.IMailService;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
import picocli.CommandLine;
import picocli.CommandLine.*;
import java.util.List;
import java.util.concurrent.Callable;
@Component
//@Command(name = "mailCommand")
@CommandLine.Command(
subcommands = {
GitAddCommand.class,
GitCommitCommand.class
}
)
public class
MailCommand implements Callable<Integer> {
@Autowired
private IMailService mailService;
@Option(names = "--to", description = "email(s) of recipient(s)", required = true)
List<String> to;
@Option(names = "--subject", description = "Subject")
String subject;
@Parameters(description = "Message to be sent")
String[] body = {};
public Integer call() throws Exception {
mailService.sendMessage(to, subject, String.join(" ", body));
return 0;
}
}
application.properties
# configuration mail service
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=email
spring.mail.password=password
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
以上只是一些关键代码,所有代码请参见下面代码仓库
代码仓库
3.测试
打包Spring Boot应用程序
mvn install
进入target目录
cd target
执行命令
//发送邮件
java -jar picocli-1.0-SNAPSHOT.jar --to ss@163.com --subject testmail text 111111
//执行子命令
java -jar picocli-1.0-SNAPSHOT.jar --to ss@163.com --subject testmail text 111111 add
打印help
java -jar picocli-1.0-SNAPSHOT.jar --help