1. What is Picocli?
Picocli is a single-file command-line parsing framework that allows you to create command-line applications with little to no code. use @Option
or @Parameters
Comment on the fields in your app, and Picocli will populate them with command line options and positional arguments, respectively. usePicoclito write a powerful command-line program.
pain point
- There is no full-fledged framework to encapsulateParameter receiving、Parameter hintsandParameter validation
- It’s hard to deal with parametersmutually exclusiveas well as the mutuality of specific commandsDependencies
- Commands cannot be madeAutocomplete
- Since the JVM interprets the execution bytecode and the JIT cannot be usedShort-term executionJava command-line programsSlow start
- After integrating SpringBoot and other components, the startup is even slower
2. Code engineering
Experiment purpose: Use Picocli to write an email sending command
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>
Startup class
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
The above are just some of the key codes, all of which can be found in the repositories below
Code repositories
3. Testing
Package the Spring Boot application
mvn install
Go to the target directory
cd target
Execute the command
//send mail
java -jar picocli-1.0-SNAPSHOT.jar --to ss@163.com --subject testmail text 111111
//sub command
java -jar picocli-1.0-SNAPSHOT.jar --to ss@163.com --subject testmail text 111111 add
Print help
java -jar picocli-1.0-SNAPSHOT.jar --help