123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519 |
- commit bda44b28b3fa32aeeffea322cdad4146a89ce719
- Author: bwcx_jzy <bwcx_jzy@163.com>
- Date: Wed Jun 11 14:27:59 2025 +0800
- refactor(server): 抽离控制台按键事件处理逻辑
-
- - 新增 KeyControl 枚举类,用于定义功能键
- - 新增 KeyEventCycle 类,用于处理按键事件
- - 从 SshHandler 中移除相关的按键处理逻辑
- - 更新应用配置文件,注释掉 Dameng 数据库配置
- diff --git a/modules/server/src/main/java/org/dromara/jpom/socket/handler/KeyControl.java b/modules/server/src/main/java/org/dromara/jpom/socket/handler/KeyControl.java
- new file mode 100644
- index 000000000..720e394c8
- --- /dev/null
- +++ b/modules/server/src/main/java/org/dromara/jpom/socket/handler/KeyControl.java
- @@ -0,0 +1,46 @@
- +package org.dromara.jpom.socket.handler;
- +
- +import java.util.Arrays;
- +
- +/**
- + * 功能键枚举
- + *
- + * @author bwcx_jzy
- + * @since 2025/6/11
- + */
- +public enum KeyControl {
- + KEY_TAB((byte) 9), // TAB
- + KEY_ETX((byte) 3), // Control + C
- + KEY_ENTER((byte) 13), // Enter
- + KEY_SEARCH((byte) 18), // Control + R
- + KEY_BACK((byte) 127), // 退格键
- + KEY_DELETE(new byte[]{27, 91, 51, 126}), // DELETE键
- + KEY_LEFT(new byte[]{27, 91, 68}), // 左
- + KEY_RIGHT(new byte[]{27, 91, 67}), // 右
- + KEY_UP(new byte[]{27, 91, 65}), // 上
- + KEY_DOWN(new byte[]{27, 91, 66}), // 下
- + KEY_HOME(new byte[]{27, 91, 72}),
- + KEY_END(new byte[]{27, 91, 70}),
- + KEY_FUNCTION(new byte[]{27, 91}), //其他功能键
- + KEY_INPUT(new byte[]{-1}); // 正常输入
- +
- + private final byte[] control;
- +
- + KeyControl(byte... control) {
- + this.control = control;
- + }
- +
- + public static KeyControl getKeyControl(byte[] bytes) {
- + for (KeyControl value : KeyControl.values()) {
- + if (Arrays.equals(value.control, bytes)) {
- + return value;
- + }
- + }
- + // 其他功能键
- + if (Arrays.equals(KEY_FUNCTION.control, Arrays.copyOf(bytes, 2))) {
- + return KEY_FUNCTION;
- + }
- + // 正常输入
- + return KEY_INPUT;
- + }
- +}
- diff --git a/modules/server/src/main/java/org/dromara/jpom/socket/handler/KeyEventCycle.java b/modules/server/src/main/java/org/dromara/jpom/socket/handler/KeyEventCycle.java
- new file mode 100644
- index 000000000..ac6da4493
- --- /dev/null
- +++ b/modules/server/src/main/java/org/dromara/jpom/socket/handler/KeyEventCycle.java
- @@ -0,0 +1,201 @@
- +package org.dromara.jpom.socket.handler;
- +
- +import lombok.Setter;
- +import lombok.extern.slf4j.Slf4j;
- +
- +import java.io.ByteArrayOutputStream;
- +import java.nio.charset.Charset;
- +import java.util.Arrays;
- +import java.util.function.Consumer;
- +
- +/**
- + * 控制台案件事件处理
- + *
- + * @author bwcx_jzy
- + * @since 2025/6/11
- + */
- +@Slf4j
- +public class KeyEventCycle {
- + // 输入缓存
- + private StringBuffer buffer = new StringBuffer();
- + // 输入后是否接收返回字符串
- + private boolean inputReceive = false;
- + // TAB 输入暂停(处理Y/N确认)
- + private boolean tabInputPause = false;
- + // 光标位置
- + private int inputSelection = 0;
- + // 搜索状态,0未开始,1开始搜索,2搜索结束
- + private int searchState = 0;
- + @Setter
- + private Charset charset;
- + private KeyControl keyControl = KeyControl.KEY_END;
- + private Consumer<String> consumer;
- +
- + /**
- + * 从控制台读取输入按键进行处理
- + *
- + * @param consumer 完整命令后输入回调
- + * @param bytes 输入按键
- + */
- + public void read(Consumer<String> consumer, byte... bytes) {
- + this.consumer = consumer;
- + String str = new String(bytes, charset);
- + if (keyControl == KeyControl.KEY_TAB && tabInputPause) {
- + if (str.equalsIgnoreCase("y") || str.equalsIgnoreCase("n")) {
- + tabInputPause = false;
- + return;
- + }
- + }
- + keyControl = KeyControl.getKeyControl(bytes);
- + if ((keyControl == KeyControl.KEY_INPUT || keyControl == KeyControl.KEY_FUNCTION) && !tabInputPause) {
- + buffer.insert(inputSelection, str);
- + inputSelection += str.length();
- + } else if (keyControl == KeyControl.KEY_ENTER) {
- + // 回车,结束当前输入周期
- + if (buffer.length() > 0 && searchState != 1) {
- + consumer.accept(buffer.toString());
- + } else if (searchState == 1) {
- + // Control + R结束
- + searchState = 2;
- + }
- + // 重置周期
- + buffer = new StringBuffer();
- + inputReceive = false;
- + inputSelection = 0;
- + } else if (keyControl == KeyControl.KEY_BACK) {
- + buffer.delete(Math.max(inputSelection - 1, 0), inputSelection);
- + inputSelection = Math.max(inputSelection - 1, 0);
- + } else if (keyControl == KeyControl.KEY_DELETE) {
- + buffer.delete(inputSelection, Math.min(inputSelection + 1, buffer.length()));
- + } else if (keyControl == KeyControl.KEY_LEFT) {
- + inputSelection = Math.max(inputSelection - 1, 0);
- + } else if (keyControl == KeyControl.KEY_RIGHT) {
- + inputSelection = Math.min(inputSelection + 1, buffer.length());
- + } else if (keyControl == KeyControl.KEY_HOME) {
- + inputSelection = 0;
- + } else if (keyControl == KeyControl.KEY_END) {
- + inputSelection = buffer.length();
- + } else if (keyControl == KeyControl.KEY_TAB) {
- + inputReceive = true;
- + } else if (keyControl == KeyControl.KEY_UP || keyControl == KeyControl.KEY_DOWN) {
- + // 清空命令缓冲
- + inputSelection = 0;
- + inputReceive = true;
- + } else if (keyControl == KeyControl.KEY_ETX) {
- + buffer = new StringBuffer();
- + inputSelection = 0;
- + } else if (keyControl == KeyControl.KEY_SEARCH) {
- + buffer = new StringBuffer();
- + searchState = 1;
- + }
- + }
- +
- + /**
- + * 从SSH服务端接收字节
- + *
- + * @param bytes 字节
- + */
- + public void receive(byte... bytes) {
- + if (searchState == 2) {
- + // 处理搜索命令结束后,接收到ssh服务器返回的完整命令
- + int index = indexOf(bytes, new byte[]{27, 91, 75});
- + if (index > -1) {
- + bytes = Arrays.copyOf(bytes, index);
- + }
- + String str = new String(bytes, charset).split("# ")[1];
- + consumer.accept(str.trim());
- + searchState = 0;
- + return;
- + }
- + if (inputReceive) {
- + String str = new String(bytes, charset);
- + if (keyControl == KeyControl.KEY_UP || keyControl == KeyControl.KEY_DOWN) {
- + // 上下键只有第一条是正常的,后面的都是根据第一条进行退格删除再补充的。
- + // 8,8,8,99,100,32,47,112,114,50,111,99,47,
- + try {
- + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
- + for (byte aByte : bytes) {
- + if (aByte == 8) {
- + // 首位是退格键,就执行删除末尾值
- + buffer.deleteCharAt(Math.max(buffer.length() - 1, 0));
- + } else if (aByte == 27) {
- + // 遇到【逃离/取消】就跳出循环
- + break;
- + } else if (aByte != 0) {
- + outputStream.write(aByte);
- + }
- + }
- + buffer.append(new String(outputStream.toByteArray(), charset));
- + }
- + inputSelection = buffer.length();
- + } catch (Exception e) {
- + log.error("", e);
- + }
- + return;
- + } else {
- + if (keyControl == KeyControl.KEY_TAB) {
- + if (bytes[0] == 7) {
- + // 接收到终端响铃,就删除响铃
- + bytes = Arrays.copyOfRange(bytes, 1, bytes.length);
- + }
- + if (Arrays.equals(new byte[]{13, 10}, bytes)) {
- + inputReceive = false;
- + return;
- + }
- + // tab下文件很多
- + if (str.contains("y or n")) {
- + tabInputPause = true;
- + inputReceive = false;
- + return;
- + }
- + // cat 'hello word.txt'
- + // cat hello\ word.txt
- + if (str.split(" ").length > 1 && (!str.contains("'") && !str.contains("\\"))) {
- + inputReceive = false;
- + return;
- + }
- + }
- + // 非上下键输入输入中,如果接受到数据就执行插入数据,根据当前光标位置执行插入
- + // 存在退格,就从光标位置开始删除
- + int backCount = 0;
- + for (byte aByte : bytes) {
- + if (aByte == 8) {
- + buffer.deleteCharAt(inputSelection - 1);
- + backCount++;
- + }
- + }
- + str = new String(Arrays.copyOfRange(bytes, 0, bytes.length - backCount), charset);
- + buffer.insert(inputSelection-1, str);
- + inputSelection += str.length();
- + }
- + }
- + inputReceive = false;
- + }
- +
- + /**
- + * 查找指定字节数组在原始字节数组中的位置
- + *
- + * @param originalArray 原始字节数组
- + * @param byteArrayToFind 要查找的字节数组
- + * @return 找到的位置索引,如果找不到返回 -1
- + */
- + private static int indexOf(byte[] originalArray, byte[] byteArrayToFind) {
- + // 遍历原始字节数组,查找匹配的起始位置
- + for (int i = 0; i <= originalArray.length - byteArrayToFind.length; i++) {
- + boolean match = true;
- + for (int j = 0; j < byteArrayToFind.length; j++) {
- + if (originalArray[i + j] != byteArrayToFind[j]) {
- + match = false;
- + break;
- + }
- + }
- + if (match) {
- + return i;
- + }
- + }
- + return -1;
- + }
- +
- +}
- +
- +
- diff --git a/modules/server/src/main/java/org/dromara/jpom/socket/handler/SshHandler.java b/modules/server/src/main/java/org/dromara/jpom/socket/handler/SshHandler.java
- index 57bb5a4e3..965d4cbb0 100644
- --- a/modules/server/src/main/java/org/dromara/jpom/socket/handler/SshHandler.java
- +++ b/modules/server/src/main/java/org/dromara/jpom/socket/handler/SshHandler.java
- @@ -334,231 +334,4 @@ public class SshHandler extends BaseTerminalHandler {
- HANDLER_ITEM_CONCURRENT_HASH_MAP.remove(session.getId());
- SocketSessionUtil.close(session);
- }
- -
- - /**
- - * 控制台案件事件处理
- - */
- - public static class KeyEventCycle {
- -
- - // 输入缓存
- - private StringBuffer buffer = new StringBuffer();
- - // 输入后是否接收返回字符串
- - private boolean inputReceive = false;
- - // TAB 输入暂停(处理Y/N确认)
- - private boolean tabInputPause = false;
- - // 光标位置
- - private int inputSelection = 0;
- - // 搜索状态,0未开始,1开始搜索,2搜索结束
- - private int searchState = 0;
- - @Setter
- - private Charset charset;
- - private KeyControl keyControl = KeyControl.KEY_END;
- - private Consumer<String> consumer;
- -
- - /**
- - * 从控制台读取输入按键进行处理
- - *
- - * @param consumer 完整命令后输入回调
- - * @param bytes 输入按键
- - */
- - public void read(Consumer<String> consumer, byte... bytes) {
- - this.consumer = consumer;
- - String str = new String(bytes, charset);
- - if (keyControl == KeyControl.KEY_TAB && tabInputPause) {
- - if (str.equalsIgnoreCase("y") || str.equalsIgnoreCase("n")) {
- - tabInputPause = false;
- - return;
- - }
- - }
- - keyControl = KeyControl.getKeyControl(bytes);
- - if ((keyControl == KeyControl.KEY_INPUT || keyControl == KeyControl.KEY_FUNCTION) && !tabInputPause) {
- - buffer.insert(inputSelection, str);
- - inputSelection += str.length();
- - } else if (keyControl == KeyControl.KEY_ENTER) {
- - // 回车,结束当前输入周期
- - if (buffer.length() > 0 && searchState != 1) {
- - consumer.accept(buffer.toString());
- - } else if (searchState == 1) {
- - // Control + R结束
- - searchState = 2;
- - }
- - // 重置周期
- - buffer = new StringBuffer();
- - inputReceive = false;
- - inputSelection = 0;
- - } else if (keyControl == KeyControl.KEY_BACK) {
- - buffer.delete(Math.max(inputSelection - 1, 0), inputSelection);
- - inputSelection = Math.max(inputSelection - 1, 0);
- - } else if (keyControl == KeyControl.KEY_DELETE) {
- - buffer.delete(inputSelection, Math.min(inputSelection + 1, buffer.length()));
- - } else if (keyControl == KeyControl.KEY_LEFT) {
- - inputSelection = Math.max(inputSelection - 1, 0);
- - } else if (keyControl == KeyControl.KEY_RIGHT) {
- - inputSelection = Math.min(inputSelection + 1, buffer.length());
- - } else if (keyControl == KeyControl.KEY_HOME) {
- - inputSelection = 0;
- - } else if (keyControl == KeyControl.KEY_END) {
- - inputSelection = buffer.length();
- - } else if (keyControl == KeyControl.KEY_TAB) {
- - inputReceive = true;
- - } else if (keyControl == KeyControl.KEY_UP || keyControl == KeyControl.KEY_DOWN) {
- - // 清空命令缓冲
- - inputSelection = 0;
- - inputReceive = true;
- - } else if (keyControl == KeyControl.KEY_ETX) {
- - buffer = new StringBuffer();
- - inputSelection = 0;
- - } else if (keyControl == KeyControl.KEY_SEARCH) {
- - buffer = new StringBuffer();
- - searchState = 1;
- - }
- - }
- -
- - /**
- - * 从SSH服务端接收字节
- - *
- - * @param bytes 字节
- - */
- - public void receive(byte... bytes) {
- - if (searchState == 2) {
- - // 处理搜索命令结束后,接收到ssh服务器返回的完整命令
- - int index = indexOf(bytes, new byte[]{27, 91, 75});
- - if (index > -1) {
- - bytes = Arrays.copyOf(bytes, index);
- - }
- - String str = new String(bytes, charset).split("# ")[1];
- - consumer.accept(str.trim());
- - searchState = 0;
- - return;
- - }
- - if (inputReceive) {
- - String str = new String(bytes, charset);
- - if (keyControl == KeyControl.KEY_UP || keyControl == KeyControl.KEY_DOWN) {
- - // 上下键只有第一条是正常的,后面的都是根据第一条进行退格删除再补充的。
- - // 8,8,8,99,100,32,47,112,114,50,111,99,47,
- - try {
- - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
- - for (byte aByte : bytes) {
- - if (aByte == 8) {
- - // 首位是退格键,就执行删除末尾值
- - buffer.deleteCharAt(Math.max(buffer.length() - 1, 0));
- - } else if (aByte == 27) {
- - // 遇到【逃离/取消】就跳出循环
- - break;
- - } else if (aByte != 0) {
- - outputStream.write(aByte);
- - }
- - }
- - buffer.append(new String(outputStream.toByteArray(), charset));
- - }
- - inputSelection = buffer.length();
- - } catch (Exception e) {
- - log.error("", e);
- - }
- - return;
- - } else {
- - if (keyControl == KeyControl.KEY_TAB) {
- - if (bytes[0] == 7) {
- - // 接收到终端响铃,就删除响铃
- - bytes = Arrays.copyOfRange(bytes, 1, bytes.length);
- - }
- - if (Arrays.equals(new byte[]{13, 10}, bytes)) {
- - inputReceive = false;
- - return;
- - }
- - // tab下文件很多
- - if (str.contains("y or n")) {
- - tabInputPause = true;
- - inputReceive = false;
- - return;
- - }
- - // cat 'hello word.txt'
- - // cat hello\ word.txt
- - if (str.split(" ").length > 1 && (!str.contains("'") && !str.contains("\\"))) {
- - inputReceive = false;
- - return;
- - }
- - }
- - // 非上下键输入输入中,如果接受到数据就执行插入数据,根据当前光标位置执行插入
- - // 存在退格,就从光标位置开始删除
- - int backCount = 0;
- - for (byte aByte : bytes) {
- - if (aByte == 8) {
- - buffer.deleteCharAt(inputSelection - 1);
- - backCount++;
- - }
- - }
- - str = new String(Arrays.copyOfRange(bytes, 0, bytes.length - backCount), charset);
- - buffer.insert(inputSelection, str);
- - inputSelection += str.length();
- - }
- - }
- - inputReceive = false;
- - }
- -
- - /**
- - * 查找指定字节数组在原始字节数组中的位置
- - *
- - * @param originalArray 原始字节数组
- - * @param byteArrayToFind 要查找的字节数组
- - * @return 找到的位置索引,如果找不到返回 -1
- - */
- - private static int indexOf(byte[] originalArray, byte[] byteArrayToFind) {
- - // 遍历原始字节数组,查找匹配的起始位置
- - for (int i = 0; i <= originalArray.length - byteArrayToFind.length; i++) {
- - boolean match = true;
- - for (int j = 0; j < byteArrayToFind.length; j++) {
- - if (originalArray[i + j] != byteArrayToFind[j]) {
- - match = false;
- - break;
- - }
- - }
- - if (match) {
- - return i;
- - }
- - }
- - return -1;
- - }
- -
- - }
- -
- - /**
- - * 功能键枚举
- - */
- - public enum KeyControl {
- - KEY_TAB((byte) 9), // TAB
- - KEY_ETX((byte) 3), // Control + C
- - KEY_ENTER((byte) 13), // Enter
- - KEY_SEARCH((byte) 18), // Control + R
- - KEY_BACK((byte) 127), // 退格键
- - KEY_DELETE(new byte[]{27, 91, 51, 126}), // DELETE键
- - KEY_LEFT(new byte[]{27, 91, 68}), // 左
- - KEY_RIGHT(new byte[]{27, 91, 67}), // 右
- - KEY_UP(new byte[]{27, 91, 65}), // 上
- - KEY_DOWN(new byte[]{27, 91, 66}), // 下
- - KEY_HOME(new byte[]{27, 91, 72}),
- - KEY_END(new byte[]{27, 91, 70}),
- - KEY_FUNCTION(new byte[]{27, 91}), //其他功能键
- - KEY_INPUT(new byte[]{-1}); // 正常输入
- -
- - private final byte[] control;
- -
- - KeyControl(byte... control) {
- - this.control = control;
- - }
- -
- - public static KeyControl getKeyControl(byte[] bytes) {
- - for (KeyControl value : KeyControl.values()) {
- - if (Arrays.equals(value.control, bytes)) {
- - return value;
- - }
- - }
- - // 其他功能键
- - if (Arrays.equals(KEY_FUNCTION.control, Arrays.copyOf(bytes, 2))) {
- - return KEY_FUNCTION;
- - }
- - // 正常输入
- - return KEY_INPUT;
- - }
- - }
- }
- diff --git a/modules/server/src/main/resources/application.yml b/modules/server/src/main/resources/application.yml
- index 712d90bdc..199af390b 100644
- --- a/modules/server/src/main/resources/application.yml
- +++ b/modules/server/src/main/resources/application.yml
- @@ -160,7 +160,7 @@ spring:
- # active: mysql
- # active: mariadb
- # active: postgresql
- - active: dameng
- + # active: dameng
-
- web:
- resources:
|