commit c07515b18c304a2f3cb5bf2c802b872872230a22 Author: dai_48k <1981669259@qq.com> Date: Tue Apr 1 15:58:54 2025 +0800 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..911c624 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ + +# 程序生成 +BKPG/target +BKPG_DEMO/target +BKPG_PROTOCAL/target +PLUGIN_BKPG_GROUP_PROCESS/target + +ext/*.jar + + + +# 个人项目 +PLUGIN_BKPG_Company diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..4c989c1 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/../../../../../:\projects_self\java\BKPG_PROj\.idea/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/artifacts/PLUGIN_BKPG_Company_jar.xml b/.idea/artifacts/PLUGIN_BKPG_Company_jar.xml new file mode 100644 index 0000000..339d191 --- /dev/null +++ b/.idea/artifacts/PLUGIN_BKPG_Company_jar.xml @@ -0,0 +1,8 @@ + + + $PROJECT_DIR$/ext + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..7325d85 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..cedf2b2 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..712ab9d --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__junit_junit_4_11.xml b/.idea/libraries/Maven__junit_junit_4_11.xml new file mode 100644 index 0000000..7ecf64f --- /dev/null +++ b/.idea/libraries/Maven__junit_junit_4_11.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_hamcrest_hamcrest_core_1_3.xml b/.idea/libraries/Maven__org_hamcrest_hamcrest_core_1_3.xml new file mode 100644 index 0000000..4d677a8 --- /dev/null +++ b/.idea/libraries/Maven__org_hamcrest_hamcrest_core_1_3.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__top_dreamcenter_bkpg_BKPG_PROTOCAL_1_0_SNAPSHOT.xml b/.idea/libraries/Maven__top_dreamcenter_bkpg_BKPG_PROTOCAL_1_0_SNAPSHOT.xml new file mode 100644 index 0000000..bfc8e29 --- /dev/null +++ b/.idea/libraries/Maven__top_dreamcenter_bkpg_BKPG_PROTOCAL_1_0_SNAPSHOT.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..aa75cb7 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,21 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..54a8179 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..e96534f --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/BKPG/BKPG.iml b/BKPG/BKPG.iml new file mode 100644 index 0000000..c8cf16d --- /dev/null +++ b/BKPG/BKPG.iml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BKPG/pom.xml b/BKPG/pom.xml new file mode 100644 index 0000000..9259af6 --- /dev/null +++ b/BKPG/pom.xml @@ -0,0 +1,60 @@ + + + + 4.0.0 + + + BKPG_PROj + top.dreamcenter + ${revision} + + + top.dreamcenter.bkpg + BKPG + + BKPG + + + + junit + junit + + + top.dreamcenter.bkpg + BKPG_PROTOCAL + ${revision} + compile + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + jar-with-dependencies + + false + + + top.dreamcenter.bkpg.App + + + + + + make-assembly + package + + single + + + + + + + + diff --git a/BKPG/src/main/java/top/dreamcenter/bkpg/App.java b/BKPG/src/main/java/top/dreamcenter/bkpg/App.java new file mode 100644 index 0000000..8c65ea6 --- /dev/null +++ b/BKPG/src/main/java/top/dreamcenter/bkpg/App.java @@ -0,0 +1,58 @@ +package top.dreamcenter.bkpg; + +import top.dreamcenter.bkpg.ui.MainFrame; + +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.net.URL; + +/** + * 应用管理器 + * + */ +public class App +{ + public static void main(String[] args){ + final MainFrame[] mainFrame = {new MainFrame()}; + mainFrame[0].setVisible(true); + + + if (SystemTray.isSupported()){ + URL url = App.class.getClassLoader().getResource("img/icon.png"); + + + Image icon = Toolkit.getDefaultToolkit().createImage(url); + SystemTray tray = SystemTray.getSystemTray(); + + + PopupMenu popupMenu = new PopupMenu(); + MenuItem reloadItem = new MenuItem("Reload"); + reloadItem.addActionListener(e -> { + mainFrame[0].setVisible(false); + mainFrame[0].reloadFrame(); + mainFrame[0].setVisible(true); + }); + MenuItem exitItem = new MenuItem("Exit"); + exitItem.addActionListener(e -> System.exit(0)); + popupMenu.add(reloadItem); + popupMenu.add(exitItem); + + TrayIcon trayIcon = new TrayIcon(icon, "任务管理器", popupMenu); + trayIcon.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getButton() == 1) { + mainFrame[0].setVisible(!mainFrame[0].isVisible()); + } + } + }); + + try { + tray.add(trayIcon); + } catch (AWTException e) { + e.printStackTrace(); + } + } + } +} diff --git a/BKPG/src/main/java/top/dreamcenter/bkpg/entity/MiniAppJListWrap.java b/BKPG/src/main/java/top/dreamcenter/bkpg/entity/MiniAppJListWrap.java new file mode 100644 index 0000000..31fbc83 --- /dev/null +++ b/BKPG/src/main/java/top/dreamcenter/bkpg/entity/MiniAppJListWrap.java @@ -0,0 +1,23 @@ +package top.dreamcenter.bkpg.entity; + +import top.dreamcenter.bkpg.protocal.MiniApp; + +/** + * 应用包装 + */ +public class MiniAppJListWrap { + private MiniApp miniApp; + + public MiniAppJListWrap(MiniApp miniApp) { + this.miniApp = miniApp; + } + + public MiniApp getMiniApp() { + return miniApp; + } + + @Override + public String toString() { + return miniApp.getName(); + } +} diff --git a/BKPG/src/main/java/top/dreamcenter/bkpg/ui/MainFrame.java b/BKPG/src/main/java/top/dreamcenter/bkpg/ui/MainFrame.java new file mode 100644 index 0000000..dffe732 --- /dev/null +++ b/BKPG/src/main/java/top/dreamcenter/bkpg/ui/MainFrame.java @@ -0,0 +1,98 @@ +package top.dreamcenter.bkpg.ui; + +import top.dreamcenter.bkpg.entity.MiniAppJListWrap; +import top.dreamcenter.bkpg.protocal.MiniApp; +import top.dreamcenter.bkpg.util.MiniAppRegister; + +import javax.swing.*; +import java.awt.*; +import java.net.URL; +import java.util.*; +import java.util.stream.Collectors; + +public class MainFrame extends JFrame { + + + private final HashMap container; + + public MainFrame() { + + container = MiniAppRegister.registerApps(); + + // 基础设置 + setSize(600,400); + setLocationRelativeTo(null); + setLayout(null); + setTitle("JM管理器"); + setResizable(false); + URL resource = MainFrame.class.getClassLoader().getResource("img/icon.png"); + Image icon = Toolkit.getDefaultToolkit().createImage(resource); + setIconImage(icon); + + initializeContent(); + + } + + private void initializeContent() { + + // 面板 + JPanel panel = new JPanel(); + panel.setLayout(new BorderLayout()); + panel.setBounds(156, 2,424,358); + panel.setBackground(new Color(250,250,250)); + panel.add(new JLabel("欢迎使用JM管理器"), BorderLayout.NORTH); + + // 任务列表 + DefaultListModel model = new DefaultListModel<>(); + for (Map.Entry next : container.entrySet()) { + model.addElement(new MiniAppJListWrap(next.getValue())); + } + JList list = new JList<>(model); + list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + list.addListSelectionListener(e -> { + if (!e.getValueIsAdjusting()){ + panel.removeAll(); + + MiniAppJListWrap entity = list.getSelectedValue(); + + panel.add(entity.getMiniApp().getPanel()); + panel.updateUI(); + } + }); + JScrollPane tasksPanelS = new JScrollPane(list); + tasksPanelS.setBounds(2,2,150,358); + + + add(tasksPanelS); + add(panel); + } + + public void reloadFrame() { + + // 1. 保护中的程序列表 + Map protectedApps = container.entrySet().stream() + .filter(item -> item.getValue().protect()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + // 2. 新的程序列表 + HashMap list = MiniAppRegister.registerApps(); + list.forEach((key, value) -> { + if (!protectedApps.containsKey(key)) { + protectedApps.put(key, value); + } + }); + + // 放入容器 + container.clear(); + container.putAll(protectedApps); + + + + getContentPane().removeAll(); + initializeContent(); + + revalidate(); + repaint(); + + } +} diff --git a/BKPG/src/main/java/top/dreamcenter/bkpg/util/JarFileFilter.java b/BKPG/src/main/java/top/dreamcenter/bkpg/util/JarFileFilter.java new file mode 100644 index 0000000..ddab804 --- /dev/null +++ b/BKPG/src/main/java/top/dreamcenter/bkpg/util/JarFileFilter.java @@ -0,0 +1,12 @@ +package top.dreamcenter.bkpg.util; + +import java.io.File; +import java.io.FilenameFilter; + +public class JarFileFilter implements FilenameFilter { + + @Override + public boolean accept(File dir, String name) { + return name.endsWith(".jar"); + } +} diff --git a/BKPG/src/main/java/top/dreamcenter/bkpg/util/MiniAppRegister.java b/BKPG/src/main/java/top/dreamcenter/bkpg/util/MiniAppRegister.java new file mode 100644 index 0000000..2349e9b --- /dev/null +++ b/BKPG/src/main/java/top/dreamcenter/bkpg/util/MiniAppRegister.java @@ -0,0 +1,95 @@ +package top.dreamcenter.bkpg.util; + +import top.dreamcenter.bkpg.protocal.MiniApp; +import top.dreamcenter.bkpg.protocal.MiniAppGroup; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + * 应用注册器 + */ +public class MiniAppRegister { + /** + * 注册 ext 文件夹下的扩展应用 + * @return + */ + public static HashMap registerApps() { + HashMap miniAppContainer = new HashMap<>(); + + Class miniAppClass = MiniApp.class; + Class miniAppGroupClass = MiniAppGroup.class; + + // 找到ext 文件夹 并且初始化ext路径类加载器 + String extDirectory = "ext"; + File file = new File(extDirectory); + + // 解析ext 目录下的 Jar文件 + File[] files = file.listFiles(new JarFileFilter()); + if (files == null) return new HashMap<>(); + + // 遍历jar文件 + for (File tmp : files) { + JarFile jarFile = null; + try { + jarFile = new JarFile("/" + tmp.getAbsoluteFile()); + } catch (IOException e) { + e.printStackTrace(); + } + + // 解析jar包 + if (jarFile != null) { + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()){ + JarEntry jarEntry = entries.nextElement(); + // 解析class文件 + if (jarEntry.getName().endsWith(".class") && !jarEntry.getName().contains("$")){ + String classRoute = jarEntry.getName().replaceAll("/", ".").replace(".class", ""); + + try { + // 装载类 + URLClassLoader loader = new URLClassLoader(new URL[]{tmp.toURI().toURL()}); + Class clazz = loader.loadClass(classRoute); + + // 校验是否符合协议 + if (miniAppClass.isAssignableFrom(clazz)) { // 单应用 + // 注册进容器 + Object obj = clazz.getConstructor().newInstance(); + miniAppContainer.put(classRoute, (MiniApp) obj); + } else if(miniAppGroupClass.isAssignableFrom(clazz)){ // 组合应用 + // 注册进容器 + Object obj = clazz.getConstructor().newInstance(); + MiniAppGroup group = (MiniAppGroup) obj; + List miniApps = group.getMiniApps(); + + // 检查返回值是否为空,如果为空则不处理 + if (miniApps != null) { + for (int i = 0; i < miniApps.size(); i++) { + MiniApp app = miniApps.get(i); + miniAppContainer.put(classRoute + "-" + app.getName(), app); + } + } + + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + } + + + // 返回结果 + return miniAppContainer; + } + +} diff --git a/BKPG/src/main/resources/META-INF/MANIFEST.MF b/BKPG/src/main/resources/META-INF/MANIFEST.MF new file mode 100644 index 0000000..17375ff --- /dev/null +++ b/BKPG/src/main/resources/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: top.dreamcenter.bkpg.App + diff --git a/BKPG/src/main/resources/img/icon.png b/BKPG/src/main/resources/img/icon.png new file mode 100644 index 0000000..54c3b2a Binary files /dev/null and b/BKPG/src/main/resources/img/icon.png differ diff --git a/BKPG/src/test/java/top/dreamcenter/bkpg/AppTest.java b/BKPG/src/test/java/top/dreamcenter/bkpg/AppTest.java new file mode 100644 index 0000000..65d435c --- /dev/null +++ b/BKPG/src/test/java/top/dreamcenter/bkpg/AppTest.java @@ -0,0 +1,20 @@ +package top.dreamcenter.bkpg; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +/** + * Unit test for simple App. + */ +public class AppTest +{ + /** + * Rigorous Test :-) + */ + @Test + public void shouldAnswerWithTrue() + { + assertTrue( true ); + } +} diff --git a/BKPG_DEMO/BKPG_DEMO.iml b/BKPG_DEMO/BKPG_DEMO.iml new file mode 100644 index 0000000..71cf44a --- /dev/null +++ b/BKPG_DEMO/BKPG_DEMO.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BKPG_DEMO/pom.xml b/BKPG_DEMO/pom.xml new file mode 100644 index 0000000..fd589bc --- /dev/null +++ b/BKPG_DEMO/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + + + BKPG_PROj + top.dreamcenter + ${revision} + + + top.dreamcenter.bkpg + BKPG_DEMO + + + + top.dreamcenter.bkpg + BKPG_PROTOCAL + ${revision} + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + ${project.parent.basedir}/ext + + + + + + \ No newline at end of file diff --git a/BKPG_DEMO/src/main/java/top/dreamcenter/bkpg/demo/DemoApp.java b/BKPG_DEMO/src/main/java/top/dreamcenter/bkpg/demo/DemoApp.java new file mode 100644 index 0000000..77e7940 --- /dev/null +++ b/BKPG_DEMO/src/main/java/top/dreamcenter/bkpg/demo/DemoApp.java @@ -0,0 +1,28 @@ +package top.dreamcenter.bkpg.demo; + +import top.dreamcenter.bkpg.demo.ui.MainPanel; +import top.dreamcenter.bkpg.protocal.MiniApp; + +import javax.swing.*; + +public class DemoApp implements MiniApp { + + private static final String DEMO_APP = "案例程序"; + + @Override + public String getName() { + return DEMO_APP; + } + + @Override + public JPanel getPanel() { + MainPanel mainPanel = new MainPanel(); + mainPanel.add(new JLabel(getName())); + return mainPanel; + } + + @Override + public boolean protect() { + return false; + } +} diff --git a/BKPG_DEMO/src/main/java/top/dreamcenter/bkpg/demo/DemoApp2.java b/BKPG_DEMO/src/main/java/top/dreamcenter/bkpg/demo/DemoApp2.java new file mode 100644 index 0000000..f9d097a --- /dev/null +++ b/BKPG_DEMO/src/main/java/top/dreamcenter/bkpg/demo/DemoApp2.java @@ -0,0 +1,17 @@ +package top.dreamcenter.bkpg.demo; + +import top.dreamcenter.bkpg.protocal.template.ProcessAppTemplate; + +public class DemoApp2 extends ProcessAppTemplate { + private static final String DEMO_APP = "案例程序2"; + + @Override + public String getName() { + return DEMO_APP; + } + + @Override + public String getCmdStr() { + return "ping 81.70.80.152 -t"; + } +} diff --git a/BKPG_DEMO/src/main/java/top/dreamcenter/bkpg/demo/DemoApp3.java b/BKPG_DEMO/src/main/java/top/dreamcenter/bkpg/demo/DemoApp3.java new file mode 100644 index 0000000..7b9e4f1 --- /dev/null +++ b/BKPG_DEMO/src/main/java/top/dreamcenter/bkpg/demo/DemoApp3.java @@ -0,0 +1,15 @@ +package top.dreamcenter.bkpg.demo; + +import top.dreamcenter.bkpg.protocal.template.ProcessAppTemplate; + +public class DemoApp3 extends ProcessAppTemplate { + @Override + public String getName() { + return "案例程序3"; + } + + @Override + public String getCmdStr() { + return "ipconfig"; + } +} diff --git a/BKPG_DEMO/src/main/java/top/dreamcenter/bkpg/demo/DemoGroupApp.java b/BKPG_DEMO/src/main/java/top/dreamcenter/bkpg/demo/DemoGroupApp.java new file mode 100644 index 0000000..511690f --- /dev/null +++ b/BKPG_DEMO/src/main/java/top/dreamcenter/bkpg/demo/DemoGroupApp.java @@ -0,0 +1,35 @@ +package top.dreamcenter.bkpg.demo; + +import top.dreamcenter.bkpg.protocal.MiniApp; +import top.dreamcenter.bkpg.protocal.MiniAppGroup; +import top.dreamcenter.bkpg.protocal.template.ProcessAppTemplate; + +import java.util.LinkedList; +import java.util.List; + +public class DemoGroupApp implements MiniAppGroup { + @Override + public List getMiniApps() { + + List list = new LinkedList<>(); + + for (int i = 0; i < 3; i++) { + int finalI = i; + MiniApp miniApp = new ProcessAppTemplate() { + @Override + public String getCmdStr() { + return "ping www.baidu.com -n " + (finalI + 1); + } + + @Override + public String getName() { + return "GroupDemo" + finalI; + } + }; + list.add(miniApp); + } + + return list; + } + +} diff --git a/BKPG_DEMO/src/main/java/top/dreamcenter/bkpg/demo/ui/MainPanel.java b/BKPG_DEMO/src/main/java/top/dreamcenter/bkpg/demo/ui/MainPanel.java new file mode 100644 index 0000000..5497877 --- /dev/null +++ b/BKPG_DEMO/src/main/java/top/dreamcenter/bkpg/demo/ui/MainPanel.java @@ -0,0 +1,15 @@ +package top.dreamcenter.bkpg.demo.ui; + +import javax.swing.*; + +public class MainPanel extends JPanel { + + public MainPanel() { + + JLabel label = new JLabel("这是一个demo"); + + add(label); + setVisible(true); + } + +} diff --git a/BKPG_PROTOCAL/BKPG_PROTOCAL.iml b/BKPG_PROTOCAL/BKPG_PROTOCAL.iml new file mode 100644 index 0000000..04b1188 --- /dev/null +++ b/BKPG_PROTOCAL/BKPG_PROTOCAL.iml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BKPG_PROTOCAL/pom.xml b/BKPG_PROTOCAL/pom.xml new file mode 100644 index 0000000..e514314 --- /dev/null +++ b/BKPG_PROTOCAL/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + top.dreamcenter.bkpg + BKPG_PROTOCAL + 1.0-SNAPSHOT + + + UTF-8 + 8 + 8 + + + \ No newline at end of file diff --git a/BKPG_PROTOCAL/src/main/java/top/dreamcenter/bkpg/protocal/MiniApp.java b/BKPG_PROTOCAL/src/main/java/top/dreamcenter/bkpg/protocal/MiniApp.java new file mode 100644 index 0000000..06264b1 --- /dev/null +++ b/BKPG_PROTOCAL/src/main/java/top/dreamcenter/bkpg/protocal/MiniApp.java @@ -0,0 +1,27 @@ +package top.dreamcenter.bkpg.protocal; + +import javax.swing.*; + +/** + * 程序基类 + */ +public interface MiniApp { + + /** + * 获取应用名称 + * @return 应用名称 + */ + String getName(); + + /** + * 获取应用面板 + * @return 面板 + */ + JPanel getPanel(); + + /** + * 保护应用,重启的时候是否重新装载 + * @return + */ + boolean protect(); +} diff --git a/BKPG_PROTOCAL/src/main/java/top/dreamcenter/bkpg/protocal/MiniAppGroup.java b/BKPG_PROTOCAL/src/main/java/top/dreamcenter/bkpg/protocal/MiniAppGroup.java new file mode 100644 index 0000000..e67c51c --- /dev/null +++ b/BKPG_PROTOCAL/src/main/java/top/dreamcenter/bkpg/protocal/MiniAppGroup.java @@ -0,0 +1,16 @@ +package top.dreamcenter.bkpg.protocal; + +import java.util.List; + +/** + * 程序组合包 + */ +public interface MiniAppGroup { + + /** + * 获取所有的组合 + * @return 组合 + */ + List getMiniApps(); + +} diff --git a/BKPG_PROTOCAL/src/main/java/top/dreamcenter/bkpg/protocal/template/ProcessAppTemplate.java b/BKPG_PROTOCAL/src/main/java/top/dreamcenter/bkpg/protocal/template/ProcessAppTemplate.java new file mode 100644 index 0000000..f1d6d7d --- /dev/null +++ b/BKPG_PROTOCAL/src/main/java/top/dreamcenter/bkpg/protocal/template/ProcessAppTemplate.java @@ -0,0 +1,191 @@ +package top.dreamcenter.bkpg.protocal.template; + +import top.dreamcenter.bkpg.protocal.MiniApp; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.concurrent.TimeUnit; + +/** + * 进程启动模板 + */ +public abstract class ProcessAppTemplate implements MiniApp, ActionListener { + + private Process process; + + private JTextArea textArea; + + private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + /** + * 需要执行的命令 + * @return CMD命令 + */ + public abstract String getCmdStr(); + + @Override + public JPanel getPanel() { + JPanel panel = new JPanel(); + panel.setLayout(new BorderLayout()); + panel.setBackground(Color.WHITE); + + JPanel centerPanel = new JPanel(); + centerPanel.setLayout(new FlowLayout()); + centerPanel.setBackground(Color.WHITE); + + // 标题 + JLabel title = new JLabel(getName()); + + // 按钮组 + JButton startBtn = new JButton("启动"); + JButton stopBtn = new JButton("停止"); + + startBtn.setBackground(Color.WHITE); + stopBtn.setBackground(Color.WHITE); + + startBtn.addActionListener(this); + stopBtn.addActionListener(this); + + startBtn.setActionCommand("start"); + stopBtn.setActionCommand("stop"); + + centerPanel.add(startBtn); + centerPanel.add(stopBtn); + + // 输出 + if (textArea == null) { + textArea = new JTextArea(); + } + textArea.setBackground(Color.DARK_GRAY); + textArea.setForeground(Color.WHITE); + textArea.setRows(15); + JScrollPane scrollPane = new JScrollPane(textArea); + + panel.add(title, BorderLayout.NORTH); + panel.add(centerPanel, BorderLayout.CENTER); + panel.add(scrollPane, BorderLayout.SOUTH); + + return panel; + } + + @Override + public void actionPerformed(ActionEvent e) { + switch (e.getActionCommand()){ + case "start": btnStartMethod(); break; + case "stop": btnStopMethod(); break; + default: + System.out.println("未找到的命令:" + e.getActionCommand()); + } + } + + /** + * 按钮 - 启动 + */ + private void btnStartMethod() { + new Thread(() -> { + successWrite("尝试启动程序..."); + if (process != null) { + failWrite("已启动过。"); + return; + } + try { + process = Runtime.getRuntime().exec(getCmdStr()); + successWrite("启动成功!"); + heartbeatCheck(); + String tmp; + + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK")); + BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "GBK")); + + while ((tmp = reader.readLine()) != null) { + successWrite(tmp); + } + + while ((tmp = errReader.readLine()) != null) { + failWrite(tmp); + } + + reader.close(); + errReader.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + }).start(); + } + + /** + * 按钮 - 停止 + */ + private void btnStopMethod() { + if (process ==null) { + failWrite("未启动。"); + return; + } + if (process.isAlive()) process.destroy(); + process = null; + successWrite("已终止。"); + } + + + /** + * 写入正确信息 + * @param raw 原文 + */ + private void successWrite(String raw) { + textArea.append(formatOutput(true, raw)); + } + + /** + * 写入错误信息 + * @param raw 原文 + */ + private void failWrite(String raw) { + textArea.append(formatOutput(false, raw)); + } + + /** + * 输出格式化 + * @param code 是否成功结果 + * @param raw 原文 + * @return 输出结果 + */ + private String formatOutput(boolean code,String raw) { + return (code ? "O" : "E") + " " + dateFormat.format(Calendar.getInstance().getTime()) + " " + raw + "\n"; + } + + /** + * 5 分钟心跳检测,如果心跳停止,则自动释放进程 + */ + private void heartbeatCheck() { + new Thread(() -> { + while (true) { + if (process == null) break; + else if (!process.isAlive()) { + failWrite("心跳停止"); + process.destroy(); + process = null; + successWrite("已释放资源"); + break; + } + try { + TimeUnit.SECONDS.sleep(5); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }).start(); + } + + @Override + public boolean protect() { + return process != null && process.isAlive(); + } +} diff --git a/BKPG_PROj.iml b/BKPG_PROj.iml new file mode 100644 index 0000000..c035f0b --- /dev/null +++ b/BKPG_PROj.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PLUGIN_BKPG_GROUP_PROCESS/PLUGIN_BKPG_GROUP_PROCESS.iml b/PLUGIN_BKPG_GROUP_PROCESS/PLUGIN_BKPG_GROUP_PROCESS.iml new file mode 100644 index 0000000..4ccc645 --- /dev/null +++ b/PLUGIN_BKPG_GROUP_PROCESS/PLUGIN_BKPG_GROUP_PROCESS.iml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PLUGIN_BKPG_GROUP_PROCESS/pom.xml b/PLUGIN_BKPG_GROUP_PROCESS/pom.xml new file mode 100644 index 0000000..0129a28 --- /dev/null +++ b/PLUGIN_BKPG_GROUP_PROCESS/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + + + BKPG_PROj + top.dreamcenter + ${revision} + + + top.dreamcenter.bkpg.plugin.group + PLUGIN_BKPG_GROUP_PROCESS + + PLUGIN_BKPG_GROUP_PROCESS + + + + top.dreamcenter.bkpg + BKPG_PROTOCAL + ${revision} + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + ${project.parent.basedir}/ext + + + + + + \ No newline at end of file diff --git a/PLUGIN_BKPG_GROUP_PROCESS/src/main/java/top/dreamcenter/bkpg/group/ProcessGroupApp.java b/PLUGIN_BKPG_GROUP_PROCESS/src/main/java/top/dreamcenter/bkpg/group/ProcessGroupApp.java new file mode 100644 index 0000000..42bf796 --- /dev/null +++ b/PLUGIN_BKPG_GROUP_PROCESS/src/main/java/top/dreamcenter/bkpg/group/ProcessGroupApp.java @@ -0,0 +1,52 @@ +package top.dreamcenter.bkpg.group; + +import top.dreamcenter.bkpg.protocal.MiniApp; +import top.dreamcenter.bkpg.protocal.MiniAppGroup; +import top.dreamcenter.bkpg.protocal.template.ProcessAppTemplate; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.util.LinkedList; +import java.util.List; + +public class ProcessGroupApp implements MiniAppGroup { + @Override + public List getMiniApps() { + + List list = new LinkedList<>(); + + + try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("ext/ProgressGroup.txt")))) { + + String line; + while ((line = reader.readLine()) != null) { + String[] split = line.split(": "); + + String appName = split[0]; + String appCmd = split[1]; + + MiniApp miniApp = new ProcessAppTemplate() { + @Override + public String getCmdStr() { + return appCmd; + } + + @Override + public String getName() { + return appName; + } + }; + + list.add(miniApp); + } + + } catch (Exception e){ + System.err.println(e.getMessage()); + return list; + } + + return list; + } + +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..3d518ca --- /dev/null +++ b/README.md @@ -0,0 +1,118 @@ + +## 项目架构 + +主工程 + +模块 | 作用 +--- | --- +BKPG | 主应用程序 +BKPG_PROTOCAL | 三方扩展协议 +BKPG_DEMO | 简单示例扩展 + +官方扩展插件工程 + +模块 | 作用 +--- | --- +PLUGIN_BKPG_GROUP_PROCESS | 命令组 + + +## 生产环境 + +- JAVA : 8 + +## 主应用程序执行逻辑 + +1. 应用启动,绘制UI,挂载到系统托盘 +2. 扫描注册ext目录下的jar包(扫描实现了MiniApp的类) +3. 程序挂载 + +## 扩展协议 + +### 可用协议 + +```text +MiniApp 基础协议 + ┗ ProcessAppTemplate 命令执行协议模板 +↑ +MiniAppGroup 程序组合包 +``` + +### 协议结构定义 + +MiniApp + - String getName(); // 获取应用名称 + - JPanel getPanel(); // 获取应用面板 + - boolean protect(); // 保护应用,重启是否重新装载 + +MiniAppGroup + - List\ getMiniApps(); // 获取所有的应用 + +ProcessAppTemplate: MiniApp + - String getName(); // 获取应用名称 + - String getCmdStr(); // 需要执行的命令 + - 其余基类函数已默认实现 + + +### 详细说明 + +**MiniApp** 为基础协议,所有的扩展实现都需要继承或者实现该协议, +主应用程序只会扫描到实现了该接口的类,并且注册到容器中。 +MiniAppGroup是对MiniApp的扩展,旨在一次性批量注入MiniApp, +同样也会被扫描到,其下的miniApp也都会被注册。 + +MiniApp中,getName 是用于获取任务名称的,不用担心重复导致程序异常 +(因为注册时采用的是类完整访问路径注册的), 不过建议名称具有标志性, +这样才能快速识别该任务所具备的特质。 + +getPanel 是绘制的面板,即右面板,实际的操作区,可以自定义, +也可以采用模板快速构建(如ProcessAppTemplate)。 +如果自定义,或者制作模板,需要注意以下几点: + +1. 长连接的任务,强烈建议做好资源的调度,适量增加 任务控制按钮 + (启动、终止);如果可监测,建议增加连接心跳监测机制, + 在一定时间后,自动断开连接。 +2. 从A任务切换到B任务,A任务面板会销毁,调用B任务面板, + 但是任务的实例不会销毁,所以,你可以将一些数据存于全局变量来存储 + 上一会话的某些状态量。 +3. 主程序面板的大小是固定的,所以,为了界面协调,建议纵向布局, + 并且内容较多的话,适量增加滚动条。 +4. 任务自身不建议开辟太大的内存空间,以免出现任务切换卡顿现象, + 如果一定要用大量内存,也做好完备的内存管控,避免出现OOM的情况。 + +protect() 是保护函数,如果返回true,则表示在BKPG进行RELOAD时,该App不会被注销, +而是保持实例不变,状态也都保持。这通常作为服务器服务非常关键,比如想要添加一个指令, +需要RELOAD但是原有服务不能关闭,如果设置为true就可以实现保护。 + +**ProcessAppTemplate** 为命令执行协议模板,为抽象类,继承实现了MiniApp接口, +用于执行命令行指令,需要实现两个接口,一个是getName,作用同上,另外一个是该抽象类 +独有的,getCmdStr,需要设置命令行的完整执行指令。当点击面板的执行按钮时, +会启动一个线程来执行该命令,并且每5s会检测一次命令心跳,如果心跳失去连接, +则会释放资源。可以作为一些应用或者服务的启动端。 + + +为了更加高效的添加命令(常用), +官方内置了一个命令AppGroup: **PLUGIN_BKPG_GROUP_PROCESS** 。 +通过配置ext/ProgressGroup.txt来添加指令应用, +指令名称和指令用英文冒号和一个空格隔开【: 】,会自动创建多组ProcessAppTemplate。 + + + +### 第三方扩展指南 +首先,下载BKPG_PROTOCAL协议JAR包,引入自己的项目中,作为环境依赖。 +之后在自己项目中实现MiniApp/MiniAppGroup接口或者ProcessAppTemplate抽象类即可。 +将JAR包生成路径配置到ext目录下,此时生成JAR包,点击主程序系统托盘右键的RELOAD选项, +即可看到JAR包中的MiniApp都已经加载完毕了。 + +你可以参考BKPG_DEMO的项目或者直接套用该demo来架构一个项目。 +注意,最后打包时,不应该包含BKPG_PROTOCAL这个依赖,是冗余的,建议排除在外。 + +一个JAR包项目中可以包含多个MiniApp,这些MiniApp如果没有特殊机制劫持, +最后全部会被装载进入到容器之中。 + +如果您开发了自己的工具包,并且认为非常具有价值,你也可以分享自己的JAR包给别人, +或者分享给官方,由我们加入README进行大众分享。 + + + + + diff --git a/ext/ProgressGroup.txt b/ext/ProgressGroup.txt new file mode 100644 index 0000000..a39b65a --- /dev/null +++ b/ext/ProgressGroup.txt @@ -0,0 +1,2 @@ +PING百度: ping www.baidu.com +PING主站: ping www.dreamcenter.top \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..0a588c0 --- /dev/null +++ b/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + + top.dreamcenter + BKPG_PROj + ${revision} + pom + + BKPG_PROj + A tool to manage all self process. + + + BKPG + BKPG_DEMO + PLUGIN_BKPG_GROUP_PROCESS + + + + 1.0-SNAPSHOT + 4.11 + UTF-8 + 8 + 8 + + + + + + junit + junit + ${junit.version} + test + + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.4.2 + + + org.apache.maven.plugins + maven-assembly-plugin + 3.6.0 + + + + + + \ No newline at end of file