# java-command-system
**Repository Path**: gitee-guhong/java-command-system
## Basic Information
- **Project Name**: java-command-system
- **Description**: 这是一个基于Java实现的windows命令行系统。在windows上用熟悉的Java来自定义各种命令。
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: https://gitee.com/gitee-guhong/java-command-system?_from=gitee_search
- **GVP Project**: No
## Statistics
- **Stars**: 11
- **Forks**: 3
- **Created**: 2020-12-04
- **Last Updated**: 2024-10-26
## Categories & Tags
**Categories**: Uncategorized
**Tags**: Linux, Windows, windows命令, java命令
## README
## 零、置顶——注意事项
### 一)、打印
如果你想在终端输出信息,请使用`PrintUtil`工具类。
### 二)、更新步骤
- pull代码到本地
- 运行start.bat
- 执行`reload`命令
### 三)、重大版本变动说明
| 版本号 | 说明 | 重要变动 |
| :----: | :----------------------------------------------------------- | ------------------------------------------------------------ |
| v1.0.0 | 纯粹的黑窗口 | |
| v2.0.0 | 首个有窗口的版本,增加命令历史 | |
| v2.1.2 | 增加命令历史机制 | |
| v2.1.3 | 增加CommandMode机制 | 将`config目录`中的`config.json`文件改为`sys-config.json` |
| v3.0.0 | 1、单独增加输入框,解决了很多问题
2、增加UIManager,为UI和数据之间的交互有了可能
3、命令全部使用异步执行
4、支持动态打印啦 | of 命令的配置文件从config目录改到了data目录,且名字从config.json改为了index.json |
| v3.0.3 | 解决3.0.0版本build之后无法启动的问题(奇怪的问题) | 把用于启动的jar包放到了start目录,删除了原先的lib目录 |
| v3.1.0 | v3正式版 | 1、of 命令的配置文件路径从:data/file/index.json改为data/of/index.json。
2、调整了部分命令的文件路径 |
## 一、项目作用
当你写代码有一定时间了,你会发现,你的手不太愿意离开键盘去碰鼠标,即便你是使用笔记本的触摸板你也不愿意去用鼠标去操作,此时你终于明白`linux`是多么舒服,用命令几乎可以完成所有事,但无奈windows的cmd不会操作,又不想学,最后接受现实,还是要用鼠标去点击各种图标
如果你有上面的苦恼,Java程序员们有福了,只要你下载本项目,就可以实现你的梦想。而且支持自定义命令,各种骚操作等你实现
## 二、特性
- Java天下第一
- 高扩展。可以自定义命令、执行器、解析器等
- 支持windows命令
- 上手0成本
## 三、安装/启动
#### 一)、环境
- windows
- Java 8
#### 二)、安装/启动
下载或clone项目到本地,然后进入`start`目录,运行`start.bat`脚本即可
## 四、目录结构介绍
### 一)、项目结构
```
config // 配置文件目录
document // 命令文档目录,存放命令的介绍
data // 数据目录,用于存放一些数据,如:缓存
start // 启动文件目录
start.bat // 这是打包好后的可执行文件,你可以给它创建一个快捷方式在桌面,方便使用
src // 源码目录
```
### 二)、源码结构
```
constant // 常量文件
dto // 存放数据传输对象,用于加载命令,可扩展
execption // 存放异常
executor // 存放命令执行器,用于执行命令,可扩展
gui // 窗体相关文件
job // 存放“工作”对象,工作就是一个命令要执行的事情
parse // 存放命令解析器,用于解析命令,可扩展
util // 存放工具类
```
## 五、系统运行流程
```
初始化:
读取配置——》加载命令传输对象(CommandDto)——》读取命令到内存
执行命令时:
在输入框中输入命令(CommandInputBox)——》键盘监听:回车(KeyListenerHandler,EnterHandler)——》
命令管理器进行调度(CommandManager)——》命令解析器(CommandParseHandler)——》
命令执行器(CommandExecutor)——》执行工作(CommandJob.run)——》记录命令历史(CommandHistoryManage)
```
## 六、核心类介绍
如果你想现在就知道怎么自定义命令,可以直接跳过核心类的介绍。当然我还是建议你看一看。
[自定义命令](#七自定义命令)
### 一)、CommandJob
`CommandJob`是个接口。
```java
/**
* 获得命令的配置
* @return 返回命令的配置
*/
public CommandConfig getCommandConfig();
/**
* 初始化
* 在命令执行前调用
*/
public default void init() { }
/**
* 初始化
* 在窗口打开后
*/
public default void windowOpened() { }
/**
* 初始化
* 在窗口关闭时
*/
public default void windowClosing() { }
/**
* 开始执行任务
* @param command 命令对象
*/
public void run(Command command);
/**
* 获得命令执行器
* @return 返回命令执行器
*/
public default CommandExecutor getExecutor() {
return new DefaultCommandExecutor();
}
/**
* 获得命令解析器
* @return 返回命令解析器
*/
public default ParseHandler getParseHandler() {
return new DefaultParseHandler();
}
```
其中`getCommandConfig`和`run`方法**必须实现,**如有需要可自行扩展`getParseHandler`和`getExecutor`。分别对应**命令解释器**和**命令执行器**。
`getCommandConfig`方法需要返回一个命令的配置对象,详情请见[**CommandConfig**](#二)CommandConfig)对象
`run`方法就是要执行命令后要运行的代码,该方法会传入一个解析好的[**Command**](#三)Command)对象
`init`方法会在执行命令之前调用,它是一个`defalut`方法,如果你有需要在执行命令前做一些事情就可以实现一下它。
`windowOpened`方法会在窗口打开时执行的一个回调。
`windowClosing`方法会在窗口关闭时执行的一个回调。
### 二)、CommandConfig
命令配置对象
```java
/**
* 是否异步执行
*/
private Boolean isAsynch = false;
/**
* 命令名字
*/
private String commandKey;
/**
* 命令所属组
*/
private String group = "default";
/**
* 命令的参数的配置
* key:参数名
* value:参数是否需要一个值,改值不会为null,除非没有输入该参数
*/
private Map paramConfig = CollectionUtil.newHashMap();
/**
* 命令介绍
*/
private String introduce = "没有任何介绍。。。";
/**
* 命令描述
* 字数限制15个字
*/
private String description = "没有任何描述";
```
该对象用于配置命令,其中`commandKey`是必须的。配置命令时必须遵守下面的规则。当然你可以实现自己的解析器。
```java
* 命令对象规则
* 1、一个命令分为三个部分:
* 命令名 、 命令参数 、 命令值
* 2、命令名是必须的,其他的可以为空
* 3、命令的参数不能是必须的
* 4、命令的值可以多个
```
### 三)、Command
命令对象
```java
/**
* 命令的名字
*/
private String key;
/**
* 命令参数
* 参数名: 参数值
*/
private Map params;
/**
* 命令的值
*/
private List valueList;
```
该对象表示一个解析好后的对象
### 四)、CommandParseHandler
命令解析器,用于解析命令
```java
/**
* 解析命令
* @param commandStr 要执行的命令
* @param commandConfig 命令的配置对象
* @return 返回一个命令对象
* @exception ParseException 解释错误会出现解析错误
*/
public Command parse(@NonNull String commandStr,
@NonNull CommandConfig commandConfig)
throws ParseException;
```
默认通过空格拆分来解析命令,可自行扩展
### 五)、CommandExecutor
命令执行器,解析好命令后会通过执行器执行命令。可自行扩展
```java
/**
* 执行命令
* @param command 执行的命令
* @param commandJob 执行的任务
* @exception ExecuteException 命令执行失败异常
*/
public void execute(Command command, CommandJob commandJob)
throws ExecuteException;
```
### 六)、CommandDto
命令传输对象,用来做命令的持久化,可自行扩展,默认会将命令持久化到json文件,运行时会把命令加载到内存中
```java
/**
* 加载所有工作
* @param packagePath 指定路径,可以多个,如果为空则全盘扫描
* @return 返回工作数据
*/
public Map> load(String... packagePath);
/**
* 重新加载工作
* @param packagePath 指定路径,可以多个,如果为空则全盘扫描
* @return 返回工作数据
*/
public Map> reload(String... packagePath);
/**
* 添加命令,可以多个
* @param commandJobList 命令列表
* @return 成功返回命令列表
*/
public List add(List commandJobList);
/**
* 获得工作列表
* @param group 组名
* @return 返回工作列表
*/
public Collection getCommandJobList(String group);
/**
* 获得指定的工作对象
* @param commandKey 命令名
* @return 返回工作对象
*/
public CommandJob getCommandJob(String commandKey);
```
#### 1、命令数据的数据结构
命令的数据结构是这样的`Map>`
解析如下:
```java
key : groupName
value:
key : commandKey
value: CommandJob对象
```
### 七)、CommandManager
顾名思义,命令管理器,它是一个大管家,你可以通过它获得一切信息
### 八)、GUI相关
2.0版本以后使用了窗体的界面,这样会有更好的交互,同样也会有很多新的问题
`2.0`是个不稳定的版本,要使用的话请选择最新版
#### 1、Terminal
一个抽象的终端接口
```java
package guhong.play.commandsystem.gui.ui.terminal;
/**
* 终端接口
*
* @author : 李双凯
* @date : 2019-11-20 22:32
**/
public interface Terminal {
/**
* 终端上打印
*
* @param message 打印的信息
*/
public void print(String message);
/**
* 终端上换行打印
*
* @param message 打印的消息
*/
public void println(String message);
/**
* 清空打印
*/
public void clear();
/**
* 获得终端上的文本
*/
public String getText();
/**
* 在终端上设置文本
* @param text 文本
*/
public void setText(String text);
}
```
#### 2、KeyListenerHandler
按键监听处理器,我希望在扩展的时候不需要修改核心逻辑,所以,把键盘监听抽象出来,只需要实现这个处理器就能实现对某个按键
的监听。
为了系统正常运行,请不要修改系统自带一下键盘监听处理器。如:`EnterHandler`、`BackspaceHandler`的监听
**注意**:实现该接口的类必须要在`guhong.play.commandsystem.gui.key`包下。
```java
/**
* 键盘监听处理器
* @author : 李双凯
* @date : 2019-11-20 22:32
**/
public interface KeyListenerHandler {
/**
* 是否监听
* @param e 事件对象
* @return 监听返回true
*/
public boolean isListener(KeyEvent e);
/**
* 监听类型
* 详情请见枚举: KeyType
*/
public default KeyType type() {
return KeyType.NOT_PRINT;
}
/**
* 执行
* @param terminal 终端对象
*/
public void execute(Terminal terminal);
}
```
#### 3、CommandContent
> 在3.0的版本中,以及没有这个类了。
这是一个命令的上下文,既在终端中命令的内容。这是为了更加方便获取命令的内容而抽象出来的。你就可
以把它看做是一个命令字符串,终端上输入的命令就是这个对象。
同样,这也是个接口,默认情况下时候`StringBuffer`来存储。
```java
/**
* 命令上下文对象
* @author : 李双凯
* @date : 2019-11-20 22:32
**/
public interface CommandContent {
/**
* 追加
* @param str 命令字符串
*/
public void append(String str);
/**
* 删除一个字符串
*/
public void delete();
/**
* 清空命令
*/
public void clear();
/**
* 获得命令字符串
* @return 返回命令字符串
*/
public String getCommandStr();
}
```
### 九)、CommandMode
命令模式。即控制默认情况下会以什么样的方式去执行命令。简单来说就是在命令找不到时,使用什么方式去处理输入的命令。
主要是为了更加方便 of 命令的使用,现在只需要在命令模式为“OF”的情况下,直接在终端上输入想打开的文
件就可以快速打开。也可以使用`mode [模式名] `来切换。详细用法可以使用`help mode`查看帮助
**注:**
- **该机制在`2.1.3`版本引入。**
- 该机制还无法进行扩展.
### 十)、CommandHistoryManage
> **注:该模块在`2.1.2`才引入。3.0版本移出了GUI范畴**
命令历史管理器,用于记录命令。有了这个之后,可以通过方向键来切换历史命令了。
## 七、自定义命令
终于来到了这里,了解了上面的介绍,自定义命令将变得非常简单
### 一)、步骤
**1、下载源码到本地**
略
**2、继承CommandJob**
打开项目,找个地方创建一个新class,然后让其继承`CommandJob`接口。
**3、reload**
测试好自己写的CommandJob的后,运行项目。然后输入`reload`命令重新加载命令,此时你就可以使用
`list`命令查看到你自定义的命令了
**4、打包项目**
确定命令没问题后,在终端上输入`build`命令,系统将自动帮你打包当前项目。打包后就可以使用
`项目路径/start/start.bat`启动你的命令系统了。
### 二)、例子
**1、下载源码到本地**
略
**2、继承CommandJob**
```java
/**
* 一个用于测试命令的工作
* @author : 李双凯
* @date : 2019-11-20 22:32
**/
@Data
public class CommandTestJob implements CommandJob {
/**
* 这个方法配置命令的一些命令
*
* @return 返回命令的配置
*/
@Override
public CommandConfig getCommandConfig() {
// 设置命令的名字
String commandKey = "test";
// 设置命令的参数
Map paramConfig = CollectionUtil.newHashMap();
// 表示 -a 参数必须有一个值
paramConfig.put("-a", true);
// 表示 -f 参数的值可以为空
paramConfig.put("-f", false);
CommandConfig commandConfig = new SystemCommandConfig(commandKey, paramConfig);
// 设置命令的介绍
commandConfig.setDescription("这是一个测试命令");
return commandConfig;
}
/**
* 开始执行任务
*
* @param command 命令对象
*/
@Override
public void run(Command command) {
// 这里写命令要执行的工作,也就是要做什么事情
// 这里,我们打印出命令的名字、参数和值
PrintUtil.println("commandKey:"+command.getKey());
Map params = command.getParams();
PrintUtil.println("commandParam: ");
for (String key : params.keySet()) {
PrintUtil.println("key: "+key + " | value: " + params.get(key) );
}
PrintUtil.println("commandValue: "+ command.getValueList());
}
}
```
**3、reload**
运行项目,此时输入`list`命令还无法看到我们刚才自定义的命令。所以我们输入`reload`命令重新加载命令
```javacommandsystem
guhong#2021-01-05 22-21 java-command-system/ : list
//......无法看到我们刚才自定义的命令
guhong#2021-01-05 22-21 java-command-system/ : reload
重新加载成功,使用[list]命令查看当前所有命令信息
guhong#2021-01-05 22-21 java-command-system/ : list
----------------------------------------------------------------------------------------------------
| 命令名 | 所属组 | 命令描述 | 执行命令的类 |
----------------------------------------------------------------------------------------------------
// ....
// 这里就出现了我们刚才自定义的命令
| test | system | 这是一个测试命令 | class guhong.play.commandsystem.job.system.job.CommandTestJob |
// .....
----------------------------------------------------------------------------------------------------
guhong#2021-01-05 22-21 java-command-system/ :
```
**4、打包项目**
最后输入`build`命令,系统将自动帮你打包当前项目。
```javacommandsystem
guhong#2021-01-05 22-21 java-command-system/ : build
// 等待一会。出现"打包完成"则表示打包成功
```
## X、以后的计划
- **优化整体代码**