java启动时接收自定义参数

命令启动jar包

常用的java applicatoin不仅仅需要 java -jar 并配合-X 和-XX:以及-D 启动就行了,通常都伴随着自定义参数的传递,自定义传递参数有两种形式实现,一种是直接衔接参数值,空格分开,如:

java -jar jfqqq.jar 18 nihao 180

另一种是指定了参数名称再加参数,如:

java -jar jfqqq.jar -age 18 -say nihao -height 180

命令好写,而对应后台的java解析就需要自己开发一下了。

其中第一种很容易解析,就遍历启动main函数的args[]数组即可,先后顺序决定了参数的对应关系。

第二种其实也是在args[]的数组中,比如上述命令打印的话会是这样:

I:\>java -jar jfqqq-jar-with-dependencies.jar -age 18 -say hello -height 180
[-age, 18, -say, hello, -height, 180]

打印的java代码:

public class App {
    public static void main(String[] args) {
        System.out.println(Arrays.toString(args));
    }
}

所以,我们就要想办法把他们解析为我们需要的数据格式,做起来才会更有意思。

下面就针对第二种命令行的解析,来做实现。

解析参数

考虑到参数的扩展性,我们将参数封装到一个pojo类中去,然后使用反射的方式映射字段赋值,这样以后加字段的话直接给pojo增加属性即可。

pojo

针对上面的命令行中,我们需要三个属性:age,say,height。定义pojo:

public class Arg {
    private Integer age;
    private String say;
    private Integer height;

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getSay() {
        return say;
    }

    public void setSay(String say) {
        this.say = say;
    }

    public Integer getHeight() {
        return height;
    }

    public void setHeight(Integer height) {
        this.height = height;
    }
}

解析

我们使用 org.apache.commons.cli.CommandLineParser来完成参数值的提取,同时还需要jackson帮忙反序列化(可选,后面还会提供不依赖jackson,直接使用反射的方式),因此在maven中增加依赖:

        <dependency>
           <groupId>commons-cli</groupId>
           <artifactId>commons-cli</artifactId>
           <version>1.3</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.10.0</version>
        </dependency>

java:

public class App {
    public static void main(String[] args) {
//        System.out.println(Arrays.toString(args)); 输出为: [-age, 18, -say, hello, -height, 180]

        Arg arg = ParseUtil.parse(args);
        System.out.println(arg);
    }
}

public class ParseUtil {
    private static ObjectMapper objectMapper = new ObjectMapper();

    public static Arg parse(String[] args) {
        CommandLineParser parser = new DefaultParser();
        //获取字段
        Field[] declaredFields = Arg.class.getDeclaredFields();
        //使用字段创建options,options是parse需要的参数
        Options options = new Options();
        for (Field declaredField : declaredFields) {
            String name = declaredField.getName();
            Option option = Option.builder(name).argName(name)
                    .desc(name)
                    .hasArg(true)
                    .type(declaredField.getType())
                    .build();
            options.addOption(option);
        }
        try {
            CommandLine cl = parser.parse(options, args);
            Map<String, String> map = new HashMap<>();
            for (Field argsField : declaredFields) {
                String name = argsField.getName();
                map.put(name, cl.getOptionValue(name));
            }
            String s = objectMapper.writeValueAsString(map);
            Arg arg = objectMapper.readValue(s, Arg.class);
            return arg;
        } catch (ParseException | JsonProcessingException e) {
            e.printStackTrace();
            return null;
        }
    }
}

输出结果:

I:\>java -jar jfqqq-jar-with-dependencies.jar -age 18 -say hello -height 180
Arg{age=18, say='hello', height=180}

这里使用了objectMapper来序列化和反序列化,简单粗暴,省去了我们对字段类型的判断等等麻烦。

下面也写出不怕麻烦的使用反射来实例化的方法:


public class ParseUtil {
    private static ObjectMapper objectMapper = new ObjectMapper();

    public static Arg parse(String[] args) {
        CommandLineParser parser = new DefaultParser();
        //获取字段
        Field[] declaredFields = Arg.class.getDeclaredFields();
        //使用字段创建options,options是parse需要的参数
        Options options = new Options();
        for (Field declaredField : declaredFields) {
            String name = declaredField.getName();
            Option option = Option.builder(name).argName(name)
                    .desc(name)
                    .hasArg(true)
                    .type(declaredField.getType())
                    .build();
            options.addOption(option);
        }
        try {
            CommandLine cl = parser.parse(options, args);
            Arg arg = new Arg();
            for (Field declaredField : declaredFields) {
                String optionValue = cl.getOptionValue(declaredField.getName());
                Class<?> type = declaredField.getType();
                declaredField.setAccessible(true);
                Object value = changeType(type, optionValue);
                declaredField.set(arg, value);
            }
            return arg;
        } catch (ParseException | IllegalAccessException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static <T>T changeType(Class<T> clazz, String value) {
        Class<? extends String> aClass = value.getClass();
        try {
            Constructor<T> declaredConstructor = clazz.getDeclaredConstructor(aClass);
            T instance = declaredConstructor.newInstance(value);
            return instance;
        } catch (NoSuchMethodException e) {
            System.out.println("没有string类型的构造函数...无法完成转换...");
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值