jpom-parent 485 B

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. commit bda44b28b3fa32aeeffea322cdad4146a89ce719
  2. Author: bwcx_jzy <bwcx_jzy@163.com>
  3. Date: Wed Jun 11 14:27:59 2025 +0800
  4. refactor(server): 抽离控制台按键事件处理逻辑
  5. - 新增 KeyControl 枚举类,用于定义功能键
  6. - 新增 KeyEventCycle 类,用于处理按键事件
  7. - 从 SshHandler 中移除相关的按键处理逻辑
  8. - 更新应用配置文件,注释掉 Dameng 数据库配置
  9. 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
  10. new file mode 100644
  11. index 000000000..720e394c8
  12. --- /dev/null
  13. +++ b/modules/server/src/main/java/org/dromara/jpom/socket/handler/KeyControl.java
  14. @@ -0,0 +1,46 @@
  15. +package org.dromara.jpom.socket.handler;
  16. +
  17. +import java.util.Arrays;
  18. +
  19. +/**
  20. + * 功能键枚举
  21. + *
  22. + * @author bwcx_jzy
  23. + * @since 2025/6/11
  24. + */
  25. +public enum KeyControl {
  26. + KEY_TAB((byte) 9), // TAB
  27. + KEY_ETX((byte) 3), // Control + C
  28. + KEY_ENTER((byte) 13), // Enter
  29. + KEY_SEARCH((byte) 18), // Control + R
  30. + KEY_BACK((byte) 127), // 退格键
  31. + KEY_DELETE(new byte[]{27, 91, 51, 126}), // DELETE键
  32. + KEY_LEFT(new byte[]{27, 91, 68}), // 左
  33. + KEY_RIGHT(new byte[]{27, 91, 67}), // 右
  34. + KEY_UP(new byte[]{27, 91, 65}), // 上
  35. + KEY_DOWN(new byte[]{27, 91, 66}), // 下
  36. + KEY_HOME(new byte[]{27, 91, 72}),
  37. + KEY_END(new byte[]{27, 91, 70}),
  38. + KEY_FUNCTION(new byte[]{27, 91}), //其他功能键
  39. + KEY_INPUT(new byte[]{-1}); // 正常输入
  40. +
  41. + private final byte[] control;
  42. +
  43. + KeyControl(byte... control) {
  44. + this.control = control;
  45. + }
  46. +
  47. + public static KeyControl getKeyControl(byte[] bytes) {
  48. + for (KeyControl value : KeyControl.values()) {
  49. + if (Arrays.equals(value.control, bytes)) {
  50. + return value;
  51. + }
  52. + }
  53. + // 其他功能键
  54. + if (Arrays.equals(KEY_FUNCTION.control, Arrays.copyOf(bytes, 2))) {
  55. + return KEY_FUNCTION;
  56. + }
  57. + // 正常输入
  58. + return KEY_INPUT;
  59. + }
  60. +}
  61. 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
  62. new file mode 100644
  63. index 000000000..ac6da4493
  64. --- /dev/null
  65. +++ b/modules/server/src/main/java/org/dromara/jpom/socket/handler/KeyEventCycle.java
  66. @@ -0,0 +1,201 @@
  67. +package org.dromara.jpom.socket.handler;
  68. +
  69. +import lombok.Setter;
  70. +import lombok.extern.slf4j.Slf4j;
  71. +
  72. +import java.io.ByteArrayOutputStream;
  73. +import java.nio.charset.Charset;
  74. +import java.util.Arrays;
  75. +import java.util.function.Consumer;
  76. +
  77. +/**
  78. + * 控制台案件事件处理
  79. + *
  80. + * @author bwcx_jzy
  81. + * @since 2025/6/11
  82. + */
  83. +@Slf4j
  84. +public class KeyEventCycle {
  85. + // 输入缓存
  86. + private StringBuffer buffer = new StringBuffer();
  87. + // 输入后是否接收返回字符串
  88. + private boolean inputReceive = false;
  89. + // TAB 输入暂停(处理Y/N确认)
  90. + private boolean tabInputPause = false;
  91. + // 光标位置
  92. + private int inputSelection = 0;
  93. + // 搜索状态,0未开始,1开始搜索,2搜索结束
  94. + private int searchState = 0;
  95. + @Setter
  96. + private Charset charset;
  97. + private KeyControl keyControl = KeyControl.KEY_END;
  98. + private Consumer<String> consumer;
  99. +
  100. + /**
  101. + * 从控制台读取输入按键进行处理
  102. + *
  103. + * @param consumer 完整命令后输入回调
  104. + * @param bytes 输入按键
  105. + */
  106. + public void read(Consumer<String> consumer, byte... bytes) {
  107. + this.consumer = consumer;
  108. + String str = new String(bytes, charset);
  109. + if (keyControl == KeyControl.KEY_TAB && tabInputPause) {
  110. + if (str.equalsIgnoreCase("y") || str.equalsIgnoreCase("n")) {
  111. + tabInputPause = false;
  112. + return;
  113. + }
  114. + }
  115. + keyControl = KeyControl.getKeyControl(bytes);
  116. + if ((keyControl == KeyControl.KEY_INPUT || keyControl == KeyControl.KEY_FUNCTION) && !tabInputPause) {
  117. + buffer.insert(inputSelection, str);
  118. + inputSelection += str.length();
  119. + } else if (keyControl == KeyControl.KEY_ENTER) {
  120. + // 回车,结束当前输入周期
  121. + if (buffer.length() > 0 && searchState != 1) {
  122. + consumer.accept(buffer.toString());
  123. + } else if (searchState == 1) {
  124. + // Control + R结束
  125. + searchState = 2;
  126. + }
  127. + // 重置周期
  128. + buffer = new StringBuffer();
  129. + inputReceive = false;
  130. + inputSelection = 0;
  131. + } else if (keyControl == KeyControl.KEY_BACK) {
  132. + buffer.delete(Math.max(inputSelection - 1, 0), inputSelection);
  133. + inputSelection = Math.max(inputSelection - 1, 0);
  134. + } else if (keyControl == KeyControl.KEY_DELETE) {
  135. + buffer.delete(inputSelection, Math.min(inputSelection + 1, buffer.length()));
  136. + } else if (keyControl == KeyControl.KEY_LEFT) {
  137. + inputSelection = Math.max(inputSelection - 1, 0);
  138. + } else if (keyControl == KeyControl.KEY_RIGHT) {
  139. + inputSelection = Math.min(inputSelection + 1, buffer.length());
  140. + } else if (keyControl == KeyControl.KEY_HOME) {
  141. + inputSelection = 0;
  142. + } else if (keyControl == KeyControl.KEY_END) {
  143. + inputSelection = buffer.length();
  144. + } else if (keyControl == KeyControl.KEY_TAB) {
  145. + inputReceive = true;
  146. + } else if (keyControl == KeyControl.KEY_UP || keyControl == KeyControl.KEY_DOWN) {
  147. + // 清空命令缓冲
  148. + inputSelection = 0;
  149. + inputReceive = true;
  150. + } else if (keyControl == KeyControl.KEY_ETX) {
  151. + buffer = new StringBuffer();
  152. + inputSelection = 0;
  153. + } else if (keyControl == KeyControl.KEY_SEARCH) {
  154. + buffer = new StringBuffer();
  155. + searchState = 1;
  156. + }
  157. + }
  158. +
  159. + /**
  160. + * 从SSH服务端接收字节
  161. + *
  162. + * @param bytes 字节
  163. + */
  164. + public void receive(byte... bytes) {
  165. + if (searchState == 2) {
  166. + // 处理搜索命令结束后,接收到ssh服务器返回的完整命令
  167. + int index = indexOf(bytes, new byte[]{27, 91, 75});
  168. + if (index > -1) {
  169. + bytes = Arrays.copyOf(bytes, index);
  170. + }
  171. + String str = new String(bytes, charset).split("# ")[1];
  172. + consumer.accept(str.trim());
  173. + searchState = 0;
  174. + return;
  175. + }
  176. + if (inputReceive) {
  177. + String str = new String(bytes, charset);
  178. + if (keyControl == KeyControl.KEY_UP || keyControl == KeyControl.KEY_DOWN) {
  179. + // 上下键只有第一条是正常的,后面的都是根据第一条进行退格删除再补充的。
  180. + // 8,8,8,99,100,32,47,112,114,50,111,99,47,
  181. + try {
  182. + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
  183. + for (byte aByte : bytes) {
  184. + if (aByte == 8) {
  185. + // 首位是退格键,就执行删除末尾值
  186. + buffer.deleteCharAt(Math.max(buffer.length() - 1, 0));
  187. + } else if (aByte == 27) {
  188. + // 遇到【逃离/取消】就跳出循环
  189. + break;
  190. + } else if (aByte != 0) {
  191. + outputStream.write(aByte);
  192. + }
  193. + }
  194. + buffer.append(new String(outputStream.toByteArray(), charset));
  195. + }
  196. + inputSelection = buffer.length();
  197. + } catch (Exception e) {
  198. + log.error("", e);
  199. + }
  200. + return;
  201. + } else {
  202. + if (keyControl == KeyControl.KEY_TAB) {
  203. + if (bytes[0] == 7) {
  204. + // 接收到终端响铃,就删除响铃
  205. + bytes = Arrays.copyOfRange(bytes, 1, bytes.length);
  206. + }
  207. + if (Arrays.equals(new byte[]{13, 10}, bytes)) {
  208. + inputReceive = false;
  209. + return;
  210. + }
  211. + // tab下文件很多
  212. + if (str.contains("y or n")) {
  213. + tabInputPause = true;
  214. + inputReceive = false;
  215. + return;
  216. + }
  217. + // cat 'hello word.txt'
  218. + // cat hello\ word.txt
  219. + if (str.split(" ").length > 1 && (!str.contains("'") && !str.contains("\\"))) {
  220. + inputReceive = false;
  221. + return;
  222. + }
  223. + }
  224. + // 非上下键输入输入中,如果接受到数据就执行插入数据,根据当前光标位置执行插入
  225. + // 存在退格,就从光标位置开始删除
  226. + int backCount = 0;
  227. + for (byte aByte : bytes) {
  228. + if (aByte == 8) {
  229. + buffer.deleteCharAt(inputSelection - 1);
  230. + backCount++;
  231. + }
  232. + }
  233. + str = new String(Arrays.copyOfRange(bytes, 0, bytes.length - backCount), charset);
  234. + buffer.insert(inputSelection-1, str);
  235. + inputSelection += str.length();
  236. + }
  237. + }
  238. + inputReceive = false;
  239. + }
  240. +
  241. + /**
  242. + * 查找指定字节数组在原始字节数组中的位置
  243. + *
  244. + * @param originalArray 原始字节数组
  245. + * @param byteArrayToFind 要查找的字节数组
  246. + * @return 找到的位置索引,如果找不到返回 -1
  247. + */
  248. + private static int indexOf(byte[] originalArray, byte[] byteArrayToFind) {
  249. + // 遍历原始字节数组,查找匹配的起始位置
  250. + for (int i = 0; i <= originalArray.length - byteArrayToFind.length; i++) {
  251. + boolean match = true;
  252. + for (int j = 0; j < byteArrayToFind.length; j++) {
  253. + if (originalArray[i + j] != byteArrayToFind[j]) {
  254. + match = false;
  255. + break;
  256. + }
  257. + }
  258. + if (match) {
  259. + return i;
  260. + }
  261. + }
  262. + return -1;
  263. + }
  264. +
  265. +}
  266. +
  267. +
  268. 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
  269. index 57bb5a4e3..965d4cbb0 100644
  270. --- a/modules/server/src/main/java/org/dromara/jpom/socket/handler/SshHandler.java
  271. +++ b/modules/server/src/main/java/org/dromara/jpom/socket/handler/SshHandler.java
  272. @@ -334,231 +334,4 @@ public class SshHandler extends BaseTerminalHandler {
  273. HANDLER_ITEM_CONCURRENT_HASH_MAP.remove(session.getId());
  274. SocketSessionUtil.close(session);
  275. }
  276. -
  277. - /**
  278. - * 控制台案件事件处理
  279. - */
  280. - public static class KeyEventCycle {
  281. -
  282. - // 输入缓存
  283. - private StringBuffer buffer = new StringBuffer();
  284. - // 输入后是否接收返回字符串
  285. - private boolean inputReceive = false;
  286. - // TAB 输入暂停(处理Y/N确认)
  287. - private boolean tabInputPause = false;
  288. - // 光标位置
  289. - private int inputSelection = 0;
  290. - // 搜索状态,0未开始,1开始搜索,2搜索结束
  291. - private int searchState = 0;
  292. - @Setter
  293. - private Charset charset;
  294. - private KeyControl keyControl = KeyControl.KEY_END;
  295. - private Consumer<String> consumer;
  296. -
  297. - /**
  298. - * 从控制台读取输入按键进行处理
  299. - *
  300. - * @param consumer 完整命令后输入回调
  301. - * @param bytes 输入按键
  302. - */
  303. - public void read(Consumer<String> consumer, byte... bytes) {
  304. - this.consumer = consumer;
  305. - String str = new String(bytes, charset);
  306. - if (keyControl == KeyControl.KEY_TAB && tabInputPause) {
  307. - if (str.equalsIgnoreCase("y") || str.equalsIgnoreCase("n")) {
  308. - tabInputPause = false;
  309. - return;
  310. - }
  311. - }
  312. - keyControl = KeyControl.getKeyControl(bytes);
  313. - if ((keyControl == KeyControl.KEY_INPUT || keyControl == KeyControl.KEY_FUNCTION) && !tabInputPause) {
  314. - buffer.insert(inputSelection, str);
  315. - inputSelection += str.length();
  316. - } else if (keyControl == KeyControl.KEY_ENTER) {
  317. - // 回车,结束当前输入周期
  318. - if (buffer.length() > 0 && searchState != 1) {
  319. - consumer.accept(buffer.toString());
  320. - } else if (searchState == 1) {
  321. - // Control + R结束
  322. - searchState = 2;
  323. - }
  324. - // 重置周期
  325. - buffer = new StringBuffer();
  326. - inputReceive = false;
  327. - inputSelection = 0;
  328. - } else if (keyControl == KeyControl.KEY_BACK) {
  329. - buffer.delete(Math.max(inputSelection - 1, 0), inputSelection);
  330. - inputSelection = Math.max(inputSelection - 1, 0);
  331. - } else if (keyControl == KeyControl.KEY_DELETE) {
  332. - buffer.delete(inputSelection, Math.min(inputSelection + 1, buffer.length()));
  333. - } else if (keyControl == KeyControl.KEY_LEFT) {
  334. - inputSelection = Math.max(inputSelection - 1, 0);
  335. - } else if (keyControl == KeyControl.KEY_RIGHT) {
  336. - inputSelection = Math.min(inputSelection + 1, buffer.length());
  337. - } else if (keyControl == KeyControl.KEY_HOME) {
  338. - inputSelection = 0;
  339. - } else if (keyControl == KeyControl.KEY_END) {
  340. - inputSelection = buffer.length();
  341. - } else if (keyControl == KeyControl.KEY_TAB) {
  342. - inputReceive = true;
  343. - } else if (keyControl == KeyControl.KEY_UP || keyControl == KeyControl.KEY_DOWN) {
  344. - // 清空命令缓冲
  345. - inputSelection = 0;
  346. - inputReceive = true;
  347. - } else if (keyControl == KeyControl.KEY_ETX) {
  348. - buffer = new StringBuffer();
  349. - inputSelection = 0;
  350. - } else if (keyControl == KeyControl.KEY_SEARCH) {
  351. - buffer = new StringBuffer();
  352. - searchState = 1;
  353. - }
  354. - }
  355. -
  356. - /**
  357. - * 从SSH服务端接收字节
  358. - *
  359. - * @param bytes 字节
  360. - */
  361. - public void receive(byte... bytes) {
  362. - if (searchState == 2) {
  363. - // 处理搜索命令结束后,接收到ssh服务器返回的完整命令
  364. - int index = indexOf(bytes, new byte[]{27, 91, 75});
  365. - if (index > -1) {
  366. - bytes = Arrays.copyOf(bytes, index);
  367. - }
  368. - String str = new String(bytes, charset).split("# ")[1];
  369. - consumer.accept(str.trim());
  370. - searchState = 0;
  371. - return;
  372. - }
  373. - if (inputReceive) {
  374. - String str = new String(bytes, charset);
  375. - if (keyControl == KeyControl.KEY_UP || keyControl == KeyControl.KEY_DOWN) {
  376. - // 上下键只有第一条是正常的,后面的都是根据第一条进行退格删除再补充的。
  377. - // 8,8,8,99,100,32,47,112,114,50,111,99,47,
  378. - try {
  379. - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
  380. - for (byte aByte : bytes) {
  381. - if (aByte == 8) {
  382. - // 首位是退格键,就执行删除末尾值
  383. - buffer.deleteCharAt(Math.max(buffer.length() - 1, 0));
  384. - } else if (aByte == 27) {
  385. - // 遇到【逃离/取消】就跳出循环
  386. - break;
  387. - } else if (aByte != 0) {
  388. - outputStream.write(aByte);
  389. - }
  390. - }
  391. - buffer.append(new String(outputStream.toByteArray(), charset));
  392. - }
  393. - inputSelection = buffer.length();
  394. - } catch (Exception e) {
  395. - log.error("", e);
  396. - }
  397. - return;
  398. - } else {
  399. - if (keyControl == KeyControl.KEY_TAB) {
  400. - if (bytes[0] == 7) {
  401. - // 接收到终端响铃,就删除响铃
  402. - bytes = Arrays.copyOfRange(bytes, 1, bytes.length);
  403. - }
  404. - if (Arrays.equals(new byte[]{13, 10}, bytes)) {
  405. - inputReceive = false;
  406. - return;
  407. - }
  408. - // tab下文件很多
  409. - if (str.contains("y or n")) {
  410. - tabInputPause = true;
  411. - inputReceive = false;
  412. - return;
  413. - }
  414. - // cat 'hello word.txt'
  415. - // cat hello\ word.txt
  416. - if (str.split(" ").length > 1 && (!str.contains("'") && !str.contains("\\"))) {
  417. - inputReceive = false;
  418. - return;
  419. - }
  420. - }
  421. - // 非上下键输入输入中,如果接受到数据就执行插入数据,根据当前光标位置执行插入
  422. - // 存在退格,就从光标位置开始删除
  423. - int backCount = 0;
  424. - for (byte aByte : bytes) {
  425. - if (aByte == 8) {
  426. - buffer.deleteCharAt(inputSelection - 1);
  427. - backCount++;
  428. - }
  429. - }
  430. - str = new String(Arrays.copyOfRange(bytes, 0, bytes.length - backCount), charset);
  431. - buffer.insert(inputSelection, str);
  432. - inputSelection += str.length();
  433. - }
  434. - }
  435. - inputReceive = false;
  436. - }
  437. -
  438. - /**
  439. - * 查找指定字节数组在原始字节数组中的位置
  440. - *
  441. - * @param originalArray 原始字节数组
  442. - * @param byteArrayToFind 要查找的字节数组
  443. - * @return 找到的位置索引,如果找不到返回 -1
  444. - */
  445. - private static int indexOf(byte[] originalArray, byte[] byteArrayToFind) {
  446. - // 遍历原始字节数组,查找匹配的起始位置
  447. - for (int i = 0; i <= originalArray.length - byteArrayToFind.length; i++) {
  448. - boolean match = true;
  449. - for (int j = 0; j < byteArrayToFind.length; j++) {
  450. - if (originalArray[i + j] != byteArrayToFind[j]) {
  451. - match = false;
  452. - break;
  453. - }
  454. - }
  455. - if (match) {
  456. - return i;
  457. - }
  458. - }
  459. - return -1;
  460. - }
  461. -
  462. - }
  463. -
  464. - /**
  465. - * 功能键枚举
  466. - */
  467. - public enum KeyControl {
  468. - KEY_TAB((byte) 9), // TAB
  469. - KEY_ETX((byte) 3), // Control + C
  470. - KEY_ENTER((byte) 13), // Enter
  471. - KEY_SEARCH((byte) 18), // Control + R
  472. - KEY_BACK((byte) 127), // 退格键
  473. - KEY_DELETE(new byte[]{27, 91, 51, 126}), // DELETE键
  474. - KEY_LEFT(new byte[]{27, 91, 68}), // 左
  475. - KEY_RIGHT(new byte[]{27, 91, 67}), // 右
  476. - KEY_UP(new byte[]{27, 91, 65}), // 上
  477. - KEY_DOWN(new byte[]{27, 91, 66}), // 下
  478. - KEY_HOME(new byte[]{27, 91, 72}),
  479. - KEY_END(new byte[]{27, 91, 70}),
  480. - KEY_FUNCTION(new byte[]{27, 91}), //其他功能键
  481. - KEY_INPUT(new byte[]{-1}); // 正常输入
  482. -
  483. - private final byte[] control;
  484. -
  485. - KeyControl(byte... control) {
  486. - this.control = control;
  487. - }
  488. -
  489. - public static KeyControl getKeyControl(byte[] bytes) {
  490. - for (KeyControl value : KeyControl.values()) {
  491. - if (Arrays.equals(value.control, bytes)) {
  492. - return value;
  493. - }
  494. - }
  495. - // 其他功能键
  496. - if (Arrays.equals(KEY_FUNCTION.control, Arrays.copyOf(bytes, 2))) {
  497. - return KEY_FUNCTION;
  498. - }
  499. - // 正常输入
  500. - return KEY_INPUT;
  501. - }
  502. - }
  503. }
  504. diff --git a/modules/server/src/main/resources/application.yml b/modules/server/src/main/resources/application.yml
  505. index 712d90bdc..199af390b 100644
  506. --- a/modules/server/src/main/resources/application.yml
  507. +++ b/modules/server/src/main/resources/application.yml
  508. @@ -160,7 +160,7 @@ spring:
  509. # active: mysql
  510. # active: mariadb
  511. # active: postgresql
  512. - active: dameng
  513. + # active: dameng
  514. web:
  515. resources: