diff --git a/src/main/java/cn/wizzer/common/core/Setup.java b/src/main/java/cn/wizzer/common/core/Setup.java index 74013f1a4..9cb5f6fa6 100644 --- a/src/main/java/cn/wizzer/common/core/Setup.java +++ b/src/main/java/cn/wizzer/common/core/Setup.java @@ -27,6 +27,7 @@ import org.nutz.mvc.NutConfig; import org.quartz.Scheduler; +import java.io.File; import java.nio.charset.Charset; import java.util.*; @@ -86,11 +87,18 @@ private void initSysPlugin(NutConfig config, Dao dao) { PluginMaster pluginMaster = config.getIoc().get(PluginMaster.class); List list = dao.query(Sys_plugin.class, Cnd.where("disabled", "=", 0)); for (Sys_plugin sysPlugin : list) { - byte[] buf = Files.readBytes(Globals.AppRoot + sysPlugin.getPath()); - IPlugin plugin = pluginMaster.build(sysPlugin.getClassName(), buf); + String name = sysPlugin.getPath().substring(sysPlugin.getPath().indexOf(".")).toLowerCase(); + File file = new File(Globals.AppRoot + sysPlugin.getPath()); + byte[] buf = Files.readBytes(file); String[] p = new String[]{}; + IPlugin plugin; + if (".jar".equals(name)) { + plugin = pluginMaster.buildFromJar(file, sysPlugin.getClassName(), buf); + } else { + plugin = pluginMaster.build(sysPlugin.getClassName(), buf); + } if (!Strings.isBlank(sysPlugin.getArgs())) { - p = StringUtils.split(sysPlugin.getArgs(), ","); + p = org.apache.commons.lang3.StringUtils.split(sysPlugin.getArgs(), ","); } pluginMaster.register(sysPlugin.getCode(), plugin, p); } diff --git a/src/main/java/cn/wizzer/common/plugin/PluginMaster.java b/src/main/java/cn/wizzer/common/plugin/PluginMaster.java index d80710cf0..aaf155475 100644 --- a/src/main/java/cn/wizzer/common/plugin/PluginMaster.java +++ b/src/main/java/cn/wizzer/common/plugin/PluginMaster.java @@ -1,5 +1,6 @@ package cn.wizzer.common.plugin; +import cn.wizzer.common.base.Globals; import org.nutz.ioc.Ioc; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; @@ -7,15 +8,18 @@ import org.nutz.log.Log; import org.nutz.log.Logs; +import java.io.File; import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; import java.util.*; /** * 实验性插件管理器 - * @author wendal * + * @author wendal */ -@IocBean(depose="depose") +@IocBean(depose = "depose") public class PluginMaster { private static final Log log = Logs.get(); @@ -30,9 +34,10 @@ public class PluginMaster { /** * 注入一个新插件 - * @param key 插件的唯一key + * + * @param key 插件的唯一key * @param plugin 插件对象 - * @param args 需要传递给插件的初始化参数 + * @param args 需要传递给插件的初始化参数 * @return true, 如果成功的话 */ public boolean register(String key, IPlugin plugin, String[] args) { @@ -42,8 +47,7 @@ public boolean register(String key, IPlugin plugin, String[] args) { log.infof("load plugin key=%s class=%s", key, plugin.getClass().getName()); plugins.put(key, plugin); // 放入插件池 return true; - } - catch (Exception e) { + } catch (Exception e) { log.infof("load plugin fail key=%s class=%s", key, plugin.getClass().getName(), e); return false; } @@ -51,8 +55,9 @@ public boolean register(String key, IPlugin plugin, String[] args) { /** * 通过类数据(byte数组)和类名,构建一个插件实例 + * * @param className 类名 - * @param buf 类数据 + * @param buf 类数据 * @return 类实例 */ public IPlugin build(final String className, byte[] buf) { @@ -60,9 +65,19 @@ public IPlugin build(final String className, byte[] buf) { ByteArrayClassLoader c = new ByteArrayClassLoader(); c._defineClass(className, buf, 0, buf.length); return (IPlugin) c.loadClass(className).newInstance(); + } catch (Exception e) { + log.info("load plugin fail name=" + className, e); + throw Lang.wrapThrow(e); } - catch (Exception e) { - log.info("load plugin fail name="+className, e); + } + + @SuppressWarnings("resource") + public IPlugin buildFromJar(final File file, final String className, byte[] buf) { + try { + log.debug(file.getAbsolutePath()); + return (IPlugin) new URLClassLoader(new URL[]{file.toURI().toURL()}, getClass().getClassLoader(), null).loadClass(className).newInstance(); + } catch (Exception e) { + log.info("load plugin fail name=" + className, e); throw Lang.wrapThrow(e); } } @@ -80,6 +95,7 @@ public void depose() { /** * 移除特定的插件 + * * @param key 插件唯一识别 */ public void remove(String key) { @@ -92,6 +108,7 @@ public void remove(String key) { /** * 获取当前插件列表 + * * @return */ public Map getPlugins() { @@ -100,6 +117,7 @@ public Map getPlugins() { /** * 根据一个方法动态获取所需要的插件列表 + * * @param method 正准备被拦截的方法 * @return 插件列表 */ diff --git a/src/main/java/cn/wizzer/modules/controllers/platform/sys/SysPluginController.java b/src/main/java/cn/wizzer/modules/controllers/platform/sys/SysPluginController.java index b6760689b..60d3390b2 100644 --- a/src/main/java/cn/wizzer/modules/controllers/platform/sys/SysPluginController.java +++ b/src/main/java/cn/wizzer/modules/controllers/platform/sys/SysPluginController.java @@ -58,12 +58,19 @@ public Object addDo(@Param("code") String code, @Param("Filedata") TempFile tf, @Param("args") String[] args) throws IOException { try { + String name = tf.getSubmittedFileName().substring(tf.getSubmittedFileName().indexOf(".")).toLowerCase(); byte[] buf = Streams.readBytesAndClose(tf.getInputStream()); - IPlugin plugin = pluginMaster.build(className, buf); - pluginMaster.register(code, plugin, args); String p = Globals.AppRoot; - String f = Globals.AppUploadPath + "/plugin/" + DateUtil.format(new Date(), "yyyyMMdd") + "/" + R.UU32() + tf.getSubmittedFileName().substring(tf.getSubmittedFileName().indexOf(".")); - Files.write(new File(p + f), tf.getInputStream()); + String f = Globals.AppUploadPath + "/plugin/" + DateUtil.format(new Date(), "yyyyMMdd") + "/" + R.UU32() + name; + File file = new File(p + f); + Files.write(f, tf.getInputStream()); + IPlugin plugin; + if (".jar".equals(name)) { + plugin = pluginMaster.buildFromJar(file, className, buf); + } else { + plugin = pluginMaster.build(className, buf); + } + pluginMaster.register(code, plugin, args); Sys_plugin sysPlugin = new Sys_plugin(); sysPlugin.setCode(code); sysPlugin.setClassName(className); @@ -98,9 +105,16 @@ public Object delete(String id) { public Object enable(String id) { try { Sys_plugin sysPlugin = sysPluginService.fetch(id); - byte[] buf = Files.readBytes(Globals.AppRoot + sysPlugin.getPath()); - IPlugin plugin = pluginMaster.build(sysPlugin.getClassName(), buf); + String name = sysPlugin.getPath().substring(sysPlugin.getPath().indexOf(".")).toLowerCase(); + File file = new File(Globals.AppRoot + sysPlugin.getPath()); + byte[] buf = Files.readBytes(file); String[] p = new String[]{}; + IPlugin plugin; + if (".jar".equals(name)) { + plugin = pluginMaster.buildFromJar(file, sysPlugin.getClassName(), buf); + } else { + plugin = pluginMaster.build(sysPlugin.getClassName(), buf); + } if (!Strings.isBlank(sysPlugin.getArgs())) { p = org.apache.commons.lang3.StringUtils.split(sysPlugin.getArgs(), ","); } diff --git a/src/main/resources/config/ioc/upload.json b/src/main/resources/config/ioc/upload.json index 3ac75b67c..300502004 100644 --- a/src/main/resources/config/ioc/upload.json +++ b/src/main/resources/config/ioc/upload.json @@ -32,7 +32,7 @@ var ioc={ // 单个文件最大尺寸(大约的值,单位为字节,即 20971520 为 20M) maxFileSize : 20971520, // 正则表达式匹配可以支持的文件名 - nameFilter : '^(.+[.])(gif|jpg|png|doc|docx|xls|xlsx|rar|zip|7z|flv|swf|mkv|avi|txt|xml|pdf|md|pptx|ppt|flv|swf|mkv|avi|rm|rmvb|wmv|mp4|mov|mpg|mpeg|class)$' + nameFilter : '^(.+[.])(gif|jpg|png|doc|docx|xls|xlsx|rar|zip|7z|flv|swf|mkv|avi|txt|xml|pdf|md|pptx|ppt|flv|swf|mkv|avi|rm|rmvb|wmv|mp4|mov|mpg|mpeg|class|jar)$' } }, fileUpload : { diff --git a/src/main/webapp/WEB-INF/views/platform/sys/plugin/index.html b/src/main/webapp/WEB-INF/views/platform/sys/plugin/index.html index 9f1ffebf9..0535be16b 100644 --- a/src/main/webapp/WEB-INF/views/platform/sys/plugin/index.html +++ b/src/main/webapp/WEB-INF/views/platform/sys/plugin/index.html @@ -181,8 +181,8 @@ 'multi': false, 'width': '100%', 'height': '35', - 'buttonText': '请选择class文件', - 'fileType': '*.class', + 'buttonText': '请选择class或jar文件', + 'fileType': '*.class;*.jar;', 'fileSizeLimit': 1024, 'queueSizeLimit': 1, 'removeCompleted': true,