<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      [CLI/Java] 基于 Java 構建 CLI 命令行工具的解決方案

      1 需求背景

      • 排查項目中的各類數據問題,測試人員和開發人員都耗費大量時間,不如將這部分排查工作所需的程序工具化。

      • 為此,稍微調研了一下cli命令行構建框架。

      • 綜合之下,目前筆者選擇的 picocli 框架。感覺其框架的易用性更好。

      • cli 命令行工具與業務工程模塊的區別在于:

      1. 參數/請求的功能、輸入數據,來源于使用者及其電腦本地。

      參數和數據的識別,是一個需要考慮的問題。

      1. 部署位置:電腦本地
      2. 使用人員:后臺支持人員,而非最終的平臺用戶(這種情況極少)。

      2 需求描述

      • 在 Java 項目中實現 CLI(命令行工具)可以通過使用框架如 Picocli 或 Apache Commons CLI 來快速完成。

      這些框架提供了強大的功能來解析命令行參數、生成幫助信息等。

      3 解決方案: 使用 Picocli 框架

      框架介紹

      • Picocli 是一個功能強大且易用的命令行工具開發框架,支持注解驅動開發

      • URL

      實現步驟

      Step1 添加依賴

      • 在 Maven 的 pom.xml 文件中引入 Picocli:
      <dependency>
        <groupId>info.picocli</groupId>
        <artifactId>picocli</artifactId>
        <version>4.7.6</version>
      </dependency>
      

      Step2 創建命令類

      • 使用注解定義命令和選項:
      import picocli.CommandLine;
      import picocli.CommandLine.Command;
      import picocli.CommandLine.Option;
      
      @Command(name = "example", mixinStandardHelpOptions = true, description = "示例 CLI 工具")
      public class ExampleCLI implements Runnable {
      
      	@Option(names = {"-n", "--name"}, description = "用戶名稱")
      	private String name;
      
      	@Override
      	public void run() {
      		System.out.println("Hello, " + (name != null ? name : "World") + "!");
      	}
      
      	public static void main(String[] args) {
      		int exitCode = new CommandLine(new ExampleCLI()).execute(args);
      		System.exit(exitCode);
      	}
      }
      

      Step3 運行程序

      • 編譯并運行程序:
      java -jar example.jar --name=John
      

      案例實踐: xxx-common-helper

      pom.xml

      <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>xxx-common-resource</artifactId>
              <groupId>cn.xxx.bd</groupId>
              <version>1.4.15-SNAPSHOT</version>
              <relativePath>../pom.xml</relativePath>
          </parent>
          <modelVersion>4.0.0</modelVersion>
      
          <artifactId>xxx-common-helper</artifactId>
          <packaging>jar</packaging>
      
          <name>xxx-common-helper</name>
          <url>http://maven.apache.org</url>
      
          <properties>
              <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
              <maven.compiler.source>8</maven.compiler.source>
              <maven.compiler.target>8</maven.compiler.target>
      
              <slf4j.version>1.7.25</slf4j.version>
              <log4j.version>2.20.0</log4j.version>
              <lombok.version>1.18.22</lombok.version>
      
              <xxx-common-resource.version>1.4.15-SNAPSHOT</xxx-common-resource.version>
              <picocli.version>4.7.6</picocli.version>
      
              <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
              <maven-jar-plugin.version>3.2.0</maven-jar-plugin.version>
              <maven-shade-plugin.version>3.2.4</maven-shade-plugin.version>
              <maven-assembly-plugin.version>3.3.0</maven-assembly-plugin.version>
      
          </properties>
      
          <dependencies>
              <dependency>
                  <groupId>junit</groupId>
                  <artifactId>junit</artifactId>
                  <version>${junit.version}</version>
                  <scope>test</scope>
              </dependency>
      
              <!-- log -->
              <dependency>
                  <groupId>org.slf4j</groupId>
                  <artifactId>slf4j-api</artifactId>
                  <version>${slf4j.version}</version>
              </dependency>
              <dependency>
                  <groupId>org.apache.logging.log4j</groupId>
                  <artifactId>log4j-api</artifactId>
                  <version>${log4j.version}</version>
              </dependency>
              <dependency>
                  <groupId>org.apache.logging.log4j</groupId>
                  <artifactId>log4j-core</artifactId>
                  <version>${log4j.version}</version>
              </dependency>
              <dependency>
                  <groupId>org.apache.logging.log4j</groupId>
                  <artifactId>log4j-slf4j-impl</artifactId>
                  <version>${log4j.version}</version>
              </dependency>
              <!-- log [end] -->
      
              <!-- xxx-common-resource [start] -->
              <dependency>
                  <groupId>cn.xxx.bd</groupId>
                  <artifactId>xxx-common-utils</artifactId>
                  <version>${xxx-common-resource.version}</version>
                  <exclusions>
                      <exclusion>
                          <artifactId>slf4j-log4j12</artifactId>
                          <groupId>org.slf4j</groupId>
                      </exclusion>
                      <exclusion>
                          <artifactId>kafka-clients</artifactId>
                          <groupId>org.apache.kafka</groupId>
                      </exclusion>
                      <exclusion>
                          <groupId>mysql</groupId>
                          <artifactId>mysql-connector-java</artifactId>
                      </exclusion>
                  </exclusions>
              </dependency>
              <dependency>
                  <groupId>cn.xxx.bd</groupId>
                  <artifactId>xxx-common-pojo</artifactId>
              </dependency>
              <!-- xxx-common-resource [end] -->
      
              <dependency>
                  <groupId>com.alibaba.fastjson2</groupId>
                  <artifactId>fastjson2</artifactId>
                  <version>${fastjson2.version}</version>
              </dependency>
      
              <!-- command framework -->
              <dependency>
                  <groupId>info.picocli</groupId>
                  <artifactId>picocli</artifactId>
                  <version>${picocli.version}</version>
              </dependency>
          </dependencies>
      
          <build>
              <plugins>
                  <plugin>
                      <groupId>org.apache.maven.plugins</groupId>
                      <artifactId>maven-shade-plugin</artifactId>
                      <version>${maven-shade-plugin.version}</version>
                      <executions>
                          <execution>
                              <phase>package</phase>
                              <goals>
                                  <goal>shade</goal>
                              </goals>
                              <configuration>
                                  <!--                            <shadedArtifactAttached>true</shadedArtifactAttached>-->
                                  <!--                            <shadedClassifierName>fat</shadedClassifierName> &lt;!&ndash; Any name that makes sense &ndash;&gt;-->
                                  <artifactSet>
                                      <excludes>
                                          <!--<exclude>com.google.code.findbugs:jsr305</exclude>-->
                                          <!--             在使用kafka生產消息時,不要過濾                       -->
                                          <!--<exclude>org.slf4j:*</exclude>-->
                                          <!--<exclude>log4j:*</exclude>-->
                                      </excludes>
                                  </artifactSet>
                                  <filters>
                                      <filter>
                                          <!-- Do not copy the signatures in the META-INF folder. Otherwise,
                                              this might cause SecurityExceptions when using the JAR. -->
                                          <artifact>*:*</artifact>
                                          <excludes>
                                              <exclude>META-INF/*.SF</exclude>
                                              <exclude>META-INF/*.DSA</exclude>
                                              <exclude>META-INF/*.RSA</exclude>
                                          </excludes>
                                      </filter>
                                  </filters>
                                  <transformers>
                                      <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
                                      <transformer implementation="org.apache.maven.plugins.shade.resource.ApacheNoticeResourceTransformer">
                                          <projectName>Apache Flink</projectName>
                                          <encoding>${project.build.sourceEncoding}</encoding>
                                      </transformer>
                                      <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                          <mainClass>cn.xxx.bd.common.helper.xxxCommandHelper</mainClass>
                                      </transformer>
                                  </transformers>
                                  <!--                            <minimizeJar>true</minimizeJar>-->
                              </configuration>
                          </execution>
                      </executions>
                  </plugin>
                  <plugin>
                      <groupId>org.apache.maven.plugins</groupId>
                      <artifactId>maven-compiler-plugin</artifactId>
                      <version>${maven-compiler-plugin.version}</version>
                      <configuration>
                          <source>${maven.compiler.source}</source>
                          <target>${maven.compiler.target}</target>
                      </configuration>
                  </plugin>
              </plugins>
          </build>
      </project>
      

      基礎組件

      Constants

      package cn.xxx.bd.common.helper.constants;
      
      /**
       * @author xxxxxx
       * @version v1.0
       * @description ...
       * @refrence-doc
       * @gpt-promt
       */
      public class Constants {
          public final static String CHARSET = "UTF-8";
      
          public static class Parameters {
              public static String COMMAND_PARAM = "command";
          }
      }
      

      CommandEnum

      package cn.xxx.bd.common.helper.enums;
      
      import java.util.ArrayList;
      import java.util.HashMap;
      import java.util.List;
      import java.util.Map;
      
      /**
       * @author xxxxxx
       * @version v1.0
       * @description ...
       * @refrence-doc
       * @gpt-promt
       */
      public enum CommandEnum {
          FILE_COMPRESS("file-compress", "文件解壓縮");
      
          private String command;
          private String description;
      
          private final static String COMMAND_PARAM = "command";
          private final static String DESCRIPTION_PARAM = "description";
      
          CommandEnum(String command, String description) {
              this.command = command;
              this.description = description;
          }
          public static CommandEnum findByCommand(String command) {
              for (CommandEnum type : values()) {
                  if (type.getCommand().equals(command)) {
                      return type;
                  }
              }
              return null;
          }
          public String getCommand() {
              return this.command;
          }
      
          public String getDescription() {
              return this.description;
          }
      
          public static List<Map<String, String>> toList() {
              List<Map<String, String>> list = new ArrayList();//Lists.newArrayList()其實和new ArrayList()幾乎一模
              for (CommandEnum item : CommandEnum.values()) {
                  Map<String, String> map = new HashMap<String, String>();
                  map.put(CommandEnum.COMMAND_PARAM, item.getCommand());
                  map.put(CommandEnum.DESCRIPTION_PARAM, item.getDescription());
                  list.add(map);
              }
              return list;
          }
      
      }
      

      CommandParameters

      package cn.xxx.bd.common.helper.entity;
      
      import lombok.Data;
      import lombok.NoArgsConstructor;
      import lombok.ToString;
      import picocli.CommandLine;
      
      import java.io.File;
      
      /**
       * @author xxxxxx
       * @version v1.0
       * @description 命令行輔助工具的所有必填參數和可選參數
       * @refrence-doc
       * @gpt-promt
       */
      @Data
      @NoArgsConstructor
      @ToString
      public class CommandParameters {
          //必填參數 @CommandLine.Parameters
          @CommandLine.Parameters(index = "0", description = "功能命令")//命令行的第1個參數
          public String command;
      
          //選填參數 @CommandLine.Option
          @CommandLine.Option(names = {"-tc", "--timeConsuming"}, description = "輸出耗時信息")
          public Boolean timeConsuming;
      
          //壓縮算法,可選值: "zstd" / "gzip"
          @CommandLine.Option(names = {"--compress"}, description = "壓縮算法")
          public String compress;
      
          @CommandLine.Option(names = {"--decompress"}, description = "壓縮算法")
          public String decompress;
      
          @CommandLine.Option(names = {"-if", "--inputFile"}, description = "輸入文件")
          private File inputFile;
      
          @CommandLine.Option(names = {"-of", "--outputFile"}, description = "輸出文件")
          private File outputFile;
      
      }
      

      AbstractXxxCommandHelper

      package cn.xxx.bd.common.helper.commands;
      
      import lombok.AllArgsConstructor;
      import lombok.Data;
      import lombok.NoArgsConstructor;
      import lombok.ToString;
      import lombok.extern.slf4j.Slf4j;
      import picocli.CommandLine;
      
      /**
       * @author xxxxxx
       * @version v1.0
       * @description ...
       * @refrence-doc
       * @gpt-promt
       */
      @Slf4j
      @Data
      @ToString
      @NoArgsConstructor
      public abstract class AbstractXxxCommandHelper implements Runnable {
          /**
           * 功能命令 := 用戶輸入的功能 := 用戶輸入的命令
           */
          //@CommandLine.Option(names = {"-cmd", "--command"}, description = "功能命令")
          //@CommandLine.Parameters(index = "0", description = "功能命令")//命令行的第1個參數 //必填參數 @CommandLine.Parameters
          protected String command;
      
          protected Boolean timeConsuming = false;
      
          public AbstractXxxCommandHelper(String command) {
              this.command = command;
          }
      
          public abstract Object execute();
      
          //參數校驗
          public abstract Boolean validate();
      
          @Override
          public void run(){
              Long startTime = System.currentTimeMillis();
              execute();
              Long endTime = System.currentTimeMillis();
              if(!timeConsuming){
                  log.info("Execute the command(`{}`) finished, and its time consuming : {}ms", command, endTime - startTime );
              }
          }
      }
      

      XxxCommandHelper extends AbstractXxxCommandHelper (Entry Class)

      package cn.xxx.bd.common.helper;
      
      import cn.xxx.bd.common.helper.commands.AbstractXxxCommandHelper;
      import cn.xxx.bd.common.helper.commands.file.FileCompressHelper;
      import cn.xxx.bd.common.helper.entity.CommandParameters;
      import cn.xxx.bd.common.helper.enums.CommandEnum;
      import com.alibaba.fastjson2.JSON;
      import picocli.CommandLine;
      
      /**
       * 大數據命令行輔助工具
       * @reference-doc
       * [1] Java 命令行參數解析方式探索(三):Picocli - juejin - https://xie.infoq.cn/article/1da75f148f8f6941793eab7ef
       */
      public abstract class XxxCommandHelper extends AbstractXxxCommandHelper {
          public static void main( String[] args ) {
              //java.util.HashMap@6c284af is not a command: it has no @Command, @Option, @Parameters or @Unmatched annotations
              //Map<String, String> commandParameters = new HashMap<>();
              CommandParameters commandParameters = new CommandParameters();
      
              CommandLine commandLine = new CommandLine(commandParameters);
              CommandLine.Parxxxult argsParxxxult = commandLine.parseArgs(args);
              AbstractXxxCommandHelper commandHelper = getCommandHelper(commandParameters);
      
              commandHelper.execute();
              System.exit(1);
              //int exitCode = commandLine.execute(args);
              //System.exit(exitCode);
          }
      
          private static AbstractXxxCommandHelper getCommandHelper(CommandParameters commandParameters){
              AbstractXxxCommandHelper commandHelper = null;
              CommandEnum commandEnum = CommandEnum.findByCommand( commandParameters.getCommand() );
      
              switch( commandEnum ) {
                  case FILE_COMPRESS: {
                      commandHelper = new FileCompressHelper(
                          commandParameters.getCompress()
                          , commandParameters.getDecompress()
                          , commandParameters.getInputFile()
                          , commandParameters.getOutputFile()
                      );
                      break;
                  }
                  default:
                      throw new RuntimeException(String.format("Not support the command(%s) now!params:%s", commandParameters.getCommand(), JSON.toJSONString( commandParameters ) ) );
              }
      
              return commandHelper;
          }
      }
      

      FileCompressHelper

      package cn.xxx.bd.common.helper.commands.file;
      
      import cn.xxx.bd.common.helper.xxxCommandHelper;
      import cn.xxx.bd.common.helper.constants.Constants;
      import cn.xxx.bd.utils.BytesUtil;
      import cn.xxx.bd.utils.FileUtils;
      import cn.xxx.bd.utils.ZstdUtils;
      import lombok.NonNull;
      import lombok.SneakyThrows;
      import lombok.extern.slf4j.Slf4j;
      import picocli.CommandLine;
      import picocli.CommandLine.Command;
      import picocli.CommandLine.Option;
      
      import java.io.*;
      import java.nio.charset.Charset;
      
      /**
       * @author xxxxxx
       * @version v1.0
       * @description 文件解壓縮工具
       * @refrence-doc
       * @gpt-promt
       */
      //@Command(name = "file-compress", mixinStandardHelpOptions = true, description = "文件解壓縮工具 CLI 工具")
      @Slf4j
      public class FileCompressHelper extends xxxCommandHelper {
      
          //壓縮算法
          //@Option(names = {"--compress"}, description = "用戶名稱")
          private String compress;
      
          //解壓算法
          private String decompress;
      
          //輸入文件 := 待解壓縮的文件
          @NonNull
          private File inputFile;
      
          //輸入文件 := 待解壓縮的文件
          @NonNull
          private File outputFile;
      
          public FileCompressHelper(String compress, String decompress, File inputFile, File outputFile) {
              this.compress = compress;
              this.decompress = decompress;
              this.inputFile = inputFile;
              this.outputFile = outputFile;
              this.validate();
          }
      
      
          @Override
          public Object execute() {
              if( this.compress != null && this.decompress == null ) {//壓縮
                  compress();
              } else if( this.compress == null && this.decompress != null ){//解壓
                  decompress();
              } else {//不知道操作目的
                  throw new RuntimeException( String.format( "Not known operation!compress:%s, decompress:%s", this.compress, this.decompress ) );
              }
              return null;
          }
      
          /**
           * 壓縮
           */
          private void compress() {
              //TODO
          }
      
          /**
           * 解壓
           */
          @SneakyThrows
          private void decompress(){
              InputStream inputFileStream = new FileInputStream( this.inputFile );
              String compressedContentHex = FileUtils.readFile2Str( inputFileStream );//讀取 .hex-bin 格式的文件為文本字符串
              inputFileStream.close();
              byte [] compressedContentBytes = BytesUtil.hexStringToByteArray( compressedContentHex );
              byte [] decompressBytes = new byte [] {};
              String decompressContent = null;
      
              switch (this.decompress) {
                  case "zstd": {
                      decompressBytes = compressedContentHex == null ? decompressBytes : ZstdUtils.decompress( compressedContentBytes );
                      decompressContent = new String( decompressBytes , Charset.forName( Constants.CHARSET ) );
                      break;
                  }
                  default: {
                      throw new RuntimeException("Not support the decompress algorithm!decompress:" + decompress);
                  }
              }
      
              Boolean createNewFileResult = null;
              if(!this.outputFile.exists()){
                  createNewFileResult = this.outputFile.createNewFile();
              }
              OutputStream outputFileStream = new FileOutputStream( this.outputFile );
              outputFileStream.write( decompressBytes );
              outputFileStream.flush();
              outputFileStream.close();
              log.info("Decompress success!decompress:{}, inputFile:{}, outputFile(createNewFileResult:{}):{}", this.decompress, this.inputFile.getAbsoluteFile(), createNewFileResult, this.outputFile.getAbsoluteFile());
          }
      
          @Override
          public Boolean validate(){
              if(this.inputFile == null){
                  throw new RuntimeException("input file param is empty!");
              }
              if(this.outputFile == null){
                  throw new RuntimeException("output file param is empty!");
              }
              if( this.compress == null && this.decompress == null ) {
                  throw new RuntimeException("compress and decompress param is empty!");
              }
              if( this.compress != null && this.decompress != null ) {
                  throw new RuntimeException("both compress and decompress param are not empty!");
              }
              return true;
          }
      }
      

      Use CASE

      • CASE 支持 .hex-bin 文件解壓
      • IDEA:
      file-compress --decompress "zstd" --inputFile "E:\tmp_data\20250827182449.zstd.hex-bin" --outputFile "E:\tmp_data\20250827182449.json"
      
      • Shell:
      java -jar xxx-common-helper-1.4.15-SNAPSHOT.jar file-compress --decompress "zstd" --inputFile "20250827182449.zstd.hex-bin" --outputFile "20250827182449.json"
      

      4 解決方案: 使用 Apache Commons CLI

      框架介紹

      • Apache Commons CLI 是一個輕量級庫,適合處理簡單的命令行參數。

      • URL

      實現步驟

      Step1 添加依賴

      • 在 Maven 的 pom.xml 文件中引入 Apache Commons CLI:
      <dependency>
        <groupId>commons-cli</groupId>
        <artifactId>commons-cli</artifactId>
        <version>1.9.0</version>
      </dependency>
      

      Step2 定義和解析選項

      • 使用 Options 和 CommandLineParser 定義和解析參數:
      import org.apache.commons.cli.*;
      
      public class ExampleCLI {
      	public static void main(String[] args) {
      		Options options = new Options();
      		options.addOption("n", "name", true, "用戶名稱");
      		options.addOption("h", "help", false, "顯示幫助信息");
      
      		CommandLineParser parser = new DefaultParser();
      		HelpFormatter formatter = new HelpFormatter();
      
      		try {
      			CommandLine cmd = parser.parse(options, args);
      
      			if (cmd.hasOption("help")) {
      				formatter.printHelp("example", options);
      				return;
      			}
      
      			String name = cmd.getOptionValue("name", "World");
      			System.out.println("Hello, " + name + "!");
      
      		} catch (ParseException e) {
      			System.out.println(e.getMessage());
      			formatter.printHelp("example", options);
      		}
      	}
      }
      

      Step3 運行程序

      • 編譯并運行程序:
      java -jar example.jar -n John
      

      Z 最佳實踐

      • 選擇框架:Picocli 更適合復雜場景的 CLI 工具開發,而 Apache Commons CLI 更適合簡單場景
      • 生成可執行文件:結合 GraalVM 的 native-image 工具,可以將 Java 程序編譯為跨平臺的可執行文件。
      • 提供幫助信息:確保工具支持 --help 參數,方便用戶了解使用方法。

      Y 推薦文獻

      X 參考文獻

      posted @ 2025-08-27 14:42  千千寰宇  閱讀(51)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 午夜不卡久久精品无码免费| 国内视频偷拍一区,二区,三区| 国产成人拍国产亚洲精品| 西西大胆午夜人体视频| 国产真人无遮挡免费视频| 人妻av一区二区三区av免费| av无码精品一区二区乱子| 婷婷亚洲综合五月天小说| 蜜臀一区二区三区精品免费| 亚洲精品久久久久久久久久吃药| 精品国产精品中文字幕| 99久久无码私人网站| 亚洲精品揄拍自拍首页一| 国产高颜值极品嫩模视频| 日韩精品国产中文字幕| 国产精品九九九一区二区| 欧美三级不卡在线观线看高清 | 国产a级三级三级三级| 精品国产中文字幕av| 国产欧美精品一区二区三区-老狼| 少妇厨房愉情理9仑片视频| 亚洲精品动漫免费二区| 久久羞羞色院精品全部免费| 日产精品久久久久久久| 麻豆精产国品一二三区区| 深夜释放自己在线观看| 亚洲国产色播AV在线| 97国产成人无码精品久久久| 国产精品嫩草99av在线| 久久综合免费一区二区三区| 亚洲国产成人片在线观看无码| 色综合色狠狠天天综合网| 亚洲熟妇av综合一区二区| 国产精品v欧美精品∨日韩| 国内精品亚洲成av人片| 中文字幕国产精品自拍| 国产成人亚洲日韩欧美| 体态丰腴的微胖熟女的特征| 野花社区视频www官网| 久久久久高潮毛片免费全部播放| 日本午夜精品一区二区三区电影|